Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2808

kernel-2.6.18-238.el5.src.rpm

From: John W. Linville <linville@redhat.com>
Date: Tue, 18 Dec 2007 17:44:29 -0500
Subject: [net] iwl4965 updates
Message-id: 20071218224428.GG11328@redhat.com
O-Subject: [RHEL5.2 PATCH 4/4] iwl4965 updates
Bugzilla: 252981

This superbly monstrous patch updates the iwlwifi driver to match
what is in wireless-2.6 as of today.  It specifically addresses the
following bugzillas:

BZ252981
BZ253027
BZ253067
BZ256001

Lot of testing by me on Dell m4300 laptop equipped w/ iwl4965 hardware.

Acked-by: "David S. Miller" <davem@redhat.com>

diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 2a05163..9d6f9d4 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -44,4 +44,5 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
 
-obj-$(CONFIG_IWLWIFI)		+= iwlwifi/
+obj-$(CONFIG_IWL3945)		+= iwlwifi/
+obj-$(CONFIG_IWL4965)		+= iwlwifi/
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 295acf2..93ee596 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,30 +1,72 @@
-config IWLWIFI
-	bool "Intel Wireless WiFi Link Drivers"
+config IWL4965
+	tristate "Intel Wireless WiFi 4965AGN"
 	depends on PCI && MAC80211 && NET_RADIO && EXPERIMENTAL
 	select FW_LOADER
-	default n
 	---help---
-	  Select to enable drivers based on the iwlwifi project.  This 
-	  project provides a common foundation for Intel's wireless 
-	  drivers designed to use the mac80211 subsystem.
-
-	  See <file:Documentation/networking/README.iwlwifi> for 
-	  information on the capabilities currently enabled in this 
-	  driver and for tips for debugging issues and problems.
-
-config IWLWIFI_DEBUG
-	bool "Enable full debugging output in iwlwifi drivers"
-	depends on IWLWIFI
-	default y
+	  Select to build the driver supporting the:
+
+	  Intel Wireless WiFi Link 4965AGN
+
+	  This driver uses the kernel's mac80211 subsystem.
+
+	  See <file:Documentation/networking/README.iwlwifi> for
+	  information on the capabilities currently enabled in this
+	  driver and for tips for debugging any issues or problems.
+
+	  In order to use this driver, you will need a microcode (uCode)
+	  image for it. You can obtain the microcode from:
+
+	          <http://intellinuxwireless.org/>.
+
+	  See the above referenced README.iwlwifi for information on where
+	  to install the microcode images.
+
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and remvoed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
+	  module will be called iwl4965.ko.
+
+config IWL4965_QOS
+	bool "Enable Wireless QoS in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable wireless quality of service (QoS) for the
+	  iw4965 driver.
+
+config IWL4965_HT
+	bool "Enable 802.11n HT features in iwl4965 driver"
+	depends on EXPERIMENTAL
+	depends on IWL4965 && IWL4965_QOS
+	depends on n
+	---help---
+	  This option enables IEEE 802.11n High Throughput features
+	  for the iwl4965 driver.
+
+config IWL4965_SPECTRUM_MEASUREMENT
+	bool "Enable Spectrum Measurement in iw4965 driver"
+	depends on IWL4965
 	---help---
-	  This option will enable debug tracing output for the iwlwifi 
-	  drivers.  
+	  This option will enable spectrum measurement for the iwl4965 driver.
 
-	  This will result in the kernel module being ~100k larger.  You can 
-	  control which debug output is sent to the kernel log by setting the 
-	  value in 
+config IWL4965_SENSITIVITY
+	bool "Enable Sensitivity Calibration in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable sensitivity calibration for the iwl4965
+	  driver.
+
+config IWL4965_DEBUG
+	bool "Enable full debugging output in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable debug tracing output for the iwl4965
+	  driver.
+
+	  This will result in the kernel module being ~100k larger.  You can
+	  control which debug output is sent to the kernel log by setting the
+	  value in
 
-	  	/sys/bus/pci/drivers/${DRIVER}/debug_level
+	          /sys/bus/pci/drivers/${DRIVER}/debug_level
 
 	  This entry will only exist if this option is enabled.
 
@@ -33,64 +75,76 @@ config IWLWIFI_DEBUG
 		  % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
 
 	  You can find the list of debug mask values in:
-		  drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h
+		  drivers/net/wireless/iwlwifi/iwl-4965-debug.h
 
 	  If this is your first time using this driver, you should say Y here
 	  as the debug information can assist others in helping you resolve
 	  any problems you may encounter.
 
-config IWL4965
-	tristate "Intel Wireless WiFi 4965AGN"
-	depends on m && IWLWIFI && EXPERIMENTAL
-	default m
+config IWL3945
+	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+	depends on PCI && MAC80211 && NET_RADIO && EXPERIMENTAL
+	select FW_LOADER
 	---help---
 	  Select to build the driver supporting the:
 
-	  Intel Wireless WiFi Link 4965AGN
+	  Intel PRO/Wireless 3945ABG/BG Network Connection
 
 	  This driver uses the kernel's mac80211 subsystem.
 
-	  See <file:Documentation/networking/README.iwlwifi> for 
-	  information on the capabilities currently enabled in this 
+	  See <file:Documentation/networking/README.iwlwifi> for
+	  information on the capabilities currently enabled in this
 	  driver and for tips for debugging any issues or problems.
 
 	  In order to use this driver, you will need a microcode (uCode)
 	  image for it. You can obtain the microcode from:
 
-	  	<http://intellinuxwireless.org/>.  
+	          <http://intellinuxwireless.org/>.
 
-	  See the above referenced README.iwlwifi for information on where 
+	  See the above referenced README.iwlwifi for information on where
 	  to install the microcode images.
 
 	  If you want to compile the driver as a module ( = code which can be
 	  inserted in and remvoed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/modules.txt>.  The module
-	  will be called iwl4965.ko.
+	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
+	  module will be called iwl3945.ko.
 
-config IWL3945
-	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
-	depends on m && IWLWIFI && EXPERIMENTAL
-	default m
+config IWL3945_QOS
+	bool "Enable Wireless QoS in iwl3945 driver"
+	depends on IWL3945
 	---help---
-	  Select to build the driver supporting the:
+	  This option will enable wireless quality of service (QoS) for the
+	  iwl3945 driver.
 
-	  Intel PRO/Wireless 3945ABG/BG Network Connection
+config IWL3945_SPECTRUM_MEASUREMENT
+	bool "Enable Spectrum Measurement in iwl3945 drivers"
+	depends on IWL3945
+	---help---
+	  This option will enable spectrum measurement for the iwl3945 driver.
 
-	  This driver uses the kernel's mac80211 subsystem.
+config IWL3945_DEBUG
+	bool "Enable full debugging output in iwl3945 driver"
+	depends on IWL3945
+	---help---
+	  This option will enable debug tracing output for the iwl3945
+	  driver.
 
-	  See <file:Documentation/networking/README.iwlwifi> for 
-	  information on the capabilities currently enabled in this 
-	  driver and for tips for debugging any issues or problems.
+	  This will result in the kernel module being ~100k larger.  You can
+	  control which debug output is sent to the kernel log by setting the
+	  value in
 
-	  In order to use this driver, you will need a microcode (uCode)
-	  image for it. You can obtain the microcode from:
+	          /sys/bus/pci/drivers/${DRIVER}/debug_level
 
-	  	<http://intellinuxwireless.org/>.  
+	  This entry will only exist if this option is enabled.
 
-	  See the above referenced README.iwlwifi for information on where 
-	  to install the microcode images.
+	  To set a value, simply echo an 8-byte hex value to the same file:
+
+		  % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+	  You can find the list of debug mask values in:
+		  drivers/net/wireless/iwlwifi/iwl-3945-debug.h
+
+	  If this is your first time using this driver, you should say Y here
+	  as the debug information can assist others in helping you resolve
+	  any problems you may encounter.
 
-	  If you want to compile the driver as a module ( = code which can be
-	  inserted in and remvoed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/modules.txt>.  The module
-	  will be called iwl3945.ko.
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 8c0bdc7..3bbd383 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,29 +1,5 @@
-# NOTE:  We use common code from base.c to build driver
-# specific binaries based on the #define IWL -- the target
-# setup below creates a specific driver target from base.c
-#
-# NOTE2: base-XXXX.o has -D"KBUILD_MODNAME=KBUILD_STR(...)" in order to 
-# prevent the following kbuild error:
-# 	include/linux/pci.h:603: error: `KBUILD_MODNAME' undeclared (first \
-#		use in this function)
-#
-# -jpk
-
 obj-$(CONFIG_IWL3945)	+= iwl3945.o
-iwl3945-objs		= base-3945.o iwl-3945.o iwl-3945-rs.o
-CFLAGS_iwl-3945.o	= -DIWL=3945
-CFLAGS_iwl-3945-rs.o	= -DIWL=3945
-CFLAGS_base-3945.o	= -DIWL=3945 -D"KBUILD_MODNAME=KBUILD_STR(iwl3945)"
-$(obj)/base-3945.o: $(src)/base.c FORCE
-	$(call cmd,force_checksrc)
-	$(call if_changed_rule,cc_o_c)
+iwl3945-objs		= iwl3945-base.o iwl-3945.o iwl-3945-rs.o
 
 obj-$(CONFIG_IWL4965)	+= iwl4965.o
-iwl4965-objs		= base-4965.o iwl-4965.o iwl-4965-rs.o
-CFLAGS_iwl-4965.o	= -DIWL=4965
-CFLAGS_iwl-4965-rs.o	= -DIWL=4965
-CFLAGS_base-4965.o	= -DIWL=4965 -D"KBUILD_MODNAME=KBUILD_STR(iwl4965)"
-$(obj)/base-4965.o: $(src)/base.c FORCE
-	$(call cmd,force_checksrc)
-	$(call if_changed_rule,cc_o_c)
-
+iwl4965-objs		= iwl4965-base.o iwl-4965.o iwl-4965-rs.o
diff --git a/drivers/net/wireless/iwlwifi/base.c b/drivers/net/wireless/iwlwifi/base.c
index 4f7fe12..e69de29 100644
--- a/drivers/net/wireless/iwlwifi/base.c
+++ b/drivers/net/wireless/iwlwifi/base.c
@@ -1,9046 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-/*
- * NOTE:  This file (base.c) is used to build to multiple hardware targets
- * by defining IWL to either 3945 or 4965.  The Makefile used when building
- * the base targets will create base-3945.o and base-4965.o
- *
- * The eventual goal is to move as many of the #if IWL / #endif blocks out of
- * this file and into the hardware specific implementation files (iwl-XXXX.c)
- * and leave only the common (non #ifdef sprinkled) code in this file
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <linux/firmware.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-
-#include <net/ieee80211_radiotap.h>
-#include <net/mac80211.h>
-
-#include <asm/div64.h>
-
-#include "iwlwifi.h"
-#include "iwl-helpers.h"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-u32 iwl_debug_level;
-#endif
-
-/******************************************************************************
- *
- * module boiler plate
- *
- ******************************************************************************/
-
-/* module parameters */
-int param_disable_hw_scan = 0;
-int param_debug = 0;
-int param_disable = 0;      /* def: enable radio */
-int param_antenna = 0;      /* def: 0 = both antennas (use diversity) */
-int param_hwcrypto = 0;     /* def: using software encryption */
-int param_qos_enable = 0;
-
-/*
- * module name, copyright, version, etc.
- * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
- */
-
-#if IWL == 3945
-#define DRV_DESCRIPTION	\
-"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
-#elif IWL == 4965
-#define DRV_DESCRIPTION	\
-"Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
-#else
-BUILD_BUG()
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENY
-#define VS "s"
-#else
-#define VS
-#endif
-
-#define IWLWIFI_VERSION "1.0.0k" VD VS
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
-#define DRV_VERSION     IWLWIFI_VERSION
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
- * DMA services
- *
- * Theory of operation
- *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The IPW operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
- *
- * The four transmit queues allow for performing quality of service (qos)
- * transmissions as per the 802.11 protocol.  Currently Linux does not
- * provide a mechanism to the user for utilizing prioritized queues, so
- * we only utilize the first data transmit queue (queue1).
- ***************************************************/
-
-static int iwl_queue_space(const struct iwl_queue *q)
-{
-	int s = q->last_used - q->first_empty;
-	if (q->last_used > q->first_empty)
-		s -= q->n_bd;
-
-	if (s <= 0)
-		s += q->n_window;
-	/* keep some reserve to not confuse empty and full situations */
-	s -= 2;
-	if (s < 0)
-		s = 0;
-	return s;
-}
-
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
-{
-	return (++index == n_bd) ? 0 : index;
-}
-
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
-{
-	return (index == 0) ? n_bd - 1 : index - 1;
-}
-
-static inline int x2_queue_used(const struct iwl_queue *q, int i)
-{
-	return q->first_empty > q->last_used ?
-	    (i >= q->last_used && i < q->first_empty) :
-	    !(i < q->last_used && i >= q->first_empty);
-}
-
-static inline u8 get_next_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
-{
-	if (is_huge)
-		return q->n_window;
-
-	return (u8) (index % q->n_window);
-}
-
-static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
-			  int count, int size, u32 id)
-{
-	q->n_bd = count;
-	q->n_window = size;
-	q->id = id;
-
-	q->low_mark = q->n_window / 4;
-	if (q->low_mark < 4)
-		q->low_mark = 4;
-
-	q->high_mark = q->n_window / 8;
-	if (q->high_mark < 2)
-		q->high_mark = 2;
-
-	q->first_empty = q->last_used = 0;
-
-	return 0;
-}
-
-static int iwl_tx_queue_alloc(struct iwl_priv *priv,
-			      struct iwl_tx_queue *txq, int count, u32 id)
-{
-	struct pci_dev *dev = priv->pci_dev;
-
-	if (id != IWL_CMD_QUEUE_NUM) {
-		txq->txb = kmalloc(sizeof(txq->txb[0]) *
-				   TFD_QUEUE_SIZE_MAX, GFP_ATOMIC);
-		if (!txq->txb) {
-			IWL_ERROR("kmalloc for auxilary BD "
-				  "structures failed\n");
-			goto error;
-		}
-	} else
-		txq->txb = NULL;
-
-	txq->bd = pci_alloc_consistent(dev,
-			sizeof(struct iwl_tfd_frame) * TFD_QUEUE_SIZE_MAX,
-			&txq->q.dma_addr);
-
-	txq->q.element_size = sizeof(struct iwl_tfd_frame);
-	if (!txq->bd) {
-		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
-			  sizeof(txq->bd[0]) * count);
-		goto error;
-	}
-	txq->q.id = id;
-
-	return 0;
-
- error:
-	if (txq->txb) {
-		kfree(txq->txb);
-		txq->txb = NULL;
-	}
-
-	return -ENOMEM;
-}
-
-int iwl_tx_queue_init(struct iwl_priv *priv,
-		      struct iwl_tx_queue *txq, int count, u32 txq_id)
-{
-	struct pci_dev *dev = priv->pci_dev;
-	int len;
-	int rc = 0;
-
-	/* alocate command space + one big command for scan since scan
-	 * command is very huge the system will not have two scan at the
-	 * same time */
-	len = sizeof(struct iwl_cmd) * count;
-	if (txq_id == IWL_CMD_QUEUE_NUM);
-		len +=  IWL_MAX_SCAN_SIZE;
-	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
-	if (!txq->cmd)
-		return -ENOMEM;
-
-	rc = iwl_tx_queue_alloc(priv, txq, count, txq_id);
-	if (rc) {
-		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
-		return -ENOMEM;
-	}
-
-	txq->need_update = 0;
-	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, count, txq_id);
-	iwl_hw_tx_queue_init(priv, txq);
-
-	return 0;
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.  txq itself is not freed.
- *
- */
-void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
-{
-	struct iwl_queue *q = &txq->q;
-	struct pci_dev *dev = priv->pci_dev;
-	int len;
-
-	if (q->n_bd == 0)
-		return;
-
-	/* first, empty all BD's */
-	for (; q->first_empty != q->last_used;
-	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
-		iwl_hw_tx_queue_free_tfd(priv, txq);
-	}
-
-	len = sizeof(txq->cmd[0]) * q->n_window;
-	if (q->id == IWL_CMD_QUEUE_NUM);
-                len +=  IWL_MAX_SCAN_SIZE;
-	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
-	/* free buffers belonging to queue itself */
-	if (txq->q.n_bd)
-		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
-				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
-
-	if (txq->txb) {
-		kfree(txq->txb);
-		txq->txb = NULL;
-	}
-
-	/* 0 fill whole structure */
-	memset(txq, 0, sizeof(*txq));
-}
-
-const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-/*************** STATION TABLE MANAGEMENT ****
- *
- * NOTE:  This needs to be overhauled to better synchronize between
- * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
- *
- * mac80211 should also be examined to determine if sta_info is duplicating
- * the functionality provided here
- */
-
-/**************************************************************/
-
-static u8 iwl_remove_station(struct iwl_priv *priv, const u8 * bssid, int is_ap)
-{
-	int index = IWL_INVALID_STATION;
-	int i;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	if (is_ap) {
-		index = IWL_AP_ID;
-		if ((priv->stations[index].used))
-			priv->stations[index].used = 0;
-	} else if (is_broadcast_ether_addr(bssid)) {
-		index = IWL_BROADCAST_ID;
-		if ((priv->stations[index].used))
-			priv->stations[index].used = 0;
-	} else
-		for (i = IWL_STA_ID; i < priv->num_stations + IWL_STA_ID; i++) {
-			if (priv->stations[i].used &&
-			    !compare_ether_addr(
-				    priv->stations[i].sta.sta.addr, bssid)) {
-				index = i;
-				priv->stations[index].used = 0;
-				break;
-			}
-		}
-
-	if (index != IWL_INVALID_STATION) {
-		if (priv->num_stations > 0)
-			priv->num_stations--;
-	}
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-	return 0;
-}
-
-static void iwl_clear_stations_table(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	priv->num_stations = 0;
-	memset(priv->stations, 0,
-	       IWL_STATION_COUNT * sizeof(struct iwl_station_entry));
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-
-u8 iwl_add_station(struct iwl_priv *priv, const u8 * bssid, int is_ap, u8 flags)
-{
-	int i = IWL_STATION_COUNT;
-	int index = IWL_INVALID_STATION;
-	struct iwl_station_entry *station;
-	unsigned long flags_spin;
-
-	spin_lock_irqsave(&priv->sta_lock, flags_spin);
-	if (is_ap) {
-		index = IWL_AP_ID;
-		if (priv->stations[index].used &&
-		    !compare_ether_addr(priv->stations[index].sta.sta.addr,
-					bssid))
-			goto done;
-	} else if (is_broadcast_ether_addr(bssid)) {
-		index = IWL_BROADCAST_ID;
-		if (priv->stations[index].used &&
-		    !compare_ether_addr(priv->stations[index].sta.sta.addr,
-					bssid))
-			goto done;
-	} else
-		for (i = IWL_STA_ID; i < priv->num_stations + IWL_STA_ID; i++) {
-			if (priv->stations[i].used &&
-			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
-						bssid))
-				goto done;
-
-			if (!priv->stations[i].used &&
-			    index == IWL_INVALID_STATION)
-				index = i;
-		}
-
-	if (index != IWL_INVALID_STATION)
-		i = index;
-
-	if (i == IWL_STATION_COUNT) {
-		index = IWL_INVALID_STATION;
-		goto done;
-	}
-
-	IWL_DEBUG_ASSOC("Adding STA ID %d: " MAC_FMT "\n", i, MAC_ARG(bssid));
-	station = &priv->stations[i];
-
-	station->used = 1;
-	station->current_rate.s.rate = IWL_RATE_1M_PLCP;
-	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
-	memcpy(station->sta.sta.addr, bssid, ETH_ALEN);
-	station->sta.mode = 0;
-	station->sta.sta.sta_id = i;
-	station->sta.station_flags = 0;
-
-	/* todoG do we need this
-	 * all TID's disabled
-	 *  priv->stations[i].sta.tid_disable_tx = 0xffff;
-	 */
-	if ((priv->phymode == MODE_IEEE80211A) ||
-	    (priv->phymode == MODE_ATHEROS_TURBO))
-		station->sta.tx_rate.rate_n_flags = IWL_RATE_6M_PLCP;
-	else
-		station->sta.tx_rate.rate_n_flags = IWL_RATE_1M_PLCP |
-						    priv->hw_setting.cck_flag;
-
-	/* Turn on both antennas for the station... */
-	station->sta.tx_rate.rate_n_flags |= RATE_MCS_ANT_AB_MSK;
-
-	/*
-	 * priv->stations[i].sta.tx_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
-	 * priv->stations[i].sta.tx_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
-	 */
-
-	station->sta.station_flags |= STA_MODIFY_TX_RATE_MSK;
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	if (is_ap) {
-		iwl4965_set_ht_add_station(priv, i, 0);
-		iwl4965_set_rxon_chain(priv);
-	}
-#endif /*CONFIG_IWLWIFI_HT*/
-#endif
-	station->current_rate.rate_n_flags = station->sta.tx_rate.rate_n_flags;
-
-	priv->num_stations++;
-	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-	iwl_send_add_station(priv, &station->sta, flags);
-	return i;
-
- done:
-	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-	return index;
-}
-
-/* iwl_hw_find_station is implemented in iwl-3945 and iwl-4965 for now... */
-
-u8 iwl_sync_station(struct iwl_priv * priv, int sta_id, u16 tx_rate, u8 flags)
-{
-	unsigned long flags_spin;
-	struct iwl_station_entry *station;
-
-	if (sta_id == IWL_INVALID_STATION)
-		return IWL_INVALID_STATION;
-
-	spin_lock_irqsave(&priv->sta_lock, flags_spin);
-	station = &priv->stations[sta_id];
-
-	station->sta.sta.modify_mask = STA_CONTROL_MODIFY_MSK;
-	station->sta.tx_rate.rate_n_flags = tx_rate;
-	station->current_rate.rate_n_flags = tx_rate;
-	station->sta.mode = STA_CONTROL_MODIFY_MSK;
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
-	iwl_send_add_station(priv, &station->sta, flags);
-	IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
-			sta_id, tx_rate);
-	return sta_id;
-}
-
-/*************** DRIVER STATUS FUNCTIONS   *****/
-
-static inline int iwl_is_ready(struct iwl_priv *priv)
-{
-	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
-	 * set but EXIT_PENDING is not */
-	return ((priv->status & (STATUS_READY |
-				 STATUS_GEO_CONFIGURED |
-				 STATUS_EXIT_PENDING)) ==
-		(STATUS_READY | STATUS_GEO_CONFIGURED)) ? 1 : 0;
-}
-
-static inline int iwl_is_alive(struct iwl_priv *priv)
-{
-	return (priv->status & STATUS_ALIVE) ? 1 : 0;
-}
-
-static inline int iwl_is_init(struct iwl_priv *priv)
-{
-	return (priv->status & STATUS_INIT) ? 1 : 0;
-}
-
-static inline int iwl_is_ready_rf(struct iwl_priv *priv)
-{
-
-	if (priv->status & STATUS_RF_KILL_MASK)
-		return 0;
-
-	return iwl_is_ready(priv);
-}
-
-/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
-
-#define IWL_CMD(x) case x : return #x
-
-static const char *get_cmd_string(u8 cmd)
-{
-	switch (cmd) {
-		IWL_CMD(SCAN_START_NOTIFICATION);
-		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
-		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
-		IWL_CMD(STATISTICS_NOTIFICATION);
-		IWL_CMD(REPLY_ALIVE);
-		IWL_CMD(REPLY_ERROR);
-		IWL_CMD(REPLY_RXON_ASSOC);
-		IWL_CMD(REPLY_RXON);
-		IWL_CMD(REPLY_QOS_PARAM);
-		IWL_CMD(REPLY_RXON_TIMING);
-		IWL_CMD(REPLY_ADD_STA);
-		IWL_CMD(REPLY_TX);
-		IWL_CMD(REPLY_BCON);
-		IWL_CMD(REPLY_RATE_SCALE);
-		IWL_CMD(REPLY_LEDS_CMD);
-		IWL_CMD(REPLY_SCAN_ABORT_CMD);
-		IWL_CMD(REPLY_TX_BEACON);
-		IWL_CMD(REPLY_BT_CONFIG);
-		IWL_CMD(REPLY_SCAN_CMD);
-		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
-		IWL_CMD(REPLY_STATISTICS_CMD);
-		IWL_CMD(REPLY_CARD_STATE_CMD);
-		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
-#if IWL == 3945
-		IWL_CMD(REPLY_3945_RX);
-#elif IWL == 4965
-		IWL_CMD(MISSED_BEACONS_NOTIFICATION_TH_CMD);
-		IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
-		IWL_CMD(SENSITIVITY_CMD);
-		IWL_CMD(REPLY_RX_MPDU_CMD);
-		IWL_CMD(REPLY_RX_PHY_CMD);
-		IWL_CMD(REPLY_4965_RX);
-#endif
-	case POWER_TABLE_CMD:
-		return "POWER_TABLE_CMD";
-	default:
-		return "UNKNOWN";
-
-	}
-}
-
-#define HOST_COMPLETE_TIMEOUT (HZ / 2)
-
-static inline int is_cmd_sync(struct iwl_host_cmd *cmd)
-{
-	return !(cmd->meta.flags & CMD_ASYNC);
-}
-
-static inline int is_cmd_small(struct iwl_host_cmd *cmd)
-{
-	return !(cmd->meta.flags & CMD_SIZE_HUGE);
-}
-
-static inline int cmd_needs_lock(struct iwl_host_cmd *cmd)
-{
-	return !(cmd->meta.flags & CMD_NO_LOCK);
-}
-
-static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
-	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
-	struct iwl_queue *q = &txq->q;
-	u8 *tfd;
-	u32 *control_flags;
-	struct iwl_cmd *out_cmd;
-	u32 idx = 0;
-	u16 fix_size = (u16) (cmd->meta.len + sizeof(out_cmd->hdr));
-	dma_addr_t phys_addr;
-#if IWL == 3945
-	int pad;
-	u16 count;
-#elif IWL == 4965
-	int rc;
-#endif
-
-	/* If any of the command structures end up being larger than
-	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
-	 * we will need to increase the size of the TFD entries */
-	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE)
-	       && is_cmd_small(cmd));
-	if (iwl_queue_space(q) < (is_cmd_sync(cmd) ? 1 : 2)) {
-		IWL_ERROR("No space for Tx\n");
-		return -ENOSPC;
-	}
-	tfd = &txq->bd[q->first_empty * q->element_size];
-	memset(tfd, 0, q->element_size);
-
-	control_flags = (u32 *) tfd;
-
-	idx = get_next_cmd_index(q, q->first_empty,
-				 cmd->meta.flags & CMD_SIZE_HUGE);
-	out_cmd = &txq->cmd[idx];
-
-	out_cmd->hdr.cmd = cmd->id;
-	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
-	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->meta.len);
-
-	/* At this point, the out_cmd now has all of the incoming cmd
-	 * information */
-
-	out_cmd->hdr.flags = 0;
-	out_cmd->hdr.sequence = QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
-	    INDEX_TO_SEQ(q->first_empty);
-	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
-		out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
-
-	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
-	    offsetof(struct iwl_cmd, hdr);
-	iwl_hw_tx_queue_attach_buffer_to_tfd(priv, tfd, phys_addr, fix_size);
-
-#if IWL == 3945
-	pad = U32_PAD(out_cmd->meta.len);
-	count = TFD_CTL_COUNT_GET(*control_flags);
-	*control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);
-#endif
-
-	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
-		     "%d bytes at %d[%d]:%d\n",
-		     get_cmd_string(out_cmd->hdr.cmd),
-		     out_cmd->hdr.cmd, out_cmd->hdr.sequence,
-		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
-
-	txq->need_update = 1;
-#if IWL == 4965
-	rc = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	iwl_tx_queue_update_write_ptr(priv, txq);
-	return rc;
-#elif IWL == 3945
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-
-	return iwl_tx_queue_update_write_ptr(priv, txq);
-#endif
-}
-
-int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
-	int rc;
-	unsigned long flags = 0;
-
-	/* If this is an asynchronous command, and we are in a shutdown
-	 * process then don't let it start */
-	if (!is_cmd_sync(cmd) && (priv->status & STATUS_EXIT_PENDING))
-		return -EBUSY;
-
-	/*
-	 * The following checks are meant to catch programming API misuse
-	 * and not run-time failures due to timing, resource constraint, etc.
-	 */
-
-	/* A command can not be asynchronous AND expect an SKB to be set */
-	if ((cmd->meta.flags & CMD_ASYNC) && (cmd->meta.flags & CMD_WANT_SKB)) {
-		IWL_ERROR("ASYNC && WANT_SKB\n");
-		return -EINVAL;
-	}
-
-	/* The skb/callback union must be NULL if an SKB is requested */
-	if (cmd->meta.u.skb && (cmd->meta.flags & CMD_WANT_SKB)) {
-		IWL_ERROR("skb != null && WANT_SKB\n");
-		return -EINVAL;
-	}
-
-	/* A command can not be synchronous AND have a callback set */
-	if (is_cmd_sync(cmd) && cmd->meta.u.callback) {
-		IWL_ERROR("callback != null && SYNC\n");
-		return -EINVAL;
-	}
-
-	/* An asynchronous command MUST have a callback */
-	if ((cmd->meta.flags & CMD_ASYNC) && !cmd->meta.u.callback) {
-		IWL_ERROR("callback == null && ASYNC\n");
-		return -EINVAL;
-	}
-
-	/* A command can not be synchronous AND not use locks */
-	if (is_cmd_sync(cmd) && (cmd->meta.flags & CMD_NO_LOCK)) {
-		IWL_ERROR("SYNC && NO_LOCK\n");
-		return -EINVAL;
-	}
-
-	if (cmd_needs_lock(cmd))
-		spin_lock_irqsave(&priv->lock, flags);
-
-	if (is_cmd_sync(cmd) && (priv->status & STATUS_HCMD_ACTIVE)) {
-		IWL_ERROR("Error sending %s: "
-			  "Already sending a host command\n",
-			  get_cmd_string(cmd->id));
-		if (cmd_needs_lock(cmd))
-			spin_unlock_irqrestore(&priv->lock, flags);
-		return -EBUSY;
-	}
-
-	if (is_cmd_sync(cmd))
-		priv->status |= STATUS_HCMD_ACTIVE;
-
-	/* When the SKB is provided in the tasklet, it needs
-	 * a backpointer to the originating caller so it can
-	 * actually copy the skb there */
-	if (cmd->meta.flags & CMD_WANT_SKB) {
-		cmd->meta.source = &cmd->meta;
-		cmd->meta.magic = CMD_VAR_MAGIC;
-	}
-
-	cmd->meta.len = cmd->len;
-
-	rc = iwl_enqueue_hcmd(priv, cmd);
-	if (rc) {
-		if (is_cmd_sync(cmd))
-			priv->status &= ~STATUS_HCMD_ACTIVE;
-		if (cmd_needs_lock(cmd))
-			spin_unlock_irqrestore(&priv->lock, flags);
-
-		IWL_ERROR("Error sending %s: "
-			  "iwl_queue_tx_hcmd failed: %d\n",
-			  get_cmd_string(cmd->id), rc);
-
-		return -ENOSPC;
-	}
-	if (cmd_needs_lock(cmd))
-		spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (is_cmd_sync(cmd)) {
-		rc = wait_event_interruptible_timeout(priv->wait_command_queue,
-						      !(priv->status &
-							STATUS_HCMD_ACTIVE),
-						      HOST_COMPLETE_TIMEOUT);
-		if (rc == 0) {
-			if (cmd_needs_lock(cmd))
-				spin_lock_irqsave(&priv->lock, flags);
-
-			if (priv->status & STATUS_HCMD_ACTIVE) {
-				IWL_ERROR("Error sending %s: "
-					  "time out after %dms.\n",
-					  get_cmd_string(cmd->id),
-					  jiffies_to_msecs
-					  (HOST_COMPLETE_TIMEOUT));
-				priv->status &= ~STATUS_HCMD_ACTIVE;
-				if ((cmd->meta.flags & CMD_WANT_SKB)
-				    && cmd->meta.u.skb) {
-					dev_kfree_skb_any(cmd->meta.u.skb);
-					cmd->meta.u.skb = NULL;
-				}
-
-				if (cmd_needs_lock(cmd))
-					spin_unlock_irqrestore(
-						&priv->lock, flags);
-				cmd->meta.magic = 0;
-				return -ETIMEDOUT;
-			}
-
-			if (cmd_needs_lock(cmd))
-				spin_unlock_irqrestore(&priv->lock, flags);
-		}
-	}
-
-	if (priv->status & STATUS_RF_KILL_HW) {
-		if ((cmd->meta.flags & CMD_WANT_SKB)
-		    && cmd->meta.u.skb) {
-			dev_kfree_skb_any(cmd->meta.u.skb);
-			cmd->meta.u.skb = NULL;
-		}
-
-		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
-			       get_cmd_string(cmd->id));
-
-		return -ECANCELED;
-	}
-
-	if (priv->status & STATUS_FW_ERROR) {
-		if ((cmd->meta.flags & CMD_WANT_SKB)
-		    && cmd->meta.u.skb) {
-			dev_kfree_skb_any(cmd->meta.u.skb);
-			cmd->meta.u.skb = NULL;
-		}
-
-		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
-			       get_cmd_string(cmd->id));
-
-		return -EIO;
-	}
-
-	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
-		IWL_ERROR("Error: Response NULL in '%s'\n",
-			  get_cmd_string(cmd->id));
-		return -EIO;
-	}
-
-	return 0;
-}
-
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
-{
-	struct iwl_host_cmd cmd = {
-		.id = id,
-		.len = len,
-		.data = data,
-	};
-
-	return iwl_send_cmd(priv, &cmd);
-}
-
-static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
-{
-	struct iwl_host_cmd cmd = {
-		.id = id,
-		.len = sizeof(val),
-		.data = &val,
-	};
-
-	return iwl_send_cmd(priv, &cmd);
-}
-
-int iwl_send_statistics_request(struct iwl_priv *priv)
-{
-	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
-}
-
-/**
- * iwl_rxon_add_station - add station into station table.
- *
- * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling the this fnction
-*/
-static int iwl_rxon_add_station(struct iwl_priv *priv,
-				const u8 * addr, int is_ap)
-{
-	u8 i;
-
-	/* Remove this station if it happens to already exist */
-	iwl_remove_station(priv, addr, is_ap);
-
-	i = iwl_add_station(priv, addr, is_ap, 0);
-
-	iwl4965_add_station(priv, addr, is_ap);
-
-	return i;
-}
-
-/**
- * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
- * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
- * @channel: Any channel valid for the requested phymode
-
- * In addition to setting the staging RXON, priv->phymode is also set.
- *
- * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
- * in the staging RXON flag structure based on the phymode
- */
-static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u8 channel)
-{
-	if (!iwl_get_channel_info(priv, phymode, channel)) {
-		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
-			       channel, phymode);
-		return -EINVAL;
-	}
-
-	if ((priv->staging_rxon.channel == channel) &&
-	    (priv->phymode == phymode))
-		return 0;
-
-	priv->staging_rxon.channel = channel;
-	if ((phymode == MODE_IEEE80211A) ||
-	    (phymode == MODE_ATHEROS_TURBO))
-		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
-	else
-		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
-
-	priv->phymode = phymode;
-
-	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
-
-	return 0;
-}
-
-/**
- * iwl_check_rxon_cmd - validate RXON structure is valid
- *
- * NOTE:  This is really only useful during development and can eventually
- * be #ifdef'd out once the driver is stable and folks aren't actively
- * making changes
- */
-static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
-{
-	int error = 0;
-	int counter = 1;
-
-	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
-		error |= (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK);
-		error |= (rxon->flags & RXON_FLG_RADAR_DETECT_MSK);
-		if (error)
-			IWL_WARNING("check 24G fields %d | %d\n",
-				    counter++, error);
-	} else {
-		error |= ((rxon->flags & RXON_FLG_SHORT_SLOT_MSK) !=
-			  RXON_FLG_SHORT_SLOT_MSK);
-		if (error)
-			IWL_WARNING("check 52 fields %d | %d\n",
-				    counter++, error);
-		error |= (rxon->flags & RXON_FLG_CCK_MSK);
-		if (error)
-			IWL_WARNING("check 52 CCK %d | %d\n",
-				    counter++, error);
-
-	}
-	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
-	if (error)
-		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
-
-	/* make sure basic rates 6Mbps and 1Mbps are supported */
-	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
-		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
-	if (error)
-		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
-
-	error |= (rxon->assoc_id > 2007);
-	if (error)
-		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
-
-	error |= ((rxon->flags &
-		   (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) ==
-		  (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
-	if (error)
-		IWL_WARNING("check CCK and short slot %d | %d\n",
-			    counter++, error);
-
-	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
-		  == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
-	if (error)
-		IWL_WARNING("check CCK & auto detect %d | %d\n",
-			    counter++, error);
-
-	error |= ((rxon->flags &
-		   (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) ==
-		  RXON_FLG_TGG_PROTECT_MSK);
-	if (error)
-		IWL_WARNING("check TGG %d | %d\n", counter++, error);
-
-#if IWL == 3945
-	if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
-		error |= ((rxon->flags &
-			   (RXON_FLG_ANT_B_MSK | RXON_FLG_ANT_A_MSK)) == 0);
-	if (error)
-		IWL_WARNING("check antenna %d %d\n", counter++, error);
-#endif
-
-	if (error)
-		IWL_WARNING("Tuning to channel %d\n",
-			    le16_to_cpu(rxon->channel));
-
-	if (error) {
-		IWL_ERROR
-		    ("Error not a valid iwl_rxon_assoc_cmd field values\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/**
- * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
- * @priv: staging_rxon is comapred to active_rxon
- *
- * If the RXON structure is changing sufficient to require a new
- * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
- * to indicate a new tune is required.
- */
-static int iwl_full_rxon_required(struct iwl_priv *priv)
-{
-
-	/* These items are only settable from the full RXON command */
-	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
-	    compare_ether_addr(priv->staging_rxon.bssid_addr,
-			       priv->active_rxon.bssid_addr) ||
-	    compare_ether_addr(priv->staging_rxon.node_addr,
-			       priv->active_rxon.node_addr) ||
-	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
-			       priv->active_rxon.wlap_bssid_addr) ||
-	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
-	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
-	    (priv->staging_rxon.air_propagation !=
-	     priv->active_rxon.air_propagation) ||
-#if IWL == 4965
-	    (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
-	     priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
-	    (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
-	     priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
-	    (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
-#endif
-	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
-		return 1;
-
-	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
-	 * be updated with the RXON_ASSOC command -- however only some
-	 * flag transitions are allowed using RXON_ASSOC */
-
-	/* Check if we are not switching bands */
-	if (iwl_check_bits(priv->staging_rxon.flags, RXON_FLG_BAND_24G_MSK) !=
-	    iwl_check_bits(priv->active_rxon.flags, RXON_FLG_BAND_24G_MSK))
-		return 1;
-
-	/* Check if we are switching association toggle */
-	if (iwl_check_bits(priv->staging_rxon.filter_flags,
-			   RXON_FILTER_ASSOC_MSK) !=
-	    iwl_check_bits(priv->active_rxon.filter_flags,
-			   RXON_FILTER_ASSOC_MSK))
-		return 1;
-
-	return 0;
-}
-
-static int iwl_send_rxon_assoc(struct iwl_priv *priv)
-{
-	int rc = 0;
-	struct iwl_rx_packet *res = NULL;
-	struct iwl_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 iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-	const struct iwl_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) &&
-#if IWL == 4965
-	    (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) &&
-#endif
-	    (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;
-#if IWL == 4965
-	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;
-#endif
-
-	rc = iwl_send_cmd(priv, &cmd);
-	if (rc)
-		return rc;
-
-	res = (struct iwl_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;
-}
-
-/**
- * iwl_commit_rxon - commit staging_rxon to hardware
- *
- * The RXON command in staging_rxon is commited to the hardware and
- * the active_rxon structure is updated with the new data.  This
- * function correctly transitions out of the RXON_ASSOC_MSK state if
- * a HW tune is required based on the RXON structure changes.
- */
-static int iwl_commit_rxon(struct iwl_priv *priv)
-{
-	/* cast away the const for active_rxon in this function */
-	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
-	int rc = 0;
-
-	if (!iwl_is_alive(priv))
-		return -1;
-
-	/* always get timestamp with Rx frame */
-	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
-
-#if IWL == 3945
-	/* select antenna */
-	priv->staging_rxon.flags &=
-	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
-	priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
-#endif
-
-	rc = iwl_check_rxon_cmd(&priv->staging_rxon);
-	if (rc) {
-		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
-		return -EINVAL;
-	}
-
-	/* If we don't need to send a full RXON, we can use
-	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
-	 * and other flags for the current radio configuration. */
-	if (!iwl_full_rxon_required(priv)) {
-		rc = iwl_send_rxon_assoc(priv);
-		if (rc) {
-			IWL_ERROR("Error setting RXON_ASSOC "
-				  "configuration (%d).\n", rc);
-			return rc;
-		}
-
-		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-
-		return 0;
-	}
-
-	/* station table will be caleared */
-	priv->assoc_station_added = 0;
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-	if (!priv->error_recovering)
-		priv->start_calib = 0;
-
-	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
-#endif /* IWL == 4965 */
-
-	/* If we are currently associated and the new config requires
-	 * an RXON_ASSOC and the new config wants the associated mask enabled,
-	 * we must clear the associated from the active configuration
-	 * before we apply the new config */
-	if (iwl_is_associated(priv) &&
-	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
-		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
-		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-		rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-				      sizeof(struct iwl_rxon_cmd),
-				      &priv->active_rxon);
-
-		/* If the mask clearing failed then we set
-		 * active_rxon back to what it was previously */
-		if (rc) {
-			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
-			IWL_ERROR("Error clearing ASSOC_MSK on current "
-				  "configuration (%d).\n", rc);
-			return rc;
-		}
-
-		/* The RXON bit toggling will have cleared out the
-		 * station table in the uCode, so blank it in the driver
-		 * as well */
-		iwl_clear_stations_table(priv);
-	} else if (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) {
-		/* When switching from non-associated to associated, the
-		 * uCode clears out the station table; so clear it in the
-		 * driver as well */
-		iwl_clear_stations_table(priv);
-	}
-
-	IWL_DEBUG_INFO("Sending RXON\n"
-		       "* with%s RXON_FILTER_ASSOC_MSK\n"
-		       "* channel = %d\n"
-		       "* bssid = " MAC_FMT "\n",
-		       ((priv->staging_rxon.filter_flags &
-			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
-		       priv->staging_rxon.channel,
-		       MAC_ARG(priv->staging_rxon.bssid_addr));
-
-	/* Apply the new configuration */
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
-	if (rc) {
-		IWL_ERROR("Error setting new configuration (%d).\n", rc);
-		return rc;
-	}
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	if (!priv->error_recovering)
-		priv->start_calib = 0;
-
-	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
-#endif /* IWL == 4965 */
-
-	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
-
-	/* If we issue a new RXON command which required a tune then we must
-	 * send a new TXPOWER command or we won't be able to Tx any frames */
-	rc = iwl_hw_reg_send_txpower(priv);
-	if (rc) {
-		IWL_ERROR("Error setting Tx power (%d).\n", rc);
-		return rc;
-	}
-
-	/* Add the broadcast address so we can send broadcast frames */
-	if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) ==
-	    IWL_INVALID_STATION) {
-		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
-		return -EIO;
-	}
-
-	/* If we have set the ASSOC_MSK and we are in BSS mode then
-	 * add the IWL_AP_ID to the station rate table */
-	if (iwl_is_associated(priv) &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-		if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
-		    == IWL_INVALID_STATION) {
-			IWL_ERROR("Error adding AP address for transmit.\n");
-			return -EIO;
-		}
-		priv->assoc_station_added = 1;
-	}
-
-	/* Init the hardware's rate fallback order based on the
-	 * phymode */
-	rc = iwl3945_init_hw_rate_table(priv);
-	if (rc) {
-		IWL_ERROR("Error setting HW rate table: %02X\n", rc);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int iwl_send_bt_config(struct iwl_priv *priv)
-{
-	struct iwl_bt_cmd bt_cmd = {
-		.flags = 3,
-		.lead_time = 0xAA,
-		.max_kill = 1,
-		.kill_ack_mask = 0,
-		.kill_cts_mask = 0,
-	};
-
-	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-				sizeof(struct iwl_bt_cmd), &bt_cmd);
-}
-
-static int iwl_send_scan_abort(struct iwl_priv *priv)
-{
-	int rc = 0;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SCAN_ABORT_CMD,
-		.meta.flags = CMD_WANT_SKB,
-	};
-
-	/* If there isn't a scan actively going on in the hardware
-	 * then we are in between scan bands and not actually
-	 * actively scanning, so don't send the abort command */
-	if (!(priv->status & STATUS_SCAN_HW)) {
-		priv->status &= ~STATUS_SCAN_ABORTING;
-		return 0;
-	}
-
-	rc = iwl_send_cmd(priv, &cmd);
-	if (rc) {
-		priv->status &= ~STATUS_SCAN_ABORTING;
-		return rc;
-	}
-
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-	if (res->u.status != CAN_ABORT_STATUS) {
-		/* The scan abort will return 1 for success or
-		 * 2 for "failure".  A failure condition can be
-		 * due to simply not being in an active scan which
-		 * can occur if we send the scan abort before we
-		 * the microcode has notified us that a scan is
-		 * completed. */
-		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
-		priv->status &= ~(STATUS_SCAN_ABORTING | STATUS_SCAN_HW);
-	}
-
-	dev_kfree_skb_any(cmd.meta.u.skb);
-
-	return rc;
-}
-
-static int iwl_card_state_sync_callback(struct iwl_priv *priv,
-					struct iwl_cmd *cmd,
-					struct sk_buff *skb)
-{
-	return 1;
-}
-
-/*
- * CARD_STATE_CMD
- *
- * Use: Sets the internal card state to enable, disable, or halt
- *
- * When in the 'enable' state the card operates as normal.
- * When in the 'disable' state, the card enters into a low power mode.
- * When in the 'halt' state, the card is shut down and must be fully
- * restarted to come back on.
- */
-static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
-{
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_CARD_STATE_CMD,
-		.len = sizeof(u32),
-		.data = &flags,
-		.meta.flags = meta_flag,
-	};
-
-	if (meta_flag & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_card_state_sync_callback;
-
-	return iwl_send_cmd(priv, &cmd);
-}
-
-static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
-				     struct iwl_cmd *cmd, struct sk_buff *skb)
-{
-	struct iwl_rx_packet *res = NULL;
-
-	if (!skb) {
-		IWL_ERROR("Error: Response NULL in " "REPLY_ADD_STA.\n");
-		return 1;
-	}
-
-	res = (struct iwl_rx_packet *)skb->data;
-	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
-			  res->hdr.flags);
-		return 1;
-	}
-
-	switch (res->u.add_sta.status) {
-	case ADD_STA_SUCCESS_MSK:
-		break;
-	default:
-		break;
-	}
-
-	/* We didn't cache the SKB; let the caller free it */
-	return 1;
-}
-
-int iwl_send_add_station(struct iwl_priv *priv,
-			 struct iwl_addsta_cmd *sta, u8 flags)
-{
-	struct iwl_rx_packet *res = NULL;
-	int rc = 0;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_ADD_STA,
-		.len = sizeof(struct iwl_addsta_cmd),
-		.meta.flags = flags,
-		.data = sta,
-	};
-
-	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_add_sta_sync_callback;
-	else
-		cmd.meta.flags |= CMD_WANT_SKB;
-
-	rc = iwl_send_cmd(priv, &cmd);
-
-	if (rc || (flags & CMD_ASYNC))
-		return rc;
-
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
-			  res->hdr.flags);
-		rc = -EIO;
-	}
-
-	if (rc == 0) {
-		switch (res->u.add_sta.status) {
-		case ADD_STA_SUCCESS_MSK:
-			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
-			break;
-		default:
-			rc = -EIO;
-			IWL_WARNING("REPLY_ADD_STA failed\n");
-			break;
-		}
-	}
-
-	priv->alloc_rxb_skb--;
-	dev_kfree_skb_any(cmd.meta.u.skb);
-
-	return rc;
-}
-
-static int iwl_update_sta_key_info(struct iwl_priv *priv,
-				   struct ieee80211_key_conf *keyconf,
-				   u8 sta_id)
-{
-	unsigned long flags;
-	u16 key_flags = 0;
-
-	switch (keyconf->alg) {
-	case ALG_CCMP:
-		key_flags |= STA_KEY_FLG_CCMP;
-		key_flags |= keyconf->keyidx << STA_KEY_FLG_KEYID_POS;
-		key_flags &= ~STA_KEY_FLG_INVALID;
-		break;
-	case ALG_TKIP:
-	case ALG_WEP:
-		return -EINVAL;
-	default:
-		return -EINVAL;
-	}
-	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_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");
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
-	return 0;
-}
-
-static void iwl_clear_free_frames(struct iwl_priv *priv)
-{
-	struct list_head *element;
-
-	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
-		       priv->frames_count);
-
-	while (!list_empty(&priv->free_frames)) {
-		element = priv->free_frames.next;
-		list_del(element);
-		kfree(list_entry(element, struct iwl_frame, list));
-		priv->frames_count--;
-	}
-
-	if (priv->frames_count) {
-		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
-			    priv->frames_count);
-		priv->frames_count = 0;
-	}
-}
-
-static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
-{
-	struct iwl_frame *frame;
-	struct list_head *element;
-	if (list_empty(&priv->free_frames)) {
-		frame = kzalloc(sizeof(*frame), GFP_ATOMIC);
-		if (!frame) {
-			IWL_ERROR("Could not allocate frame!\n");
-			return NULL;
-		}
-
-		priv->frames_count++;
-		return frame;
-	}
-
-	element = priv->free_frames.next;
-	list_del(element);
-	return list_entry(element, struct iwl_frame, list);
-}
-
-static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
-{
-	memset(frame, 0, sizeof(*frame));
-	list_add(&frame->list, &priv->free_frames);
-}
-
-int iwl_fill_beacon_frame(struct iwl_priv *priv,
-			  struct ieee80211_hdr *hdr, const u8 * dest, int left)
-{
-
-	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
-	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
-	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
-		return 0;
-
-	if (priv->ibss_beacon->len > left)
-		return 0;
-
-	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
-
-	return priv->ibss_beacon->len;
-}
-
-static int iwl_send_beacon_cmd(struct iwl_priv *priv)
-{
-	struct iwl_frame *frame;
-	int frame_size, rc;
-	u16 rate;
-
-	frame = iwl_get_free_frame(priv);
-
-	if (!frame) {
-		IWL_ERROR("Coult not obtain free frame buffer for beacon "
-			  "command.\n");
-		return -ENOMEM;
-	}
-
-	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
-						0xFF0);
-		if (rate <= 0)
-			rate = IWL_RATE_6M_PLCP;
-	} else {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
-		if (rate <= 0)
-			rate = IWL_RATE_1M_PLCP;
-	}
-
-	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
-
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
-			      &frame->u.cmd[0]);
-
-	iwl_free_frame(priv, frame);
-
-	return rc;
-}
-
-/******************************************************************************
- *
- * EEPROM related functions
- *
- ******************************************************************************/
-
-static void get_eeprom_mac(struct iwl_priv *priv, u8 * mac)
-{
-	memcpy(mac, priv->eeprom.mac_address, 6);
-}
-
-/**
- * iwl_eeprom_init - read EEPROM contents
- *
- * Load the EEPROM from adapter into priv->eeprom
- *
- * NOTE:  This routine uses the non-debug IO access functions.
- */
-int iwl_eeprom_init(struct iwl_priv *priv)
-{
-	u16 *e = (u16 *) & priv->eeprom;
-	u32 r;
-	int to;
-	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
-	u16 sz = sizeof(priv->eeprom);
-	int rc;
-	u16 addr;
-
-	/* The EEPROM structure has several padding buffers within it
-	 * and when adding new EEPROM maps is subject to programmer errors
-	 * which may be very difficult to identify without explicitly
-	 * checking the resulting size of the eeprom map. */
-	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
-
-	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
-		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
-		return -ENOENT;
-	}
-#if IWL == 3945
-	_iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_OWNER);
-#endif
-
-	for (addr = 0, r = 0; addr < sz; addr += 2) {
-		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
-		_iwl_clear_bit(priv, CSR_EEPROM_REG, 0x00000002);
-		rc = _iwl_grab_restricted_access(priv);
-		if (rc)
-			return rc;
-
-		for (to = 0; to < 10; to++) {
-			r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
-			if (r & 1)
-				break;
-			udelay(5);
-		}
-
-		_iwl_release_restricted_access(priv);
-
-		if (!(r & 1)) {
-			IWL_ERROR("Time out reading EEPROM[%d]", addr);
-			return -ETIMEDOUT;
-		}
-
-		e[addr / 2] = le16_to_cpu(r >> 16);
-	}
-
-	return 0;
-}
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/**
- * iwl_report_frame - dump frame to syslog during debug sessions
- *
- * hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- *
- * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
- *        info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
- *        is 3945-specific and gives bad output for 4965.  Need to split the
- *        functionality, keep common stuff here.
- */
-void iwl_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
-		      struct ieee80211_hdr *header, int group100)
-{
-	u32 to_us;
-	u32 print_summary = 0;
-	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
-	u32 hundred = 0;
-	u32 dataframe = 0;
-
-	/* these are declared without "=" to avoid compiler warnings if we
-	 *   don't use them in the debug messages below */
-	u16 frame_ctl;
-	u16 seq_ctl;
-	u16 channel;
-	u16 phy_flags;
-	int rate_sym;
-	u16 length;
-	u16 status;
-	u16 bcn_tmr;
-	u32 tsf_low;
-	u64 tsf;
-	u8 rssi;
-	u8 agc;
-	u16 sig_avg;
-	u16 noise_diff;
-
-	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
-	u8 *data = IWL_RX_DATA(pkt);
-
-	/* MAC header */
-	frame_ctl = le16_to_cpu(header->frame_control);
-	seq_ctl = le16_to_cpu(header->seq_ctrl);
-
-	/* metadata */
-	channel = le16_to_cpu(rx_hdr->channel);
-	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
-	rate_sym = rx_hdr->rate;
-	length = le16_to_cpu(rx_hdr->len);
-
-	/* end-of-frame status and timestamp */
-	status = le32_to_cpu(rx_end->status);
-	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
-	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
-	tsf = le64_to_cpu(rx_end->timestamp);
-
-	/* signal statistics */
-	rssi = rx_stats->rssi;
-	agc = rx_stats->agc;
-	sig_avg = le16_to_cpu(rx_stats->sig_avg);
-	noise_diff = le16_to_cpu(rx_stats->noise_diff);
-
-	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
-	/* if data frame is to us and all is good,
-	 *   (optionally) print summary for only 1 out of every 100 */
-	if (to_us && (frame_ctl & ~IEEE80211_FCTL_PROTECTED) ==
-	    (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
-		dataframe = 1;
-		if (!group100) {
-			print_summary = 1;	/* print each frame */
-		} else if (priv->framecnt_to_us < 100) {
-			priv->framecnt_to_us++;
-			print_summary = 0;
-		} else {
-			priv->framecnt_to_us = 0;
-			print_summary = 1;
-			hundred = 1;
-		}
-	} else {
-		/* print summary for all other frames */
-		print_summary = 1;
-	}
-
-	if (print_summary) {
-		char *title;
-		u32 rate;
-
-		if (hundred)
-			title = "100Frames";
-		else if (frame_ctl & IEEE80211_FCTL_RETRY)
-			title = "Retry";
-		else if (ieee80211_is_assoc_response(frame_ctl))
-			title = "AscRsp";
-		else if (ieee80211_is_reassoc_response(frame_ctl))
-			title = "RasRsp";
-		else if (ieee80211_is_probe_response(frame_ctl)) {
-			title = "PrbRsp";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_beacon(frame_ctl)) {
-			title = "Beacon";
-			print_dump = 1;	/* dump frame contents */
-		} else if (ieee80211_is_atim(frame_ctl))
-			title = "ATIM";
-		else if (ieee80211_is_auth(frame_ctl))
-			title = "Auth";
-		else if (ieee80211_is_deauth(frame_ctl))
-			title = "DeAuth";
-		else if (ieee80211_is_disassoc(frame_ctl))
-			title = "DisAssoc";
-		else
-			title = "Frame";
-
-		rate = iwl_rate_index_from_plcp(rate_sym);
-		if (rate == -1)
-			rate = 0;
-		else
-			rate = iwl_rates[rate].ieee / 2;
-
-		/* print frame summary.
-		 * MAC addresses show just the last byte (for brevity),
-		 *    but you can hack it to show more, if you'd like to. */
-		if (dataframe) {
-			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
-				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
-				     title, frame_ctl, header->addr1[5],
-				     length, rssi, channel, rate);
-		} else {
-			/* src/dst addresses assume managed mode */
-			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
-				     "src=0x%02x, rssi=%u, tim=%lu usec, "
-				     "phy=0x%02x, chnl=%d\n",
-				     title, frame_ctl, header->addr1[5],
-				     header->addr3[5], rssi,
-				     tsf_low - priv->scan_start_tsf,
-				     phy_flags, channel);
-		}
-	}
-	if (print_dump)
-		printk_buf(IWL_DL_RX, data, length);
-}
-#endif
-
-static void iwl_unset_hw_setting(struct iwl_priv *priv)
-{
-	if (priv->hw_setting.shared_virt)
-		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct iwl_shared),
-				    priv->hw_setting.shared_virt,
-				    priv->hw_setting.shared_phys);
-}
-
-/**
- * iwl_supported_rate_to_ie - fill in the supported rate in IE field
- *
- * return : set the bit for each supported rate insert in ie
- */
-static u16 iwl_supported_rate_to_ie(u8 * ie, u16 supported_rate,
-				    u16 basic_rate, int max_count)
-{
-	u16 ret_rates = 0, bit;
-	int i;
-	u8 *rates;
-
-	rates = &(ie[1]);
-
-	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
-		if (bit & supported_rate) {
-			ret_rates |= bit;
-			rates[*ie] = iwl_rates[i].ieee |
-			    ((bit & basic_rate) ? 0x80 : 0x00);
-			*ie = *ie + 1;
-			if (*ie >= max_count)
-				break;
-		}
-	}
-
-	return ret_rates;
-}
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-void static d_get_ht_capab (struct ieee80211_hw *hw,
-		     struct ieee80211_ht_capability *ht_cap_param);
-#endif
-#endif
-
-/**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
- */
-static int iwl_fill_probe_req(struct iwl_priv *priv,
-			      struct ieee80211_mgmt *frame,
-			      int left, int is_direct)
-{
-	int len = 0;
-	u8 *pos = NULL;
-	u16 ret_rates;
-
-	/* Make sure there is enough space for the probe request,
-	 * two mandatory IEs and the data */
-	left -= 24;
-	if (left < 0)
-		return 0;
-	len += 24;
-
-	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-	memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
-	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
-	memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
-	frame->seq_ctrl = 0;
-
-	/* fill in our indirect SSID IE */
-	/* ...next IE... */
-
-	left -= 2;
-	if (left < 0)
-		return 0;
-	len += 2;
-	pos = &(frame->u.probe_req.variable[0]);
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = 0;
-
-	/* fill in our direct SSID IE... */
-	if (is_direct) {
-		/* ...next IE... */
-		left -= 2 + priv->essid_len;
-		if (left < 0)
-			return 0;
-		/* ... fill it in... */
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = priv->essid_len;
-		memcpy(pos, priv->essid, priv->essid_len);
-		pos += priv->essid_len;
-		len += 2 + priv->essid_len;
-	}
-
-	/* fill in supported rate */
-	/* ...next IE... */
-	left -= 2;
-	if (left < 0)
-		return 0;
-	/* ... fill it in... */
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos = 0;
-	ret_rates = priv->active_rate = priv->rates_mask;
-	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
-
-	iwl_supported_rate_to_ie(pos, priv->active_rate,
-				 priv->active_rate_basic, left);
-	len += 2 + *pos;
-	pos += (*pos) + 1;
-	ret_rates = ~ret_rates & priv->active_rate;
-
-	if (ret_rates == 0)
-		goto fill_end;
-
-	/* fill in supported extended rate */
-	/* ...next IE... */
-	left -= 2;
-	if (left < 0)
-		return 0;
-	/* ... fill it in... */
-	*pos++ = WLAN_EID_EXT_SUPP_RATES;
-	*pos = 0;
-	iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left);
-	if (*pos > 0)
-		len += 2 + *pos;
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	if (is_direct && priv->is_ht_enabled) {
-		pos += (*pos) + 1;
-		*pos++ = WLAN_EID_HT_CAPABILITY;
-		*pos++ = sizeof(struct ieee80211_ht_capability);
-		d_get_ht_capab(NULL, (struct ieee80211_ht_capability *)pos);
-		len += 2 + sizeof(struct ieee80211_ht_capability);
-	}
-#endif  /*CONFIG_IWLWIFI_HT */
-#endif
-
- fill_end:
-	return len;
-}
-
-/*
- * Power management (not Tx power!) functions
- */
-#define MSEC_TO_USEC 1024
-
-#if IWL == 3945
-#define NOSLP 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK
-#elif IWL == 4965
-#define NOSLP 0, 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#endif
-
-/* default power management (not Tx power) table values */
-/* for tim  0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
-	{{NOSLP, 0 * MSEC_TO_USEC, 0 * MSEC_TO_USEC, {0, 0, 0, 0, 0}}, 0},
-	{{SLP, 200 * MSEC_TO_USEC, 500 * MSEC_TO_USEC, {1, 2, 3, 4, 4}}, 0},
-	{{SLP, 200 * MSEC_TO_USEC, 300 * MSEC_TO_USEC, {2, 4, 6, 7, 7}}, 0},
-	{{SLP, 50 * MSEC_TO_USEC, 100 * MSEC_TO_USEC, {2, 6, 9, 9, 10}}, 0},
-	{{SLP, 50 * MSEC_TO_USEC, 25 * MSEC_TO_USEC, {2, 7, 9, 9, 10}}, 1},
-	{{SLP, 25 * MSEC_TO_USEC, 25 * MSEC_TO_USEC, {4, 7, 10, 10, 10}}, 1}
-};
-
-/* for tim > 10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
-	{{NOSLP, 0 * MSEC_TO_USEC, 0 * MSEC_TO_USEC, {0, 0, 0, 0, 0}}, 0},
-	{{SLP, 200 * MSEC_TO_USEC, 500 * MSEC_TO_USEC, {1, 2, 3, 4, 0xFF}}, 0},
-	{{SLP, 200 * MSEC_TO_USEC, 300 * MSEC_TO_USEC, {2, 4, 6, 7, 0xFF}}, 0},
-	{{SLP, 50 * MSEC_TO_USEC, 100 * MSEC_TO_USEC, {2, 6, 9, 9, 0xFF}}, 0},
-	{{SLP, 50 * MSEC_TO_USEC, 25 * MSEC_TO_USEC, {2, 7, 9, 9, 0xFF}}, 0},
-	{{SLP, 25 * MSEC_TO_USEC, 25 * MSEC_TO_USEC, {4, 7, 10, 10, 0xFF}}, 0}
-};
-
-int iwl_power_init_handle(struct iwl_priv *priv)
-{
-	int rc = 0, i;
-	struct iwl_power_mgr *pow_data;
-	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
-	u16 pci_pm;
-
-	IWL_DEBUG_POWER("Initialize power \n");
-
-	pow_data = &(priv->power_data);
-
-	memset(pow_data, 0, sizeof(*pow_data));
-
-	pow_data->active_index = IWL_POWER_RANGE_0;
-	pow_data->dtim_val = 0xffff;
-
-	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
-	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
-
-	rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
-	if (rc != 0)
-		return 0;
-	else {
-		struct iwl_powertable_cmd *cmd;
-
-		IWL_DEBUG_POWER("adjust power command flags\n");
-
-		for (i = 0; i < IWL_POWER_AC; i++) {
-			cmd = &pow_data->pwr_range_0[i].cmd;
-
-			if (pci_pm & 0x1)
-				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
-			else
-				cmd->flags |= IWL_POWER_PCI_PM_MSK;
-		}
-	}
-	return rc;
-}
-
-static int iwl_update_power_cmd(struct iwl_priv *priv,
-				struct iwl_powertable_cmd *cmd, u32 mode)
-{
-	int rc = 0, i;
-	u8 skip;
-	u32 max_sleep = 0;
-	struct iwl_power_vec_entry *range;
-	u8 period = 0;
-	struct iwl_power_mgr *pow_data;
-
-	if (mode > IWL_POWER_INDEX_5) {
-		IWL_DEBUG_POWER("Error invalid power mode \n");
-		return -1;
-	}
-	pow_data = &(priv->power_data);
-
-	if (pow_data->active_index == IWL_POWER_RANGE_0)
-		range = &pow_data->pwr_range_0[0];
-	else
-		range = &pow_data->pwr_range_1[1];
-
-	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
-
-#ifdef IWL_MAC80211_DISABLE
-	if (priv->assoc_network != NULL) {
-		unsigned long flags;
-
-		period = priv->assoc_network->tim.tim_period;
-	}
-#endif				/*IWL_MAC80211_DISABLE */
-	skip = range[mode].no_dtim;
-
-	if (period == 0) {
-		period = 1;
-		skip = 0;
-	}
-
-	if (skip == 0) {
-		max_sleep = period;
-		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
-	} else {
-		max_sleep = (cmd->sleep_interval[IWL_POWER_TABLE_SIZE - 1] /
-			     period) * period;
-		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
-	}
-
-	for (i = 0; i < IWL_POWER_TABLE_SIZE; i++) {
-		if (cmd->sleep_interval[i] > max_sleep)
-			cmd->sleep_interval[i] = max_sleep;
-	}
-
-	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
-	IWL_DEBUG_POWER("Tx timeout = %u\n", cmd->tx_data_timeout);
-	IWL_DEBUG_POWER("Rx timeout = %u\n", cmd->rx_data_timeout);
-	IWL_DEBUG_POWER
-	    ("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
-	     cmd->sleep_interval[0], cmd->sleep_interval[1],
-	     cmd->sleep_interval[2], cmd->sleep_interval[3],
-	     cmd->sleep_interval[4]);
-
-	return rc;
-}
-
-static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
-{
-	u32 final_mode = mode;
-	int rc;
-	unsigned long flags;
-	struct iwl_powertable_cmd cmd;
-
-	/* If on battery, set to 3,
-	 * if plugged into AC power, set to CAM ("continuosly aware mode"),
-	 * else user level */
-	switch (mode) {
-	case IWL_POWER_BATTERY:
-		final_mode = IWL_POWER_INDEX_3;
-		break;
-	case IWL_POWER_AC:
-		final_mode = IWL_POWER_MODE_CAM;
-		break;
-	default:
-		final_mode = mode;
-		break;
-	}
-
-#if IWL == 4965
-	cmd.keep_alive_beacons = 0;
-#endif
-
-	iwl_update_power_cmd(priv, &cmd, final_mode);
-
-	rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (final_mode == IWL_POWER_MODE_CAM) {
-		priv->status &= ~STATUS_POWER_PMI;
-	} else {
-		priv->status |= STATUS_POWER_PMI;
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-	return rc;
-}
-
-int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
-{
-	/* Filter incoming packets to determine if they are targeted toward
-	 * this network, discarding packets coming from ourselves */
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
-		/* packets from our adapter are dropped (echo) */
-		if (!compare_ether_addr(header->addr2, priv->mac_addr))
-			return 0;
-		/* {broad,multi}cast packets to our IBSS go through */
-		if (is_multicast_ether_addr(header->addr1))
-			return !compare_ether_addr(header->addr3, priv->bssid);
-		/* packets to our adapter go through */
-		return !compare_ether_addr(header->addr1, priv->mac_addr);
-	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
-		/* packets from our adapter are dropped (echo) */
-		if (!compare_ether_addr(header->addr3, priv->mac_addr))
-			return 0;
-		/* {broad,multi}cast packets to our BSS go through */
-		if (is_multicast_ether_addr(header->addr1))
-			return !compare_ether_addr(header->addr2, priv->bssid);
-		/* packets to our adapter go through */
-		return !compare_ether_addr(header->addr1, priv->mac_addr);
-	}
-
-	return 1;
-}
-
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-
-const char *iwl_get_tx_fail_reason(u32 status)
-{
-	switch (status & TX_STATUS_MSK) {
-	case TX_STATUS_SUCCESS:
-		return "SUCCESS";
-		TX_STATUS_ENTRY(SHORT_LIMIT);
-		TX_STATUS_ENTRY(LONG_LIMIT);
-		TX_STATUS_ENTRY(FIFO_UNDERRUN);
-		TX_STATUS_ENTRY(MGMNT_ABORT);
-		TX_STATUS_ENTRY(NEXT_FRAG);
-		TX_STATUS_ENTRY(LIFE_EXPIRE);
-		TX_STATUS_ENTRY(DEST_PS);
-		TX_STATUS_ENTRY(ABORTED);
-		TX_STATUS_ENTRY(BT_RETRY);
-		TX_STATUS_ENTRY(STA_INVALID);
-		TX_STATUS_ENTRY(FRAG_DROPPED);
-		TX_STATUS_ENTRY(TID_DISABLE);
-		TX_STATUS_ENTRY(FRAME_FLUSHED);
-		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
-		TX_STATUS_ENTRY(TX_LOCKED);
-		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
-	}
-
-	return "UNKNOWN";
-}
-
-/**
- * iwl_scan_cancel - Cancel any currently executing HW scan
- * @ms: amount of time to wait (in milliseconds) for scan to abort
- *
- * NOTE: priv->mutex must be held before calling this function
- */
-static int iwl_scan_cancel(struct iwl_priv *priv, unsigned long ms)
-{
-	unsigned long now = jiffies;
-
-	if (!(priv->status & STATUS_SCAN_HW)) {
-		priv->status &= ~STATUS_SCANNING;
-		return 0;
-	}
-
-	if (priv->status & STATUS_SCAN_PENDING) {
-		IWL_DEBUG_SCAN("Canceling pending scan request.\n");
-		priv->status &= ~STATUS_SCAN_PENDING;
-	}
-
-	if (priv->status & STATUS_SCANNING) {
-		if (!(priv->status & STATUS_SCAN_ABORTING)) {
-			IWL_DEBUG_SCAN("Queuing scan abort.\n");
-			priv->status |= STATUS_SCAN_ABORTING;
-			queue_work(priv->workqueue, &priv->abort_scan);
-
-		} else {
-			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
-		}
-
-		mutex_unlock(&priv->mutex);
-		if (ms)
-			while (!time_after(jiffies,
-					   now + msecs_to_jiffies(ms)) &&
-			       priv->status & STATUS_SCANNING)
-				msleep(1);
-
-		mutex_lock(&priv->mutex);
-	}
-
-	return (priv->status & STATUS_SCANNING);
-}
-
-static void iwl_sequence_reset(struct iwl_priv *priv)
-{
-	/* Reset ieee stats */
-
-	/* We don't reset the net_device_stats (ieee->stats) on
-	 * re-association */
-
-	priv->last_seq_num = -1;
-	priv->last_frag_num = -1;
-	priv->last_packet_time = 0;
-
-	iwl_scan_cancel(priv, 0);
-}
-
-#if IWL == 4965
-#define MAX_UCODE_BEACON_INTERVAL	4096
-#else
-#define MAX_UCODE_BEACON_INTERVAL	1024
-#endif
-#define INTEL_CONN_LISTEN_INTERVAL	0xA
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
-	u16 new_val = 0;
-	u16 beacon_factor = 0;
-
-	beacon_factor =
-	    (beacon_val +
-	     MAX_UCODE_BEACON_INTERVAL) / MAX_UCODE_BEACON_INTERVAL;
-	new_val = beacon_val / beacon_factor;
-
-	return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
-	u64 interval_tm_unit;
-	u64 tsf, result;
-	unsigned long flags;
-	struct ieee80211_conf *conf = NULL;
-	u16 beacon_int = 0;
-
-	conf = ieee80211_get_hw_conf(priv->hw);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->rxon_timing.timestamp.dw[1] = priv->timestamp1;
-	priv->rxon_timing.timestamp.dw[0] = priv->timestamp0;
-
-	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
-	tsf = priv->timestamp1;
-	tsf = ((tsf << 32) | priv->timestamp0);
-
-	beacon_int = priv->beacon_int;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
-		if (beacon_int == 0) {
-			priv->rxon_timing.beacon_interval = 100;
-			priv->rxon_timing.beacon_init_val = 102400;
-		} else {
-			priv->rxon_timing.beacon_interval = beacon_int;
-			priv->rxon_timing.beacon_interval =
-			    iwl_adjust_beacon_interval(
-				    priv->rxon_timing.beacon_interval);
-		}
-
-		priv->rxon_timing.atim_window = 0;
-	} else {
-		priv->rxon_timing.beacon_interval =
-			iwl_adjust_beacon_interval(conf->beacon_int);
-		/* TODO: we need to get atim_window from upper stack
-		 * for now we set to 0 */
-		priv->rxon_timing.atim_window = 0;
-	}
-
-	interval_tm_unit = (priv->rxon_timing.beacon_interval * 1024);
-	result = do_div(tsf, interval_tm_unit);
-	priv->rxon_timing.beacon_init_val =
-	    (u32) ((u64) interval_tm_unit - result);
-
-	IWL_DEBUG_ASSOC
-	    ("beacon interval %d beacon timer %d beacon tim %d\n",
-	     priv->rxon_timing.beacon_interval,
-	     priv->rxon_timing.beacon_init_val, priv->rxon_timing.atim_window);
-}
-
-static int iwl_scan_initiate(struct iwl_priv *priv)
-{
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-		IWL_ERROR("APs don't scan.\n");
-		return 0;
-	}
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
-		return -EIO;
-	}
-
-	if (priv->status & STATUS_SCANNING) {
-		IWL_DEBUG_SCAN("Scan already in progress.\n");
-		return -EAGAIN;
-	}
-
-	if (priv->status & STATUS_SCAN_ABORTING) {
-		IWL_DEBUG_SCAN("Scan request while abort pending.  "
-			       "Queuing.\n");
-		return -EAGAIN;
-	}
-
-	IWL_DEBUG_INFO("Starting scan...\n");
-	priv->scan_bands = 2;
-	priv->status |= STATUS_SCANNING;
-	priv->scan_start = jiffies;
-	priv->scan_pass_start = priv->scan_start;
-
-	queue_work(priv->workqueue, &priv->request_scan);
-
-	return 0;
-}
-
-static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
-{
-	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
-
-	if (hw_decrypt)
-		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
-	else
-		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
-
-	return 0;
-}
-
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
-{
-	if ((phymode == MODE_IEEE80211A) ||
-	    (phymode == MODE_ATHEROS_TURBO)) {
-		priv->staging_rxon.flags &=
-		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
-		      | RXON_FLG_CCK_MSK);
-		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
-	} else {
-		/* Copied from iwl_bg_post_associate() */
-		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
-			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
-		else
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
-		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
-		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
-	}
-}
-
-/*
- * initilize rxon structure with default values fromm eeprom
- */
-static void iwl_connection_init_rx_config(struct iwl_priv *priv)
-{
-	const struct iwl_channel_info *ch_info;
-
-	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
-
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_AP:
-		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
-		break;
-
-	case IEEE80211_IF_TYPE_STA:
-		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
-		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
-		break;
-
-	case IEEE80211_IF_TYPE_IBSS:
-		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
-		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
-		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
-						  RXON_FILTER_ACCEPT_GRP_MSK;
-		break;
-
-	case IEEE80211_IF_TYPE_MNTR:
-		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
-		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
-		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
-		break;
-	}
-
-#if 0
-	/* TODO:  Figure out when short_preamble would be set and cache from
-	 * that */
-	if (!hw_to_local(priv->hw)->short_preamble)
-		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-	else
-		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-#endif
-
-	ch_info = iwl_get_channel_info(priv, priv->phymode,
-				       priv->staging_rxon.channel);
-
-	if (!ch_info)
-		ch_info = &priv->channel_info[0];
-
-	/*
-	 * in some case A channels are all non IBSS
-	 * in this case force B/G channel
-	 */
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-	    !(is_channel_ibss(ch_info)))
-		ch_info = &priv->channel_info[0];
-
-	priv->staging_rxon.channel = ch_info->channel;
-	if (is_channel_a_band(ch_info))
-		priv->phymode = MODE_IEEE80211A;
-	else
-		priv->phymode = MODE_IEEE80211G;
-
-	iwl_set_flags_for_phymode(priv, priv->phymode);
-
-	priv->staging_rxon.ofdm_basic_rates =
-	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-	priv->staging_rxon.cck_basic_rates =
-	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
-
-#if IWL == 4965
-	priv->staging_rxon.flags |= RXON_FLG_CHANNEL_MODE_LEGACY_MSK;
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
-	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
-	priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
-	iwl4965_set_rxon_chain(priv);
-#endif
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, int mode)
-{
-	if (!iwl_is_ready_rf(priv))
-		return -EAGAIN;
-
-	if (mode == IEEE80211_IF_TYPE_IBSS) {
-		const struct iwl_channel_info *ch_info;
-
-		ch_info = iwl_get_channel_info(priv,
-					       priv->phymode,
-					       priv->staging_rxon.channel);
-
-		if (!ch_info || !is_channel_ibss(ch_info)) {
-			IWL_ERROR("channel %d not IBSS channel\n",
-				  priv->staging_rxon.channel);
-			return -EINVAL;
-		}
-	}
-
-	cancel_delayed_work(&priv->scan_check);
-	priv->status &= ~STATUS_SCAN_PENDING;
-	if (iwl_scan_cancel(priv, 100)) {
-		IWL_WARNING("Aborted scan still in progress " "after 100ms\n");
-		IWL_DEBUG_MAC80211("leaving - scan abort " "failed.\n");
-		return -EAGAIN;
-	}
-
-	priv->iw_mode = mode;
-
-	iwl_connection_init_rx_config(priv);
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
-	iwl_clear_stations_table(priv);
-
-	iwl_commit_rxon(priv);
-
-	return 0;
-}
-
-static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
-				      struct ieee80211_tx_control *ctl,
-				      struct iwl_cmd *cmd,
-				      struct sk_buff *skb_frag,
-				      int last_frag)
-{
-	struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
-
-	switch (keyinfo->alg) {
-	case ALG_CCMP:
-		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
-
-		cmd->cmd.tx.hdr[0].frame_control |=
-		    cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-		/* XXX: ACK flag must be set for CCMP even if it
-		 * is a multicast/broadcast packet, because CCMP
-		 * group communication encrypted by GTK is
-		 * actually done by the AP. */
-		cmd->cmd.tx.tx_flags |= TX_CMD_FLG_ACK_MSK;
-		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
-		IWL_DEBUG_TX("tx_cmd with aes  hwcrypto\n");
-		break;
-	case ALG_TKIP:
-#if 0
-		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
-
-		if (last_frag)
-			memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
-			       8);
-		else
-			memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
-
-		cmd->cmd.tx.hdr[0].frame_control |=
-		    cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-		/* XXX: ACK flag must be set for CCMP even if it
-		 * is a multicast/broadcast packet, because CCMP
-		 * group communication encrypted by GTK is
-		 * actually done by the AP. */
-		cmd->cmd.tx.tx_flags |= TX_CMD_FLG_ACK_MSK;
-#endif
-		break;
-	case ALG_WEP:
-		cmd->cmd.tx.sec_ctl = 1 |	/* WEP */
-		    (ctl->key_idx & 0x3) << 6;
-
-		if (keyinfo->keylen == 13)
-			cmd->cmd.tx.sec_ctl |= (1 << 3);	/* 128-bit */
-
-		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
-
-		cmd->cmd.tx.hdr[0].frame_control |=
-		    cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-
-		IWL_DEBUG_TX("Configuring packet for WEP encryption "
-			     "with key %d\n", ctl->key_idx);
-		break;
-
-	case ALG_NONE:
-		IWL_DEBUG_TX("Tx packet in the clear "
-			     "(encrypt requested).\n");
-		break;
-
-	default:
-		printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
-		break;
-	}
-
-}
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
-				  struct iwl_cmd *cmd,
-				  struct ieee80211_tx_control *ctrl,
-				  struct ieee80211_hdr *hdr,
-				  int is_unicast, u8 std_id)
-{
-	u32 tx_flags;
-	u16 fc = le16_to_cpu(hdr->frame_control);
-	u16 *qc;
-
-	tx_flags = cmd->cmd.tx.tx_flags;
-
-	cmd->cmd.tx.stop_time.life_time = 0xFFFFFFFF;
-	if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
-		tx_flags |= TX_CMD_FLG_ACK_MSK;
-		if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT)
-			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-		if (ieee80211_is_probe_response(fc) &&
-		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
-			tx_flags |= TX_CMD_FLG_TSF_MSK;
-	} else {
-		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
-		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-	}
-
-	cmd->cmd.tx.sta_id = std_id;
-	if (ieee80211_get_morefrag(hdr))
-		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-
-	qc = ieee80211_get_qos_ctrl(hdr);
-	if (qc) {
-		cmd->cmd.tx.tid_tspec = (u8) (*qc & 0xf);
-		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-	} else
-		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-
-	if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
-		tx_flags |= TX_CMD_FLG_RTS_MSK;
-		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-	} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-		tx_flags |= TX_CMD_FLG_CTS_MSK;
-	}
-
-	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
-
-	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
-	if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) {
-		if (((WLAN_FC_GET_STYPE(fc)) == IEEE80211_STYPE_ASSOC_REQ) ||
-		    ((WLAN_FC_GET_STYPE(fc)) == IEEE80211_STYPE_REASSOC_REQ))
-			cmd->cmd.tx.timeout.pm_frame_timeout = 3;
-		else
-			cmd->cmd.tx.timeout.pm_frame_timeout = 2;
-	} else
-		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
-
-	cmd->cmd.tx.driver_txop = 0;
-	cmd->cmd.tx.tx_flags = tx_flags;
-	cmd->cmd.tx.next_frame_len = 0;
-}
-
-static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
-{
-	int sta_id;
-	u16 fc = le16_to_cpu(hdr->frame_control);
-
-	/* If this frame is broadcast or not data then use the broadcast
-	 * station id */
-	if ((WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) ||
-	    is_multicast_ether_addr(hdr->addr1))
-		return IWL_BROADCAST_ID;
-
-	/* If this frame is part of a BSS network (we're a station), then
-	 * we use the AP's station id */
-	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
-		return IWL_AP_ID;
-
-	/* If this frame is part of a IBSS network, then we use the
-	 * target specific station id */
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
-		sta_id = iwl_hw_find_station(priv, hdr->addr1);
-		if (sta_id != IWL_INVALID_STATION)
-			return sta_id;
-
-		sta_id = iwl_add_station(priv, hdr->addr1, 0,
-					 (CMD_ASYNC | CMD_NO_LOCK));
-
-		if (sta_id != IWL_INVALID_STATION)
-			return sta_id;
-
-		IWL_DEBUG_DROP("Station " MAC_FMT " not in station map. "
-			       "Defaulting to broadcast...\n",
-			       MAC_ARG(hdr->addr1));
-		printk_buf(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
-		return IWL_BROADCAST_ID;
-	}
-
-	/* Otherwise we default to the broadcast station id */
-	return IWL_BROADCAST_ID;
-}
-
-/*
- * start REPLY_TX command process
- */
-static int iwl_tx_skb(struct iwl_priv *priv,
-		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	u8 *tfd;
-	u32 *control_flags;
-	int txq_id = ctl->queue;
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
-	dma_addr_t phys_addr;
-	dma_addr_t txcmd_phys;
-	struct iwl_cmd *out_cmd = NULL;
-	u16 len, idx, len_org;
-	u8 id, hdr_len, unicast;
-	u8 sta_id;
-	u16 seq_number = 0;
-	u16 fc;
-	u16 *qc;
-	u8 wait_write_ptr = 0;
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (priv->status & STATUS_RF_KILL_MASK) {
-		IWL_DEBUG_DROP("Dropping - RF KILL\n");
-		goto drop;
-	}
-
-	if (!priv->interface_id) {
-		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
-		goto drop;
-	}
-
-	if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
-		IWL_ERROR("ERROR: No TX rate available.\n");
-		goto drop;
-	}
-
-	unicast = !is_multicast_ether_addr(hdr->addr1);
-	id = 0;
-
-	fc = le16_to_cpu(hdr->frame_control);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (ieee80211_is_auth(fc))
-		IWL_DEBUG_TX("Sending AUTH frame\n");
-	else if (ieee80211_is_assoc_request(fc))
-		IWL_DEBUG_TX("Sending ASSOC frame\n");
-	else if (ieee80211_is_reassoc_request(fc))
-		IWL_DEBUG_TX("Sending REASSOC frame\n");
-#endif
-
-	if (!iwl_is_associated(priv) &&
-	    (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA)) {
-		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
-		goto drop;
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	hdr_len = ieee80211_get_hdrlen(fc);
-	sta_id = iwl_get_sta_id(priv, hdr);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_DEBUG_DROP("Dropping - INVALID STATION: " MAC_FMT "\n",
-			       MAC_ARG(hdr->addr1));
-		spin_lock_irqsave(&priv->lock, flags);
-		goto drop;
-	}
-
-	IWL_DEBUG_RATE("station Id %d\n", sta_id);
-
-	qc = ieee80211_get_qos_ctrl(hdr);
-	if (qc) {
-		u8 tid = (u8)(*qc & 0xf);
-		seq_number = priv->stations[sta_id].tid[tid].seq_number &
-			IEEE80211_SCTL_SEQ;
-		hdr->seq_ctrl = cpu_to_le16(seq_number) |
-			(hdr->seq_ctrl & IEEE80211_SCTL_FRAG);
-		seq_number += 0x10;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-	tfd = (u8 *) (&txq->bd[q->first_empty * q->element_size]);
-	memset(tfd, 0, q->element_size);
-	control_flags = (u32 *) tfd;
-	idx = get_next_cmd_index(q, q->first_empty, 0);
-
-	memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
-	txq->txb[q->first_empty].skb[0] = skb;
-	memcpy(&(txq->txb[q->first_empty].status.control),
-	       ctl, sizeof(struct ieee80211_tx_control));
-	out_cmd = &txq->cmd[idx];
-	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
-	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
-	out_cmd->hdr.cmd = REPLY_TX;
-	out_cmd->hdr.sequence = QUEUE_TO_SEQ(txq_id) |
-		INDEX_TO_SEQ(q->first_empty);
-	/* copy frags header */
-	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
-
-	/* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
-	len = priv->hw_setting.tx_cmd_len +
-		sizeof(struct iwl_cmd_header) + hdr_len;
-
-	len_org = len;
-	len = (len + 3) & ~3;
-
-	if (len_org != len) {
-		len_org = 1;
-	} else
-		len_org = 0;
-	txcmd_phys =
-		txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
-		offsetof(struct iwl_cmd, hdr);
-
-	iwl_hw_tx_queue_attach_buffer_to_tfd(priv, tfd, txcmd_phys,
-					     cpu_to_le16(len));
-
-	if (ctl->key_idx != -1)
-		iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
-
-	/* 802.11 null functions have no payload... */
-	len = skb->len - hdr_len;
-	if (len) {
-		phys_addr = cpu_to_le32(pci_map_single(priv->pci_dev,
-						       skb->data + hdr_len,
-						       len, PCI_DMA_TODEVICE));
-		iwl_hw_tx_queue_attach_buffer_to_tfd(priv, tfd, phys_addr,
-						     cpu_to_le16(len));
-	}
-
-	out_cmd->cmd.tx.len = skb->len;
-
-#if IWL == 3945
-	/* If there is no payload, then only one TFD is used */
-	if (!len)
-		*control_flags = TFD_CTL_COUNT_SET(1);
-	else
-		*control_flags = TFD_CTL_COUNT_SET(2) |
-			TFD_CTL_PAD_SET(U32_PAD(len));
-#else
-	if (len_org)
-		out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-#endif
-
-	/* todoG need this for burst mode later on */
-	iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
-
-	/* set is_hcca to 0; it probably will never be implemented */
-	iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
-
-	len = out_cmd->cmd.tx.len;
-
-#if IWL == 4965
-	iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
-		       hdr, hdr_len, ctl, NULL);
-#elif IWL == 3945
-	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
-	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
-#endif
-
-	if (!(ieee80211_get_morefrag(hdr))) {
-		txq->need_update = 1;
-		if ( qc ) {
-			u8 tid = (u8)(*qc & 0xf);
-			priv->stations[sta_id].tid[tid].seq_number =
-				seq_number;
-		}
-	} else {
-		wait_write_ptr = 1;
-		txq->need_update = 0;
-	}
-
-	printk_buf(IWL_DL_TX, out_cmd->cmd.payload, sizeof(out_cmd->cmd.tx));
-
-	printk_buf(IWL_DL_TX, (u8 *) out_cmd->cmd.tx.hdr,
-		   ieee80211_get_hdrlen(out_cmd->cmd.tx.hdr->frame_control));
-
-	iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
-
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	rc = iwl_tx_queue_update_write_ptr(priv, txq);
-	spin_unlock_irqrestore(&priv->lock, flags);
-	if (rc)
-		return rc;
-
-	if ((iwl_queue_space(q) < q->high_mark)
-	    && priv->mac80211_registered) {
-		if (wait_write_ptr) {
-			spin_lock_irqsave(&priv->lock, flags);
-			txq->need_update = 1;
-			iwl_tx_queue_update_write_ptr(priv, txq);
-			spin_unlock_irqrestore(&priv->lock, flags);
-		}
-
-		ieee80211_stop_queue(priv->hw, ctl->queue);
-	}
-
-	return 0;
-
- drop:
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return -1;
-}
-
-static void iwl_set_rate(struct iwl_priv *priv)
-{
-	const struct ieee80211_hw_mode *hw = NULL;
-	struct ieee80211_rate *rate;
-	int i;
-
-	hw = iwl_get_hw_mode(priv, priv->phymode);
-
-	priv->active_rate = 0;
-	priv->active_rate_basic = 0;
-
-	IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
-		       ((hw->mode == MODE_IEEE80211A) ||
-			(hw->mode == MODE_ATHEROS_TURBO)) ?
-		       'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
-
-	for (i = 0; i < hw->num_rates; i++) {
-		rate = &(hw->rates[i]);
-		if ((rate->val < IWL_RATE_COUNT) &&
-		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
-			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
-				       rate->val, iwl_rates[rate->val].plcp,
-				       (rate->flags & IEEE80211_RATE_BASIC) ?
-				       "*" : "");
-			priv->active_rate |= (1 << rate->val);
-			if (rate->flags & IEEE80211_RATE_BASIC)
-				priv->active_rate_basic |= (1 << rate->val);
-		} else {
-			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
-				       rate->val, iwl_rates[rate->val].plcp);
-		}
-	}
-
-	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
-		       priv->active_rate, priv->active_rate_basic);
-
-	/*
-	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
-	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
-	 * OFDM
-	 */
-	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
-		priv->staging_rxon.cck_basic_rates =
-		    ((priv->active_rate_basic &
-		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
-	else
-		priv->staging_rxon.cck_basic_rates =
-		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
-
-	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
-		priv->staging_rxon.ofdm_basic_rates =
-		    ((priv->active_rate_basic &
-		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
-		      IWL_FIRST_OFDM_RATE) & 0xFF;
-	else
-		priv->staging_rxon.ofdm_basic_rates =
-		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-}
-
-static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
-{
-	unsigned long flags;
-
-	if ((disable_radio ? 1 : 0) ==
-	    ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
-		return;
-
-	IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
-			  disable_radio ? "OFF" : "ON");
-
-	if (disable_radio) {
-		iwl_scan_cancel(priv, 0);
-		/* FIXME: This is a workaround for AP */
-		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
-			spin_lock_irqsave(&priv->lock, flags);
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-				    CSR_UCODE_SW_BIT_RFKILL);
-			spin_unlock_irqrestore(&priv->lock, flags);
-			iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
-			priv->status |= STATUS_RF_KILL_SW;
-		}
-		return;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-	priv->status &= ~STATUS_RF_KILL_SW;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* wake up ucode */
-	msleep(10);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_read32(priv, CSR_UCODE_DRV_GP1);
-	if (!iwl_grab_restricted_access(priv))
-		iwl_release_restricted_access(priv);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	if (priv->status & STATUS_RF_KILL_HW) {
-		IWL_DEBUG_RF_KILL("Can not turn radio back on - "
-				  "disabled by HW switch\n");
-		return;
-	}
-
-	queue_work(priv->workqueue, &priv->restart);
-	return;
-}
-
-void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
-			    u32 decrypt_res, struct ieee80211_rx_status *stats)
-{
-	u16 fc =
-	    le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
-
-	if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
-		return;
-
-	if (!(fc & IEEE80211_FCTL_PROTECTED))
-		return;
-
-	IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
-	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
-	case RX_RES_STATUS_SEC_TYPE_TKIP:
-		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-		    RX_RES_STATUS_BAD_ICV_MIC)
-			stats->flag |= RX_FLAG_MMIC_ERROR;
-	case RX_RES_STATUS_SEC_TYPE_WEP:
-	case RX_RES_STATUS_SEC_TYPE_CCMP:
-		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-		    RX_RES_STATUS_DECRYPT_OK) {
-			IWL_DEBUG_RX("hw decrypt successfully!!!\n");
-			stats->flag |= RX_FLAG_DECRYPTED;
-		}
-		break;
-
-	default:
-		break;
-	}
-}
-
-void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb,
-				    void *data, short len,
-				    struct ieee80211_rx_status *stats,
-				    u16 phy_flags)
-{
-	struct iwl_rt_rx_hdr *iwl_rt;
-
-	/* First cache any information we need before we overwrite
-	 * the information provided in the skb from the hardware */
-	s8 signal = stats->ssi;
-	s8 noise = 0;
-	u16 channel = stats->channel;
-	int rate = stats->rate;
-	u64 tsf = stats->mactime;
-
-	/* We received data from the HW, so stop the watchdog */
-	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
-		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
-		return;
-	}
-
-	/* copy the frame data to write after where the radiotap header goes */
-	iwl_rt = (void *)rxb->skb->data;
-	memmove(iwl_rt->payload, data, len);
-
-	iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
-	/* total header + data */
-	iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
-
-	/* Set the size of the skb to the size of the frame */
-	skb_put(rxb->skb, sizeof(*iwl_rt) + len);
-
-	/* Big bitfield of all the fields we provide in radiotap */
-	iwl_rt->rt_hdr.it_present =
-	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-			(1 << IEEE80211_RADIOTAP_FLAGS) |
-			(1 << IEEE80211_RADIOTAP_RATE) |
-			(1 << IEEE80211_RADIOTAP_CHANNEL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-			(1 << IEEE80211_RADIOTAP_ANTENNA));
-
-	/* Zero the flags, we'll add to them as we go */
-	iwl_rt->rt_flags = 0;
-
-	iwl_rt->rt_tsf = cpu_to_le64(tsf);
-
-	/* Convert to dBm */
-	iwl_rt->rt_dbmsignal = signal;
-	iwl_rt->rt_dbmnoise = noise;
-
-	/* Convert the channel data and set the flags */
-	iwl_rt->rt_channel = cpu_to_le16(channel);
-	if (!(phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK)) {
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
-	} else if (phy_flags & RX_RES_PHY_FLAGS_MOD_CCK_MSK) {
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
-	} else {		/* 802.11g */
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-	}
-
-	rate = iwl_rate_index_from_plcp(rate);
-	if (rate == -1)
-		iwl_rt->rt_rate = 0;
-	else
-		iwl_rt->rt_rate = iwl_rates[rate].ieee;
-
-	/* antenna number */
-	iwl_rt->rt_antenna = (phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
-	/* set the preamble flag if we have it */
-	if (phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
-	stats->flag |= RX_FLAG_RADIOTAP;
-	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
-	rxb->skb = NULL;
-}
-
-
-#define IWL_PACKET_RETRY_TIME HZ
-
-int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
-{
-	u16 sc = le16_to_cpu(header->seq_ctrl);
-	u16 seq = WLAN_GET_SEQ_SEQ(sc);
-	u16 frag = WLAN_GET_SEQ_FRAG(sc);
-	u16 *last_seq, *last_frag;
-	unsigned long *last_time;
-
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_IBSS:{
-		struct list_head *p;
-		struct iwl_ibss_seq *entry = NULL;
-		u8 *mac = header->addr2;
-		int index = mac[5] % IWL_IBSS_MAC_HASH_SIZE;
-
-		__list_for_each(p, &priv->ibss_mac_hash[index]) {
-			entry =
-				list_entry(p, struct iwl_ibss_seq, list);
-			if (!compare_ether_addr(entry->mac, mac))
-				break;
-		}
-		if (p == &priv->ibss_mac_hash[index]) {
-			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
-			if (!entry) {
-				IWL_ERROR
-					("Cannot malloc new mac entry\n");
-				return 0;
-			}
-			memcpy(entry->mac, mac, ETH_ALEN);
-			entry->seq_num = seq;
-			entry->frag_num = frag;
-			entry->packet_time = jiffies;
-			list_add(&entry->list,
-				 &priv->ibss_mac_hash[index]);
-			return 0;
-		}
-		last_seq = &entry->seq_num;
-		last_frag = &entry->frag_num;
-		last_time = &entry->packet_time;
-		break;
-	}
-	case IEEE80211_IF_TYPE_STA:
-		last_seq = &priv->last_seq_num;
-		last_frag = &priv->last_frag_num;
-		last_time = &priv->last_packet_time;
-		break;
-	default:
-		return 0;
-	}
-	if ((*last_seq == seq) &&
-	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
-		if (*last_frag == frag)
-			goto drop;
-		if (*last_frag + 1 != frag)
-			/* out-of-order fragment */
-			goto drop;
-	} else
-		*last_seq = seq;
-
-	*last_frag = frag;
-	*last_time = jiffies;
-	return 0;
-
- drop:
-	return 1;
-}
-
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-
-#include "iwl-spectrum.h"
-
-#define BEACON_TIME_MASK_LOW	0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH	0xFF000000
-#define TIME_UNIT		1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
-	u32 quot;
-	u32 rem;
-	u32 interval = beacon_interval * 1024;
-
-	if (!interval || !usec)
-		return 0;
-
-	quot = (usec / interval) % 0x100;
-	rem = (usec % interval) % BEACON_TIME_MASK_LOW;
-
-	return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static u32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
-	u32 base_low = base & BEACON_TIME_MASK_LOW;
-	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
-	u32 interval = beacon_interval * TIME_UNIT;
-	u32 res = (base & BEACON_TIME_MASK_HIGH) +
-	    (addon & BEACON_TIME_MASK_HIGH);
-
-	if (base_low > addon_low)
-		res += base_low - addon_low;
-	else if (base_low < addon_low) {
-		res += interval + base_low - addon_low;
-		res += (1 << 24);
-	} else
-		res += (1 << 24);
-
-	return res;
-}
-
-static int iwl_get_measurement(struct iwl_priv *priv,
-			       struct ieee80211_measurement_params *params,
-			       u8 type)
-{
-	struct iwl_spectrum_cmd spectrum;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
-		.data = (void *)&spectrum,
-		.meta.flags = CMD_WANT_SKB,
-	};
-	u32 add_time = params->start_time;
-	int rc;
-
-	if (iwl_is_associated(priv))
-		add_time =
-		    iwl_usecs_to_beacons(params->start_time - priv->last_tsf,
-					 priv->rxon_timing.beacon_interval);
-
-	memset(&spectrum, 0, sizeof(spectrum));
-
-	spectrum.channel_count = 1;
-	spectrum.flags =
-	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
-	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
-	cmd.len = sizeof(spectrum);
-	spectrum.len = cmd.len - sizeof(spectrum.len);
-
-	if (iwl_is_associated(priv))
-		spectrum.start_time =
-		    iwl_add_beacon_time(priv->last_beacon_time,
-					add_time,
-					priv->rxon_timing.beacon_interval);
-	else
-		spectrum.start_time = params->start_time;
-
-	spectrum.channels[0].duration = params->duration * TIME_UNIT;
-	spectrum.channels[0].channel = params->channel;
-	spectrum.channels[0].type = type;
-	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
-		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
-		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
-
-	rc = iwl_send_cmd(priv, &cmd);
-	if (rc)
-		return rc;
-
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
-	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
-		rc = -EIO;
-	}
-
-	switch (res->u.spectrum.status) {
-	case 0:		/* Command will be handled */
-		if (res->u.spectrum.id != 0xff) {
-			IWL_DEBUG_INFO
-			    ("Replaced existing measurement: %d\n",
-			     res->u.spectrum.id);
-			priv->measurement_status &= ~MEASUREMENT_READY;
-		}
-		priv->measurement_status |= MEASUREMENT_ACTIVE;
-		rc = 0;
-		break;
-
-	case 1:		/* Command will not be handled */
-		rc = -EAGAIN;
-		break;
-	}
-
-	dev_kfree_skb_any(cmd.meta.u.skb);
-
-	return rc;
-}
-#endif
-
-static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
-				 struct iwl_tx_info *tx_sta)
-{
-
-	tx_sta->status.ack_signal = 0;
-	tx_sta->status.excessive_retries = 0;
-	tx_sta->status.queue_length = 0;
-	tx_sta->status.queue_number = 0;
-
-	if (in_interrupt())
-		ieee80211_tx_status_irqsafe(priv->hw,
-					    tx_sta->skb[0], &(tx_sta->status));
-	else
-		ieee80211_tx_status(priv->hw,
-				    tx_sta->skb[0], &(tx_sta->status));
-
-	tx_sta->skb[0] = NULL;
-}
-
-/**
- * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
- *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
- */
-static int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
-{
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
-	u8 is_next = 0;
-	int used;
-	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
-		IWL_ERROR("Read index for DMA queue (%d) is out of "
-			  "range [0-%d) %d %d\n",
-			  index, q->n_bd, q->first_empty, q->last_used);
-		goto done;
-	}
-	index = iwl_queue_inc_wrap(index, q->n_bd);
-	for (; q->last_used != index;
-	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
-		if (is_next) {
-			IWL_WARNING("command skipped\n");
-			queue_work(priv->workqueue, &priv->restart);
-		}
-		if (txq_id != IWL_CMD_QUEUE_NUM) {
-			iwl_txstatus_to_ieee(priv,
-					     &(txq->txb[txq->q.last_used]));
-			iwl_hw_tx_queue_free_tfd(priv, txq);
-		} else
-			is_next = 1;
-	}
- done:
-	if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0)
-	    && (txq_id != IWL_CMD_QUEUE_NUM)
-	    && priv->mac80211_registered)
-		ieee80211_wake_queue(priv->hw, txq_id);
-
-	used = q->first_empty - q->last_used;
-	if (used < 0)
-		used += q->n_window;
-	return used;
-}
-
-static int iwl_is_tx_success(u32 status)
-{
-#if IWL == 3945
-	return (status & 0xFF) == 0x1;
-#elif IWL == 4965
-	status &= TX_STATUS_MSK;
-	return (status == TX_STATUS_SUCCESS)
-	    || (status == TX_STATUS_DIRECT_DONE);
-#endif
-}
-
-/******************************************************************************
- *
- * Generic RX handler implementations
- *
- ******************************************************************************/
-
-static void iwl_rx_reply_tx(struct iwl_priv *priv,
-			    struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	u16 sequence = pkt->hdr.sequence;
-	int txq_id = SEQ_TO_QUEUE(sequence);
-	int index = SEQ_TO_INDEX(sequence);
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
-	struct ieee80211_tx_status *status;
-	struct iwl_tx_resp *resp = (void *)&pkt->u.raw[0];
-
-	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
-		IWL_ERROR("Read index for DMA queue (%d) "
-			  "is out of range [0-%d) %d %d\n",
-			  index, txq->q.n_bd, txq->q.first_empty,
-			  txq->q.last_used);
-		return;
-	}
-
-	status = &(txq->txb[txq->q.last_used].status);
-
-	status->retry_count = resp->failure_frame;
-	status->queue_number = resp->status;
-	status->queue_length = resp->bt_kill_count;
-	status->queue_length |= resp->failure_rts;
-
-	status->flags =
-	    iwl_is_tx_success(resp->status) ? IEEE80211_TX_STATUS_ACK : 0;
-
-#if IWL == 3945
-
-	status->control.tx_rate = iwl_rate_index_from_plcp(resp->rate);
-
-	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
-		     txq_id, iwl_get_tx_fail_reason(resp->status),
-		     resp->status, resp->rate, resp->failure_frame);
-
-#elif IWL == 4965
-
-	status->control.tx_rate = resp->rate.s.rate | (resp->rate.s.flags << 8);
-
-	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
-		     txq_id, iwl_get_tx_fail_reason(resp->status),
-		     resp->status, resp->rate.s.rate, resp->failure_frame);
-#endif
-
-	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
-	if (index != -1)
-		iwl_tx_queue_reclaim(priv, txq_id, index);
-
-	if (iwl_check_bits(resp->status, TX_ABORT_REQUIRED_MSK))
-		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
-}
-
-
-static void iwl_rx_reply_alive(struct iwl_priv *priv,
-			   struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_alive_resp *palive;
-	struct work_struct *pwork;
-
-	palive = &pkt->u.alive_frame;
-
-	IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
-		       "0x%01X 0x%01X\n",
-		       palive->is_valid, palive->ver_type,
-		       palive->ver_subtype);
-
-	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
-		IWL_DEBUG_INFO("Initialization Alive received.\n");
-		memcpy(&priv->card_alive_init,
-		       &pkt->u.alive_frame,
-		       sizeof(struct iwl_init_alive_resp));
-		pwork = &priv->init_alive_start;
-	} else {
-		IWL_DEBUG_INFO("Runtime Alive received.\n");
-		memcpy(&priv->card_alive, &pkt->u.alive_frame,
-		       sizeof(struct iwl_alive_resp));
-		pwork = &priv->alive_start;
-#if IWL == 3945
-		/* For debugging (selective disable not supported in 4965) */
-		iwl_disable_events(priv);
-#endif
-	}
-
-	/* We delay the ALIVE response by 5ms to
-	 * give the HW RF Kill time to activate... */
-	if (palive->is_valid == UCODE_VALID_OK)
-		queue_delayed_work(priv->workqueue, pwork,
-				   msecs_to_jiffies(5));
-	else
-		IWL_WARNING("uCode did not respond OK.\n");
-}
-
-static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
-				 struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
-	return;
-}
-
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	u32 err_type = pkt->u.err_resp.error_type;
-	u8 cmd_id = pkt->u.err_resp.cmd_id;
-	u16 seq = pkt->u.err_resp.bad_cmd_seq_num;
-	u32 ser = pkt->u.err_resp.error_info;
-	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
-		  "seq 0x%04X ser 0x%08X\n",
-		  err_type, get_cmd_string(cmd_id), cmd_id, seq, ser);
-	return;
-}
-
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
-	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
-	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
-		      csa->channel, csa->status);
-	rxon->channel = priv->staging_rxon.channel = cpu_to_le16(csa->channel);
-}
-
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-					  struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
-	if (!report->state) {
-		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
-			  "Spectrum Measure Notification: Start\n");
-		return;
-	}
-
-	memcpy(&priv->measure_report, report, sizeof(*report));
-	priv->measurement_status |= MEASUREMENT_READY;
-#endif
-}
-
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-				  struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
-	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
-		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
-}
-
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-					     struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
-			"notification for %s:\n",
-			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-	printk_buf(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
-}
-
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
-#if IWL == 3945
-	u8 rate = beacon->beacon_notify_hdr.rate;
-#elif IWL == 4965
-	u8 rate = beacon->beacon_notify_hdr.rate.s.rate;
-#endif
-	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
-		     "tsf %d %d rate %d\n",
-		     beacon->beacon_notify_hdr.status & TX_STATUS_MSK,
-		     beacon->beacon_notify_hdr.failure_frame,
-		     beacon->ibss_mgr_status,
-		     beacon->high_tsf, beacon->low_tsf, rate);
-#endif
-}
-
-static void iwl_rx_reply_scan(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanreq_notification *notif =
-	    (struct iwl_scanreq_notification *)pkt->u.raw;
-	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
-}
-
-static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanstart_notification *notif =
-	    (struct iwl_scanstart_notification *)pkt->u.raw;
-	priv->scan_start_tsf = notif->tsf_low;
-	IWL_DEBUG_SCAN("Scan start: "
-		       "%d [802.11%s] "
-		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
-		       notif->channel,
-		       notif->band ? "bg" : "a",
-		       notif->tsf_high,
-		       notif->tsf_low, notif->status, notif->beacon_timer);
-}
-
-static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
-				      struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanresults_notification *notif =
-	    (struct iwl_scanresults_notification *)pkt->u.raw;
-
-	IWL_DEBUG_SCAN("Scan ch.res: "
-		       "%d [802.11%s] "
-		       "(TSF: 0x%08X:%08X) - %d "
-		       "elapsed=%lu usec (%dms since last)\n",
-		       notif->channel,
-		       notif->band ? "bg" : "a",
-		       notif->tsf_high,
-		       notif->tsf_low,
-		       notif->statistics[0],
-		       notif->tsf_low - priv->scan_start_tsf,
-		       jiffies_to_msecs(elapsed_jiffies
-					(priv->last_scan_jiffies, jiffies)));
-
-	priv->last_scan_jiffies = jiffies;
-}
-
-static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-				       struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scancomplete_notification *scan_notif =
-	    (struct iwl_scancomplete_notification *)pkt->u.raw;
-	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
-		       scan_notif->scanned_channels,
-		       scan_notif->tsf_low,
-		       scan_notif->tsf_high, scan_notif->status);
-
-	/* The HW is no longer scanning */
-	priv->status &= ~STATUS_SCAN_HW;
-
-	/* The scan completion notification came in, so kill that timer... */
-	cancel_delayed_work(&priv->scan_check);
-
-	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-		       (priv->scan_bands == 2) ? "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--;
-
-	/* If a request to abort was given, or the scan did not succeed
-	 * then we reset the scan state machine and terminate,
-	 * re-queuing another scan if one has been requested */
-	if (priv->status & STATUS_SCAN_ABORTING) {
-		IWL_DEBUG_INFO("Aborted scan completed.\n");
-		priv->status &= ~STATUS_SCAN_ABORTING;
-	} else {
-		/* If there are more bands on this scan pass reschedule */
-		if (priv->scan_bands > 0)
-			goto reschedule;
-	}
-
-	priv->last_scan_jiffies = jiffies;
-	IWL_DEBUG_INFO("Setting scan to off\n");
-
-	priv->status &= ~STATUS_SCANNING;
-
-	IWL_DEBUG_INFO("Scan took %dms\n",
-		       jiffies_to_msecs(elapsed_jiffies
-					(priv->scan_start, jiffies)));
-
-	queue_work(priv->workqueue, &priv->scan_completed);
-
-	return;
-
- reschedule:
-	priv->scan_pass_start = jiffies;
-	queue_work(priv->workqueue, &priv->request_scan);
-}
-
-/* Handle notification from uCode that card's power state is changing
- * due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
-	u32 status = priv->status;
-	IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
-			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
-			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
-#if IWL == 4965
-	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
-		     RF_CARD_DISABLED)) {
-
-		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-		if (!iwl_grab_restricted_access(priv)) {
-			iwl_write_restricted(
-				priv, HBUS_TARG_MBX_C,
-				HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-			iwl_release_restricted_access(priv);
-		}
-
-		if (!(flags & RXON_CARD_DISABLED)) {
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-			if (!iwl_grab_restricted_access(priv)) {
-				iwl_write_restricted(
-					priv, HBUS_TARG_MBX_C,
-					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
-
-				iwl_release_restricted_access(priv);
-			}
-		}
-
-		if (flags & RF_CARD_DISABLED) {
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-			iwl_read32(priv, CSR_UCODE_DRV_GP1);
-			if (!iwl_grab_restricted_access(priv))
-				iwl_release_restricted_access(priv);
-		}
-	}
-#else
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-#endif
-	if (flags & HW_CARD_DISABLED)
-		priv->status |= STATUS_RF_KILL_HW;
-	else
-		priv->status &= ~STATUS_RF_KILL_HW;
-
-
-	if (flags & SW_CARD_DISABLED)
-		priv->status |= STATUS_RF_KILL_SW;
-	else
-		priv->status &= ~STATUS_RF_KILL_SW;
-
-#if IWL == 4965
-	if (!(flags & RXON_CARD_DISABLED))
-		iwl_scan_cancel(priv, 0);
-#else
-		iwl_scan_cancel(priv, 0);
-#endif
-
-	if (((status & STATUS_RF_KILL_HW) != (priv->status & STATUS_RF_KILL_HW))
-	    || ((status & STATUS_RF_KILL_SW) !=
-		(priv->status & STATUS_RF_KILL_SW)))
-		queue_work(priv->workqueue, &priv->rf_kill);
-	else
-		wake_up_interruptible(&priv->wait_command_queue);
-}
-
-/**
- * iwl_setup_rx_handlers - Initialize Rx handler callbacks
- *
- * Setup the RX handlers for each of the reply types sent from the uCode
- * to the host.
- *
- * This function chains into the hardware specific files for them to setup
- * any hardware specific handlers as well.
- */
-static void iwl_setup_rx_handlers(struct iwl_priv *priv)
-{
-	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
-	priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
-	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
-	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
-	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-	    iwl_rx_spectrum_measure_notif;
-	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
-	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-	    iwl_rx_pm_debug_statistics_notif;
-	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
-
-	/* NOTE:  iwl_rx_statistics is different based on whether
-	 * the build is for the 3945 or the 4965.  See the
-	 * corresponding implementation in iwl-XXXX.c
-	 *
-	 * The same handler is used for both the REPLY to a
-	 * discrete statistics request from the host as well as
-	 * for the periodic statistics notification from the uCode
-	 */
-	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
-	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
-
-	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
-	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
-	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-	    iwl_rx_scan_results_notif;
-	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-	    iwl_rx_scan_complete_notif;
-	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
-	priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
-
-	/* Setup hardware specific Rx handlers */
-	iwl_hw_rx_handler_setup(priv);
-}
-
-/**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-static void iwl_tx_cmd_complete(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
-{
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	int txq_id = SEQ_TO_QUEUE(pkt->hdr.sequence);
-	int index = SEQ_TO_INDEX(pkt->hdr.sequence);
-	int is_huge = (pkt->hdr.sequence & SEQ_HUGE_FRAME);
-	int cmd_index;
-	struct iwl_cmd *cmd;
-
-	/* If a Tx command is being handled and it isn't in the actual
-	 * command queue then there a command routing bug has been introduced
-	 * in the queue management code. */
-	WARN_ON(txq_id != IWL_CMD_QUEUE_NUM);
-	if (txq_id != IWL_CMD_QUEUE_NUM) {
-		IWL_ERROR("Kernel BUG! Please report below info:\n");
-		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
-			  txq_id, pkt->hdr.cmd);
-	}
-
-	cmd_index = get_next_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index,
-				       is_huge);
-	cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
-
-	/* Input error checking is done when commands are added to queue. */
-	if (cmd->meta.flags & CMD_WANT_SKB) {
-		/* FIXME: we use cmd->meta.magic to indicate the
-		 * memory cmd->meta.source points to is still valid or
-		 * not at this point since caller may pass a local
-		 * variable to us and returned before we get here.
-		 * In this case, caller must ensure the ->magic field
-		 * is set correctly to indicate the availability of the
-		 * pointer cmd->meta.source. */
-		if (cmd->meta.source->magic == CMD_VAR_MAGIC) {
-			cmd->meta.source->u.skb = rxb->skb;
-			cmd->meta.source->magic = 0;
-			rxb->skb = NULL;
-		}
-	} else if (cmd->meta.u.callback &&
-		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
-		rxb->skb = NULL;
-
-	iwl_tx_queue_reclaim(priv, txq_id, index);
-
-	if (!(cmd->meta.flags & CMD_ASYNC)) {
-		priv->status &= ~STATUS_HCMD_ACTIVE;
-		wake_up_interruptible(&priv->wait_command_queue);
-	}
-}
-
-/************************** RX-FUNCTIONS ****************************/
-/*
- * Rx theory of operation
- *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer it will advance the READ index
- * and fire the RX interrupt.  The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free.  When
- *   ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replensish the ipw->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
- *   ipw->rxq is replenished and the READ INDEX is updated (updating the
- *   'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- *   detached from the ipw->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
- *   INDEX is not incremented and ipw->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl_rx_queue_alloc()       Allocates rx_free
- * iwl_rx_replenish()         Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock()     Moves available buffers from rx_free into Rx
- *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
- *                            READ INDEX, detaching the SKB from the pool.
- *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
- *                            slots.
- * ...
- *
- */
-
-/**
- * iwl_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
-{
-	int s = q->read - q->write;
-	if (s <= 0)
-		s += RX_QUEUE_SIZE;
-	/* keep some buffer to not confuse full and empty queue */
-	s -= 2;
-	if (s < 0)
-		s = 0;
-	return s;
-}
-
-/**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- *
- * NOTE: This function has 3945 and 4965 specific code sections
- * but is declared in base due to the majority of the
- * implementation being the same (only a numeric constant is
- * different)
- *
- */
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
-{
-	u32 reg = 0;
-	int rc = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&q->lock, flags);
-
-	if (q->need_update == 0)
-		goto exit_unlock;
-
-	if (priv->status & STATUS_POWER_PMI) {
-		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
-		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-			iwl_set_bit(priv, CSR_GP_CNTRL,
-				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-			goto exit_unlock;
-		}
-
-		rc = iwl_grab_restricted_access(priv);
-		if (rc)
-			goto exit_unlock;
-
-		iwl_write_restricted(priv,
-				     FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
-		iwl_release_restricted_access(priv);
-	} else {
-		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
-	}
-
-	q->need_update = 0;
-
- exit_unlock:
-	spin_unlock_irqrestore(&q->lock, flags);
-	return rc;
-}
-
-/**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that  need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-int iwl_rx_queue_restock(struct iwl_priv *priv)
-{
-	struct iwl_rx_queue *rxq = &priv->rxq;
-	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
-	unsigned long flags;
-	int counter = 0, write, rc;
-
-	spin_lock_irqsave(&rxq->lock, flags);
-	write = rxq->write & ~0x7;
-	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-		element = rxq->rx_free.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-		list_del(element);
-		((u32 *) rxq->bd)[rxq->write] =
-		    iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
-		rxq->queue[rxq->write] = rxb;
-		rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
-		rxq->free_count--;
-		counter++;
-	}
-	spin_unlock_irqrestore(&rxq->lock, flags);
-	/* If the pre-allocated buffer pool is dropping low, schedule to
-	 * refill it */
-
-	if (rxq->free_count <= RX_LOW_WATERMARK)
-		queue_work(priv->workqueue, &priv->rx_replenish);
-
-	counter = iwl_rx_queue_space(rxq);
-	/* If we've added more space for the firmware to place data, tell it */
-	if ((write != (rxq->write & ~0x7) || (rxq->write < write))
-	    || (abs(rxq->write - rxq->read) > 7)) {
-		spin_lock_irqsave(&rxq->lock, flags);
-		rxq->need_update = 1;
-		spin_unlock_irqrestore(&rxq->lock, flags);
-		rc = iwl_rx_queue_update_write_ptr(priv, rxq);
-		if (rc)
-			return rc;
-	}
-
-	return 0;
-}
-
-/**
- * iwl_rx_replensih - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during intialization)
- */
-void iwl_rx_replenish(void *data, u8 do_lock)
-{
-	struct iwl_priv *priv = data;
-	struct iwl_rx_queue *rxq = &priv->rxq;
-	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
-	unsigned long flags = 0;
-
-	spin_lock_irqsave(&rxq->lock, flags);
-	while (!list_empty(&rxq->rx_used)) {
-		element = rxq->rx_used.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-		rxb->skb =
-		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
-		if (!rxb->skb) {
-			if (net_ratelimit())
-				printk(KERN_CRIT DRV_NAME
-				       ": Can not allocate SKB buffers\n");
-			/* We don't reschedule replenish work here -- we will
-			 * call the restock method and if it still needs
-			 * more buffers it will schedule replenish */
-			break;
-		}
-		priv->alloc_rxb_skb++;
-		list_del(element);
-		rxb->dma_addr =
-		    pci_map_single(priv->pci_dev, rxb->skb->data,
-				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-		list_add_tail(&rxb->list, &rxq->rx_free);
-		rxq->free_count++;
-	}
-	spin_unlock_irqrestore(&rxq->lock, flags);
-
-	if (do_lock)
-		spin_lock_irqsave(&priv->lock, flags);
-	iwl_rx_queue_restock(priv);
-	if (do_lock)
-		spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-	int i;
-	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-		if (rxq->pool[i].skb != NULL) {
-			pci_unmap_single(priv->pci_dev,
-					 rxq->pool[i].dma_addr,
-					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(rxq->pool[i].skb);
-		}
-	}
-
-	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-			    rxq->dma_addr);
-	rxq->bd = NULL;
-}
-
-int iwl_rx_queue_alloc(struct iwl_priv *priv)
-{
-	struct iwl_rx_queue *rxq = &priv->rxq;
-	struct pci_dev *dev = priv->pci_dev;
-	int i;
-
-	spin_lock_init(&rxq->lock);
-	INIT_LIST_HEAD(&rxq->rx_free);
-	INIT_LIST_HEAD(&rxq->rx_used);
-	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
-	if (!rxq->bd)
-		return -ENOMEM;
-	/* Fill the rx_used queue with _all_ of the Rx buffers */
-	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
-		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-	/* Set us so that we have processed and used all buffers, but have
-	 * not restocked the Rx queue with fresh buffers */
-	rxq->read = rxq->write = 0;
-	rxq->free_count = 0;
-	rxq->need_update = 0;
-	return 0;
-}
-
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-	unsigned long flags;
-	int i;
-	spin_lock_irqsave(&rxq->lock, flags);
-	INIT_LIST_HEAD(&rxq->rx_free);
-	INIT_LIST_HEAD(&rxq->rx_used);
-	/* Fill the rx_used queue with _all_ of the Rx buffers */
-	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-		/* In the reset function, these buffers may have been allocated
-		 * to an SKB, so we need to unmap and free potential storage */
-		if (rxq->pool[i].skb != NULL) {
-			pci_unmap_single(priv->pci_dev,
-					 rxq->pool[i].dma_addr,
-					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-			priv->alloc_rxb_skb--;
-			dev_kfree_skb(rxq->pool[i].skb);
-			rxq->pool[i].skb = NULL;
-		}
-		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-	}
-
-	/* Set us so that we have processed and used all buffers, but have
-	 * not restocked the Rx queue with fresh buffers */
-	rxq->read = rxq->write = 0;
-	rxq->free_count = 0;
-	spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-/* Convert linear signal-to-noise ratio into dB */
-u8 ratio2dB[100] = {
-/*	 0   1   2   3   4   5   6   7   8   9 */
-	 0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
-	20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
-	26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
-	29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
-	32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
-	34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
-	36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
-	37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
-	38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
-	39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
-};
-
-/* Calculates a relative dB value from a ratio of linear
- *   (i.e. not dB) signal levels.
- * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
-int iwl_calc_db_from_ratio(int sig_ratio)
-{
-	/* Anything above 1000:1 just report as 60 dB */
-	if (sig_ratio > 1000)
-		return 60;
-
-	/* Above 100:1, divide by 10 and use table,
-	 *   add 20 dB to make up for divide by 10 */
-	if (sig_ratio > 100)
-		return (20 + (int)ratio2dB[sig_ratio/10]);
-
-	/* We shouldn't see this */
-	if (sig_ratio < 1)
-		return 0;
-
-	/* Use table for ratios 1:1 - 99:1 */
-	return (int)ratio2dB[sig_ratio];
-}
-
-#define PERFECT_RSSI (-20) /* dBm */
-#define WORST_RSSI (-95)   /* dBm */
-#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
-
-/* Calculate an indication of rx signal quality (a percentage, not dBm!).
- * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
- *   about formulas used below. */
-int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
-{
-	int sig_qual;
-	int degradation = PERFECT_RSSI - rssi_dbm;
-
-	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
-	 * as indicator; formula is (signal dbm - noise dbm).
-	 * SNR at or above 40 is a great signal (100%).
-	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
-	 * Weakest usable signal is usually 10 - 15 dB SNR. */
-	if (noise_dbm) {
-		if (rssi_dbm - noise_dbm >= 40)
-			return 100;
-		else if (rssi_dbm < noise_dbm)
-			return 0;
-		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
-
-	/* Else use just the signal level.
-	 * This formula is a least squares fit of data points collected and
-	 *   compared with a reference system that had a percentage (%) display
-	 *   for signal quality. */
-	} else {
-		sig_qual =
-			(100 * (RSSI_RANGE * RSSI_RANGE) -
-			degradation * (15 * RSSI_RANGE + 62 * degradation)) /
-			(RSSI_RANGE * RSSI_RANGE);
-	}
-	if (sig_qual > 100)
-		sig_qual = 100;
-	else if (sig_qual < 1)
-		sig_qual = 0;
-	return sig_qual;
-}
-
-/**
- * iwl_rx_handle - Main entry function for receiving responses from the uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers including command response and 802.11
- * frame availability.
- */
-static void iwl_rx_handle(struct iwl_priv *priv)
-{
-	struct iwl_rx_mem_buffer *rxb;
-	struct iwl_rx_packet *pkt;
-	struct iwl_rx_queue *rxq = &priv->rxq;
-	u32 r, i;
-	int reclaim;
-	unsigned long flags;
-
-	r = iwl_hw_get_rx_read(priv);
-	i = rxq->read;
-
-	while (i != r) {
-		rxb = rxq->queue[i];
-
-		/* If an RXB doesn't have a queue slot associated with it
-		 * then a bug has been introduced in the queue refilling
-		 * routines -- catch it here */
-		BUG_ON(rxb == NULL);
-
-		rxq->queue[i] = NULL;
-
-		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-					    IWL_RX_BUF_SIZE,
-					    PCI_DMA_FROMDEVICE);
-		pkt = (struct iwl_rx_packet *)rxb->skb->data;
-
-		/* need to reclaim cmd buffer(s) */
-		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
-#if IWL == 4965
-			(pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
-#endif
-			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
-			(pkt->hdr.cmd != REPLY_TX);
-
-		/* Based on type of command response or notification,
-		 *   handle those that need handling via function in
-		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
-		if (priv->rx_handlers[pkt->hdr.cmd]) {
-			priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
-			IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR,
-				"r = %d, i = %d, rx_handler %s\n", r, i,
-				get_cmd_string(pkt->hdr.cmd));
-		} else {
-			/* No handling needed */
-			IWL_DEBUG_HC("UNHANDLED - #0x%02x %s\n",
-				     pkt->hdr.cmd,
-				     get_cmd_string(pkt->hdr.cmd));
-		}
-
-		if (reclaim) {
-			/* Invoke any callbacks, transfer the skb to
-			 * caller, and fire off the (possibly) blocking
-			 * iwl_send_cmd() via as we reclaim the queue... */
-			if (rxb && rxb->skb)
-				iwl_tx_cmd_complete(priv, rxb);
-			else
-				IWL_WARNING("Claim null rxb?\n");
-		}
-
-		/* For now we just don't re-use anything.  We can tweak this
-		 * later to try and re-use notification packets and SKBs that
-		 * fail to Rx correctly */
-		if (rxb->skb != NULL) {
-			priv->alloc_rxb_skb--;
-			dev_kfree_skb_any(rxb->skb);
-			rxb->skb = NULL;
-		}
-
-		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-				 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
-		spin_lock_irqsave(&rxq->lock, flags);
-		list_add_tail(&rxb->list, &priv->rxq.rx_used);
-		spin_unlock_irqrestore(&rxq->lock, flags);
-		i = (i + 1) % RX_QUEUE_SIZE;
-	}
-
-	/* Backtrack one entry */
-	priv->rxq.read = i;
-
-	/* is a lot of queue space refill up right away
-	 * so ucode wont assert */
-	if (iwl_rx_queue_space(rxq) > RX_SPACE_HIGH_MARK)
-		iwl_rx_replenish(priv, 0);
-	else
-		iwl_rx_queue_restock(priv);
-}
-
-int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
-				  struct iwl_tx_queue *txq)
-{
-	u32 reg = 0;
-	int rc = 0;
-	int txq_id = txq->q.id;
-
-	if (txq->need_update == 0)
-		return rc;
-
-	/* if we're trying to save power */
-	if (priv->status & STATUS_POWER_PMI) {
-		/* 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 = 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);
-			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 = iwl_grab_restricted_access(priv);
-		if (rc)
-			return rc;
-		iwl_write_restricted(priv, HBUS_TARG_WRPTR,
-				     txq->q.first_empty | (txq_id << 8));
-		iwl_release_restricted_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 {
-		iwl_write32(priv, HBUS_TARG_WRPTR,
-			    txq->q.first_empty | (txq_id << 8));
-	}
-
-	txq->need_update = 0;
-
-	return rc;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
-{
-	IWL_DEBUG_RADIO("RX CONFIG:\n");
-	printk_buf(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
-	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", rxon->channel);
-	IWL_DEBUG_RADIO("u32 flags: 0x%08X " BIT_FMT32 "\n",
-			rxon->flags, BIT_ARG32(rxon->flags));
-	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x " BIT_FMT32 "\n",
-			rxon->filter_flags, BIT_ARG32(rxon->filter_flags));
-	IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
-	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x " BIT_FMT8 "\n",
-			rxon->ofdm_basic_rates,
-			BIT_ARG8(rxon->ofdm_basic_rates));
-	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x " BIT_FMT8 "\n",
-			rxon->cck_basic_rates, BIT_ARG8(rxon->cck_basic_rates));
-	IWL_DEBUG_RADIO("u8[6] node_addr: " MAC_FMT "\n",
-			MAC_ARG(rxon->node_addr));
-	IWL_DEBUG_RADIO("u8[6] bssid_addr: " MAC_FMT "\n",
-			MAC_ARG(rxon->bssid_addr));
-	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", rxon->assoc_id);
-}
-
-#endif
-
-static void iwl_enable_interrupts(struct iwl_priv *priv)
-{
-	IWL_DEBUG_ISR("Enabling interrupts\n");
-	priv->status |= STATUS_INT_ENABLED;
-	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
-}
-
-static inline void iwl_disable_interrupts(struct iwl_priv *priv)
-{
-	priv->status &= ~STATUS_INT_ENABLED;
-
-	/* disable interrupts from uCode/NIC to host */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-	/* acknowledge/clear/reset any interrupts still pending
-	 * from uCode or flow handler (Rx/Tx DMA) */
-	iwl_write32(priv, CSR_INT, 0xffffffff);
-	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-	IWL_DEBUG_ISR("Disabled interrupts\n");
-}
-
-static const char *desc_lookup(int i)
-{
-	switch (i) {
-	case 1:
-		return "FAIL";
-	case 2:
-		return "BAD_PARAM";
-	case 3:
-		return "BAD_CHECKSUM";
-	case 4:
-		return "NMI_INTERRUPT";
-	case 5:
-		return "SYSASSERT";
-	case 6:
-		return "FATAL_ERROR";
-	}
-
-	return "UNKNOWN";
-}
-
-#define ERROR_START_OFFSET  (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
-
-static void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
-#if IWL == 3945
-	u32 i;
-#else /* IWL == 4965 */
-	u32 data2, line;
-#endif
-	u32 desc, time, count, base, data1;
-	u32 blink1, blink2, ilink1, ilink2;
-	int rc;
-
-	base = priv->card_alive.error_event_table_ptr;
-
-	if (!VALID_RTC_DATA_ADDR(base)) {
-		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
-		return;
-	}
-
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
-		IWL_WARNING("Can not read from adapter at this time.\n");
-		return;
-	}
-
-	count = iwl_read_restricted_mem(priv, base);
-
-	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
-		IWL_ERROR("Start IWL Error Log Dump:\n");
-		IWL_ERROR("Status: 0x%08X, Config: %08X count: %d\n",
-			  priv->status, priv->config, count);
-	}
-
-#if IWL == 3945
-	IWL_ERROR("Desc       Time       asrtPC  blink2 "
-		  "ilink1  nmiPC   Line\n");
-	for (i = ERROR_START_OFFSET;
-	     i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
-	     i += ERROR_ELEM_SIZE) {
-		desc = iwl_read_restricted_mem(priv, base + i);
-		time =
-		    iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32));
-		blink1 =
-		    iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32));
-		blink2 =
-		    iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32));
-		ilink1 =
-		    iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32));
-		ilink2 =
-		    iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32));
-		data1 =
-		    iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32));
-
-		IWL_ERROR
-		    ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
-		     desc_lookup(desc), desc, time, blink1, blink2,
-		     ilink1, ilink2, data1);
-	}
-#else  /* 4965 Error format */
-	desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32));
-	blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32));
-	blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32));
-	ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32));
-	ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32));
-	data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32));
-	data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32));
-	line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32));
-	time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32));
-
-	IWL_ERROR("Desc               Time       "
-		  "data1      data2      line\n");
-	IWL_ERROR
-	    ("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
-	     desc_lookup(desc), desc, time, data1, data2, line);
-	IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
-	IWL_ERROR
-	    ("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2);
-
-#endif  /* IWL 3945 */
-
-	iwl_release_restricted_access(priv);
-
-}
-
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
-				u32 num_events, u32 mode)
-{
-	u32 i;
-	u32 base;       /* SRAM byte address of event log header */
-	u32 event_size;	/* 2 u32s, or 3 u32s if timestamp recorded */
-	u32 ptr;        /* SRAM byte address of log data */
-	u32 ev, time, data; /* event log data */
-
-	if (num_events == 0)
-		return;
-
-	base = priv->card_alive.log_event_table_ptr;
-
-	if (mode == 0)
-		event_size = 2 * sizeof(u32);
-	else
-		event_size = 3 * sizeof(u32);
-
-	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-	/* "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 = iwl_read_restricted_mem(priv, ptr);
-		ptr += sizeof(u32);
-		time = iwl_read_restricted_mem(priv, ptr);
-		ptr += sizeof(u32);
-		if (mode == 0) {
-			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
-		} else {
-			data = iwl_read_restricted_mem(priv, ptr);
-			ptr += sizeof(u32);
-			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
-		}
-	}
-}
-
-static void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
-	int rc;
-	u32 base;       /* SRAM byte address of event log header */
-	u32 capacity;   /* event log capacity in # entries */
-	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-	u32 num_wraps;  /* # times uCode wrapped to top of log */
-	u32 next_entry; /* index of next entry to be written by uCode */
-	u32 size;       /* # entries that we'll print */
-
-	base = priv->card_alive.log_event_table_ptr;
-	if (!VALID_RTC_DATA_ADDR(base)) {
-		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
-		return;
-	}
-
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
-		IWL_WARNING("Can not read from adapter at this time.\n");
-		return;
-	}
-
-	/* event log header */
-	capacity = iwl_read_restricted_mem(priv, base);
-	mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
-	num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
-	next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
-
-	size = num_wraps ? capacity : next_entry;
-
-	/* bail out if nothing in log */
-	if (size == 0) {
-		IWL_ERROR("Start IPW Event Log Dump: nothing in log\n");
-		iwl_release_restricted_access(priv);
-		return;
-	}
-
-	IWL_ERROR("Start IPW Event Log Dump: display count %d, wraps %d\n",
-		  size, num_wraps);
-
-	/* if uCode has wrapped back to top of log, start at the oldest entry,
-	 *    i.e the next one that uCode would fill. */
-	if (num_wraps) {
-		iwl_print_event_log(priv, next_entry,
-				    capacity - next_entry, mode);
-	}
-
-	/* (then/else) start at top of log */
-	iwl_print_event_log(priv, 0, next_entry, mode);
-
-	iwl_release_restricted_access(priv);
-}
-
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-static void iwl_irq_handle_error(struct iwl_priv *priv)
-{
-	/* Set the FW error flag -- cleared on iwl_down */
-	priv->status |= STATUS_FW_ERROR;
-
-	/* Cancel currently queued command. */
-	priv->status &= ~STATUS_HCMD_ACTIVE;
-
-	IWL_WARNING("RX write index: %d read index %d\n",
-		     priv->rxq.write, priv->rxq.read);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_FW_ERRORS) {
-		iwl_dump_nic_error_log(priv);
-		iwl_dump_nic_event_log(priv);
-		iwl_print_rx_config_cmd(&priv->staging_rxon);
-	}
-#endif
-
-	wake_up_interruptible(&priv->wait_command_queue);
-
-	/* Keep the restart process from trying to send host
-	 * commands by clearing the INIT status bit */
-	priv->status &= ~STATUS_READY;
-	if (!(priv->status & STATUS_EXIT_PENDING)) {
-		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
-			  "Restarting adapter due to uCode error.\n");
-		if (iwl_is_associated(priv)) {
-			memcpy(&priv->recovery_rxon, &priv->active_rxon,
-			       sizeof(priv->recovery_rxon));
-			priv->error_recovering = 1;
-		}
-
-		queue_work(priv->workqueue, &priv->restart);
-	}
-}
-
-static void iwl_error_recovery(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
-	       sizeof(priv->staging_rxon));
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-
-	iwl_rxon_add_station(priv, priv->bssid, 1);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->assoc_id = priv->staging_rxon.assoc_id;
-	priv->error_recovering = 0;
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void iwl_irq_tasklet(struct iwl_priv *priv)
-{
-	u32 inta, inta_mask, handled = 0;
-	u32 inta_fh;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* 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 = 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 = iwl_read32(priv, CSR_FH_INT_STATUS);
-	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
-
-	inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
-	IWL_DEBUG_ISR
-	    ("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-	     inta, inta_mask, inta_fh);
-
-	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
-	 * atomic, make sure that inta covers all the interrupts that
-	 * we've discovered, even if FH interrupt came in just after
-	 * reading CSR_INT. */
-	if (inta_fh & FH_INT_RX_MASK)
-		inta |= BIT_INT_FH_RX;
-	if (inta_fh & FH_INT_TX_MASK)
-		inta |= BIT_INT_FH_TX;
-
-	/* Now service all interrupt bits discovered above. */
-	if (inta & BIT_INT_ERR) {
-		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
-
-		/* Tell the device to stop sending interrupts */
-		iwl_disable_interrupts(priv);
-
-		iwl_irq_handle_error(priv);
-
-		handled |= BIT_INT_ERR;
-
-		spin_unlock_irqrestore(&priv->lock, flags);
-
-		return;
-	}
-
-	if (inta & BIT_INT_RF_KILL) {
-		int hw_rf_kill = 0;
-		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
-				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-			hw_rf_kill = 1;
-
-		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
-				"RF_KILL bit toggled to %s.\n",
-				hw_rf_kill ? "disable radio":"enable radio");
-
-		/* Queue restart only if RF_KILL switch was set to "kill"
-		 *   when we loaded driver, and is now set to "enable".
-		 * After we're Alive, RF_KILL gets handled by
-		 *   iwl_rx_card_state_notif() */
-		if (!hw_rf_kill && !(priv->status & STATUS_ALIVE))
-			queue_work(priv->workqueue, &priv->restart);
-
-		handled |= BIT_INT_RF_KILL;
-	}
-
-	if (inta & BIT_INT_CT_KILL) {
-		IWL_ERROR("Microcode CT kill error detected.\n");
-		handled |= BIT_INT_CT_KILL;
-	}
-
-	if (inta & BIT_INT_SWERROR) {
-		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
-			  inta);
-		iwl_irq_handle_error(priv);
-		handled |= BIT_INT_SWERROR;
-	}
-
-	if (inta & BIT_INT_WAKEUP) {
-		IWL_DEBUG_ISR("Wakeup interrupt\n");
-		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
-
-		handled |= BIT_INT_WAKEUP;
-	}
-
-	/* Alive notification via Rx interrupt will do the real work */
-	if (inta & BIT_INT_ALIVE) {
-		IWL_DEBUG_ISR("Alive interrupt\n");
-		handled |= BIT_INT_ALIVE;
-	}
-
-	/* All uCode command responses, including Tx command responses,
-	 * Rx "responses" (frame-received notification), and other
-	 * notifications from uCode come through here*/
-	if (inta & (BIT_INT_FH_RX | BIT_INT_SW_RX)) {
-		iwl_rx_handle(priv);
-		handled |= (BIT_INT_FH_RX | BIT_INT_SW_RX);
-	}
-
-	if (inta & BIT_INT_FH_TX) {
-		IWL_DEBUG_ISR("Tx interrupt\n");
-
-#if IWL == 3945
-		iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
-		if (!iwl_grab_restricted_access(priv)) {
-			iwl_write_restricted(priv,
-					     FH_TCSR_CREDIT
-					     (ALM_FH_SRVC_CHNL), 0x0);
-			iwl_release_restricted_access(priv);
-		}
-#endif /* IWL == 3945 */
-		handled |= BIT_INT_FH_TX;
-	}
-
-	if (inta & ~handled)
-		IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
-
-	if (inta & ~CSR_INI_SET_MASK) {
-		IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
-			 inta & ~CSR_INI_SET_MASK);
-		IWL_WARNING("   with FH_INT = 0x%08x\n", inta_fh);
-	}
-
-	/* Re-enable all interrupts */
-	iwl_enable_interrupts(priv);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & (IWL_DL_ISR)) {
-		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);
-	}
-#endif
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static irqreturn_t iwl_isr(int irq, void *data, struct pt_regs *regs)
-{
-	struct iwl_priv *priv = data;
-	u32 inta, inta_mask;
-	u32 inta_fh;
-	if (!priv)
-		return IRQ_NONE;
-
-	spin_lock(&priv->lock);
-
-	/* Disable (but don't clear!) interrupts here to avoid
-	 *    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 = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-	/* Discover which interrupts are active/pending */
-	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,
-	 * or due to sporadic interrupts thrown from our NIC. */
-	if (!inta && !inta_fh) {
-		IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
-		goto none;
-	}
-
-	if ((inta == 0xFFFFFFFF) || (inta == 0xa5a5a5a5)
-	    || (inta == 0x5a5a5a5a)) {
-		/* Hardware disappeared */
-		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
-		goto none;
-	}
-
-	IWL_DEBUG_ISR ("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-	     inta, inta_mask, inta_fh);
-
-	/* iwl_irq_tasklet() will service interrupts and re-enable them */
-	tasklet_schedule(&priv->irq_tasklet);
-	spin_unlock(&priv->lock);
-
-	return IRQ_HANDLED;
-
- none:
-	/* re-enable interrupts here since we don't have anything to service. */
-	iwl_enable_interrupts(priv);
-	spin_unlock(&priv->lock);
-	return IRQ_NONE;
-}
-
-/************************** EEPROM BANDS ****************************
- *
- * The iwl_eeprom_band definitions below provide the mapping from the
- * EEPROM contents to the specific channel number supported for each
- * band.
- *
- * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
- * definition below maps to physical channel 42 in the 5.2GHz spectrum.
- * The specific geography and calibration information for that channel
- * is contained in the eeprom map itself.
- *
- * During init, we copy the eeprom information and channel map
- * information into priv->channel_info_24/52 and priv->channel_map_24/52
- *
- * channel_map_24/52 provides the index in the channel_info array for a
- * given channel.  We have to have two separate maps as there is channel
- * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
- * band_2
- *
- * A value of 0xff stored in the channel_map indicates that the channel
- * is not supported by the hardware at all.
- *
- * A value of 0xfe in the channel_map indicates that the channel is not
- * valid for Tx with the current hardware.  This means that
- * while the system can tune and receive on a given channel, it may not
- * be able to associate or transmit any frames on that
- * channel.  There is no corresponding channel information for that
- * entry.
- *
- *********************************************************************/
-
-/* 2.4 GHz */
-static const u8 iwl_eeprom_band_1[14] = {
-	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
-};
-
-/* 5.2 GHz bands */
-static const u8 iwl_eeprom_band_2[] = {
-	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
-};
-
-static const u8 iwl_eeprom_band_3[] = {	/* 5205-5320MHz */
-	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
-};
-
-static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
-	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
-};
-
-static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
-	145, 149, 153, 157, 161, 165
-};
-
-#if IWL == 4965
-static u8 iwl_eeprom_band_6[] = {       /* 2.4 FAT channel */
-	1, 2, 3, 4, 5, 6, 7
-};
-
-static u8 iwl_eeprom_band_7[] = {       /* 5.2 FAT channel */
-	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
-};
-#endif
-
-static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
-				    int *eeprom_ch_count,
-				    const struct iwl_eeprom_channel
-				    **eeprom_ch_info,
-				    const u8 **eeprom_ch_index)
-{
-	switch (band) {
-	case 1:		/* 2.4GHz band */
-		*eeprom_ch_count = GLOBAL_ARRAY_SIZE(iwl_eeprom_band_1);
-		*eeprom_ch_info = priv->eeprom.band_1_channels;
-		*eeprom_ch_index = iwl_eeprom_band_1;
-		break;
-	case 2:		/* 5.2GHz band */
-		*eeprom_ch_count = GLOBAL_ARRAY_SIZE(iwl_eeprom_band_2);
-		*eeprom_ch_info = priv->eeprom.band_2_channels;
-		*eeprom_ch_index = iwl_eeprom_band_2;
-		break;
-	case 3:		/* 5.2GHz band */
-		*eeprom_ch_count = GLOBAL_ARRAY_SIZE(iwl_eeprom_band_3);
-		*eeprom_ch_info = priv->eeprom.band_3_channels;
-		*eeprom_ch_index = iwl_eeprom_band_3;
-		break;
-	case 4:		/* 5.2GHz band */
-		*eeprom_ch_count = GLOBAL_ARRAY_SIZE(iwl_eeprom_band_4);
-		*eeprom_ch_info = priv->eeprom.band_4_channels;
-		*eeprom_ch_index = iwl_eeprom_band_4;
-		break;
-	case 5:		/* 5.2GHz band */
-		*eeprom_ch_count = GLOBAL_ARRAY_SIZE(iwl_eeprom_band_5);
-		*eeprom_ch_info = priv->eeprom.band_5_channels;
-		*eeprom_ch_index = iwl_eeprom_band_5;
-		break;
-#if IWL == 4965
-	case 6:
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
-		*eeprom_ch_info = priv->eeprom.band_24_channels;
-		*eeprom_ch_index = iwl_eeprom_band_6;
-		break;
-	case 7:
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
-		*eeprom_ch_info = priv->eeprom.band_52_channels;
-		*eeprom_ch_index = iwl_eeprom_band_7;
-		break;
-#endif
-	default:
-		BUG();
-		return;
-	}
-}
-
-const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
-						    int phymode, int channel)
-{
-	int i;
-
-	switch (phymode) {
-	case MODE_ATHEROS_TURBO:
-	case MODE_IEEE80211A:
-		for (i = 14; i < priv->channel_count; i++) {
-			if (priv->channel_info[i].channel == channel)
-				return &priv->channel_info[i];
-		}
-		break;
-
-	case MODE_IEEE80211B:
-	case MODE_IEEE80211G:
-	case MODE_ATHEROS_TURBOG:
-		if (channel >= 1 && channel <= 14)
-			return &priv->channel_info[channel - 1];
-		break;
-
-	}
-
-	return NULL;
-}
-
-#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
-			    ? # x " " : "")
-
-static int iwl_init_channel_map(struct iwl_priv *priv)
-{
-	int eeprom_ch_count = 0;
-	const u8 *eeprom_ch_index = NULL;
-	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
-	int band, ch;
-	struct iwl_channel_info *ch_info;
-
-	if (priv->channel_count) {
-		IWL_DEBUG_INFO("Channel map already initialized.\n");
-		return 0;
-	}
-
-	if (priv->eeprom.version < 0x2f) {
-		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
-			    priv->eeprom.version);
-		return -EINVAL;
-	}
-
-	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
-
-	priv->channel_count =
-	    GLOBAL_ARRAY_SIZE(iwl_eeprom_band_1) +
-	    GLOBAL_ARRAY_SIZE(iwl_eeprom_band_2) +
-	    GLOBAL_ARRAY_SIZE(iwl_eeprom_band_3) +
-	    GLOBAL_ARRAY_SIZE(iwl_eeprom_band_4) +
-	    GLOBAL_ARRAY_SIZE(iwl_eeprom_band_5);
-
-	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
-
-	priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
-				     priv->channel_count, GFP_KERNEL);
-	if (!priv->channel_info) {
-		IWL_ERROR("Could not allocate channel_info\n");
-		priv->channel_count = 0;
-		return -ENOMEM;
-	}
-
-	ch_info = priv->channel_info;
-
-	/* Loop through the 5 EEPROM bands adding them in order to the
-	 * channel map we maintain (that contains additional information than
-	 * what just in the EEPROM) */
-	for (band = 1; band <= 5; band++) {
-
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
-					&eeprom_ch_info, &eeprom_ch_index);
-
-		/* Loop through each band adding each of the channels */
-		for (ch = 0; ch < eeprom_ch_count; ch++) {
-			ch_info->channel = eeprom_ch_index[ch];
-			ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
-			    MODE_IEEE80211A;
-
-			/* permanently store EEPROM's channel regulatory flags
-			 *   and max power in channel info database. */
-			ch_info->eeprom = eeprom_ch_info[ch];
-
-			/* Copy the run-time flags so they are there even on
-			 * invalid channels */
-			ch_info->flags = eeprom_ch_info[ch].flags;
-
-			if (!(is_channel_valid(ch_info))) {
-				IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
-					       "No Tx\n",
-					       ch_info->channel,
-					       ch_info->flags,
-					       is_channel_a_band(ch_info) ?
-					       "5.2" : "2.4");
-				ch_info++;
-				continue;
-			}
-
-			/* Initialize regulatory-based run-time data */
-			ch_info->max_power_avg = ch_info->curr_txpow =
-			    eeprom_ch_info[ch].max_power_avg;
-			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
-			ch_info->min_power = 0;
-
-			IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(" BIT_FMT8
-				       " %ddBm): Ad-Hoc %ssupported\n",
-				       ch_info->channel,
-				       is_channel_a_band(ch_info) ?
-				       "5.2" : "2.4",
-				       CHECK_AND_PRINT(IBSS),
-				       CHECK_AND_PRINT(ACTIVE),
-				       CHECK_AND_PRINT(RADAR),
-				       CHECK_AND_PRINT(WIDE),
-				       CHECK_AND_PRINT(NARROW),
-				       CHECK_AND_PRINT(DFS),
-				       BIT_ARG8(eeprom_ch_info[ch].flags),
-				       eeprom_ch_info[ch].
-				       max_power_avg,
-				       ((eeprom_ch_info[ch].
-					 flags & EEPROM_CHANNEL_IBSS)
-					&& !(eeprom_ch_info[ch].
-					     flags & EEPROM_CHANNEL_RADAR))
-				       ? "" : "not ");
-
-			/* Set the user_txpower_limit to the highest power
-			 * supported by any channel */
-			if (eeprom_ch_info[ch].max_power_avg >
-			    priv->user_txpower_limit)
-				priv->user_txpower_limit =
-				    eeprom_ch_info[ch].max_power_avg;
-
-			ch_info++;
-		}
-	}
-#if IWL == 4965
-	for (band = 6; band <= 7; band++) {
-		int phymode;
-		u8 fat_extension_chan;
-
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
-					&eeprom_ch_info, &eeprom_ch_index);
-
-		phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
-		/* Loop through each band adding each of the channels */
-		for (ch = 0; ch < eeprom_ch_count; ch++) {
-
-			if ((band == 6) &&
-			    ((eeprom_ch_index[ch] == 5) ||
-			    (eeprom_ch_index[ch] == 6) ||
-			    (eeprom_ch_index[ch] == 7)))
-			       fat_extension_chan = HT_IE_EXT_CHANNEL_MAX;
-			else
-				fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
-
-			iwl4965_set_fat_chan_info(priv, phymode,
-						  eeprom_ch_index[ch],
-						  &(eeprom_ch_info[ch]),
-						  fat_extension_chan);
-
-			iwl4965_set_fat_chan_info(priv, phymode,
-						  (eeprom_ch_index[ch] + 4),
-						  &(eeprom_ch_info[ch]),
-						  HT_IE_EXT_CHANNEL_BELOW);
-		}
-	}
-#endif
-
-	if (iwl3945_txpower_set_from_eeprom(priv))
-		return -EIO;
-
-	return 0;
-}
-
-/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
- * sending probe req.  This should be set long enough to hear probe responses
- * from more than one AP.  */
-#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52    (10)
-
-/* For faster active scanning, scan will move to the next channel if fewer than
- * PLCP_QUIET_THRESH packets are heard on this channel within
- * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
- * time if it's a quiet channel (nothing responded to our probe, and there's
- * no other traffic).
- * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
-#define IWL_PLCP_QUIET_THRESH       (1)	/* packets */
-#define IWL_ACTIVE_QUIET_TIME       (5)	/* msec */
-
-/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
- * Must be set longer than active dwell time.
- * For the most reliable scan, set > AP beacon interval (typically 100msec). */
-#define IWL_PASSIVE_DWELL_TIME_24   (20)	/* all times in msec */
-#define IWL_PASSIVE_DWELL_TIME_52   (10)
-#define IWL_PASSIVE_DWELL_BASE      (100)
-#define IWL_CHANNEL_TUNE_TIME       5
-
-static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
-{
-	if ((phymode == MODE_IEEE80211A) ||
-	    (phymode == MODE_ATHEROS_TURBO))
-		return IWL_ACTIVE_DWELL_TIME_52;
-	else
-		return IWL_ACTIVE_DWELL_TIME_24;
-}
-
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
-{
-	u16 active = iwl_get_active_dwell_time(priv, phymode);
-	u16 passive = ((phymode != MODE_IEEE80211A) &&
-		       (phymode != MODE_ATHEROS_TURBO)) ?
-	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
-	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
-
-	if (iwl_is_associated(priv)) {
-		/* If we're associated, we clamp the maximum passive
-		 * dwell time to be 98% of the beacon interval (minus
-		 * 2 * channel tune time) */
-		passive = priv->beacon_int;
-		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
-			passive = IWL_PASSIVE_DWELL_BASE;
-		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
-	}
-
-	if (passive <= active)
-		passive = active + 1;
-
-	return passive;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
-				     u8 is_active, u8 direct_mask,
-				     struct iwl_scan_channel *scan_ch)
-{
-	const struct ieee80211_channel *channels = NULL;
-	const struct ieee80211_hw_mode *hw_mode;
-	const struct iwl_channel_info *ch_info;
-	u16 passive_dwell = 0;
-	u16 active_dwell = 0;
-	int added, i;
-
-	hw_mode = iwl_get_hw_mode(priv, phymode);
-	if (!hw_mode)
-		return 0;
-
-	channels = hw_mode->channels;
-
-	active_dwell = iwl_get_active_dwell_time(priv, phymode);
-	passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
-
-	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
-		if (channels[i].chan ==
-		    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 = channels[i].chan;
-
-		ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
-		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
-				       scan_ch->channel);
-			continue;
-		}
-
-		if (!is_active || is_channel_passive(ch_info) ||
-		    !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
-			scan_ch->type = 0;	/* passive */
-		else
-			scan_ch->type = 1;	/* active */
-
-		if (scan_ch->type & 1)
-			scan_ch->type |= (direct_mask << 1);
-
-		if (is_channel_narrow(ch_info))
-			scan_ch->type |= (1 << 7);
-
-		scan_ch->active_dwell = active_dwell;
-		scan_ch->passive_dwell = passive_dwell;
-
-		/* Set power levels to defaults */
-		scan_ch->tpc.dsp_atten = 110;
-		/* scan_pwr_info->tpc.dsp_atten; */
-
-		/*scan_pwr_info->tpc.tx_gain; */
-		if ((phymode == MODE_IEEE80211A) ||
-		    (phymode == MODE_ATHEROS_TURBO)) {
-			scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
-		} else {
-			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
-			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-			 * power level
-			 scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
-			 */
-		}
-
-		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
-			       scan_ch->channel,
-			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
-			       (scan_ch->type & 1) ?
-			       active_dwell : passive_dwell);
-
-		scan_ch++;
-		added++;
-	}
-
-	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
-	return added;
-}
-
-static void iwl_reset_channel_flag(struct iwl_priv *priv)
-{
-	int i, j;
-	for (i = 0; i < 3; i++) {
-		struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
-		for (j = 0; j < hw_mode->num_channels; j++)
-			hw_mode->channels[j].flag = hw_mode->channels[j].val;
-	}
-}
-
-static void iwl_init_hw_rates(struct iwl_priv *priv,
-			      struct ieee80211_rate *rates)
-{
-	int i;
-
-	for (i = 0; i < IWL_RATE_COUNT; i++) {
-		rates[i].rate = iwl_rates[i].ieee * 5;
-		rates[i].val = i; /* Rate scaling will work on indexes */
-		rates[i].val2 = i;
-		rates[i].flags = IEEE80211_RATE_SUPPORTED;
-		/* Only OFDM have the bits-per-symbol set */
-		if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
-			rates[i].flags |= IEEE80211_RATE_OFDM;
-		else {
-			/*
-			 * If CCK 1M then set rate flag to CCK else CCK_2
-			 * which is CCK | PREAMBLE2
-			 */
-			rates[i].flags |= (iwl_rates[i].plcp == 10) ?
-			    IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
-		}
-
-		/* Set up which ones are basic rates... */
-		if (IWL_BASIC_RATES_MASK & (1 << i))
-			rates[i].flags |= IEEE80211_RATE_BASIC;
-	}
-
-#if IWL == 4965
-	iwl4965_init_hw_rates(priv, rates);
-#endif
-}
-
-/**
- * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-static int iwl_init_geos(struct iwl_priv *priv)
-{
-	struct iwl_channel_info *ch;
-	struct ieee80211_hw_mode *modes;
-	struct ieee80211_channel *channels;
-	struct ieee80211_channel *geo_ch;
-	struct ieee80211_rate *rates;
-	int i = 0;
-#if IWL == 4965
-	enum {
-		A = 0,
-		B = 1,
-		G = 2,
-		A_11N = 3,
-		G_11N = 4,
-	};
-	int mode_count = 5;
-#else
-	enum {
-		A = 0,
-		B = 1,
-		G = 2,
-	};
-	int mode_count = 3;
-#endif
-
-	if (priv->modes) {
-		IWL_DEBUG_INFO("Geography modes already initialized.\n");
-		priv->status |= STATUS_GEO_CONFIGURED;
-		return 0;
-	}
-
-	modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
-			GFP_ATOMIC);
-	if (!modes)
-		return -ENOMEM;
-
-	channels = kzalloc(sizeof(struct ieee80211_channel) *
-			   priv->channel_count, GFP_ATOMIC);
-	if (!channels) {
-		kfree(modes);
-		return -ENOMEM;
-	}
-
-	rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
-			GFP_ATOMIC);
-	if (!rates) {
-		kfree(modes);
-		kfree(channels);
-		return -ENOMEM;
-	}
-
-	/* 0 = 802.11a
-	 * 1 = 802.11b
-	 * 2 = 802.11g
-	 */
-
-	/* 5.2GHz channels start after the 2.4GHz channels */
-	modes[A].mode = MODE_IEEE80211A;
-	modes[A].channels = &channels[GLOBAL_ARRAY_SIZE(iwl_eeprom_band_1)];
-	modes[A].rates = rates;
-	modes[A].num_rates = 8;	/* just OFDM */
-#if IWL == 4965
-	modes[A].rates = &rates[4];
-#endif
-	modes[A].num_channels = 0;
-
-	modes[B].mode = MODE_IEEE80211B;
-	modes[B].channels = channels;
-#if IWL == 3945
-	modes[B].rates = &rates[8];
-#elif IWL == 4965
-	modes[B].rates = rates;
-#endif
-	modes[B].num_rates = 4;	/* just CCK */
-	modes[B].num_channels = 0;
-
-	modes[G].mode = MODE_IEEE80211G;
-	modes[G].channels = channels;
-	modes[G].rates = rates;
-	modes[G].num_rates = 12;	/* OFDM & CCK */
-	modes[G].num_channels = 0;
-
-#if IWL == 4965
-	modes[G_11N].mode = MODE_ATHEROS_TURBOG;
-	modes[G_11N].channels = channels;
-	modes[G_11N].num_rates = 13;        /* OFDM & CCK */
-	modes[G_11N].rates = rates;
-	modes[G_11N].num_channels = 0;
-
-	modes[A_11N].mode = MODE_ATHEROS_TURBO;
-	modes[A_11N].channels = &channels[GLOBAL_ARRAY_SIZE(iwl_eeprom_band_1)];
-	modes[A_11N].rates = &rates[4];
-	modes[A_11N].num_rates = 9; /* just OFDM */
-	modes[A_11N].num_channels = 0;
-#endif
-	priv->ieee_channels = channels;
-	priv->ieee_rates = rates;
-
-	iwl_init_hw_rates(priv, rates);
-
-	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
-		ch = &priv->channel_info[i];
-
-		if (!is_channel_valid(ch)) {
-			IWL_WARNING("Channel %d [%sGHz] is Tx only -- "
-				    "skipping.\n",
-				    ch->channel, is_channel_a_band(ch) ?
-				    "5.2" : "2.4");
-			continue;
-		}
-
-		if (is_channel_a_band(ch)) {
-			geo_ch = &modes[A].channels[modes[A].num_channels++];
-#if IWL == 4965
-			modes[A_11N].num_channels++;
-#endif
-		} else {
-			geo_ch = &modes[B].channels[modes[B].num_channels++];
-			modes[G].num_channels++;
-#if IWL == 4965
-			modes[G_11N].num_channels++;
-#endif
-		}
-
-		geo_ch->freq = ieee80211chan2mhz(ch->channel);
-		geo_ch->chan = ch->channel;
-		geo_ch->power_level = ch->max_power_avg;
-		geo_ch->antenna_max = 0xff;
-
-		if (is_channel_valid(ch)) {
-			geo_ch->flag = IEEE80211_CHAN_W_SCAN;
-			if (ch->flags & EEPROM_CHANNEL_IBSS)
-				geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
-
-			if (ch->flags & EEPROM_CHANNEL_ACTIVE)
-				geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
-
-			if (ch->flags & EEPROM_CHANNEL_RADAR)
-				geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
-
-			if (ch->max_power_avg > priv->max_channel_txpower_limit)
-				priv->max_channel_txpower_limit =
-				    ch->max_power_avg;
-		}
-
-		geo_ch->val = geo_ch->flag;
-	}
-
-	if ((modes[A].num_channels == 0) && priv->is_abg) {
-		printk(KERN_INFO DRV_NAME
-		       ": Incorrectly detected BG card as ABG.  Please send "
-		       "your PCI ID 0x%04X:0x%04X to maintainer.\n",
-		       priv->pci_dev->device, priv->pci_dev->subsystem_device);
-		priv->is_abg = 0;
-	}
-
-	printk(KERN_INFO DRV_NAME
-	       ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
-	       modes[G].num_channels, modes[A].num_channels);
-
-	/*
-	 * NOTE:  We register these in preference of order -- the
-	 * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
-	 * a phymode based on rates or AP capabilities but seems to
-	 * configure it purely on if the channel being configured
-	 * is supported by a mode -- and the first match is taken
-	 */
-
-	if (modes[G].num_channels)
-		ieee80211_register_hwmode(priv->hw, &modes[G]);
-	if (modes[B].num_channels)
-		ieee80211_register_hwmode(priv->hw, &modes[B]);
-	if (modes[A].num_channels)
-		ieee80211_register_hwmode(priv->hw, &modes[A]);
-
-	priv->modes = modes;
-	priv->status |= STATUS_GEO_CONFIGURED;
-
-	return 0;
-}
-
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
-{
-	if (priv->ucode_code.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_code.len,
-				    priv->ucode_code.v_addr,
-				    priv->ucode_code.p_addr);
-		priv->ucode_code.v_addr = NULL;
-	}
-	if (priv->ucode_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data.len,
-				    priv->ucode_data.v_addr,
-				    priv->ucode_data.p_addr);
-		priv->ucode_data.v_addr = NULL;
-	}
-	if (priv->ucode_data_backup.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data_backup.len,
-				    priv->ucode_data_backup.v_addr,
-				    priv->ucode_data_backup.p_addr);
-		priv->ucode_data_backup.v_addr = NULL;
-	}
-	if (priv->ucode_init.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init.len,
-				    priv->ucode_init.v_addr,
-				    priv->ucode_init.p_addr);
-		priv->ucode_init.v_addr = NULL;
-	}
-	if (priv->ucode_init_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init_data.len,
-				    priv->ucode_init_data.v_addr,
-				    priv->ucode_init_data.p_addr);
-		priv->ucode_init_data.v_addr = NULL;
-	}
-	if (priv->ucode_boot.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_boot.len,
-				    priv->ucode_boot.v_addr,
-				    priv->ucode_boot.p_addr);
-		priv->ucode_boot.v_addr = NULL;
-	}
-}
-
-/**
- * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
- *     looking at all data.
- */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32* image, u32 len)
-{
-	u32 val;
-	u32 save_len = len;
-	int rc = 0;
-	u32 errcnt;
-
-	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
-	rc = iwl_grab_restricted_access(priv);
-	if (rc)
-		return rc;
-
-	iwl_write_restricted(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 = _iwl_read_restricted(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",
-				  save_len - len, val, le32_to_cpu(*image));
-			rc = -EIO;
-			errcnt++;
-			if (errcnt >= 20)
-				break;
-		}
-	}
-
-	iwl_release_restricted_access(priv);
-
-	if (!errcnt)
-		IWL_DEBUG_INFO
-		    ("ucode image in INSTRUCTION memory is good\n");
-
-	return rc;
-}
-
-
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32* image, u32 len)
-{
-	u32 val;
-	int rc = 0;
-	u32 errcnt = 0;
-	u32 i;
-
-	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
-	rc = iwl_grab_restricted_access(priv);
-	if (rc)
-		return rc;
-
-	for (i = 0; i < len; i += 100, image += 100/sizeof(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 */
-		iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
-			i + RTC_INST_LOWER_BOUND);
-		val = _iwl_read_restricted(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 "
-				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
-				  i, val, *image);
-#endif
-			rc = -EIO;
-			errcnt++;
-			if (errcnt >= 3)
-				break;
-		}
-	}
-
-	iwl_release_restricted_access(priv);
-
-	return rc;
-}
-
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl_verify_ucode(struct iwl_priv *priv)
-{
-	__le32 *image;
-	u32 len;
-	int rc = 0;
-
-	/* Try bootstrap */
-	image = (__le32*)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
-	if (rc == 0) {
-		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	/* Try initialize */
-	image = (__le32*)priv->ucode_init.v_addr;
-	len = priv->ucode_init.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
-	if (rc == 0) {
-		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	/* Try runtime/protocol */
-	image = (__le32*)priv->ucode_code.v_addr;
-	len = priv->ucode_code.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
-	if (rc == 0) {
-		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
-		return 0;
-	}
-
-	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
-	/* Show first several data entries in instruction SRAM.
-	 * Selection of bootstrap image is arbitrary. */
-	image = (__le32*)priv->ucode_boot.v_addr;
-	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_full(priv, image, len);
-
-	return rc;
-}
-
-
-/* check contents of special bootstrap uCode SRAM */
-static int iwl_verify_bsm(struct iwl_priv *priv)
-{
-	__le32 *image = priv->ucode_boot.v_addr;
-	u32 len = priv->ucode_boot.len;
-	u32 reg;
-	u32 val;
-
-	IWL_DEBUG_INFO("Begin verify bsm\n");
-
-	/* verify BSM SRAM contents */
-	val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
-	for (reg = BSM_SRAM_LOWER_BOUND;
-	     reg < BSM_SRAM_LOWER_BOUND + len;
-	     reg += sizeof(u32), image ++) {
-		val = iwl_read_restricted_reg(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",
-				  BSM_SRAM_LOWER_BOUND,
-				  reg - BSM_SRAM_LOWER_BOUND, len,
-				  val, le32_to_cpu(* image));
-			return -EIO;
-		}
-	}
-
-	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
-
-	return 0;
-}
-
-/**
- * iwl_load_bsm - Load bootstrap instructions
- *
- * BSM operation:
- *
- * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
- * in special SRAM that does not power down during RFKILL.  When powering back
- * up after power-saving sleeps (or during initial uCode load), the BSM loads
- * the bootstrap program into the on-board processor, and starts it.
- *
- * The bootstrap program loads (via DMA) instructions and data for a new
- * program from host DRAM locations indicated by the host driver in the
- * BSM_DRAM_* registers.  Once the new program is loaded, it starts
- * automatically.
- *
- * When initializing the NIC, the host driver points the BSM to the
- * "initialize" uCode image.  This uCode sets up some internal data, then
- * notifies host via "initialize alive" that it is complete.
- *
- * The host then replaces the BSM_DRAM_* pointer values to point to the
- * normal runtime uCode instructions and a backup uCode data cache buffer
- * (filled initially with starting data values for the on-board processor),
- * then triggers the "initialize" uCode to load and launch the runtime uCode,
- * which begins normal operation.
- *
- * When doing a power-save shutdown, runtime uCode saves data SRAM into
- * the backup data cache in DRAM before SRAM is powered down.
- *
- * When powering back up, the BSM loads the bootstrap program.  This reloads
- * the runtime uCode instructions and the backup data cache into SRAM,
- * and re-launches the runtime uCode from where it left off.
- */
-static int iwl_load_bsm(struct iwl_priv *priv)
-{
-	__le32 *image = priv->ucode_boot.v_addr;
-	u32 len = priv->ucode_boot.len;
-	dma_addr_t pinst;
-	dma_addr_t pdata;
-	u32 inst_len;
-	u32 data_len;
-	int rc;
-	int i;
-	u32 done;
-	u32 reg_offset;
-
-	IWL_DEBUG_INFO("Begin load bsm\n");
-
-	/* make sure bootstrap program is no larger than BSM's SRAM size */
-	if (len > IWL_MAX_BSM_SIZE)
-		return -EINVAL;
-
-	/* Tell bootstrap uCode where to find the "Initialize" uCode
-	 *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
-	 * NOTE:  iwl_initialize_alive_start() will replace these values,
-	 *        after the "initialize" uCode has run, to point to
-	 *        runtime/protocol instructions and backup data cache. */
-#if IWL == 3945
-	pinst = priv->ucode_init.p_addr;
-	pdata = priv->ucode_init_data.p_addr;
-#elif IWL == 4965
-	pinst = priv->ucode_init.p_addr >> 4;
-	pdata = priv->ucode_init_data.p_addr >> 4;
-#endif
-	inst_len = priv->ucode_init.len;
-	data_len = priv->ucode_init_data.len;
-
-	rc = iwl_grab_restricted_access(priv);
-	if (rc)
-		return rc;
-
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
-	iwl_write_restricted_reg(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++)
-		_iwl_write_restricted_reg(priv, reg_offset, le32_to_cpu(*image));
-
-	rc = iwl_verify_bsm(priv);
-	if (rc){
-		iwl_release_restricted_access(priv);
-		return rc;
-	}
-
-	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
-				 RTC_INST_LOWER_BOUND);
-	iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
-
-	/* Load bootstrap code into instruction SRAM now,
-	 *   to prepare to load "initialize" uCode */
-	iwl_write_restricted_reg(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 = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
-		if (!(done & BSM_WR_CTRL_REG_BIT_START))
-			break;
-		udelay(10);
-	}
-	if (i < 100)
-		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
-	else {
-		IWL_ERROR("BSM write did not complete!\n");
-		return -EIO;
-	}
-
-	/* Enable future boot loads whenever power management unit triggers it
-	 *   (e.g. when powering back up after power-save shutdown) */
-	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
-		BSM_WR_CTRL_REG_BIT_START_EN);
-
-	iwl_release_restricted_access(priv);
-
-	return 0;
-}
-
-static void iwl_nic_start(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	/* Remove all resets to allow NIC to operate */
-	iwl_write32(priv, CSR_RESET, 0);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/**
- * iwl_read_ucode - Read uCode images from disk file.
- *
- * Copy into buffers for card to fetch via bus-mastering
- */
-static int iwl_read_ucode(struct iwl_priv *priv)
-{
-	struct iwl_ucode *ucode;
-	int rc = 0;
-	const struct firmware *ucode_raw;
-#if IWL == 3945
-	const char *name = "iwlwifi-3945.ucode";	/* firmware file name */
-#elif IWL == 4965
-	const char *name = "iwlwifi-4965.ucode";	/* firmware file name */
-#endif
-	u8 *src;
-	size_t len;
-	u32 ver,inst_size,data_size,init_size,init_data_size,boot_size;
-
-	/* Ask kernel firmware_class module to get the boot firmware off disk.
-	 * request_firmware() is synchronous call, file is in memory on return.
-	 * TODO:  Would it be more polite to use asynchronous
-	 *        request_firmware_nowait()??  If so, put request back into
-	 *        iwl_pci_probe(), and rest of this function would serve as
-	 *        the callback for request_firmware_nowait().  Also need to
-	 *        make sure everything waits for this callback to complete! */
-	rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-	if (rc < 0) {
-		IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
-		goto error;
-	}
-
-	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
-		       name, ucode_raw->size);
-
-	/* Make sure that we got at least our header! */
-	if (ucode_raw->size < sizeof(*ucode)) {
-		IWL_ERROR("File size way too small!\n");
-		rc = -EINVAL;
-		goto err_release;
-	}
-
-	/* Data from ucode file:  header followed by uCode images */
-	ucode = (void *)ucode_raw->data;
-
-	ver = le32_to_cpu(ucode->ver);
-	inst_size = le32_to_cpu(ucode->inst_size);
-	data_size = le32_to_cpu(ucode->data_size);
-	init_size = le32_to_cpu(ucode->init_size);
-	init_data_size = le32_to_cpu(ucode->init_data_size);
-	boot_size = le32_to_cpu(ucode->boot_size);
-
-	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
-	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
-		       inst_size);
-	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
-		       data_size);
-	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
-		       init_size);
-	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
-		       init_data_size);
-	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
-		       boot_size);
-
-	/* Verify size of file vs. image size info in file's header */
-	if (ucode_raw->size < sizeof(*ucode) +
-		inst_size + data_size + init_size +
-		init_data_size + boot_size) {
-
-		IWL_DEBUG_INFO("uCode file size %d too small\n",
-			       (int)ucode_raw->size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-
-	/* Verify that uCode images will fit in card's SRAM */
-	if (inst_size > IWL_MAX_INST_SIZE) {
-		IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
-			       (int)inst_size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-
-	if (data_size > IWL_MAX_DATA_SIZE) {
-		IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
-			       (int)data_size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-	if (init_size > IWL_MAX_INST_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode init instr len %d too large to fit in card\n",
-		     (int)init_size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-	if (init_data_size > IWL_MAX_DATA_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode init data len %d too large to fit in card\n",
-		     (int)init_data_size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-	if (boot_size > IWL_MAX_BSM_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode boot instr len %d too large to fit in bsm\n",
-		     (int)boot_size);
-		rc = -EINVAL;
-		goto err_release;
-	}
-
-	/* Allocate ucode buffers for card's bus-master loading ... */
-
-	/* Runtime instructions and 2 copies of data:
-	 * 1) unmodified from disk
-	 * 2) backup cache for save/restore during power-downs */
-	priv->ucode_code.len = inst_size;
-	priv->ucode_code.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_code.len,
-				 &(priv->ucode_code.p_addr));
-
-	priv->ucode_data.len = data_size;
-	priv->ucode_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data.len,
-				 &(priv->ucode_data.p_addr));
-
-	priv->ucode_data_backup.len = data_size;
-	priv->ucode_data_backup.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data_backup.len,
-				 &(priv->ucode_data_backup.p_addr));
-
-
-	/* Initialization instructions and data */
-	priv->ucode_init.len = init_size;
-	priv->ucode_init.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init.len,
-				 &(priv->ucode_init.p_addr));
-
-	priv->ucode_init_data.len = init_data_size;
-	priv->ucode_init_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init_data.len,
-				 &(priv->ucode_init_data.p_addr));
-
-	/* Bootstrap (instructions only, no data) */
-	priv->ucode_boot.len = boot_size;
-	priv->ucode_boot.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_boot.len,
-				 &(priv->ucode_boot.p_addr));
-
-	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
-	    !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
-	    !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
-		goto err_pci_alloc;
-
-	/* Copy images into buffers for card's bus-master reads ... */
-
-	/* Runtime instructions (first block of data in file) */
-	src = &ucode->data[0];
-	len = priv->ucode_code.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
-		       (int)len);
-	memcpy(priv->ucode_code.v_addr, src, len);
-	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
-		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
-
-	/* Runtime data (2nd block)
-	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-	src = &ucode->data[inst_size];
-	len = priv->ucode_data.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
-		       (int)len);
-	memcpy(priv->ucode_data.v_addr, src, len);
-	memcpy(priv->ucode_data_backup.v_addr, src, len);
-
-	/* Initialization instructions (3rd block) */
-	if (init_size) {
-		src = &ucode->data[inst_size + data_size];
-		len = priv->ucode_init.len;
-		IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
-			       (int)len);
-		memcpy(priv->ucode_init.v_addr, src, len);
-	}
-
-	/* Initialization data (4th block) */
-	if (init_data_size) {
-		src = &ucode->data[inst_size + data_size + init_size];
-		len = priv->ucode_init_data.len;
-		IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
-			       (int)len);
-		memcpy(priv->ucode_init_data.v_addr, src, len);
-	}
-
-	/* Bootstrap instructions (5th block) */
-	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
-	len = priv->ucode_boot.len;
-	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
-		       (int)len);
-	memcpy(priv->ucode_boot.v_addr, src, len);
-
-	/* We have our copies now, allow OS release its copies */
-	release_firmware(ucode_raw);
-	return 0;
-
- err_pci_alloc:
-	IWL_ERROR("failed to allocate pci memory\n");
-	rc = -ENOMEM;
-	iwl_dealloc_ucode_pci(priv);
-
- err_release:
-	release_firmware(ucode_raw);
-
- error:
-	return rc;
-}
-
-
-/**
- * iwl_set_ucode_ptrs - Set uCode address location
- *
- * Tell initialization uCode where to find runtime uCode.
- *
- * BSM registers initially contain pointers to initialization uCode.
- * We need to replace them to load runtime uCode inst and data,
- * and to save runtime data when powering down.
- */
-static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
-{
-	dma_addr_t pinst;
-	dma_addr_t pdata;
-	int rc = 0;
-	unsigned long flags;
-
-#if IWL == 3945
-	/* bits 31:0 for 3945 */
-	pinst = priv->ucode_code.p_addr;
-	pdata = priv->ucode_data_backup.p_addr;
-#else
-	/* bits 35:4 for 4965 */
-	pinst = priv->ucode_code.p_addr >> 4;
-	pdata = priv->ucode_data_backup.p_addr >> 4;
-#endif
-
-	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
-	}
-
-	/* Tell bootstrap uCode where to find image to load */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(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 */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
-				 priv->ucode_code.len | 0x80000000);
-
-	iwl_release_restricted_access(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
-
-	return rc;
-}
-
-/**
- * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
- *
- * Called after REPLY_ALIVE notification received from "initialize" uCode.
- *
- * The 4965 "initialize" ALIVE reply contains calibration data for:
- *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
- *   (3945 does not contain this data).
- *
- * Tell "initialize" uCode to go ahead and load the runtime uCode.
-*/
-static void iwl_init_alive_start(struct iwl_priv *priv)
-{
-	/* Check alive response for "valid" sign from uCode */
-	if (priv->card_alive_init.is_valid != 1) {
-		/* We had an error bringing up the hardware, so take it
-		 * all the way back down so we can try again */
-		IWL_DEBUG_INFO("Initialize Alive failed.\n");
-		goto restart;
-	}
-
-	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
-	 * This is a paranoid check, because we would not have gotten the
-	 * "initialize" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
-		/* Runtime instruction load was bad;
-		 * take it all the way back down so we can try again */
-		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
-		goto restart;
-	}
-
-#if IWL == 4965
-	/* Calculate temperature */
-	priv->temperature = iwl4965_get_temperature(priv);
-#endif
-
-	/* Send pointers to protocol/runtime uCode image ... init code will
-	 * load and launch runtime uCode, which will send us another "Alive"
-	 * notification. */
-	IWL_DEBUG_INFO("Initialization Alive received.\n");
-	if (iwl_set_ucode_ptrs(priv)) {
-		/* Runtime instruction load won't happen;
-		 * take it all the way back down so we can try again */
-		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
-		goto restart;
-	}
-	return;
-
- restart:
-	queue_work(priv->workqueue, &priv->restart);
-}
-
-
-/**
- * iwl_alive_start - called after REPLY_ALIVE notification received
- *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl_init_alive_start()).
- */
-static void iwl_alive_start(struct iwl_priv *priv)
-{
-	int rc = 0;
-#if IWL == 3945
-	int thermal_spin = 0;
-	u32 rfkill;
-#endif
-
-	IWL_DEBUG_INFO("Runtime Alive received.\n");
-
-	if (priv->card_alive.is_valid != 1) {
-		/* We had an error bringing up the hardware, so take it
-		 * all the way back down so we can try again */
-		IWL_DEBUG_INFO("Alive failed.\n");
-		goto restart;
-	}
-
-	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
-	 * This is a paranoid check, because we would not have gotten the
-	 * "runtime" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
-		/* Runtime instruction load was bad;
-		 * take it all the way back down so we can try again */
-		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
-		goto restart;
-	}
-
-	iwl_clear_stations_table(priv);
-
-#if IWL == 4965
-	rc = iwl4965_alive_notify(priv);
-	if (rc) {
-		IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
-			    rc);
-		goto restart;
-	}
-#elif IWL == 3945
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
-		IWL_WARNING("Can not read rfkill status from adapter\n");
-		return;
-	}
-
-	rfkill = iwl_read_restricted_reg(priv, ALM_APMG_RFKILL);
-	IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
-	iwl_release_restricted_access(priv);
-
-	if (rfkill & 0x1) {
-		priv->status &= ~STATUS_RF_KILL_HW;
-		/* if rfkill is not on, then wait for thermal
-		 * sensor in adapter to kick in */
-		while (iwl_hw_get_temperature(priv) == 0) {
-			thermal_spin++;
-			udelay(10);
-		}
-
-		if (thermal_spin)
-			IWL_DEBUG_INFO("Thermal calibration took %dus\n",
-				       thermal_spin * 10);
-	} else
-		priv->status |= STATUS_RF_KILL_HW;
-#endif
-
-	/* After the ALIVE response, we can process host commands */
-	priv->status |= STATUS_ALIVE;
-
-	/* Clear out the uCode error bit if it is set */
-	priv->status &= ~STATUS_FW_ERROR;
-
-	rc = iwl_init_channel_map(priv);
-	if (rc) {
-		IWL_ERROR("initializing regulatory failed: %d\n", rc);
-		return;
-	}
-
-	iwl_init_geos(priv);
-
-	if (priv->status & STATUS_RF_KILL_MASK)
-		return;
-
-	if (!priv->mac80211_registered) {
-		/* Unlock so any user space entry points can call back into
-		 * the driver without a deadlock... */
-		mutex_unlock(&priv->mutex);
-		iwl_rate_control_register();
-		rc = ieee80211_register_hw(priv->hw);
-		priv->hw->conf.beacon_int = 100;
-		mutex_lock(&priv->mutex);
-
-		if (rc) {
-			IWL_ERROR("Failed to register network "
-				  "device (error %d)\n", rc);
-			return;
-		}
-
-		priv->mac80211_registered = 1;
-
-		iwl_reset_channel_flag(priv);
-	} else
-		ieee80211_start_queues(priv->hw);
-
-	priv->active_rate = priv->rates_mask;
-	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
-
-	iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
-
-	/* Initialize our rx_config data */
-	iwl_connection_init_rx_config(priv);
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
-        if (iwl_is_associated(priv)) {
-		struct iwl_rxon_cmd *active_rxon =
-				(struct iwl_rxon_cmd *)(&priv->active_rxon);
-
-		memcpy(&priv->staging_rxon, &priv->active_rxon,
-			sizeof(priv->staging_rxon));
-		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	}
-
-	/* Configure BT coexistence */
-	iwl_send_bt_config(priv);
-
-	/* Configure the adapter for unassociated operation */
-	iwl_commit_rxon(priv);
-
-	/* At this point, the NIC is initialized and operational */
-	priv->notif_missed_beacons = 0;
-	priv->status |= STATUS_READY;
-
-	iwl3945_reg_txpower_periodic(priv);
-
-#if IWL == 4965
-	iwl4965_rf_kill_ct_config(priv);
-#endif
-	IWL_DEBUG_INFO("ALIVE processing complete.\n");
-
-	if (priv->error_recovering)
-		iwl_error_recovery(priv);
-
-	return;
-
- restart:
-	queue_work(priv->workqueue, &priv->restart);
-}
-
-static void iwl_cancel_deferred_work(struct iwl_priv *priv);
-
-void iwl_down(struct iwl_priv *priv)
-{
-	unsigned long flags;
-	int exit_pending = priv->status & STATUS_EXIT_PENDING;
-	struct ieee80211_conf *conf = NULL;
-
-	IWL_WARNING("ipw going down \n");
-
-	conf = ieee80211_get_hw_conf(priv->hw);
-
-	priv->status |= STATUS_EXIT_PENDING;
-
-	iwl_clear_stations_table(priv);
-
-	/* Unblock any waiting calls */
-	wake_up_interruptible_all(&priv->wait_command_queue);
-
-	iwl_cancel_deferred_work(priv);
-
-	/* Wipe out the EXIT_PENDING status bit if we are not actually
-	 * exiting the module */
-	if (!exit_pending)
-		priv->status &= ~STATUS_EXIT_PENDING;
-
-	/* stop and reset the on-board processor */
-	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
-
-	if (priv->mac80211_registered)
-		ieee80211_stop_queues(priv->hw);
-
-	/* If we have not previously called iwl_init() then
-	 * clear all bits but the RF Kill and SUSPEND bits and return */
-	if (!iwl_is_init(priv)) {
-		priv->status &= (STATUS_RF_KILL_MASK | STATUS_IN_SUSPEND);
-		goto exit;
-	}
-
-	/* ...otherwise clear out all the status bits but the RF Kill and
-	 * SUSPEND bits and continue taking the NIC down. */
-	priv->status &=
-	    (STATUS_RF_KILL_MASK | STATUS_IN_SUSPEND | STATUS_FW_ERROR);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	iwl_hw_txq_ctx_stop(priv);
-	iwl_hw_rxq_stop(priv);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, ALM_APMG_CLK_DIS,
-					 APMG_CLK_REG_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	udelay(5);
-
-	iwl_hw_nic_stop_master(priv);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	iwl_hw_nic_reset(priv);
-
- exit:
-	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
-
-	if (priv->ibss_beacon)
-		dev_kfree_skb(priv->ibss_beacon);
-	priv->ibss_beacon = NULL;
-
-	/* clear out any free frames */
-	iwl_clear_free_frames(priv);
-}
-
-#define MAX_HW_RESTARTS 5
-
-static int iwl_up(struct iwl_priv *priv)
-{
-	int rc, i;
-	u32 hw_rf_kill = 0;
-
-	if (priv->status & STATUS_EXIT_PENDING) {
-		IWL_WARNING("Exit pending; will not bring the NIC up\n");
-		return -EIO;
-	}
-
-	if (priv->status & STATUS_RF_KILL_SW) {
-		IWL_WARNING("Radio disabled by SW RF kill (module "
-			    "parameter)\n");
-		return 0;
-	}
-
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-	rc = iwl_hw_nic_init(priv);
-	if (rc) {
-		IWL_ERROR("Unable to int nic\n");
-		return rc;
-	}
-
-	/* make sure rfkill handshake bits are cleared */
-	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 */
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_enable_interrupts(priv);
-
-	/* really make sure rfkill handshake bits are cleared */
-	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
-	 * data SRAM for a clean start when the runtime program first loads. */
-	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-			priv->ucode_data.len);
-
-	/* If platform's RF_KILL switch is set to KILL, wait for BIT_INT_RF_KILL
-	 *   interrupt before loading uCode and getting things started */
-	if (!(iwl_read32(priv, CSR_GP_CNTRL) &
-	     CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-		hw_rf_kill = 1;
-
-	if ((priv->status & STATUS_RF_KILL_HW) || hw_rf_kill) {
-		IWL_WARNING("Radio disabled by HW RF Kill switch\n");
-		return 0;
-	}
-
-	for (i = 0; i < MAX_HW_RESTARTS; i++) {
-
-		iwl_clear_stations_table(priv);
-
-		/* load bootstrap state machine,
-		 * load bootstrap program into processor's memory,
-		 * prepare to load the "initialize" uCode */
-		rc = iwl_load_bsm(priv);
-
-		if (rc) {
-			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
-			continue;
-		}
-
-		/* start card; "initialize" will load runtime ucode */
-		iwl_nic_start(priv);
-
-		/* MAC Address location in EEPROM same for 3945/4965 */
-		get_eeprom_mac(priv, priv->mac_addr);
-		IWL_DEBUG_INFO("MAC address: " MAC_FMT "\n",
-			       MAC_ARG(priv->mac_addr));
-
-		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
-
-		return 0;
-	}
-
-	priv->status |= STATUS_EXIT_PENDING;
-	iwl_down(priv);
-
-	/* tried to restart and config the device for as long as our
-	 * patience could withstand */
-	IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
-	return -EIO;
-}
-
-
-/*****************************************************************************
- *
- * Workqueue callbacks
- *
- *****************************************************************************/
-
-static void iwl_bg_init_alive_start(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	iwl_init_alive_start(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_alive_start(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	iwl_alive_start(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_rf_kill(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	wake_up_interruptible(&priv->wait_command_queue);
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-
-	if (!(priv->status & STATUS_RF_KILL_MASK)) {
-		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
-			  "HW and/or SW RF Kill no longer active, restarting "
-			  "device\n");
-		if (!(priv->status & STATUS_EXIT_PENDING))
-			queue_work(priv->workqueue, &priv->restart);
-	} else {
-
-		if (!(priv->status & STATUS_RF_KILL_HW))
-			IWL_DEBUG_RF_KILL
-			    ("Can not turn radio back on - "
-			     "disabled by SW switch\n");
-		else
-			IWL_WARNING
-			    ("Radio Frequency Kill Switch is On:\n"
-			     "Kill switch must be turned off for "
-			     "wireless networking to work.\n");
-	}
-	mutex_unlock(&priv->mutex);
-}
-
-#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
-
-static void iwl_bg_scan_check(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
-		IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
-			  "Scan completion watchdog resetting "
-			  "adapter (%dms).\n",
-			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
-		if (!(priv->status & STATUS_EXIT_PENDING))
-			queue_work(priv->workqueue, &priv->restart);
-	}
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_request_scan(void *p)
-{
-	struct iwl_priv *priv = p;
-	struct iwl_host_cmd cmd = {
-		.id = REPLY_SCAN_CMD,
-		.len = sizeof(struct iwl_scan_cmd),
-		.meta.flags = CMD_SIZE_HUGE,
-	};
-	int rc = 0;
-	struct iwl_scan_cmd *scan;
-	struct ieee80211_conf *conf = NULL;
-	u8 direct_mask;
-	int phymode;
-
-	conf = ieee80211_get_hw_conf(priv->hw);
-
-	mutex_lock(&priv->mutex);
-
-	if (!iwl_is_ready(priv)) {
-		IWL_WARNING("request scan called when driver not ready.\n");
-		goto done;
-	}
-
-	/* Make sure the scan wasn't cancelled before this queued work
-	 * was given the chance to run... */
-	if (!(priv->status & STATUS_SCANNING))
-		goto done;
-
-	/* This should never be called or scheduled if there is currently
-	 * a scan active in the hardware. */
-	if (priv->status & STATUS_SCAN_HW) {
-		IWL_DEBUG_INFO
-		    ("Multiple concurrent scan requests in parallel. "
-		     "Ignoring second request.\n");
-		rc = -EIO;
-		goto done;
-	}
-
-	if (priv->status & STATUS_EXIT_PENDING) {
-		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
-		goto done;
-	}
-
-	if (priv->status & STATUS_SCAN_ABORTING) {
-		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
-		goto done;
-	}
-
-	if (priv->status & STATUS_RF_KILL_MASK) {
-		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
-		goto done;
-	}
-
-	if (!(priv->status & STATUS_READY)) {
-		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
-		goto done;
-	}
-
-	if (!priv->scan_bands) {
-		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
-		goto done;
-	}
-
-	if (!priv->scan) {
-		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
-				     IWL_MAX_SCAN_SIZE, GFP_ATOMIC);
-		if (!priv->scan) {
-			rc = -ENOMEM;
-			goto done;
-		}
-	}
-	scan = priv->scan;
-	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
-
-	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
-	if (iwl_is_associated(priv)) {
-		u16 interval = 0;
-		u32 extra;
-		u32 suspend_time = 100;
-		unsigned long flags;
-
-		IWL_DEBUG_INFO("Scanning while associated...\n");
-
-		spin_lock_irqsave(&priv->lock, flags);
-		interval = priv->beacon_int;
-		spin_unlock_irqrestore(&priv->lock, flags);
-
-		scan->suspend_time = 0;
-		scan->max_out_time = 600 * 1024;
-		if (interval) {
-#if IWL == 3945
-			/*
-			 * suspend time format:
-			 *  0-19: beacon interval in usec (time before exec.)
-			 * 20-23: 0
-			 * 24-31: number of beacons (suspend between channels)
-			 */
-
-			extra = (suspend_time / interval) << 24;
-			scan->suspend_time = 0xFF0FFFFF &
-			    (extra | ((suspend_time % interval) * 1024));
-#else
-			extra = (suspend_time / interval) << 22;
-			scan->suspend_time = (extra |
-			    ((suspend_time % interval) * 1024));
-			IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
-				       scan->suspend_time, interval);
-#endif
-		}
-	}
-
-	/* We should add the ability for user to lock to PASSIVE ONLY */
-	if (priv->one_direct_scan) {
-		IWL_DEBUG_SCAN
-		    ("Kicking off one direct scan for '%s'\n",
-		     iwl_escape_essid(priv->direct_ssid,
-				      priv->direct_ssid_len));
-		scan->direct_scan[0].id = WLAN_EID_SSID;
-		scan->direct_scan[0].len = priv->direct_ssid_len;
-		memcpy(scan->direct_scan[0].ssid,
-		       priv->direct_ssid, priv->direct_ssid_len);
-		direct_mask = 1;
-	} else if (!iwl_is_associated(priv)) {
-		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 {
-		direct_mask = 0;
-	}
-
-	/* We don't build a direct scan probe request; the uCode will do
-	 * that based on the direct_mask added to each channel entry */
-	scan->tx_cmd.len =
-	    iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-			       IWL_MAX_SCAN_SIZE - sizeof(scan), 0);
-	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-	scan->tx_cmd.sta_id = IWL_BROADCAST_ID;
-	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-	/* flags + rate selection */
-
-#if IWL == 4965
-	scan->tx_cmd.tx_flags |= 0x200;
-#endif
-
-	switch (priv->scan_bands) {
-	case 2:
-		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-#if IWL == 3945
-		scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
-#elif IWL == 4965
-		scan->tx_cmd.rate.s.rate = IWL_RATE_1M_PLCP;
-		scan->tx_cmd.rate.s.flags = 0x80 | 0x2;
-#endif
-		scan->good_CRC_th = 0;
-		phymode = MODE_IEEE80211G;
-		break;
-
-	case 1:
-#if IWL == 3945
-		scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
-#elif IWL == 4965
-		scan->tx_cmd.rate.s.rate = IWL_RATE_6M_PLCP;
-		scan->tx_cmd.rate.s.flags = 0x80;
-#endif
-		scan->good_CRC_th = IWL_GOOD_CRC_TH;
-		phymode = MODE_IEEE80211A;
-		break;
-
-	default:
-		IWL_WARNING("Invalid scan band count\n");
-		goto done;
-	}
-
-	/* select Rx antennas/chains */
-#if IWL == 3945
-	scan->flags |= iwl3945_get_antenna_flags(priv);
-
-#elif IWL == 4965
-	/* Force use of chains B and C (0x6) for scan Rx.
-	 * Avoid A (0x1) because of its off-channel reception on A-band.
-	 * MIMO is not used here, but value is required to make uCode happy. */
-	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
-			(0x7 << RXON_RX_CHAIN_VALID_POS) |
-			(0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
-			(0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS);
-#endif
-
-	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",
-		     iwl_escape_essid(priv->essid, priv->essid_len));
-	else
-		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
-
-	scan->channel_count =
-		iwl_get_channels_for_scan(
-			priv, phymode, 1, /* active */
-			direct_mask, (void *)&scan->data[scan->tx_cmd.len]);
-
-	cmd.len += scan->tx_cmd.len +
-	    scan->channel_count * sizeof(struct iwl_scan_channel);
-	cmd.data = scan;
-	scan->len = cmd.len;
-
-	priv->status |= STATUS_SCAN_HW;
-	rc = iwl_send_cmd(priv, &cmd);
-	if (rc)
-		goto done;
-
-	queue_delayed_work(priv->workqueue, &priv->scan_check,
-			   IWL_SCAN_CHECK_WATCHDOG);
-
-	priv->status &= ~STATUS_SCAN_PENDING;
-
-	mutex_unlock(&priv->mutex);
-	return;
-
- done:
-	/* inform mac80211 sacn aborted */
-	queue_work(priv->workqueue, &priv->scan_completed);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_up(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	iwl_up(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_restart(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	iwl_down(priv);
-	mutex_unlock(&priv->mutex);
-
-	queue_work(priv->workqueue, &priv->up);
-}
-
-static void iwl_bg_rx_replenish(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-	iwl_rx_replenish(priv, 1);
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_post_associate(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	int rc = 0;
-	struct ieee80211_conf *conf = NULL;
-
-	IWL_DEBUG_ASSOC("Associated as %d to: " MAC_FMT "\n",
-			priv->assoc_id, MAC_ARG(priv->active_rxon.bssid_addr));
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	mutex_lock(&priv->mutex);
-
-	conf = ieee80211_get_hw_conf(priv->hw);
-
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-
-	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-	iwl_setup_rxon_timing(priv);
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
-			      sizeof(priv->rxon_timing), &priv->rxon_timing);
-	if (rc)
-		IWL_WARNING("REPLY_RXON_TIMING failed - "
-			    "Attempting to continue.\n");
-
-	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
-		iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
-	else {
-		priv->active_rate_ht[0] = 0;
-		priv->active_rate_ht[1] = 0;
-		priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-	}
-#endif /* CONFIG_IWLWIFI_HT*/
-	iwl4965_set_rxon_chain(priv);
-#endif
-	priv->staging_rxon.assoc_id = priv->assoc_id;
-
-	IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
-			priv->assoc_id, priv->beacon_int);
-
-	if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
-	else
-		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
-
-	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
-			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
-		else
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
-			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
-	}
-
-	iwl_commit_rxon(priv);
-
-	switch (priv->iw_mode) {
-	case IEEE80211_IF_TYPE_STA:
-		iwl_sync_station(priv, IWL_AP_ID,
-				 ((priv->phymode == MODE_IEEE80211A) ||
-				  (priv->phymode == MODE_ATHEROS_TURBO)) ?
-				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
-				 CMD_ASYNC);
-		iwl_rate_scale_init(priv->hw, IWL_AP_ID);
-
-		break;
-
-	case IEEE80211_IF_TYPE_IBSS:
-
-		/* clear out the station table */
-		iwl_clear_stations_table(priv);
-
-		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
-		iwl_rxon_add_station(priv, priv->bssid, 0);
-
-		iwl_sync_station(priv, IWL_STA_ID,
-				 ((priv->phymode == MODE_IEEE80211A) ||
-				  (priv->phymode == MODE_ATHEROS_TURBO)) ?
-				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
-				 CMD_ASYNC);
-		iwl_rate_scale_init(priv->hw, IWL_STA_ID);
-		iwl_send_beacon_cmd(priv);
-
-		break;
-
-	case IEEE80211_IF_TYPE_AP:
-
-		/* clear out the station table */
-		iwl_clear_stations_table(priv);
-
-		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
-		iwl_send_beacon_cmd(priv);
-
-		break;
-	}
-
-	/* FIXME: not sure why this doesn't work in AP mode */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_AP)
-		iwl_sequence_reset(priv);
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	/* Enable Rx differential gain and sensitivity calibrations */
-	iwl4965_chain_noise_reset(priv);
-	priv->start_calib = 1;
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
-#endif /* IWL == 4965 */
-
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_abort_scan(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	if (!iwl_is_ready(priv))
-		return;
-
-	mutex_lock(&priv->mutex);
-	priv->status &= ~STATUS_SCAN_PENDING;
-	priv->status |= STATUS_SCAN_ABORTING;
-
-	iwl_send_scan_abort(priv);
-
-	mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_scan_completed(void *p)
-{
-	struct iwl_priv *priv = p;
-
-	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
-
-	if (priv->status & STATUS_EXIT_PENDING)
-		return;
-
-	ieee80211_scan_completed(priv->hw);
-
-	/* Since setting the TXPOWER may have been deferred while
-	 * performing the scan, fire one off */
-	mutex_lock(&priv->mutex);
-	iwl_hw_reg_send_txpower(priv);
-	mutex_unlock(&priv->mutex);
-}
-
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static int d_open(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	/* we should be verifying the device is ready to be opened */
-	mutex_lock(&priv->mutex);
-
-	priv->is_open = 1;
-
-	if (!(priv->status & STATUS_RF_KILL_MASK))
-		ieee80211_start_queues(priv->hw);
-
-	mutex_unlock(&priv->mutex);
-	IWL_DEBUG_MAC80211("leave\n");
-	return 0;
-}
-
-static int d_stop(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-	priv->is_open = 0;
-	/*netif_stop_queue(dev); */
-	flush_workqueue(priv->workqueue);
-	IWL_DEBUG_MAC80211("leave\n");
-
-	return 0;
-}
-
-static int d_tx(struct ieee80211_hw *hw,
-		struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		IWL_DEBUG_MAC80211("leave - monitor\n");
-		return -1;
-	}
-
-	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-		     ctl->tx_rate);
-
-	if (iwl_tx_skb(priv, skb, ctl))
-		dev_kfree_skb_any(skb);
-
-	IWL_DEBUG_MAC80211("leave\n");
-	return 0;
-}
-
-static int d_add_interface(struct ieee80211_hw *hw,
-			   struct ieee80211_if_init_conf *conf)
-{
-	struct iwl_priv *priv = hw->priv;
-	unsigned long flags;
-
-	IWL_DEBUG_MAC80211("enter - id %d, type %d, MAC " MAC_FMT "\n",
-			   conf->if_id, conf->type, MAC_ARG(conf->mac_addr));
-
-	if (priv->interface_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
-		return 0;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->interface_id = conf->if_id;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	mutex_lock(&priv->mutex);
-	iwl_set_mode(priv, conf->type);
-
-	IWL_DEBUG_MAC80211("leave\n");
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-/**
- * d_config - mac80211 config callback
- *
- * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
- * be set inappropriately and the driver currently sets the hardware up to
- * use it whenever needed.
- */
-static int d_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
-{
-	struct iwl_priv *priv = hw->priv;
-	const struct iwl_channel_info *ch_info;
-	unsigned long flags;
-
-	mutex_lock(&priv->mutex);
-	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
-
-	if (!iwl_is_ready(priv)) {
-		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
-	}
-
-	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
-	 * what is exposed through include/ declrations */
-	if (unlikely
-	    (!param_disable_hw_scan && (priv->status & STATUS_SCANNING))) {
-		IWL_DEBUG_MAC80211("leave - scanning\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
-	if (!is_channel_valid(ch_info)) {
-		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
-			       conf->channel, conf->phymode);
-		IWL_DEBUG_MAC80211("leave - invalid channel\n");
-		spin_unlock_irqrestore(&priv->lock, flags);
-		mutex_unlock(&priv->mutex);
-		return -EINVAL;
-	}
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	/* if we are switching fron ht to 2.4 clear flags
-	 * from any ht related info since 2.4 does not
-	 * support ht */
-	if (is_channel_bg_band(ch_info) &&
-	    (priv->staging_rxon.channel != conf->channel))
-		priv->staging_rxon.flags = 0;
-#endif /* CONFIG_IWLWIFI_HT */
-#endif /* IWL == 4965 */
-
-	iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
-
-	iwl_set_flags_for_phymode(priv, conf->phymode);
-
-	/* The list of supported rates and rate mask can be different
-	 * for each phymode; since the phymode may have changed, reset
-	 * the rate mask to what mac80211 lists */
-	iwl_set_rate(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	iwl_radio_kill_sw(priv, !conf->radio_enabled);
-
-	if (!conf->radio_enabled) {
-		IWL_DEBUG_MAC80211("leave - radio disabled\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
-	}
-
-	if (priv->status & STATUS_RF_KILL_MASK) {
-		IWL_DEBUG_MAC80211("leave - RF kill\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
-	}
-
-	iwl_set_rate(priv);
-
-	if (memcmp(&priv->active_rxon,
-		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
-		iwl_commit_rxon(priv);
-	else
-		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
-
-	IWL_DEBUG_MAC80211("leave\n");
-
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-static int d_config_interface(struct ieee80211_hw *hw,
-			      int if_id, struct ieee80211_if_conf *conf)
-{
-	struct iwl_priv *priv = hw->priv;
-	unsigned long flags;
-
-	if (conf == NULL)
-		return -EIO;
-
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
-	    (!conf->beacon || !conf->ssid_len)) {
-		IWL_DEBUG_MAC80211
-		    ("Leaving in AP mode because HostAPD is not ready.\n");
-		return 0;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
-	if (conf->bssid)
-		IWL_DEBUG_MAC80211("bssid: " MAC_FMT "\n",
-				   MAC_ARG(conf->bssid));
-
-	if (unlikely(priv->status & STATUS_SCANNING) &&
-	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
-		IWL_DEBUG_MAC80211("leave - scanning\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
-	}
-
-	if (priv->interface_id != if_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
-	}
-
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-		if (!conf->bssid) {
-			conf->bssid = priv->mac_addr;
-			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
-			IWL_DEBUG_MAC80211("bssid was set to: " MAC_FMT "\n",
-					   MAC_ARG(conf->bssid));
-		}
-		if (priv->ibss_beacon) {
-			dev_kfree_skb(priv->ibss_beacon);
-		}
-		priv->ibss_beacon = conf->beacon;
-	}
-
-	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
-	    !is_multicast_ether_addr(conf->bssid)) {
-		/* If there is currently a HW scan going on in the background
-		 * then we need to cancel it else the RXON below will fail. */
-		if (iwl_scan_cancel(priv, 100)) {
-			IWL_WARNING("Aborted scan still in progress "
-				    "after 100ms\n");
-			IWL_DEBUG_MAC80211("leaving - scan abort " "failed.\n");
-			mutex_unlock(&priv->mutex);
-			return -EAGAIN;
-		}
-		memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
-		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-
-		/* TODO: Audit driver for usage of these members and see
-		 * if mac80211 deprecates them (priv->bssid looks like it
-		 * shouldn't be there, but I haven't scanned the IBSS code
-		 * to verify) - jpk */
-		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
-
-		iwl_commit_rxon(priv);
-		if (priv->iw_mode != IEEE80211_IF_TYPE_AP)
-			iwl_rxon_add_station(
-				priv, priv->active_rxon.bssid_addr, 1);
-
-		if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-			/* FIXME: The unlock here is a patch. the Locks
-			 * should be moved out of iwl_bg_post_associate */
-			mutex_unlock(&priv->mutex);
-			iwl_bg_post_associate(&priv->post_associate);
-			mutex_lock(&priv->mutex);
-		}
-	} else {
-		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!conf->ssid_len)
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-	else
-		memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-	priv->essid_len = conf->ssid_len;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	IWL_DEBUG_MAC80211("leave\n");
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-static void d_remove_interface(struct ieee80211_hw *hw,
-			       struct ieee80211_if_init_conf *conf)
-{
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	mutex_lock(&priv->mutex);
-	if (priv->interface_id == conf->if_id) {
-		priv->interface_id = 0;
-		memset(priv->bssid, 0, ETH_ALEN);
-		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-		priv->essid_len = 0;
-	}
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211("leave\n");
-
-}
-
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static int d_hw_scan(struct ieee80211_hw *hw, u8 * ssid, size_t len)
-{
-	int rc = 0;
-	unsigned long flags;
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (!iwl_is_ready_rf(priv)) {
-		rc = -EIO;
-		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
-		goto out_unlock;
-	}
-
-	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
-		rc = -EIO;
-		IWL_ERROR("ERROR: APs don't scan\n");
-		goto out_unlock;
-	}
-
-	/* if we just finished scan ask for delay */
-	if (priv->last_scan_jiffies &&
-	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
-		       jiffies)) {
-		rc = -EAGAIN;
-		goto out_unlock;
-	}
-	if (len) {
-		IWL_DEBUG_SCAN("direct scan for  "
-			       "%s [%d]\n ",
-			       iwl_escape_essid(ssid, len), (int)len);
-
-		priv->one_direct_scan = 1;
-		priv->direct_ssid_len = (u8)
-		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
-		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
-	}
-
-	rc = iwl_scan_initiate(priv);
-
-	IWL_DEBUG_MAC80211("leave\n");
-
- out_unlock:
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return rc;
-}
-
-static int d_set_key(struct ieee80211_hw *hw,
-		     set_key_cmd cmd,
-		     u8 * addr, struct ieee80211_key_conf *key, int aid)
-{
-	struct iwl_priv *priv = hw->priv;
-	int rc = 0;
-	u8 sta_id;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	if (!param_hwcrypto) {
-		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
-		return -EOPNOTSUPP;
-	}
-
-	sta_id = iwl_hw_find_station(priv, addr);
-	if (sta_id == IWL_INVALID_STATION) {
-		IWL_DEBUG_MAC80211("leave - " MAC_FMT
-				   " not in station map.\n", MAC_ARG(addr));
-		return -EINVAL;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	if (cmd == SET_KEY)
-		rc = iwl_update_sta_key_info(priv, key, sta_id);
-	else
-		rc = -EINVAL;
-
-	if (!rc) {
-		iwl_set_rxon_hwcrypto(priv, 1);
-		iwl_commit_rxon(priv);
-		key->flags &= (u32)
-			(~IEEE80211_KEY_FORCE_SW_ENCRYPT);
-		key->hw_key_idx = sta_id;
-		/* TODO do we need below */
-		/*
-		 * conf->sw_encrypt = 0;
-		 * conf->sw_decrypt = 0;
-		 */
-		IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
-	}
-
-	IWL_DEBUG_MAC80211("leave\n");
-	mutex_unlock(&priv->mutex);
-
-	return rc;
-}
-
-static int d_conf_tx(struct ieee80211_hw *hw, int queue,
-		     const struct ieee80211_tx_queue_params *params)
-{
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - RF not ready\n");
-		return -EIO;
-	}
-
-	if (queue >= AC_NUM) {
-		IWL_DEBUG_MAC80211("leave - queue >= AC_NUM\n");
-		return 0;
-	}
-	IWL_DEBUG_MAC80211("leave\n");
-	return 0;
-}
-
-static int d_get_tx_stats(struct ieee80211_hw *hw,
-			  struct ieee80211_tx_queue_stats *stats)
-{
-	struct iwl_priv *priv = hw->priv;
-	int i, avail;
-	struct iwl_tx_queue *txq;
-	struct iwl_queue *q;
-	unsigned long flags;
-
-	IWL_DEBUG_MAC80211("enter\n");
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - RF not ready\n");
-		return -EIO;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	for (i = 0; i < AC_NUM; i++) {
-		txq = &priv->txq[i];
-		q = &txq->q;
-		avail = iwl_queue_space(q);
-
-		stats->data[i].len = q->n_window - avail;
-		stats->data[i].limit = q->n_window - q->high_mark;
-		stats->data[i].count = q->n_window;
-
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	IWL_DEBUG_MAC80211("leave\n");
-
-	return 0;
-}
-
-static int d_get_stats(struct ieee80211_hw *hw,
-		       struct ieee80211_low_level_stats *stats)
-{
-	IWL_DEBUG_MAC80211("enter\n");
-	IWL_DEBUG_MAC80211("leave\n");
-
-	return 0;
-}
-
-static u64 d_get_tsf(struct ieee80211_hw *hw)
-{
-	IWL_DEBUG_MAC80211("enter\n");
-	IWL_DEBUG_MAC80211("leave\n");
-
-	return 0;
-}
-
-static void d_reset_tsf(struct ieee80211_hw *hw)
-{
-	struct iwl_priv *priv = hw->priv;
-	unsigned long flags;
-
-	mutex_lock(&priv->mutex);
-	IWL_DEBUG_MAC80211("enter\n");
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	spin_lock_irqsave(&priv->lock, flags);
-	memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
-	spin_unlock_irqrestore(&priv->lock, flags);
-#endif /* CONFIG_IWLWIFI_HT */
-#endif /* IWL == 4965 */
-
-	cancel_delayed_work(&priv->post_associate);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	priv->assoc_id = 0;
-	priv->assoc_capability = 0;
-	priv->call_post_assoc_from_beacon = 0;
-	priv->assoc_station_added = 0;
-
-	/* new association get rid of ibss beacon skb */
-	if (priv->ibss_beacon)
-		dev_kfree_skb(priv->ibss_beacon);
-
-	priv->ibss_beacon = NULL;
-
-	priv->beacon_int = priv->hw->conf.beacon_int;
-	priv->timestamp1 = 0;
-	priv->timestamp0 = 0;
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
-		priv->beacon_int = 0;
-	
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* Per mac80211.h: This is only used in IBSS mode... */
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
-		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
-	priv->only_active_channel = 0;
-
-	iwl_set_rate(priv);
-
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_MAC80211("leave\n");
-
-}
-
-static int d_beacon_update(struct ieee80211_hw *hw,
-			   struct sk_buff *skb,
-			   struct ieee80211_tx_control *control)
-{
-	struct iwl_priv *priv = hw->priv;
-	unsigned long flags;
-
-	mutex_lock(&priv->mutex);
-	IWL_DEBUG_MAC80211("enter\n");
-
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - RF not ready\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
-	}
-
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
-		IWL_DEBUG_MAC80211("leave - not IBSS\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
-	}
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (priv->ibss_beacon)
-		dev_kfree_skb(priv->ibss_beacon);
-
-	priv->ibss_beacon = skb;
-
-	priv->assoc_id = 0;
-
-	IWL_DEBUG_MAC80211("leave\n");
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	queue_work(priv->workqueue, &priv->post_associate);
-
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-union ht_cap_info {
-	struct {
-		u16 advanced_coding_cap		:1;
-		u16 supported_chan_width_set	:1;
-		u16 mimo_power_save_mode	:2;
-		u16 green_field			:1;
-		u16 short_GI20			:1;
-		u16 short_GI40			:1;
-		u16 tx_stbc			:1;
-		u16 rx_stbc			:1;
-		u16 beam_forming		:1;
-		u16 delayed_ba			:1;
-		u16 maximal_amsdu_size		:1;
-		u16 cck_mode_at_40MHz		:1;
-		u16 psmp_support		:1;
-		u16 stbc_ctrl_frame_support	:1;
-		u16 sig_txop_protection_support	:1;
-	};
-	u16 val;
-}__attribute__ ((packed));
-
-union ht_param_info{
-	struct {
-		u8 max_rx_ampdu_factor	:2;
-		u8 mpdu_density		:3;
-		u8 reserved		:3;
-	};
-	u8 val;
-}__attribute__ ((packed));
-
-union ht_exra_param_info{
-	struct {
-		u8 ext_chan_offset		:2;
-		u8 tx_chan_width		:1;
-		u8 rifs_mode			:1;
-		u8 controlled_access_only	:1;
-		u8 service_interval_granularity	:3;
-	};
-	u8 val;
-}__attribute__ ((packed));
-
-union ht_operation_mode{
-	struct {
-		u16 op_mode	:2;
-		u16 non_GF	:1;
-		u16 reserved	:13;
-	};
-	u16 val;
-}__attribute__ ((packed));
-
-static int d_conf_ht(struct ieee80211_hw *hw,
-		     struct ieee80211_ht_capability *ht_cap_param,
-		     struct ieee80211_ht_additional_info *ht_extra_param)
-{
-	struct iwl_priv *priv = hw->priv;
-	struct sta_ht_info *ht_info = &priv->current_assoc_ht;
-	union ht_cap_info cap;
-	union ht_operation_mode op_mode;
-	union ht_param_info param_info;
-	union ht_exra_param_info extra_param_info;
-
-	IWL_DEBUG_MAC80211("enter: \n");
-	cap.val = (u16) le16_to_cpu(ht_cap_param->capabilities_info);
-	op_mode.val = (u16) le16_to_cpu(ht_extra_param->operation_mode);
-	param_info.val = ht_cap_param->mac_ht_params_info;
-	extra_param_info.val = ht_extra_param->ht_param;
-
-	ht_info->is_ht = 1;
-	ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
-	ht_info->control_chan = ht_extra_param->control_chan;
-	ht_info->is_green_field = cap.green_field;
-	if (cap.short_GI20)
-		ht_info->sgf |= 0x1;
-	if (cap.short_GI40)
-		ht_info->sgf |= 0x2;
-	ht_info->operating_mode = op_mode.op_mode;
-	ht_info->mpdu_density = param_info.mpdu_density;
-	ht_info->max_amsdu_size = cap.maximal_amsdu_size;
-	ht_info->supported_chan_width = cap.supported_chan_width_set;
-	ht_info->extension_chan_offset = extra_param_info.ext_chan_offset;
-	ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
-
-	memcpy(ht_info->supp_rates, ht_cap_param->supported_mcs_set, 16);
-
-	priv->active_rate_ht[0] = ht_info->supp_rates[0];
-	priv->active_rate_ht[1] = ht_info->supp_rates[1];
-
-	iwl4965_set_rxon_chain(priv);
-
-	if (priv && priv->assoc_id &&
-	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&priv->lock, flags);
-		if (priv->beacon_int)
-			queue_work(priv->workqueue, &priv->post_associate.work);
-		else
-			priv->call_post_assoc_from_beacon = 1;
-		spin_unlock_irqrestore(&priv->lock, flags);
-	}
-
-	IWL_DEBUG_MAC80211("leave: control channel %d\n",
-			    ht_extra_param->control_chan);
-	return 0;
-}
-
-static void d_get_ht_capab(struct ieee80211_hw *hw,
-			   struct ieee80211_ht_capability *ht_cap_param)
-{
-	union ht_cap_info cap;
-	union ht_param_info param_info;
-
-	IWL_DEBUG_MAC80211("enter: \n");
-	cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
-	cap.green_field = 1;
-	cap.short_GI20 = 1;
-	cap.short_GI40 = 1;
-	cap.supported_chan_width_set = 1;
-	cap.mimo_power_save_mode = 0x3;
-
-	param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-	param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
-	ht_cap_param->capabilities_info = (__le16) cpu_to_le16(cap.val);
-	ht_cap_param->mac_ht_params_info = (u8) param_info.val;
-
-	ht_cap_param->supported_mcs_set[0] = 0xff;
-	ht_cap_param->supported_mcs_set[1] = 0xff;
-	ht_cap_param->supported_mcs_set[4] =
-				(cap.supported_chan_width_set) ? 0x1: 0x0;
-
-	IWL_DEBUG_MAC80211("leave: \n");
-}
-
-
-
-#endif /*CONFIG_IWLWIFI_HT*/
-
-#ifdef CONFIG_IWLWIFI_HT_AGG
-
-static int kdrn_txq_ctx_activate_free(struct iwl_priv *priv);
-static int d_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
-			     u16 *start_seq_num)
-{
-
-	struct iwl_priv *priv = hw->priv;
-	int sta_id;
-	int tx_fifo;
-	int txq_id;
-	int ssn = -1;
-	unsigned long flags;
-	struct ipw_tid_data *tid_data;
-
-	if (likely(tid < ARRAY_SIZE(default_tid_to_ac)))
-		tx_fifo = default_tid_to_ac[tid];
-	else
-		return -EINVAL;
-
-	IWL_DEBUG_MAC80211("iwl-AGG d_ht_tx_agg_start on da=" MAC_FMT " tid="
-			   "%d\n", MAC_ARG(da), tid);
-
-	sta_id = ipw_find_station(priv, da);
-	if (sta_id == IPW_INVALID_STATION)
-		return -ENXIO;
-
-	txq_id = kdrn_txq_ctx_activate_free(priv);
-	if (txq_id == -1)
-		return -ENXIO;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	tid_data = &priv->stations[sta_id].tid[tid];
-	ssn = SEQ_TO_SN(tid_data->seq_number);
-	tid_data->txq_id = txq_id;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	*start_seq_num = ssn;
-	return kdrn_tx_queue_agg_enable(priv, txq_id, tx_fifo, sta_id, tid,
-					ssn);
-}
-
-
-static int d_ht_tx_agg_stop(struct ieee80211_hw *hw,
-				u8 *da, u16 tid, int generator)
-{
-
-	struct iwl_priv *priv = hw->priv;
-	int tx_fifo_id, sta_id, ssn = -1;
-	if (!da) {
-		IWL_ERROR("%s: da = NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	if (likely(tid < ARRAY_SIZE(default_tid_to_ac)))
-		tx_fifo_id = default_tid_to_ac[tid];
-	else
-		return -EINVAL;
-
-	sta_id = ipw_find_station(priv, da);
-
-	if (sta_id == IPW_INVALID_STATION)
-		return -ENXIO;
-
-	ssn = (priv->stations[sta_id].tid[tid].seq_number &
-	       IEEE80211_SCTL_SEQ) >> 4;
-
-	kdrn_tx_queue_agg_disable(priv, 7, ssn, tx_fifo_id);
-	IWL_DEBUG_MAC80211("iwl-AGG d_ht_tx_agg_stop on da=" MAC_FMT " tid="
-			   "%d\n", MAC_ARG(da), tid);
-
-	return 0;
-}
-
-#endif /*CONFIG_IWLWIFI_HT_AGG*/
-#endif /*IWL == 4965*/
-/*****************************************************************************
- *
- * sysfs attributes
- *
- *****************************************************************************/
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
- * used for controlling the debug level.
- *
- * See the level definitions in ipw for details.
- */
-
-static ssize_t show_debug_level(struct device_driver *d, char *buf)
-{
-	return sprintf(buf, "0x%08X\n", iwl_debug_level);
-}
-static ssize_t store_debug_level(struct device_driver *d,
-				 const char *buf, size_t count)
-{
-	char *p = (char *)buf;
-	u32 val;
-
-	val = simple_strtoul(p, &p, 0);
-	if (p == buf)
-		printk(KERN_INFO DRV_NAME
-		       ": %s is not in hex or decimal form.\n", buf);
-	else
-		iwl_debug_level = val;
-
-	return strnlen(buf, count);
-}
-
-static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
-		   show_debug_level, store_debug_level);
-
-#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 = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
-	    ((priv->status & STATUS_RF_KILL_HW) ? 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);
-	iwl_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)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
-}
-
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-
-static ssize_t show_rs_window(struct device *d,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	struct iwl_priv *priv = d->driver_data;
-	return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
-}
-static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
-
-static ssize_t show_tx_power(struct device *d,
-			     struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	return sprintf(buf, "%d\n", priv->user_txpower_limit);
-}
-
-static ssize_t store_tx_power(struct device *d,
-			      struct device_attribute *attr,
-			      const char *buf, size_t count)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	char *p = (char *)buf;
-	u32 val;
-
-	val = simple_strtoul(p, &p, 10);
-	if (p == buf)
-		printk(KERN_INFO DRV_NAME
-		       ": %s is not in decimal form.\n", buf);
-	else
-		iwl_hw_reg_set_txpower(priv, val);
-
-	return count;
-}
-
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
-
-static ssize_t show_flags(struct device *d,
-			  struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
-	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
-}
-
-static ssize_t store_flags(struct device *d,
-			   struct device_attribute *attr,
-			   const char *buf, size_t count)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	u16 flags = simple_strtoul(buf, NULL, 0);
-
-	mutex_lock(&priv->mutex);
-	if (priv->staging_rxon.flags != flags) {
-		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel(priv, 100)) {
-			IWL_WARNING("Could not cancel scan.\n");
-		} else {
-			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
-				       flags);
-			priv->staging_rxon.flags = flags;
-			iwl_commit_rxon(priv);
-		}
-	}
-	mutex_unlock(&priv->mutex);
-
-	return count;
-}
-
-static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
-
-static ssize_t show_filter_flags(struct device *d,
-				 struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
-	return sprintf(buf, "0x%04X\n", priv->active_rxon.filter_flags);
-}
-
-static ssize_t store_filter_flags(struct device *d,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	u16 filter_flags = simple_strtoul(buf, NULL, 0);
-
-	mutex_lock(&priv->mutex);
-	if (priv->staging_rxon.filter_flags != filter_flags) {
-		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel(priv, 100)) {
-			IWL_WARNING("Could not cancel scan.\n");
-		} else {
-			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
-				       "0x%04X\n", filter_flags);
-			priv->staging_rxon.filter_flags = filter_flags;
-			iwl_commit_rxon(priv);
-		}
-	}
-	mutex_unlock(&priv->mutex);
-
-	return count;
-}
-
-static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
-		   store_filter_flags);
-
-static ssize_t show_tune(struct device *d,
-			 struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
-	return sprintf(buf, "0x%04X\n",
-		       (priv->phymode << 8) | priv->active_rxon.channel);
-}
-
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
-
-static ssize_t store_tune(struct device *d,
-			  struct device_attribute *attr,
-			  const char *buf, size_t count)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	char *p = (char *)buf;
-	u16 tune = simple_strtoul(p, &p, 0);
-	u8 phymode = (tune >> 8) & 0xff;
-	u8 channel = tune & 0xff;
-
-	IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
-
-	mutex_lock(&priv->mutex);
-	if ((priv->staging_rxon.channel != channel) ||
-	    (priv->phymode != phymode)) {
-		const struct iwl_channel_info *ch_info;
-
-		ch_info = iwl_get_channel_info(priv, phymode, channel);
-		if (!ch_info) {
-			IWL_WARNING("Requested invalid phymode/channel "
-				    "combination: %d %d\n", phymode, channel);
-			mutex_unlock(&priv->mutex);
-			return -EINVAL;
-		}
-
-		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel(priv, 100)) {
-			IWL_WARNING("Could not cancel scan.\n");
-		} else {
-			IWL_DEBUG_INFO("Committing phymode and "
-				       "rxon.channel = %d %d\n",
-				       phymode, channel);
-
-			iwl_set_rxon_channel(priv, phymode, channel);
-			iwl_set_flags_for_phymode(priv, phymode);
-
-			iwl_set_rate(priv);
-			iwl_commit_rxon(priv);
-		}
-	}
-	mutex_unlock(&priv->mutex);
-
-	return count;
-}
-
-static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
-
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-
-static ssize_t show_measurement(struct device *d,
-				struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct iwl_spectrum_notification measure_report;
-
-	u32 size = sizeof(measure_report), len = 0, ofs = 0;
-	u8 *data = (u8 *) & measure_report;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!(priv->measurement_status & MEASUREMENT_READY)) {
-		spin_unlock_irqrestore(&priv->lock, flags);
-		return 0;
-	}
-	memcpy(&measure_report, &priv->measure_report, size);
-	priv->measurement_status = 0;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	while (size && (PAGE_SIZE - len)) {
-		len +=
-		    snprint_line(&buf[len], PAGE_SIZE - len,
-				 &data[ofs], min(size, 16U), ofs);
-		if (PAGE_SIZE - len)
-			buf[len++] = '\n';
-
-		ofs += 16;
-		size -= min(size, 16U);
-	}
-
-	return len;
-}
-
-static ssize_t store_measurement(struct device *d,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct ieee80211_measurement_params params = {
-		.channel = priv->active_rxon.channel,
-		.start_time = priv->last_tsf,
-		.duration = 1,
-	};
-	u8 type = IWL_MEASURE_BASIC;
-	u8 buffer[32];
-	u8 channel;
-
-	if (count) {
-		char *p = buffer;
-		strncpy(buffer, buf, min(sizeof(buffer), count));
-		channel = simple_strtoul(p, NULL, 0);
-		if (channel)
-			params.channel = channel;
-
-		p = buffer;
-		while (*p && *p != ' ')
-			p++;
-		if (*p)
-			type = simple_strtoul(p + 1, NULL, 0);
-	}
-
-	IWL_DEBUG_INFO("Invoking measurement of type %d on "
-		       "channel %d (for '%s')\n", type, params.channel, buf);
-	iwl_get_measurement(priv, &params, type);
-
-	return count;
-}
-
-static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
-		   show_measurement, store_measurement);
-#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
-
-static ssize_t show_rate(struct device *d,
-			 struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
-		i = priv->stations[IWL_STA_ID].current_rate.s.rate;
-	else
-		i = priv->stations[IWL_AP_ID].current_rate.s.rate;
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-	i = iwl_rate_index_from_plcp(i);
-	if (i == -1)
-		return sprintf(buf, "0\n");
-
-	return sprintf(buf, "%d%s\n",
-		       (iwl_rates[i].ieee >> 1),
-		       (iwl_rates[i].ieee % 2) ? ".5" : "");
-}
-
-static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
-
-static ssize_t store_retry_rate(struct device *d,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-
-	priv->retry_rate = simple_strtoul(buf, NULL, 0);
-	if (priv->retry_rate <= 0)
-		priv->retry_rate = 1;
-
-	return count;
-}
-
-static ssize_t show_retry_rate(struct device *d,
-			       struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	return sprintf(buf, "%d", priv->retry_rate);
-}
-
-static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
-		   store_retry_rate);
-
-static ssize_t store_power_level(struct device *d,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	int rc;
-	int mode;
-
-	mode = simple_strtoul(buf, NULL, 0);
-	mutex_lock(&priv->mutex);
-
-	if (!iwl_is_ready(priv)) {
-		rc = -EAGAIN;
-		goto out;
-	}
-
-	if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
-		mode = IWL_POWER_AC;
-	else
-		mode |= IWL_POWER_ENABLED;
-
-	if (mode != priv->power_mode) {
-		rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
-		if (rc) {
-			IWL_DEBUG_MAC80211("failed setting power mode.\n");
-			goto out;
-		}
-		priv->power_mode = mode;
-	}
-
-	rc = count;
-
- out:
-	mutex_unlock(&priv->mutex);
-	return rc;
-}
-
-#define MAX_WX_STRING 80
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
-	350000,
-	250000,
-	75000,
-	37000,
-	25000,
-};
-static const s32 period_duration[] = {
-	400000,
-	700000,
-	1000000,
-	1000000,
-	1000000
-};
-
-static ssize_t show_power_level(struct device *d,
-				struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	int level = IWL_POWER_LEVEL(priv->power_mode);
-	char *p = buf;
-
-	p += sprintf(p, "%d ", level);
-	switch (level) {
-	case IWL_POWER_MODE_CAM:
-	case IWL_POWER_AC:
-		p += sprintf(p, "(AC)");
-		break;
-	case IWL_POWER_BATTERY:
-		p += sprintf(p, "(BATTERY)");
-		break;
-	default:
-		p += sprintf(p,
-			     "(Timeout %dms, Period %dms)",
-			     timeout_duration[level - 1] / 1000,
-			     period_duration[level - 1] / 1000);
-	}
-
-	if (!(priv->power_mode & IWL_POWER_ENABLED))
-		p += sprintf(p, " OFF\n");
-	else
-		p += sprintf(p, " \n");
-
-	return (p - buf + 1);
-
-}
-
-static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
-		   store_power_level);
-
-static ssize_t show_channels(struct device *d,
-			     struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	int len = 0, i;
-	struct ieee80211_channel *channels = NULL;
-	const struct ieee80211_hw_mode *hw_mode = NULL;
-	int count = 0;
-
-	if (!iwl_is_ready(priv))
-		return -EAGAIN;
-
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
-	if (!hw_mode)
-		hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
-	if (hw_mode) {
-		channels = hw_mode->channels;
-		count = hw_mode->num_channels;
-	}
-
-	len +=
-	    sprintf(&buf[len],
-		    "Displaying %d channels in 2.4GHz band "
-		    "(802.11bg):\n", count);
-
-	for (i = 0; i < count; i++) {
-		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
-			       channels[i].chan,
-			       channels[i].power_level,
-			       channels[i].
-			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
-			       " (IEEE 802.11h required)" : "",
-			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
-				|| (channels[i].
-				    flag &
-				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
-			       ", IBSS",
-			       channels[i].
-			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
-			       "active/passive" : "passive only");
-	}
-
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
-	if (hw_mode) {
-		channels = hw_mode->channels;
-		count = hw_mode->num_channels;
-	} else {
-		channels = NULL;
-		count = 0;
-	}
-
-	len +=
-	    sprintf(&buf[len],
-		    "Displaying %d channels in 5.2GHz band "
-		    "(802.11a):\n", count);
-
-	for (i = 0; i < count; i++) {
-		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
-			       channels[i].chan,
-			       channels[i].power_level,
-			       channels[i].
-			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
-			       " (IEEE 802.11h required)" : "",
-			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
-				|| (channels[i].
-				    flag &
-				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
-			       ", IBSS",
-			       channels[i].
-			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
-			       "active/passive" : "passive only");
-	}
-
-	return len;
-}
-
-static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
-
-static ssize_t show_statistics(struct device *d,
-			       struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	u32 size = sizeof(struct iwl_notif_statistics);
-	u32 len = 0, ofs = 0;
-	u8 *data = (u8 *) & priv->statistics;
-	int rc = 0;
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	mutex_lock(&priv->mutex);
-	rc = iwl_send_statistics_request(priv);
-	mutex_unlock(&priv->mutex);
-
-	if (rc) {
-		len = sprintf(buf,
-			      "Error sending statistics request: 0x%08X\n", rc);
-		return len;
-	}
-
-	while (size && (PAGE_SIZE - len)) {
-		len +=
-		    snprint_line(&buf[len], PAGE_SIZE - len,
-				 &data[ofs], min(size, 16U), ofs);
-		if (PAGE_SIZE - len)
-			buf[len++] = '\n';
-
-		ofs += 16;
-		size -= min(size, 16U);
-	}
-
-	return len;
-}
-
-static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
-
-static ssize_t show_antenna(struct device *d,
-			    struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = dev_get_drvdata(d);
-
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-
-	return sprintf(buf, "%d\n", priv->antenna);
-}
-
-static ssize_t store_antenna(struct device *d,
-			     struct device_attribute *attr,
-			     const char *buf, size_t count)
-{
-	int ant;
-	struct iwl_priv *priv = dev_get_drvdata(d);
-
-	if (count == 0)
-		return 0;
-
-	if (sscanf(buf, "%1i", &ant) != 1) {
-		IWL_DEBUG_INFO("not in hex or decimal form.\n");
-		return count;
-	}
-
-	if ((ant >= 0) && (ant <= 2)) {
-		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
-		priv->antenna = (enum iwl_antenna)ant;
-	} else {
-		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
-	}
-
-	return count;
-}
-
-static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
-
-static ssize_t show_status(struct device *d,
-			   struct device_attribute *attr, char *buf)
-{
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	if (!iwl_is_alive(priv))
-		return -EAGAIN;
-	return sprintf(buf, "0x%08x\n", (int)priv->status);
-}
-
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
-
-static ssize_t dump_error_log(struct device *d,
-			      struct device_attribute *attr,
-			      const char *buf, size_t count)
-{
-	char *p = (char *)buf;
-
-	if (p[0] == '1')
-		iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
-
-	return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
-
-static ssize_t dump_event_log(struct device *d,
-			      struct device_attribute *attr,
-			      const char *buf, size_t count)
-{
-	char *p = (char *)buf;
-
-	if (p[0] == '1')
-		iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
-
-	return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-	priv->workqueue = create_workqueue(DRV_NAME);
-
-	init_waitqueue_head(&priv->wait_command_queue);
-
-	INIT_WORK(&priv->up, iwl_bg_up, priv);
-	INIT_WORK(&priv->restart, iwl_bg_restart, priv);
-	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish, priv);
-	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed, priv);
-	INIT_WORK(&priv->request_scan, iwl_bg_request_scan, priv);
-	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan, priv);
-	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill, priv);
-	INIT_WORK(&priv->post_associate, iwl_bg_post_associate, priv);
-	INIT_WORK(&priv->init_alive_start, iwl_bg_init_alive_start, priv);
-	INIT_WORK(&priv->alive_start, iwl_bg_alive_start, priv);
-	INIT_WORK(&priv->scan_check, iwl_bg_scan_check, priv);
-
-	iwl_hw_setup_deferred_work(priv);
-
-	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-		     iwl_irq_tasklet, (unsigned long)priv);
-}
-
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-	iwl_hw_cancel_deferred_work(priv);
-
-	cancel_delayed_work(&priv->scan_check);
-	cancel_delayed_work(&priv->alive_start);
-	cancel_delayed_work(&priv->post_associate);
-}
-
-static struct attribute *iwl_sysfs_entries[] = {
-	&dev_attr_antenna.attr,
-	&dev_attr_channels.attr,
-	&dev_attr_dump_errors.attr,
-	&dev_attr_dump_events.attr,
-	&dev_attr_flags.attr,
-	&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-	&dev_attr_measurement.attr,
-#endif
-	&dev_attr_power_level.attr,
-	&dev_attr_rate.attr,
-	&dev_attr_retry_rate.attr,
-	&dev_attr_rf_kill.attr,
-	&dev_attr_rs_window.attr,
-	&dev_attr_statistics.attr,
-	&dev_attr_status.attr,
-	&dev_attr_temperature.attr,
-	&dev_attr_tune.attr,
-	&dev_attr_tx_power.attr,
-
-	NULL
-};
-
-static struct attribute_group iwl_attribute_group = {
-	.name = NULL,		/* put in device directory */
-	.attrs = iwl_sysfs_entries,
-};
-
-static struct ieee80211_ops iwl_hw_ops = {
-	.tx = d_tx,
-	.open = d_open,
-	.stop = d_stop,
-	.add_interface = d_add_interface,
-	.remove_interface = d_remove_interface,
-	.config = d_config,
-	.config_interface = d_config_interface,
-	.set_key = d_set_key,
-	.get_stats = d_get_stats,
-	.get_tx_stats = d_get_tx_stats,
-	.conf_tx = d_conf_tx,
-	.get_tsf = d_get_tsf,
-	.reset_tsf = d_reset_tsf,
-	.beacon_update = d_beacon_update,
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-	.conf_ht = d_conf_ht,
-	.get_ht_capab = d_get_ht_capab,
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	.ht_tx_agg_start = d_ht_tx_agg_start,
-	.ht_tx_agg_stop = d_ht_tx_agg_stop,
-#endif  /* CONFIG_IWLWIFI_HT_AGG */
-#endif  /* CONFIG_IWLWIFI_HT */
-#endif
-	.hw_scan = d_hw_scan
-
-};
-
-static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int err = 0;
-	void __iomem *base;
-	u32 length;
-	u32 pci_id;
-	struct iwl_priv *priv;
-	struct ieee80211_hw *hw;
-	int i;
-
-	if (param_disable_hw_scan) {
-		IWL_DEBUG_INFO("Disabling hw_scan\n");
-		iwl_hw_ops.hw_scan = NULL;
-	}
-
-	/* mac80211 allocates memory for this device instance, including
-	 *   space for this driver's private structure */
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
-	if (hw == NULL) {
-		IWL_ERROR("Can not allocate network device\n");
-		err = -ENOMEM;
-		goto out;
-	}
-	SET_IEEE80211_DEV(hw, &pdev->dev);
-
-	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
-	priv = hw->priv;
-	priv->hw = hw;
-
-	priv->pci_dev = pdev;
-	priv->antenna = (enum iwl_antenna)param_antenna;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	iwl_debug_level = param_debug;
-#endif
-	priv->retry_rate = 1;
-
-	priv->ibss_beacon = NULL;
-
-	/* Tell mac80211 and its clients (e.g. Wireless Extensions)
-	 *   the range of signal quality values that we'll provide.
-	 * Negative values for level/noise indicate that we'll provide dBm.
-	 * For WE, at least, non-0 values here *enable* display of values
-	 *   in app (iwconfig). */
-	hw->max_rssi = -20;	/* signal level, negative indicates dBm */
-	hw->max_noise = -20;	/* noise level, negative indicates dBm */
-	hw->max_signal = 100;	/* link quality indication (%) */
-
-	/* Tell mac80211 our Tx characteristics */
-	hw->flags = IEEE80211_HW_WEP_INCLUDE_IV |
-	    IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
-	hw->queues = 4;
-
-	spin_lock_init(&priv->lock);
-	spin_lock_init(&priv->power_data.lock);
-	spin_lock_init(&priv->sta_lock);
-#if IWL == 4965
-	spin_lock_init(&priv->lq_mngr.lock);
-#endif
-
-	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
-		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
-	INIT_LIST_HEAD(&priv->free_frames);
-
-	mutex_init(&priv->mutex);
-	if (pci_enable_device(pdev)) {
-		err = -ENODEV;
-		goto out_ieee80211_free_hw;
-	}
-
-	pci_set_master(pdev);
-
-	iwl_clear_stations_table(priv);
-
-	memset(&(priv->txq[0]), 0,
-	       sizeof(struct iwl_tx_queue) * IWL_MAX_NUM_QUEUES);
-	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
-	priv->data_retry_limit = -1;
-	priv->ieee_channels = NULL;
-	priv->ieee_rates = NULL;
-	priv->phymode = -1;
-
-	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-	if (!err)
-		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-	if (err) {
-		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
-		goto out_pci_disable_device;
-	}
-
-	pci_set_drvdata(pdev, priv);
-	err = pci_request_regions(pdev, DRV_NAME);
-	if (err)
-		goto out_pci_disable_device;
-	/* We disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state */
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
-	length = pci_resource_len(pdev, 0);
-	priv->hw_len = length;
-	base = ioremap_nocache(pci_resource_start(pdev, 0), length);
-	if (!base) {
-		err = -ENODEV;
-		goto out_pci_release_regions;
-	}
-
-	priv->hw_base = base;
-	IWL_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
-	IWL_DEBUG_INFO("pci_resource_base = %p\n", base);
-
-	/* Initialize module parameter values here */
-
-	if (param_disable) {
-		priv->status |= STATUS_RF_KILL_SW;
-		IWL_DEBUG_INFO("Radio disabled.\n");
-	}
-
-	priv->iw_mode = IEEE80211_IF_TYPE_STA;
-
-	pci_id =
-	    (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
-
-#if IWL == 4965
-	priv->ps_mode = 0;
-	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
-	priv->is_ht_enabled = 1;
-	priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
-	priv->valid_antenna = 0x7;	/* assume all 3 connected */
-	priv->ps_mode = IWL_MIMO_PS_NONE;
-	priv->cck_power_index_compensation = iwl_read32(
-		priv, CSR_HW_REV_WA_REG);
-
-	iwl4965_set_rxon_chain(priv);
-
-	printk(KERN_INFO DRV_NAME
-	       ": Detected Intel Wireless WiFi Link 4965AGN\n");
-#else
-	switch (pci_id) {
-	case 0x42221005:	/* 0x4222 0x8086 0x1005 is BG SKU */
-	case 0x42221034:	/* 0x4222 0x8086 0x1034 is BG SKU */
-	case 0x42271014:	/* 0x4227 0x8086 0x1014 is BG SKU */
-	case 0x42221044:	/* 0x4222 0x8086 0x1044 is BG SKU */
-		priv->is_abg = 0;
-		break;
-
-	/*
-	 * Rest are assumed ABG SKU -- if this is not the
-	 * case then the card will get the wrong 'Detected'
-	 * line in the kernel log however the code that
-	 * initializes the GEO table will detect no A-band
-	 * channels and remove the is_abg mask.
-	 */
-	default:
-		priv->is_abg = 1;
-		break;
-	}
-
-	printk(KERN_INFO DRV_NAME
-	       ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
-	       priv->is_abg ? "A" : "");
-#endif
-
-	/* Device-specific setup */
-	if (iwl_hw_set_hw_setting(priv)) {
-		IWL_ERROR("failed to set hw settings\n");
-		mutex_unlock(&priv->mutex);
-		goto out_iounmap;
-	}
-
-	iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
-	iwl_setup_deferred_work(priv);
-	iwl_setup_rx_handlers(priv);
-
-	priv->rates_mask = IWL_RATES_MASK;
-	/* If power management is turned on, default to AC mode */
-	priv->power_mode = IWL_POWER_AC;
-	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
-	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
-	if (err) {
-		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
-		goto out_destroy_workqueue;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
-	if (err) {
-		IWL_ERROR("failed to create sysfs device attributes\n");
-		mutex_unlock(&priv->mutex);
-		goto out_release_irq;
-	}
-
-	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
-	 * ucode filename and max sizes are card-specific. */
-	err = iwl_read_ucode(priv);
-	if (err) {
-		IWL_ERROR("Could not read microcode: %d\n", err);
-		mutex_unlock(&priv->mutex);
-		goto out_pci_alloc;
-	}
-
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_INFO("Queing UP work.\n");
-
-	queue_work(priv->workqueue, &priv->up);
-
-	return 0;
-
- out_pci_alloc:
-	iwl_dealloc_ucode_pci(priv);
-
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
-
- out_release_irq:
-	free_irq(pdev->irq, priv);
-
- out_destroy_workqueue:
-	destroy_workqueue(priv->workqueue);
-	priv->workqueue = NULL;
-	iwl_unset_hw_setting(priv);
-
- out_iounmap:
-	iounmap(priv->hw_base);
- out_pci_release_regions:
-	pci_release_regions(pdev);
- out_pci_disable_device:
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
- out_ieee80211_free_hw:
-	ieee80211_free_hw(priv->hw);
- out:
-	return err;
-}
-
-static void iwl_pci_remove(struct pci_dev *pdev)
-{
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-	struct list_head *p, *q;
-	int i;
-
-	if (!priv)
-		return;
-
-	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
-
-	mutex_lock(&priv->mutex);
-
-	priv->status |= STATUS_EXIT_PENDING;
-
-	iwl_down(priv);
-
-	mutex_unlock(&priv->mutex);
-
-	/* 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]) {
-			list_del(p);
-			kfree(list_entry(p, struct iwl_ibss_seq, list));
-		}
-	}
-
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
-
-	iwl_dealloc_ucode_pci(priv);
-
-	if (priv->rxq.bd)
-		iwl_rx_queue_free(priv, &priv->rxq);
-	iwl_hw_txq_ctx_free(priv);
-
-	iwl_unset_hw_setting(priv);
-	iwl_clear_stations_table(priv);
-
-	if (priv->mac80211_registered) {
-		ieee80211_unregister_hw(priv->hw);
-		iwl_rate_control_unregister();
-	}
-
-	/* ieee80211_unregister_hw calls d_stop, which flushes
-	 * priv->workqueue... so we can't take down the workqueue
-	 * until now... */
-	destroy_workqueue(priv->workqueue);
-	priv->workqueue = NULL;
-
-	free_irq(pdev->irq, priv);
-	iounmap(priv->hw_base);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-
-	kfree(priv->channel_info);
-
-	kfree(priv->ieee_channels);
-	kfree(priv->ieee_rates);
-
-	if (priv->ibss_beacon)
-		dev_kfree_skb(priv->ibss_beacon);
-
-	ieee80211_free_hw(priv->hw);
-}
-
-#ifdef CONFIG_PM
-
-static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-
-	mutex_lock(&priv->mutex);
-
-	priv->status |= STATUS_IN_SUSPEND;
-
-	/* Take down the device; powers it off, etc. */
-	iwl_down(priv);
-
-	if (priv->mac80211_registered)
-		ieee80211_stop_queues(priv->hw);
-
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
-	pci_set_power_state(pdev, PCI_D3hot);
-
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-static void iwl_resume(struct iwl_priv *priv)
-{
-	unsigned long flags;
-
-	/* The following it a temporary work around due to the
-	 * suspend / resume not fully initializing the NIC correctly.
-	 * Without all of the following, resume will not attempt to take
-	 * down the NIC (it shouldn't really need to) and will just try
-	 * and bring the NIC back up.  However that fails during the
-	 * ucode verification process.  This then causes iwl_down to be
-	 * called *after* iwl_hw_nic_init() has succeeded -- which
-	 * then lets the next init sequence succeed.  So, we've
-	 * replicated all of that NIC init code here... */
-
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-	iwl_hw_nic_init(priv);
-
-	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);
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	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);
-
-	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, ALM_APMG_CLK_DIS,
-					 APMG_CLK_REG_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	udelay(5);
-
-	iwl_hw_nic_reset(priv);
-
-	/* Bring the device back up */
-	priv->status &= ~STATUS_IN_SUSPEND;
-	queue_work(priv->workqueue, &priv->up);
-}
-
-static int iwl_pci_resume(struct pci_dev *pdev)
-{
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-	int err;
-
-	printk(KERN_INFO "Coming out of suspend...\n");
-
-	mutex_lock(&priv->mutex);
-
-	pci_set_power_state(pdev, PCI_D0);
-	err = pci_enable_device(pdev);
-	pci_restore_state(pdev);
-
-	/*
-	 * Suspend/Resume resets the PCI configuration space, so we have to
-	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
-	 * from interfering with C3 CPU state. pci_restore_state won't help
-	 * here since it only restores the first 64 bytes pci config header.
-	 */
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
-	iwl_resume(priv);
-	mutex_unlock(&priv->mutex);
-
-	return 0;
-}
-
-#endif /* CONFIG_PM */
-
-/*****************************************************************************
- *
- * driver and module entry point
- *
- *****************************************************************************/
-
-static struct pci_driver iwl_driver = {
-	.name = DRV_NAME,
-	.id_table = iwl_hw_card_ids,
-	.probe = iwl_pci_probe,
-	.remove = __devexit_p(iwl_pci_remove),
-#ifdef CONFIG_PM
-	.suspend = iwl_pci_suspend,
-	.resume = iwl_pci_resume,
-#endif
-};
-
-static int __init iwl_init(void)
-{
-
-	int ret;
-	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
-	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-	ret = pci_register_driver(&iwl_driver);
-	if (ret) {
-		IWL_ERROR("Unable to initialize PCI module\n");
-		return ret;
-	}
-#ifdef CONFIG_IWLWIFI_DEBUG
-	ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
-	if (ret) {
-		IWL_ERROR("Unable to create driver sysfs file\n");
-		pci_unregister_driver(&iwl_driver);
-		return ret;
-	}
-#endif
-
-	return ret;
-}
-
-static void __exit iwl_exit(void)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
-#endif
-	pci_unregister_driver(&iwl_driver);
-}
-
-module_param_named(antenna, param_antenna, int, 0444);
-MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(disable, param_disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-module_param_named(hwcrypto, param_hwcrypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto,
-		 "using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, param_debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-module_param_named(disable_hw_scan, param_disable_hw_scan, int, 0444);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-/* QoS */
-module_param_named(qos_enable, param_qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
-
-module_exit(iwl_exit);
-module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
new file mode 100644
index 0000000..3cac2c8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
@@ -0,0 +1,1639 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-3945-commands.h) only for uCode API definitions.
+ * Please use iwl-3945-hw.h for hardware-related definitions.
+ * Please use iwl-3945.h for driver implementation definitions.
+ */
+
+#ifndef __iwl_3945_commands_h__
+#define __iwl_3945_commands_h__
+
+enum {
+	REPLY_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+
+	/* RXON and QOS commands */
+	REPLY_RXON = 0x10,
+	REPLY_RXON_ASSOC = 0x11,
+	REPLY_QOS_PARAM = 0x13,
+	REPLY_RXON_TIMING = 0x14,
+
+	/* Multi-Station support */
+	REPLY_ADD_STA = 0x18,
+	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+
+	/* RX, TX, LEDs */
+	REPLY_3945_RX = 0x1b,		/* 3945 only */
+	REPLY_TX = 0x1c,
+	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
+	REPLY_LEDS_CMD = 0x48,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+	/* 802.11h related */
+	RADAR_NOTIFICATION = 0x70,	/* not used */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
+	REPLY_CHANNEL_SWITCH = 0x72,
+	CHANNEL_SWITCH_NOTIFICATION = 0x73,
+	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+	/* Power Management */
+	POWER_TABLE_CMD = 0x77,
+	PM_SLEEP_NOTIFICATION = 0x7A,
+	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+	/* Scan commands and notifications */
+	REPLY_SCAN_CMD = 0x80,
+	REPLY_SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* IBSS/AP commands */
+	BEACON_NOTIFICATION = 0x90,
+	REPLY_TX_BEACON = 0x91,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
+
+	/* Miscellaneous commands */
+	QUIET_NOTIFICATION = 0x96,		/* not used */
+	REPLY_TX_PWR_TABLE_CMD = 0x97,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
+
+	/* Bluetooth device coexistance config command */
+	REPLY_BT_CONFIG = 0x9b,
+
+	/* Statistics */
+	REPLY_STATISTICS_CMD = 0x9c,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	REPLY_CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	/* Missed beacons notification */
+	MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+	REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, txpower
+ *
+ *****************************************************************************/
+
+/* iwl3945_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
+/**
+ * struct iwl3945_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl3945_cmd_header {
+	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
+	u8 flags;	/* IWL_CMD_* */
+	/*
+	 * The driver sets up the sequence number to values of its chosing.
+	 * uCode does not use this value, but passes it back to the driver
+	 * when sending the response to each driver-originated command, so
+	 * the driver can match the response to the command.  Since the values
+	 * don't get used by uCode, the driver may set up an arbitrary format.
+	 *
+	 * There is one exception:  uCode sets bit 15 when it originates
+	 * the response/notification, i.e. when the response/notification
+	 * is not a direct response to a command sent by the driver.  For
+	 * example, uCode issues REPLY_3945_RX when it sends a received frame
+	 * to the driver; it is not a direct response to any driver command.
+	 *
+	 * The Linux driver uses the following format:
+	 *
+	 *  0:7    index/position within Tx queue
+	 *  8:13   Tx queue selection
+	 * 14:14   driver sets this to indicate command is in the 'huge'
+	 *         storage at the end of the command buffers, i.e. scan cmd
+	 * 15:15   uCode sets this in uCode-originated response/notification
+	 */
+	__le16 sequence;
+
+	/* command or response/notification data follows immediately */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_tx_power
+ *
+ * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Each entry contains two values:
+ * 1)  DSP gain (or sometimes called DSP attenuation).  This is a fine-grained
+ *     linear value that multiplies the output of the digital signal processor,
+ *     before being sent to the analog radio.
+ * 2)  Radio gain.  This sets the analog gain of the radio Tx path.
+ *     It is a coarser setting, and behaves in a logarithmic (dB) fashion.
+ *
+ * Driver obtains values from struct iwl3945_tx_power power_gain_table[][].
+ */
+struct iwl3945_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_power_per_rate
+ *
+ * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ */
+struct iwl3945_power_per_rate {
+	u8 rate;		/* plcp */
+	struct iwl3945_tx_power tpc;
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
+/*
+ * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "initialize alive" notification once the initialization
+ * uCode image has completed its work, and is ready to load the runtime image.
+ * This is the *first* "alive" notification that the driver will receive after
+ * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ */
+struct iwl3945_init_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;			/* "9" for initialize alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+struct iwl3945_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;			/* not "9" for runtime alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
+
+union tsf {
+	u8 byte[8];
+	__le16 word[4];
+	__le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl3945_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+	__le16 reserved2;
+	__le32 error_info;
+	union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+struct iwl3945_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+	__le16 reserved4;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+	__le16 reserved5;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl3945_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl3945_rxon_time_cmd {
+	union tsf timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl3945_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl3945_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl3945_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl3945_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl3945_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define	IWL_AP_ID		0
+#define IWL_MULTICAST_ID	1
+#define	IWL_STA_ID		2
+#define	IWL3945_BROADCAST_ID	24
+#define IWL3945_STATION_COUNT	25
+
+#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
+#define	IWL_INVALID_STATION 	255
+
+#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1<<2);
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1<<8);
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+
+/*
+ * Antenna masks:
+ * bit14:15 01 B inactive, A active
+ *          10 B active, A inactive
+ *          11 Both active
+ */
+#define RATE_MCS_ANT_A_POS	14
+#define RATE_MCS_ANT_B_POS	15
+#define RATE_MCS_ANT_A_MSK	0x4000
+#define RATE_MCS_ANT_B_MSK	0x8000
+#define RATE_MCS_ANT_AB_MSK	0xc000
+
+struct iwl3945_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	__le16 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * 3945 uses REPLY_RATE_SCALE to set up rate tables).
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+struct iwl3945_addsta_cmd {
+	u8 mode;		/* 1: modify existing, 0: add new station */
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl3945_keyinfo key;
+	__le32 station_flags;		/* STA_FLG_* */
+	__le32 station_flags_msk;	/* STA_FLG_* */
+
+	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+	 * corresponding to bit (e.g. bit 5 controls TID 5).
+	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+	__le16 tid_disable_tx;
+
+	__le16 rate_n_flags;
+
+	/* TID for which to add block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	u8 add_immediate_ba_tid;
+
+	/* TID for which to remove block-ack support.
+	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+	u8 remove_immediate_ba_tid;
+
+	/* Starting Sequence Number for added block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	__le16 add_immediate_ba_ssn;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK		0x1
+#define ADD_STA_NO_ROOM_IN_TABLE	0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl3945_add_sta_resp {
+	u8 status;	/* ADD_STA_* */
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl3945_rx_frame_stats {
+	u8 phy_count;
+	u8 id;
+	u8 rssi;
+	u8 agc;
+	__le16 sig_avg;
+	__le16 noise_diff;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl3945_rx_frame_hdr {
+	__le16 channel;
+	__le16 phy_flags;
+	u8 reserved1;
+	u8 rate;
+	__le16 len;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+#define	RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
+#define	RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+
+#define	RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
+#define	RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
+#define	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
+#define	RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
+#define	RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+
+#define	RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+
+#define	RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define	RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define	RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+struct iwl3945_rx_frame_end {
+	__le32 status;
+	__le64 timestamp;
+	__le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl3945_rx_frame {
+	struct iwl3945_rx_frame_stats stats;
+	struct iwl3945_rx_frame_hdr hdr;
+	struct iwl3945_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
+#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
+#define IWL_AGC_DB_POS		(7)
+struct iwl4965_rx_non_cfg_phy {
+	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
+	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
+	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
+	u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
+	__le32 reserved2;
+	__le32 rate_n_flags;
+	__le16 byte_count;		/* frame's byte-count */
+	__le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device.  When the device's
+ * Tx scheduler and uCode are preparing to transmit, the device pulls the
+ * Tx command over the PCI bus via one of the device's Tx DMA channels,
+ * to fill an internal FIFO from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_RATE_SCALE (for 3945) or
+ * REPLY_TX_LINK_QUALITY_CMD (4965).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/* 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+
+/* 1: Transmit Clear-To-Send to self before this frame.
+ * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+
+/* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+
+/* 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set. */
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+
+/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+ * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl3945_tx_cmd {
+	/*
+	 * MPDU byte count:
+	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+	 * + 8 byte IV for CCM or TKIP (not used for WEP)
+	 * + Data payload
+	 * + 8-byte MIC (not used for CCM/WEP)
+	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+	 * Range: 14-2342 bytes.
+	 */
+	__le16 len;
+
+	/*
+	 * MPDU or MSDU byte count for next frame.
+	 * Used for fragmentation and bursting, but not 11n aggregation.
+	 * Same as "len", but for next frame.  Set to 0 if not applicable.
+	 */
+	__le16 next_frame_len;
+
+	__le32 tx_flags;	/* TX_CMD_FLG_* */
+
+	u8 rate;
+
+	/* Index of recipient station in uCode's station table */
+	u8 sta_id;
+	u8 tid_tspec;
+	u8 sec_ctl;
+	u8 key[16];
+	union {
+		u8 byte[8];
+		__le16 word[4];
+		__le32 dw[2];
+	} tkip_mic;
+	__le32 next_frame_info;
+	union {
+		__le32 life_time;
+		__le32 attempt;
+	} stop_time;
+	u8 supp_rates[2];
+	u8 rts_retry_limit;	/*byte 50 */
+	u8 data_retry_limit;	/*byte 51 */
+	union {
+		__le16 pm_frame_timeout;
+		__le16 attempt_duration;
+	} timeout;
+
+	/*
+	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+	 */
+	__le16 driver_txop;
+
+	/*
+	 * MAC header goes here, followed by 2 bytes padding if MAC header
+	 * length is 26 or 30 bytes, followed by payload data
+	 */
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
+ */
+enum {
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+	TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_TX_LOCKED = 0x90,
+	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
+
+enum {
+	TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+	TX_STATUS_MSK = 0x000000ff,	/* bits 0:7 */
+	TX_STATUS_DELAY_MSK = 0x00000040,
+	TX_STATUS_ABORT_MSK = 0x00000080,
+	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
+	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
+	TX_RESERVED = 0x00780000,	/* bits 19:22 */
+	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
+	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
+};
+
+/*
+ * REPLY_TX = 0x1c (response)
+ */
+struct iwl3945_tx_resp {
+	u8 failure_rts;
+	u8 failure_frame;
+	u8 bt_kill_count;
+	u8 rate;
+	__le32 wireless_media_time;
+	__le32 status;		/* TX status */
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ */
+struct iwl3945_txpowertable_cmd {
+	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
+	u8 reserved;
+	__le16 channel;
+	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+struct iwl3945_rate_scaling_info {
+	__le16 rate_n_flags;
+	u8 try_cnt;
+	u8 next_rate_index;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response
+ *
+ * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
+ *
+ * NOTE: The table of rates passed to the uCode via the
+ * RATE_SCALE command sets up the corresponding order of
+ * rates used for all related commands, including rate
+ * masks, etc.
+ *
+ * For example, if you set 9MB (PLCP 0x0f) as the first
+ * rate in the rate table, the bit mask for that rate
+ * when passed through ofdm_basic_rates on the REPLY_RXON
+ * command would be bit 0 (1<<0)
+ */
+struct iwl3945_rate_scaling_cmd {
+	u8 table_id;
+	u8 reserved[3];
+	struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl3945_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl3945_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl3945_measure_type */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl3945_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl3945_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl3945_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl3945_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl3945_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl3945_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl3945_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __attribute__ ((packed));
+
+enum iwl3945_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl3945_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl3945_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl3945_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl3945_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl3945_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1<<3)
+struct iwl3945_powertable_cmd {
+	__le32 flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+} __attribute__((packed));
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl3945_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl3945_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl3945_card_state_notif {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl3945_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+struct iwl3945_scan_channel {
+	/* type is defined as:
+	 * 0:0 active (0 - passive)
+	 * 1:4 SSID direct
+	 *     If 1 is set then corresponding SSID IE is transmitted in probe
+	 * 5:7 reserved
+	 */
+	u8 type;
+	u8 channel;
+	struct iwl3945_tx_power tpc;
+	__le16 active_dwell;
+	__le16 passive_dwell;
+} __attribute__ ((packed));
+
+struct iwl3945_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX        0x4
+#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
+struct iwl3945_scan_cmd {
+	__le16 len;
+	u8 reserved0;
+	u8 channel_count;
+	__le16 quiet_time;     /* dwell only this long on quiet chnl
+				* (active scan) */
+	__le16 quiet_plcp_th;  /* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;    /* passive -> active promotion threshold */
+	__le16 reserved1;
+	__le32 max_out_time;   /* max usec to be out of associated (service)
+				* chnl */
+	__le32 suspend_time;   /* pause scan this long when returning to svc
+				* chnl.
+				* 3945 -- 31:24 # beacons, 19:0 additional usec,
+				* 4965 -- 31:22 # beacons, 21:0 additional usec.
+				*/
+	__le32 flags;
+	__le32 filter_flags;
+
+	struct iwl3945_tx_cmd tx_cmd;
+	struct iwl3945_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+	u8 data[0];
+	/*
+	 * The channels start after the probe request payload and are of type:
+	 *
+	 * struct iwl3945_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * can not mix 2.4GHz channels and 5.2GHz channels and must
+	 * request a scan multiple times (not concurrently)
+	 *
+	 */
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl3945_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl3945_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __attribute__ ((packed));
+
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl3945_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl3945_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 reserved;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl3945_beacon_notif {
+	struct iwl3945_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl3945_tx_beacon_cmd {
+	struct iwl3945_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
+	u8 reserved1;
+	struct ieee80211_hdr frame[0];	/* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+} __attribute__ ((packed));
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+} __attribute__ ((packed));
+
+struct statistics_rx {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy general;
+} __attribute__ ((packed));
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
+} __attribute__ ((packed));
+
+struct statistics_general {
+	__le32 temperature;
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl3945_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl3945_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl3945_missed_beacon_notif {
+	__le32 consequtive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ *****************************************************************************/
+
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+#define HD_TABLE_SIZE  (11)
+
+struct iwl3945_sensitivity_cmd {
+	__le16 control;
+	__le16 table[HD_TABLE_SIZE];
+} __attribute__ ((packed));
+
+struct iwl3945_calibration_cmd {
+	u8 opCode;
+	u8 flags;
+	__le16 reserved;
+	s8 diff_gain_a;
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl3945_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl3945_rx_packet {
+	__le32 len;
+	struct iwl3945_cmd_header hdr;
+	union {
+		struct iwl3945_alive_resp alive_frame;
+		struct iwl3945_rx_frame rx_frame;
+		struct iwl3945_tx_resp tx_resp;
+		struct iwl3945_spectrum_notification spectrum_notif;
+		struct iwl3945_csa_notification csa_notif;
+		struct iwl3945_error_resp err_resp;
+		struct iwl3945_card_state_notif card_state_notif;
+		struct iwl3945_beacon_notif beacon_status;
+		struct iwl3945_add_sta_resp add_sta;
+		struct iwl3945_sleep_notification sleep_notif;
+		struct iwl3945_spectrum_resp spectrum;
+		struct iwl3945_notif_statistics stats;
+		__le32 status;
+		u8 raw[0];
+	} u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl3945_rx_frame))
+
+#endif				/* __iwl3945_3945_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
new file mode 100644
index 0000000..ebf0168
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl3945_debug_h__
+#define __iwl3945_debug_h__
+
+#ifdef CONFIG_IWL3945_DEBUG
+extern u32 iwl3945_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl3945_debug_level & (level)) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif				/* CONFIG_IWL3945_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IWL_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl3945_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWL3945_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO          (1<<0)
+#define IWL_DL_MAC80211      (1<<1)
+#define IWL_DL_HOST_COMMAND  (1<<2)
+#define IWL_DL_STATE         (1<<3)
+
+#define IWL_DL_RADIO         (1<<7)
+#define IWL_DL_POWER         (1<<8)
+#define IWL_DL_TEMP          (1<<9)
+
+#define IWL_DL_NOTIF         (1<<10)
+#define IWL_DL_SCAN          (1<<11)
+#define IWL_DL_ASSOC         (1<<12)
+#define IWL_DL_DROP          (1<<13)
+
+#define IWL_DL_TXPOWER       (1<<14)
+
+#define IWL_DL_AP            (1<<15)
+
+#define IWL_DL_FW            (1<<16)
+#define IWL_DL_RF_KILL       (1<<17)
+#define IWL_DL_FW_ERRORS     (1<<18)
+
+#define IWL_DL_LED           (1<<19)
+
+#define IWL_DL_RATE          (1<<20)
+
+#define IWL_DL_CALIB         (1<<21)
+#define IWL_DL_WEP           (1<<22)
+#define IWL_DL_TX            (1<<23)
+#define IWL_DL_RX            (1<<24)
+#define IWL_DL_ISR           (1<<25)
+#define IWL_DL_HT            (1<<26)
+#define IWL_DL_IO            (1<<27)
+#define IWL_DL_11H           (1<<28)
+
+#define IWL_DL_STATS         (1<<29)
+#define IWL_DL_TX_REPLY      (1<<30)
+#define IWL_DL_QOS           (1<<31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...)    IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...)     IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...)   IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...)   IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...)     IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...)     IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...)    IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...)    IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+	IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...)  IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index b127450..3020e5d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -60,31 +60,647 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-3945-hw.h) only for hardware-related definitions.
+ * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-3945.h for driver implementation definitions.
+ */
 
 #ifndef __iwl_3945_hw__
 #define __iwl_3945_hw__
 
-#define IWL_RX_BUF_SIZE 3000
-#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945 and 4965.
+ */
+#define IWL_CMD_QUEUE_NUM       4
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+#define IWL_HT_RATES 0
+#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#define IWL_RSSI_OFFSET	95
+
+/*
+ * EEPROM related constants, enums, and structures.
+ */
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
+ *   then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
+ *   CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
+
+/*
+ * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags.
+ *
+ * IBSS and/or AP operation is allowed *only* on those channels with
+ * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
+ * RADAR detection is not supported by the 3945 driver, but is a
+ * requirement for establishing a new network for legal operation on channels
+ * requiring RADAR detection or restricting ACTIVE scanning.
+ *
+ * NOTE:  "WIDE" flag indicates that 20 MHz channel is supported;
+ *        3945 does not support FAT 40 MHz-wide channels.
+ *
+ * NOTE:  Using a channel inappropriately will result in a uCode error!
+ */
+enum {
+	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
+	EEPROM_CHANNEL_IBSS = (1 << 1),		/* usable as an IBSS channel */
+	/* Bit 2 Reserved */
+	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
+	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
+	EEPROM_CHANNEL_WIDE = (1 << 5),		/* 20 MHz channel okay */
+	EEPROM_CHANNEL_NARROW = (1 << 6),	/* 10 MHz channel (not used) */
+	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
+};
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
+#define EEPROM_SKU_CAP_OP_MODE_MRC                      (1 << 7)
+
+/* *regulatory* channel data from eeprom, one for each channel */
+struct iwl3945_eeprom_channel {
+	u8 flags;		/* flags copied from EEPROM */
+	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/*
+ * Mapping of a Tx power level, at factory calibration temperature,
+ *   to a radio/DSP gain table index.
+ * One for each of 5 "sample" power levels in each band.
+ * v_det is measured at the factory, using the 3945's built-in power amplifier
+ *   (PA) output voltage detector.  This same detector is used during Tx of
+ *   long packets in normal operation to provide feedback as to proper output
+ *   level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl3945_eeprom_txpower_sample {
+	u8 gain_index;		/* index into power (gain) setup table ... */
+	s8 power;		/* ... for this pwr level for this chnl group */
+	u16 v_det;		/* PA output voltage */
+} __attribute__ ((packed));
+
+/*
+ * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
+ * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
+ * Tx power setup code interpolates between the 5 "sample" power levels
+ *    to determine the nominal setup for a requested power level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl3945_eeprom_txpower_group {
+	struct iwl3945_eeprom_txpower_sample samples[5];  /* 5 power levels */
+	s32 a, b, c, d, e;	/* coefficients for voltage->power
+				 * formula (signed) */
+	s32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
+				 * frequency (signed) */
+	s8 saturation_power;	/* highest power possible by h/w in this
+				 * band */
+	u8 group_channel;	/* "representative" channel # in this band */
+	s16 temperature;	/* h/w temperature at factory calib this band
+				 * (signed) */
+} __attribute__ ((packed));
+
+/*
+ * Temperature-based Tx-power compensation data, not band-specific.
+ * These coefficients are use to modify a/b/c/d/e coeffs based on
+ *   difference between current temperature and factory calib temperature.
+ * Data copied from EEPROM.
+ */
+struct iwl3945_eeprom_temperature_corr {
+	u32 Ta;
+	u32 Tb;
+	u32 Tc;
+	u32 Td;
+	u32 Te;
+} __attribute__ ((packed));
+
+/*
+ * EEPROM map
+ */
+struct iwl3945_eeprom {
+	u8 reserved0[16];
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+	u16 device_id;	/* abs.ofs: 16 */
+	u8 reserved1[2];
+#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
+	u16 pmc;		/* abs.ofs: 20 */
+	u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+	u8 mac_address[6];	/* abs.ofs: 42 */
+	u8 reserved3[58];
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+	u16 board_revision;	/* abs.ofs: 106 */
+	u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+	u8 board_pba_number[9];	/* abs.ofs: 119 */
+	u8 reserved5[8];
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+	u16 version;		/* abs.ofs: 136 */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
+	u8 sku_cap;		/* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
+	u8 leds_mode;		/* abs.ofs: 139 */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+	u16 oem_mode;
+#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
+	u8 leds_off_time;	/* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
+	u8 leds_on_time;	/* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
+	u8 almgor_m_version;	/* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
+	u8 antenna_switch_type;	/* abs.ofs: 149 */
+	u8 reserved6[42];
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
+	u8 sku_id[4];		/* abs.ofs: 192 */
+
+/*
+ * Per-channel regulatory data.
+ *
+ * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
+ * txpower (MSB).
+ *
+ * Entries immediately below are for 20 MHz channel width.  FAT (40 MHz)
+ * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
+ *
+ * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
+	u16 band_1_count;	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
+	struct iwl3945_eeprom_channel band_1_channels[14];  /* abs.ofs: 196 */
+
+/*
+ * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
+ * 5.0 GHz channels 7, 8, 11, 12, 16
+ * (4915-5080MHz) (none of these is ever supported)
+ */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
+	u16 band_2_count;	/* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
+	struct iwl3945_eeprom_channel band_2_channels[13];  /* abs.ofs: 228 */
+
+/*
+ * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+ * (5170-5320MHz)
+ */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
+	u16 band_3_count;	/* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
+	struct iwl3945_eeprom_channel band_3_channels[12];  /* abs.ofs: 256 */
+
+/*
+ * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+ * (5500-5700MHz)
+ */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
+	u16 band_4_count;	/* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
+	struct iwl3945_eeprom_channel band_4_channels[11];  /* abs.ofs: 282 */
+
+/*
+ * 5.7 GHz channels 145, 149, 153, 157, 161, 165
+ * (5725-5825MHz)
+ */
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
+	u16 band_5_count;	/* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
+	struct iwl3945_eeprom_channel band_5_channels[6];  /* abs.ofs: 306 */
+
+	u8 reserved9[194];
+
+/*
+ * 3945 Txpower calibration data.
+ */
+#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
+#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
+#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
+#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
+#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
+#define IWL_NUM_TX_CALIB_GROUPS 5
+	struct iwl3945_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
+/* abs.ofs: 512 */
+#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
+	struct iwl3945_eeprom_temperature_corr corrections;  /* abs.ofs: 832 */
+	u8 reserved16[172];	/* fill out to full 1024 byte block */
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+/* End of EEPROM */
+
+
+#include "iwl-3945-commands.h"
+
+#define PCI_LINK_CTRL      0x0F0
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
+
+#define CSR_SW_VER              (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL            (CSR_BASE+0x024)
+
+/*
+ * Hardware revision info
+ * Bit fields:
+ * 31-8:  Reserved
+ *  7-4:  Type of device:  0x0 = 4965, 0xd = 3945
+ *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
+ *  1-0:  "Dash" value, as in A-1, etc.
+ */
+#define CSR_HW_REV              (CSR_BASE+0x028)
+
+/* EEPROM reads */
+#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+
+/* Analog phase-lock-loop configuration (3945 only)
+ * Set bit 24. */
+#define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
+
+/* Bits for CSR_HW_IF_CONFIG_REG */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM     (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2  (1<<18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6  (1<<6)  /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL2 | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL6 | \
+				 CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0 )
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH		(0x00880300)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
+
+/*
+ * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
+ * structures, error log, event log, verifying uCode load).
+ * First write to address register, then read from or write to data register
+ * to complete the job.  Once the address register is set up, accesses to
+ * data registers auto-increment the address by one dword.
+ * Bit usage for address registers (read or write):
+ *  0-31:  memory address within device
+ */
+#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
+
+/*
+ * Registers for accessing device's internal peripheral registers
+ * (e.g. SCD, BSM, etc.).  First write to address register,
+ * then read from or write to data register to complete the job.
+ * Bit usage for address registers (read or write):
+ *  0-15:  register address (offset) within device
+ * 24-25:  (# bytes - 1) to read or write (e.g. 3 for dword)
+ */
+#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
+
+/*
+ * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Indicates index to next TFD that driver will fill (1 past latest filled).
+ * Bit usage:
+ *  0-7:  queue write index
+ * 11-8:  queue selector
+ */
+#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
+
+/* SCD (3945 Tx Frame Scheduler) */
+#define SCD_BASE                        (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG                    (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE     (0x800)
+
+#define FH_CBCC_TABLE           (FH_BASE+0x140)
+#define FH_TFDB_TABLE           (FH_BASE+0x180)
+#define FH_RCSR_TABLE           (FH_BASE+0x400)
+#define FH_RSSR_TABLE           (FH_BASE+0x4c0)
+#define FH_TCSR_TABLE           (FH_BASE+0x500)
+#define FH_TSSR_TABLE           (FH_BASE+0x680)
+
+/* TFDB (Transmit Frame Buffer Descriptor) */
+#define FH_TFDB(_channel, buf) \
+	(FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
+#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
+	(FH_TFDB_TABLE + 0x50 * _channel)
+/* CBCC _channel is [0,2] */
+#define FH_CBCC(_channel)           (FH_CBCC_TABLE+(_channel)*0x8)
+#define FH_CBCC_CTRL(_channel)      (FH_CBCC(_channel)+0x00)
+#define FH_CBCC_BASE(_channel)      (FH_CBCC(_channel)+0x04)
+
+/* RCSR _channel is [0,2] */
+#define FH_RCSR(_channel)           (FH_RCSR_TABLE+(_channel)*0x40)
+#define FH_RCSR_CONFIG(_channel)    (FH_RCSR(_channel)+0x00)
+#define FH_RCSR_RBD_BASE(_channel)  (FH_RCSR(_channel)+0x04)
+#define FH_RCSR_WPTR(_channel)      (FH_RCSR(_channel)+0x20)
+#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
+
+#define FH_RSCSR_CHNL0_WPTR        (FH_RCSR_WPTR(0))
+
+/* RSSR */
+#define FH_RSSR_CTRL            (FH_RSSR_TABLE+0x000)
+#define FH_RSSR_STATUS          (FH_RSSR_TABLE+0x004)
+/* TCSR */
+#define FH_TCSR(_channel)           (FH_TCSR_TABLE+(_channel)*0x20)
+#define FH_TCSR_CONFIG(_channel)    (FH_TCSR(_channel)+0x00)
+#define FH_TCSR_CREDIT(_channel)    (FH_TCSR(_channel)+0x04)
+#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
+/* TSSR */
+#define FH_TSSR_CBB_BASE        (FH_TSSR_TABLE+0x000)
+#define FH_TSSR_MSG_CONFIG      (FH_TSSR_TABLE+0x008)
+#define FH_TSSR_TX_STATUS       (FH_TSSR_TABLE+0x010)
+
+
+/* DBM */
+
+#define ALM_FH_SRVC_CHNL                            (6)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE     (20)
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH      (4)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN    (0x08000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE        (0x80000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE           (0x20000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128         (0x01000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST         (0x00001000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH               (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00004000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON      (0xFF000000)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON      (0x00FF0000)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B    (0x00000400)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON       (0x00000100)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON       (0x00000080)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH     (0x00000020)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH           (0x00000005)
+
+#define ALM_TB_MAX_BYTES_COUNT      (0xFFF0)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
+	((1LU << _channel) << 24)
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
+	((1LU << _channel) << 16)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
+	(ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
+	 ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
+#define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)	/* bit 6    */
+#define PCI_CFG_REV_ID_BIT_RTP                      (0x80)	/* bit 7    */
+
+#define TFD_QUEUE_MIN           0
+#define TFD_QUEUE_MAX           6
+#define TFD_QUEUE_SIZE_MAX      (256)
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+#define IWL_DEFAULT_TX_RETRY  15
+
+/*********************************************/
+
+#define RFD_SIZE                              4
+#define NUM_TFD_CHUNKS                        4
+
+#define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
+#define RX_QUEUE_SIZE_LOG                     8
+
+#define U32_PAD(n)		((4-(n))&0x3)
+
+#define TFD_CTL_COUNT_SET(n)       (n<<24)
+#define TFD_CTL_COUNT_GET(ctl)     ((ctl>>24) & 7)
+#define TFD_CTL_PAD_SET(n)         (n<<28)
+#define TFD_CTL_PAD_GET(ctl)       (ctl>>28)
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \
+			      sizeof(struct iwl3945_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+/* Sizes and addresses for instruction and data memory (SRAM) in
+ * 3945's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
+#define RTC_INST_LOWER_BOUND			(0x000000)
+#define ALM_RTC_INST_UPPER_BOUND		(0x014000)
+
+#define RTC_DATA_LOWER_BOUND			(0x800000)
+#define ALM_RTC_DATA_UPPER_BOUND		(0x808000)
+
+#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
 #define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE
 #define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE
 
-/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE
- * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
-struct iwl_shared {
+/* Size of uCode instruction memory in bootstrap state machine */
+#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+
+#define IWL_MAX_NUM_QUEUES	8
+
+static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
+{
+	return (addr >= RTC_DATA_LOWER_BOUND) &&
+	       (addr < ALM_RTC_DATA_UPPER_BOUND);
+}
+
+/* Base physical address of iwl3945_shared is provided to FH_TSSR_CBB_BASE
+ * and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
+struct iwl3945_shared {
 	__le32 tx_base_ptr[8];
 	__le32 rx_read_ptr[3];
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame_data {
+struct iwl3945_tfd_frame_data {
 	__le32 addr;
 	__le32 len;
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame {
+struct iwl3945_tfd_frame {
 	__le32 control_flags;
-	struct iwl_tfd_frame_data pa[4];
+	struct iwl3945_tfd_frame_data pa[4];
 	u8 reserved[28];
 } __attribute__ ((packed));
 
+static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags)
+{
+	return le16_to_cpu(rate_n_flags) & 0xFF;
+}
+
+static inline u16 iwl3945_hw_get_rate_n_flags(__le16 rate_n_flags)
+{
+	return le16_to_cpu(rate_n_flags);
+}
+
+static inline __le16 iwl3945_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+	return cpu_to_le16((u16)rate|flags);
+}
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
new file mode 100644
index 0000000..75e20d0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -0,0 +1,431 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl3945_io_h__
+#define __iwl3945_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-3945-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * and the current line number is printed in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl3945_read_direct32 calls the non-check version of
+ * _iwl3945_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O.  In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl3945_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *iwl,
+				 u32 ofs, u32 val)
+{
+	IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
+	_iwl3945_write32(iwl, ofs, val);
+}
+#define iwl3945_write32(iwl, ofs, val) \
+	__iwl3945_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl3945_write32(iwl, ofs, val) _iwl3945_write32(iwl, ofs, val)
+#endif
+
+#define _iwl3945_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *iwl, u32 ofs)
+{
+	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+	return _iwl3945_read32(iwl, ofs);
+}
+#define iwl3945_read32(iwl, ofs) __iwl3945_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl3945_read32(p, o) _iwl3945_read32(p, o)
+#endif
+
+static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr,
+				u32 bits, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask))
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_poll_bit(const char *f, u32 l,
+				 struct iwl3945_priv *priv, u32 addr,
+				 u32 bits, u32 mask, int timeout)
+{
+	int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
+	if (unlikely(ret  == -ETIMEDOUT))
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+		     addr, bits, mask, f, l);
+	else
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+		     addr, bits, mask, ret, f, l);
+	return ret;
+}
+#define iwl3945_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl3945_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl3945_poll_bit(p, a, b, m, t) _iwl3945_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl3945_set_bit(struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	_iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bit(const char *f, u32 l,
+				 struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read32(priv, reg) | mask;
+	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl3945_write32(priv, reg, val);
+}
+#define iwl3945_set_bit(p, r, m) __iwl3945_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl3945_set_bit(p, r, m) _iwl3945_set_bit(p, r, m)
+#endif
+
+static inline void _iwl3945_clear_bit(struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	_iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_clear_bit(const char *f, u32 l,
+				   struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read32(priv, reg) & ~mask;
+	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl3945_write32(priv, reg, val);
+}
+#define iwl3945_clear_bit(p, r, m) __iwl3945_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl3945_clear_bit(p, r, m) _iwl3945_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv)
+{
+	int ret;
+	u32 gp_ctl;
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+			"wakes up NIC\n");
+
+		/* 10 msec allows time for NIC to complete its data save */
+		gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL);
+		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+				"gpctl = 0x%08x\n", gp_ctl);
+			mdelay(10);
+		} else
+			IWL_DEBUG_RF_KILL("power-down complete, "
+					  "gpctl = 0x%08x\n", gp_ctl);
+	}
+
+	/* this bit wakes up the NIC */
+	_iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+	if (ret < 0) {
+		IWL_ERROR("MAC is in deep sleep!\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IWL3945_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_grab_nic_access(const char *f, u32 l,
+					       struct iwl3945_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
+
+	IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l);
+	return _iwl3945_grab_nic_access(priv);
+}
+#define iwl3945_grab_nic_access(priv) \
+	__iwl3945_grab_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl3945_grab_nic_access(priv) \
+	_iwl3945_grab_nic_access(priv)
+#endif
+
+static inline void _iwl3945_release_nic_access(struct iwl3945_priv *priv)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl3945_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_release_nic_access(const char *f, u32 l,
+					    struct iwl3945_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld nic access at line %d.\n", l);
+
+	IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l);
+	_iwl3945_release_nic_access(priv);
+}
+#define iwl3945_release_nic_access(priv) \
+	__iwl3945_release_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl3945_release_nic_access(priv) \
+	_iwl3945_release_nic_access(priv)
+#endif
+
+static inline u32 _iwl3945_read_direct32(struct iwl3945_priv *priv, u32 reg)
+{
+	return _iwl3945_read32(priv, reg);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read_direct32(const char *f, u32 l,
+					struct iwl3945_priv *priv, u32 reg)
+{
+	u32 value = _iwl3945_read_direct32(priv, reg);
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from %s %d\n", f, l);
+	IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+		     f, l);
+	return value;
+}
+#define iwl3945_read_direct32(priv, reg) \
+	__iwl3945_read_direct32(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl3945_read_direct32 _iwl3945_read_direct32
+#endif
+
+static inline void _iwl3945_write_direct32(struct iwl3945_priv *priv,
+					 u32 reg, u32 value)
+{
+	_iwl3945_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static void __iwl3945_write_direct32(u32 line,
+				   struct iwl3945_priv *priv, u32 reg, u32 value)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl3945_write_direct32(priv, reg, value);
+}
+#define iwl3945_write_direct32(priv, reg, value) \
+	__iwl3945_write_direct32(__LINE__, priv, reg, value)
+#else
+#define iwl3945_write_direct32 _iwl3945_write_direct32
+#endif
+
+static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv,
+					       u32 reg, u32 len, u32 *values)
+{
+	u32 count = sizeof(u32);
+
+	if ((priv != NULL) && (values != NULL)) {
+		for (; 0 < len; len -= count, reg += count, values++)
+			_iwl3945_write_direct32(priv, reg, *values);
+	}
+}
+
+static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv,
+					   u32 addr, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl3945_read_direct32(priv, addr) & mask) == mask)
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_poll_direct_bit(const char *f, u32 l,
+					    struct iwl3945_priv *priv,
+					    u32 addr, u32 mask, int timeout)
+{
+	int ret  = _iwl3945_poll_direct_bit(priv, addr, mask, timeout);
+
+	if (unlikely(ret == -ETIMEDOUT))
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
+	else
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, ret, f, l);
+	return ret;
+}
+#define iwl3945_poll_direct_bit(iwl, addr, mask, timeout) \
+	__iwl3945_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl3945_poll_direct_bit _iwl3945_poll_direct_bit
+#endif
+
+static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg)
+{
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read_prph(u32 line, struct iwl3945_priv *priv, u32 reg)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	return _iwl3945_read_prph(priv, reg);
+}
+
+#define iwl3945_read_prph(priv, reg) \
+	__iwl3945_read_prph(__LINE__, priv, reg)
+#else
+#define iwl3945_read_prph _iwl3945_read_prph
+#endif
+
+static inline void _iwl3945_write_prph(struct iwl3945_priv *priv,
+					     u32 addr, u32 val)
+{
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
+			      ((addr & 0x0000FFFF) | (3 << 24)));
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_write_prph(u32 line, struct iwl3945_priv *priv,
+					      u32 addr, u32 val)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access from line %d\n", line);
+	_iwl3945_write_prph(priv, addr, val);
+}
+
+#define iwl3945_write_prph(priv, addr, val) \
+	__iwl3945_write_prph(__LINE__, priv, addr, val);
+#else
+#define iwl3945_write_prph _iwl3945_write_prph
+#endif
+
+#define _iwl3945_set_bits_prph(priv, reg, mask) \
+	_iwl3945_write_prph(priv, reg, (_iwl3945_read_prph(priv, reg) | mask))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bits_prph(u32 line, struct iwl3945_priv *priv,
+					u32 reg, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+
+	_iwl3945_set_bits_prph(priv, reg, mask);
+}
+#define iwl3945_set_bits_prph(priv, reg, mask) \
+	__iwl3945_set_bits_prph(__LINE__, priv, reg, mask)
+#else
+#define iwl3945_set_bits_prph _iwl3945_set_bits_prph
+#endif
+
+#define _iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \
+	_iwl3945_write_prph(priv, reg, ((_iwl3945_read_prph(priv, reg) & mask) | bits))
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bits_mask_prph(u32 line,
+		struct iwl3945_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl3945_set_bits_mask_prph(priv, reg, bits, mask);
+}
+#define iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \
+	__iwl3945_set_bits_mask_prph(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl3945_set_bits_mask_prph _iwl3945_set_bits_mask_prph
+#endif
+
+static inline void iwl3945_clear_bits_prph(struct iwl3945_priv
+						 *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read_prph(priv, reg);
+	_iwl3945_write_prph(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 addr,
+					  u32 len, u32 *values)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	for (; 0 < len; len -= sizeof(u32), values++)
+		iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 2bffb11..adcd106 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -37,18 +37,13 @@
 
 #include <linux/workqueue.h>
 
-#include <net/mac80211.h>
-#include <linux/wireless.h>
-
 #include "../net/mac80211/ieee80211_rate.h"
 
-#include "iwl-3945-rs.h"
-#include "iwlwifi.h"
-#include "iwl-helpers.h"
+#include "iwl-3945.h"
 
 #define RS_NAME "iwl-3945-rs"
 
-struct iwl_rate_scale_data {
+struct iwl3945_rate_scale_data {
 	u64 data;
 	s32 success_counter;
 	s32 success_ratio;
@@ -57,43 +52,44 @@ struct iwl_rate_scale_data {
 	unsigned long stamp;
 };
 
-struct iwl_rate_scale_priv {
+struct iwl3945_rate_scale_priv {
 	spinlock_t lock;
 	s32 *expected_tpt;
 	unsigned long last_partial_flush;
 	unsigned long last_flush;
-	u8 flush_pending;
 	u32 flush_time;
 	u32 last_tx_packets;
-	u8 tgg;
 	u32 tx_packets;
+	u8 tgg;
+	u8 flush_pending;
 	u8 start_rate;
+	u8 ibss_sta_added;
 	struct timer_list rate_scale_flush;
-	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+	struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
 };
 
-static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = {
-	0, 0, 76, 104, 130, 168, 191, 202, 7, 13, 35, 58
+static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
 };
 
-static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = {
-	0, 0, 0, 80, 93, 113, 123, 125, 7, 13, 35, 58
+static s32 iwl3945_expected_tpt_g_prot[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
 };
 
-static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = {
-	40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0, 0
+static s32 iwl3945_expected_tpt_a[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
 };
 
-static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 35, 58
+static s32 iwl3945_expected_tpt_b[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
-struct iwl_tpt_entry {
+struct iwl3945_tpt_entry {
 	s8 min_rssi;
 	u8 index;
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_a[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = {
 	{-60, IWL_RATE_54M_INDEX},
 	{-64, IWL_RATE_48M_INDEX},
 	{-72, IWL_RATE_36M_INDEX},
@@ -104,7 +100,7 @@ static struct iwl_tpt_entry iwl_tpt_table_a[] = {
 	{-89, IWL_RATE_6M_INDEX}
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_b[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = {
 	{-86, IWL_RATE_11M_INDEX},
 	{-88, IWL_RATE_5M_INDEX},
 	{-90, IWL_RATE_2M_INDEX},
@@ -112,7 +108,7 @@ static struct iwl_tpt_entry iwl_tpt_table_b[] = {
 
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_g[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
 	{-60, IWL_RATE_54M_INDEX},
 	{-64, IWL_RATE_48M_INDEX},
 	{-68, IWL_RATE_36M_INDEX},
@@ -133,30 +129,30 @@ static struct iwl_tpt_entry iwl_tpt_table_g[] = {
 #define IWL_RATE_MIN_SUCCESS_TH       8
 #define IWL_RATE_DECREASE_TH       1920
 
-static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
+static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode)
 {
 	u32 index = 0;
 	u32 table_size = 0;
-	struct iwl_tpt_entry *tpt_table = NULL;
+	struct iwl3945_tpt_entry *tpt_table = NULL;
 
 	if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
 		rssi = IWL_MIN_RSSI_VAL;
 
 	switch (mode) {
 	case MODE_IEEE80211G:
-		tpt_table = iwl_tpt_table_g;
-		table_size = GLOBAL_ARRAY_SIZE(iwl_tpt_table_g);
+		tpt_table = iwl3945_tpt_table_g;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_g);
 		break;
 
 	case MODE_IEEE80211A:
-		tpt_table = iwl_tpt_table_a;
-		table_size = GLOBAL_ARRAY_SIZE(iwl_tpt_table_a);
+		tpt_table = iwl3945_tpt_table_a;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_a);
 		break;
 
 	default:
 	case MODE_IEEE80211B:
-		tpt_table = iwl_tpt_table_b;
-		table_size = GLOBAL_ARRAY_SIZE(iwl_tpt_table_b);
+		tpt_table = iwl3945_tpt_table_b;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_b);
 		break;
 	}
 
@@ -168,7 +164,7 @@ static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
 	return tpt_table[index].index;
 }
 
-static void iwl_clear_window(struct iwl_rate_scale_data *window)
+static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window)
 {
 	window->data = 0;
 	window->success_counter = 0;
@@ -179,13 +175,13 @@ static void iwl_clear_window(struct iwl_rate_scale_data *window)
 }
 
 /**
- * iwl_rate_scale_flush_windows - flush out the rate scale windows
+ * iwl3945_rate_scale_flush_windows - flush out the rate scale windows
  *
  * Returns the number of windows that have gathered data but were
  * not flushed.  If there were any that were not flushed, then
  * reschedule the rate flushing routine.
  */
-static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
+static int iwl3945_rate_scale_flush_windows(struct iwl3945_rate_scale_priv *rs_priv)
 {
 	int unflushed = 0;
 	int i;
@@ -206,7 +202,7 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
 			IWL_DEBUG_RATE("flushing %d samples of rate "
 				       "index %d\n",
 				       rs_priv->win[i].counter, i);
-			iwl_clear_window(&rs_priv->win[i]);
+			iwl3945_clear_window(&rs_priv->win[i]);
 		} else
 			unflushed++;
 		spin_unlock_irqrestore(&rs_priv->lock, flags);
@@ -218,16 +214,16 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
 #define IWL_RATE_FLUSH_MAX              5000	/* msec */
 #define IWL_RATE_FLUSH_MIN              50	/* msec */
 
-static void iwl_bg_rate_scale_flush(unsigned long data)
+static void iwl3945_bg_rate_scale_flush(unsigned long data)
 {
-	struct iwl_rate_scale_priv *rs_priv = (void *)data;
+	struct iwl3945_rate_scale_priv *rs_priv = (void *)data;
 	int unflushed = 0;
 	unsigned long flags;
 	u32 packet_count, duration, pps;
 
 	IWL_DEBUG_RATE("enter\n");
 
-	unflushed = iwl_rate_scale_flush_windows(rs_priv);
+	unflushed = iwl3945_rate_scale_flush_windows(rs_priv);
 
 	spin_lock_irqsave(&rs_priv->lock, flags);
 
@@ -281,21 +277,20 @@ static void iwl_bg_rate_scale_flush(unsigned long data)
 }
 
 /**
- * iwl_collect_tx_data - Update the success/failure sliding window
+ * iwl3945_collect_tx_data - Update the success/failure sliding window
  *
  * We keep a sliding window of the last 64 packets transmitted
  * at this rate.  window->data contains the bitmask of successful
  * packets.
  */
-static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
-				struct iwl_rate_scale_data *window,
+static void iwl3945_collect_tx_data(struct iwl3945_rate_scale_priv *rs_priv,
+				struct iwl3945_rate_scale_data *window,
 				int success, int retries)
 {
 	unsigned long flags;
 
 	if (!retries) {
-		IWL_DEBUG_RATE("leave: retries == 0 -- should be at "
-			       "least 1\n");
+		IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
 		return;
 	}
 
@@ -353,30 +348,37 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 
 	sta->last_txrate = sta->txrate;
 
+	/* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */
+        if (local->hw.conf.phymode == MODE_IEEE80211A)
+                sta->last_txrate += IWL_FIRST_OFDM_RATE;
+
 	IWL_DEBUG_RATE("leave\n");
 }
 
 static void *rs_alloc(struct ieee80211_local *local)
 {
-	IWL_DEBUG_RATE("enter\n");
-	IWL_DEBUG_RATE("leave\n");
 	return local->hw.priv;
 }
 
-static void rs_free(void *data)
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv)
 {
-	IWL_DEBUG_RATE("enter\n");
-	IWL_DEBUG_RATE("leave\n");
+	return;
+}
+static void rs_clear(void *priv)
+{
+	return;
 }
 
+
 static void *rs_alloc_sta(void *priv, gfp_t gfp)
 {
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rate_scale_priv *rs_priv;
 	int i;
 
 	IWL_DEBUG_RATE("enter\n");
 
-	rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+	rs_priv = kzalloc(sizeof(struct iwl3945_rate_scale_priv), gfp);
 	if (!rs_priv) {
 		IWL_DEBUG_RATE("leave: ENOMEM\n");
 		return NULL;
@@ -387,19 +389,20 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
 	rs_priv->start_rate = IWL_RATE_INVALID;
 
 	/* default to just 802.11b */
-	rs_priv->expected_tpt = iwl_expected_tpt_b;
+	rs_priv->expected_tpt = iwl3945_expected_tpt_b;
 
 	rs_priv->last_partial_flush = jiffies;
 	rs_priv->last_flush = jiffies;
 	rs_priv->flush_time = IWL_RATE_FLUSH;
 	rs_priv->last_tx_packets = 0;
+	rs_priv->ibss_sta_added = 0;
 
 	init_timer(&rs_priv->rate_scale_flush);
 	rs_priv->rate_scale_flush.data = (unsigned long)rs_priv;
-	rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush;
+	rs_priv->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush;
 
 	for (i = 0; i < IWL_RATE_COUNT; i++)
-		iwl_clear_window(&rs_priv->win[i]);
+		iwl3945_clear_window(&rs_priv->win[i]);
 
 	IWL_DEBUG_RATE("leave\n");
 
@@ -408,7 +411,7 @@ static void *rs_alloc_sta(void *priv, gfp_t gfp)
 
 static void rs_free_sta(void *priv, void *priv_sta)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	struct iwl3945_rate_scale_priv *rs_priv = priv_sta;
 
 	IWL_DEBUG_RATE("enter\n");
 	del_timer_sync(&rs_priv->rate_scale_flush);
@@ -416,15 +419,37 @@ static void rs_free_sta(void *priv, void *priv_sta)
 	IWL_DEBUG_RATE("leave\n");
 }
 
-static void rs_clear(void *priv)
+
+/*
+ * get ieee prev rate from rate scale table.
+ * for A and B mode we need to overright prev
+ * value
+ */
+static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
 {
-	IWL_DEBUG_RATE("NOP\n");
-}
+	int next_rate = iwl3945_get_prev_ieee_rate(rate);
+
+	switch (priv->phymode) {
+	case MODE_IEEE80211A:
+		if (rate == IWL_RATE_12M_INDEX)
+			next_rate = IWL_RATE_9M_INDEX;
+		else if (rate == IWL_RATE_6M_INDEX)
+			next_rate = IWL_RATE_6M_INDEX;
+		break;
+	case MODE_IEEE80211B:
+		if (rate == IWL_RATE_11M_INDEX_TABLE)
+			next_rate = IWL_RATE_5M_INDEX_TABLE;
+		break;
+	default:
+		break;
+	}
 
+	return next_rate;
+}
 /**
  * rs_tx_status - Update rate control values based on Tx results
  *
- * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
+ * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by
  * the hardware for each rate.
  */
 static void rs_tx_status(void *priv_rate,
@@ -437,9 +462,9 @@ static void rs_tx_status(void *priv_rate,
 	unsigned long flags;
 	struct sta_info *sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rate_scale_priv *rs_priv;
 
 	IWL_DEBUG_RATE("enter\n");
 
@@ -483,12 +508,13 @@ static void rs_tx_status(void *priv_rate,
 			last_index = scale_rate_index;
 		} else {
 			current_count = priv->retry_rate;
-			last_index = iwl_get_prev_ieee_rate(scale_rate_index);
+			last_index = rs_adjust_next_rate(priv,
+							 scale_rate_index);
 		}
 
 		/* Update this rate accounting for as many retries
 		 * as was used for it (per current_count) */
-		iwl_collect_tx_data(rs_priv,
+		iwl3945_collect_tx_data(rs_priv,
 				    &rs_priv->win[scale_rate_index],
 				    0, current_count);
 		IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
@@ -498,15 +524,16 @@ static void rs_tx_status(void *priv_rate,
 
 		if (retries)
 			scale_rate_index =
-			    iwl_get_prev_ieee_rate(scale_rate_index);
+			    rs_adjust_next_rate(priv, scale_rate_index);
 	}
 
+
 	/* Update the last index window with success/failure based on ACK */
 	IWL_DEBUG_RATE("Update rate %d with %s.\n",
 		       last_index,
 		       (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
 		       "success" : "failure");
-	iwl_collect_tx_data(rs_priv,
+	iwl3945_collect_tx_data(rs_priv,
 			    &rs_priv->win[last_index],
 			    tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
 
@@ -533,7 +560,7 @@ static void rs_tx_status(void *priv_rate,
 	return;
 }
 
-static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
+static struct ieee80211_rate *iwl3945_get_lowest_rate(struct ieee80211_local
 						  *local)
 {
 	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
@@ -549,13 +576,13 @@ static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
 	return &mode->rates[0];
 }
 
-static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
+static u16 iwl3945_get_adjacent_rate(struct iwl3945_rate_scale_priv *rs_priv,
 				 u8 index, u16 rate_mask, int phymode)
 {
 	u8 high = IWL_RATE_INVALID;
 	u8 low = IWL_RATE_INVALID;
 
-	/* 802.11A walks to the next literal adjascent rate in
+	/* 802.11A walks to the next literal adjacent rate in
 	 * the rate table */
 	if (unlikely(phymode == MODE_IEEE80211A)) {
 		int i;
@@ -585,9 +612,9 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
 	low = index;
 	while (low != IWL_RATE_INVALID) {
 		if (rs_priv->tgg)
-			low = iwl_rates[low].prev_rs_tgg;
+			low = iwl3945_rates[low].prev_rs_tgg;
 		else
-			low = iwl_rates[low].prev_rs;
+			low = iwl3945_rates[low].prev_rs;
 		if (low == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << low))
@@ -598,9 +625,9 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
 	high = index;
 	while (high != IWL_RATE_INVALID) {
 		if (rs_priv->tgg)
-			high = iwl_rates[high].next_rs_tgg;
+			high = iwl3945_rates[high].next_rs_tgg;
 		else
-			high = iwl_rates[high].next_rs;
+			high = iwl3945_rates[high].next_rs;
 		if (high == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << high))
@@ -636,8 +663,8 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 	u8 high = IWL_RATE_INVALID;
 	u16 high_low;
 	int index;
-	struct iwl_rate_scale_priv *rs_priv;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl3945_rate_scale_priv *rs_priv;
+	struct iwl3945_rate_scale_data *window = NULL;
 	int current_tpt = IWL_INVALID_VALUE;
 	int low_tpt = IWL_INVALID_VALUE;
 	int high_tpt = IWL_INVALID_VALUE;
@@ -648,7 +675,8 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct sta_info *sta;
 	u16 fc, rate_mask;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
+	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RATE("enter\n");
 
@@ -663,7 +691,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 		IWL_DEBUG_RATE("leave: lowest rate (not data or is "
 			       "multicast)\n");
 
-		return iwl_get_lowest_rate(local);
+		return iwl3945_get_lowest_rate(local);
 	}
 
 	sta = sta_info_get(local, hdr->addr1);
@@ -675,10 +703,27 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 	}
 
 	rate_mask = sta->supp_rates;
-	index = min(sta->txrate & 0xffff, IWL_RATE_COUNT - 1);
+	index = min(sta->last_txrate & 0xffff, IWL_RATE_COUNT - 1);
+
+	if (priv->phymode == (u8) MODE_IEEE80211A)
+		rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
 
 	rs_priv = (void *)sta->rate_ctrl_priv;
 
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !rs_priv->ibss_sta_added) {
+		u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
+
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, hdr->addr1));
+			sta_id = iwl3945_add_station(priv,
+				    hdr->addr1, 0, CMD_ASYNC);
+		}
+		if (sta_id != IWL_INVALID_STATION)
+			rs_priv->ibss_sta_added = 1;
+	}
+
 	spin_lock_irqsave(&rs_priv->lock, flags);
 
 	if (rs_priv->start_rate != IWL_RATE_INVALID) {
@@ -710,7 +755,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 				rs_priv->expected_tpt[index] + 64) / 128);
 	current_tpt = window->average_tpt;
 
-	high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask,
+	high_low = iwl3945_get_adjacent_rate(rs_priv, index, rate_mask,
 					 local->hw.conf.phymode);
 	low = high_low & 0xff;
 	high = (high_low >> 8) & 0xff;
@@ -729,9 +774,9 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
 		scale_action = -1;
 	} else if ((low_tpt == IWL_INVALID_VALUE) &&
-		   (high_tpt == IWL_INVALID_VALUE)) {
+		   (high_tpt == IWL_INVALID_VALUE))
 		scale_action = 1;
-	} else if ((low_tpt != IWL_INVALID_VALUE) &&
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
 		   (high_tpt != IWL_INVALID_VALUE)
 		   && (low_tpt < current_tpt)
 		   && (high_tpt < current_tpt)) {
@@ -790,7 +835,11 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
  out:
 
 	sta->last_txrate = index;
-	sta->txrate = sta->last_txrate;
+	if (priv->phymode == (u8) MODE_IEEE80211A)
+		sta->txrate = sta->last_txrate - IWL_FIRST_OFDM_RATE;
+	else
+		sta->txrate = sta->last_txrate;
+
 	sta_info_put(sta);
 
 	IWL_DEBUG_RATE("leave: %d\n", index);
@@ -811,11 +860,11 @@ static struct rate_control_ops rs_ops = {
 	.free_sta = rs_free_sta,
 };
 
-int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_priv *priv = hw->priv;
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_priv *priv = hw->priv;
+	struct iwl3945_rate_scale_priv *rs_priv;
 	struct sta_info *sta;
 	unsigned long flags;
 	int count = 0, i;
@@ -841,7 +890,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		int j;
 
 		count +=
-		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+		    sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2);
 
 		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
 		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
@@ -850,7 +899,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 
 		samples += rs_priv->win[i].counter;
 		good += rs_priv->win[i].success_counter;
-		success += rs_priv->win[i].success_counter * iwl_rates[i].ieee;
+		success += rs_priv->win[i].success_counter * iwl3945_rates[i].ieee;
 
 		if (rs_priv->win[i].stamp) {
 			int delta =
@@ -863,7 +912,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		} else
 			buf[count++] = '\n';
 
-		j = iwl_get_prev_ieee_rate(i);
+		j = iwl3945_get_prev_ieee_rate(i);
 		if (j == i)
 			break;
 		i = j;
@@ -874,7 +923,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 	/* Display the average rate of all samples taken.
 	 *
 	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
-	 * added from iwl_rates is actually 2X the rate */
+	 * added from iwl3945_rates is actually 2X the rate */
 	if (samples)
 		count += sprintf(
 			&buf[count],
@@ -888,21 +937,20 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 	return count;
 }
 
-void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	s32 rssi = 0;
 	unsigned long flags;
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rate_scale_priv *rs_priv;
 	struct sta_info *sta;
 
 	IWL_DEBUG_RATE("enter\n");
 
 	if (!local->rate_ctrl->ops->name ||
 	    strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
-		IWL_WARNING("iwl-3945-rs not selected as rate control "
-			    "aglo!\n");
+		IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
 		IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
 		return;
 	}
@@ -924,19 +972,19 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 	case MODE_IEEE80211G:
 		if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
 			rs_priv->tgg = 1;
-			rs_priv->expected_tpt = iwl_expected_tpt_g_prot;
+			rs_priv->expected_tpt = iwl3945_expected_tpt_g_prot;
 		} else
-			rs_priv->expected_tpt = iwl_expected_tpt_g;
+			rs_priv->expected_tpt = iwl3945_expected_tpt_g;
 		break;
 
 	case MODE_IEEE80211A:
-		rs_priv->expected_tpt = iwl_expected_tpt_a;
+		rs_priv->expected_tpt = iwl3945_expected_tpt_a;
 		break;
 
 	default:
 		IWL_WARNING("Invalid phymode.  Defaulting to 802.11b\n");
 	case MODE_IEEE80211B:
-		rs_priv->expected_tpt = iwl_expected_tpt_b;
+		rs_priv->expected_tpt = iwl3945_expected_tpt_b;
 		break;
 	}
 
@@ -949,19 +997,19 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
 	IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
 
-	rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode);
+	rs_priv->start_rate = iwl3945_get_rate_index_by_rssi(rssi, priv->phymode);
 
 	IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
 		       "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate,
-		       iwl_rates[rs_priv->start_rate].plcp);
+		       iwl3945_rates[rs_priv->start_rate].plcp);
 }
 
-void iwl_rate_control_register(void)
+void iwl3945_rate_control_register(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_register(&rs_ops);
 }
 
-void iwl_rate_control_unregister(void)
+void iwl3945_rate_control_unregister(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_unregister(&rs_ops);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index 25bdbcb..e21a5ba 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -27,19 +27,29 @@
 #ifndef __iwl_3945_rs_h__
 #define __iwl_3945_rs_h__
 
-struct iwl_rate_info {
-	u8 plcp;
-	u8 ieee;
+struct iwl3945_rate_info {
+	u8 plcp;		/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 ieee;		/* MAC header:  IWL_RATE_6M_IEEE, etc. */
 	u8 prev_ieee;		/* previous rate in IEEE speeds */
 	u8 next_ieee;		/* next rate in IEEE speeds */
 	u8 prev_rs;		/* previous rate used in rs algo */
 	u8 next_rs;		/* next rate used in rs algo */
 	u8 prev_rs_tgg;		/* previous rate used in TGG rs algo */
 	u8 next_rs_tgg;		/* next rate used in TGG rs algo */
+        u8 table_rs_index;	/* index in rate scale table cmd */
+        u8 prev_table_rs;	/* prev in rate table cmd */
 };
 
+/*
+ * These serve as indexes into
+ * struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT];
+ */
 enum {
-	IWL_RATE_6M_INDEX = 0,
+	IWL_RATE_1M_INDEX = 0,
+	IWL_RATE_2M_INDEX,
+	IWL_RATE_5M_INDEX,
+	IWL_RATE_11M_INDEX,
+	IWL_RATE_6M_INDEX,
 	IWL_RATE_9M_INDEX,
 	IWL_RATE_12M_INDEX,
 	IWL_RATE_18M_INDEX,
@@ -47,16 +57,28 @@ enum {
 	IWL_RATE_36M_INDEX,
 	IWL_RATE_48M_INDEX,
 	IWL_RATE_54M_INDEX,
-	IWL_RATE_1M_INDEX,
-	IWL_RATE_2M_INDEX,
-	IWL_RATE_5M_INDEX,
-	IWL_RATE_11M_INDEX,
 	IWL_RATE_COUNT,
 	IWL_RATE_INVM_INDEX,
 	IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
 };
 
 enum {
+	IWL_RATE_6M_INDEX_TABLE = 0,
+	IWL_RATE_9M_INDEX_TABLE,
+	IWL_RATE_12M_INDEX_TABLE,
+	IWL_RATE_18M_INDEX_TABLE,
+	IWL_RATE_24M_INDEX_TABLE,
+	IWL_RATE_36M_INDEX_TABLE,
+	IWL_RATE_48M_INDEX_TABLE,
+	IWL_RATE_54M_INDEX_TABLE,
+	IWL_RATE_1M_INDEX_TABLE,
+	IWL_RATE_2M_INDEX_TABLE,
+	IWL_RATE_5M_INDEX_TABLE,
+	IWL_RATE_11M_INDEX_TABLE,
+	IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX,
+};
+
+enum {
 	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
 	IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
 	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
@@ -77,6 +99,7 @@ enum {
 #define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
 #define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
 
+/* 3945 uCode API values for (legacy) bit rates, both OFDM and CCK */
 enum {
 	IWL_RATE_6M_PLCP = 13,
 	IWL_RATE_9M_PLCP = 15,
@@ -92,6 +115,7 @@ enum {
 	IWL_RATE_11M_PLCP = 110,
 };
 
+/* MAC header values for bit rates */
 enum {
 	IWL_RATE_6M_IEEE = 12,
 	IWL_RATE_9M_IEEE = 18,
@@ -140,82 +164,52 @@ enum {
 #define IWL_MIN_RSSI_VAL                 -100
 #define IWL_MAX_RSSI_VAL                    0
 
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
-
-static inline int iwl_rate_index_from_plcp(int plcp)
-{
-	int i = 0;
-	for (i = 0; i < IWL_RATE_COUNT; i++)
-		if (iwl_rates[i].plcp == plcp)
-			return i;
-	return -1;
-}
+extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT];
 
-static inline u8 iwl_rate_get_lowest_plcp(int rate_mask)
+static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
 {
-	u8 i;
+	u8 rate = iwl3945_rates[rate_index].prev_ieee;
 
-	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-	     i = iwl_rates[i].next_ieee) {
-		if (rate_mask & (1 << i))
-			return iwl_rates[i].plcp;
-	}
-
-	return IWL_RATE_INVALID;
-}
-
-static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
-{
-	u8 rate = iwl_rates[rate_index].prev_ieee;
 	if (rate == IWL_RATE_INVALID)
 		rate = rate_index;
 	return rate;
 }
 
-#if IWL == 3945
 /**
- * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ * iwl3945_fill_rs_info - Fill an output text buffer with the rate representation
  *
  * NOTE:  This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control alogirthm and is not meant to be
+ * the performance of the rate control algorithm and is not meant to be
  * parsed software.
  */
-extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
 
 /**
- * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
  *
- * The specific througput table used is based on the type of network
+ * The specific throughput table used is based on the type of network
  * the associated with, including A, B, G, and G w/ TGG protection
  */
-extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
 
 /**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
+ * iwl3945_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
+ * iwl3945_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
  */
-extern void iwl_rate_control_register(void);
+extern void iwl3945_rate_control_register(struct ieee80211_hw *hw);
 
 /**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
+ * iwl3945_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
  */
-extern void iwl_rate_control_unregister(void);
-#else
-static inline int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf,
-				   u8 sta_id)
-{ return -ENOTSUPP; }
-static inline void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) {}
-static inline void iwl_rate_control_register(void) {}
-static inline void iwl_rate_control_unregister(void) {}
-#endif /* IWL == 3945 */
+extern void iwl3945_rate_control_unregister(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 4325ff0..53e7927 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -38,11 +38,9 @@
 #include <net/mac80211.h>
 
 #include <linux/etherdevice.h>
-#include <linux/delay.h>
 
-#include "iwlwifi.h"
-#include "iwl-helpers.h"
 #include "iwl-3945.h"
+#include "iwl-helpers.h"
 #include "iwl-3945-rs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
@@ -53,7 +51,9 @@
 				    IWL_RATE_##rp##M_INDEX, \
 				    IWL_RATE_##rn##M_INDEX, \
 				    IWL_RATE_##pp##M_INDEX, \
-				    IWL_RATE_##np##M_INDEX }
+				    IWL_RATE_##np##M_INDEX, \
+				    IWL_RATE_##r##M_INDEX_TABLE, \
+				    IWL_RATE_##ip##M_INDEX_TABLE }
 
 /*
  * Parameter order:
@@ -63,7 +63,11 @@
  * maps to IWL_RATE_INVALID
  *
  */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+	IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */
 	IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
 	IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11),       /*  9mbps */
 	IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
@@ -72,18 +76,14 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
 	IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
 	IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
-	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
-	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
-	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-	IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */
 };
 
-/* 1 = enable the iwl_disable_events() function */
+/* 1 = enable the iwl3945_disable_events() function */
 #define IWL_EVT_DISABLE (0)
 #define IWL_EVT_DISABLE_SIZE (1532/32)
 
 /**
- * iwl_disable_events - Disable selected events in uCode event log
+ * iwl3945_disable_events - Disable selected events in uCode event log
  *
  * Disable an event by writing "1"s into "disable"
  *   bitmap in SRAM.  Bit position corresponds to Event # (id/type).
@@ -91,9 +91,9 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
  * Use for only special debugging.  This function is just a placeholder as-is,
  *   you'll need to provide the special bits! ...
  *   ... and set IWL_EVT_DISABLE to 1. */
-void iwl_disable_events(struct iwl_priv *priv)
+void iwl3945_disable_events(struct iwl3945_priv *priv)
 {
-	int rc;
+	int ret;
 	int i;
 	u32 base;		/* SRAM address of event log header */
 	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
@@ -148,33 +148,32 @@ void iwl_disable_events(struct iwl_priv *priv)
 		0x00000000,	/* 1503 - 1472 */
 	};
 
-	base = priv->card_alive.log_event_table_ptr;
-	if (!VALID_RTC_DATA_ADDR(base)) {
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
+	ret = iwl3945_grab_nic_access(priv);
+	if (ret) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
-	disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));
-	array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));
-	iwl_release_restricted_access(priv);
+	disable_ptr = iwl3945_read_targ_mem(priv, base + (4 * sizeof(u32)));
+	array_size = iwl3945_read_targ_mem(priv, base + (5 * sizeof(u32)));
+	iwl3945_release_nic_access(priv);
 
 	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
 		IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
 			       disable_ptr);
-		rc = iwl_grab_restricted_access(priv);
-		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) {
-			iwl_write_restricted_mem(priv,
-						 disable_ptr +
-						 (i * sizeof(u32)),
-						 evt_disable[i]);
-		}
-		iwl_release_restricted_access(priv);
+		ret = iwl3945_grab_nic_access(priv);
+		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
+			iwl3945_write_targ_mem(priv,
+					   disable_ptr + (i * sizeof(u32)),
+					   evt_disable[i]);
+
+		iwl3945_release_nic_access(priv);
 	} else {
 		IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
 		IWL_DEBUG_INFO("  by writing \"1\"s into disable bitmap\n");
@@ -195,7 +194,7 @@ void iwl_disable_events(struct iwl_priv *priv)
  * IWL_ANTENNA_MAIN      - Force MAIN antenna
  * IWL_ANTENNA_AUX       - Force AUX antenna
  */
-int iwl3945_get_antenna_flags(const struct iwl_priv *priv)
+__le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv)
 {
 	switch (priv->antenna) {
 	case IWL_ANTENNA_DIVERSITY:
@@ -223,15 +222,15 @@ int iwl3945_get_antenna_flags(const struct iwl_priv *priv)
  *
  *  RX handler implementations
  *
- *  Used by base.c
+ *  Used by iwl-base.c
  *
  *****************************************************************************/
 
-void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
-		     (int)sizeof(struct iwl_notif_statistics),
+		     (int)sizeof(struct iwl3945_notif_statistics),
 		     le32_to_cpu(pkt->len));
 
 	memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
@@ -239,15 +238,15 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	priv->last_statistics_time = jiffies;
 }
 
-static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
-				   struct iwl_rx_mem_buffer *rxb,
+static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
+				   struct iwl3945_rx_mem_buffer *rxb,
 				   struct ieee80211_rx_status *stats,
 				   u16 phy_flags)
 {
 	struct ieee80211_hdr *hdr;
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	short len = le16_to_cpu(rx_hdr->len);
 
 	/* We received data from the HW, so stop the watchdog */
@@ -258,16 +257,16 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
 
 	/* We only process data packets if the interface is open */
 	if (unlikely(!priv->is_open)) {
-		IWL_DEBUG_DROP
+		IWL_DEBUG_DROP_LIMIT
 		    ("Dropping packet while interface is not open.\n");
 		return;
 	}
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		if (param_hwcrypto)
-			iwl_set_decrypted_flag(priv, rxb->skb,
+		if (iwl3945_param_hwcrypto)
+			iwl3945_set_decrypted_flag(priv, rxb->skb,
 					       le32_to_cpu(rx_end->status),
 					       stats);
-		iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
+		iwl3945_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
 					       len, stats, phy_flags);
 		return;
 	}
@@ -278,25 +277,29 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
 
 	hdr = (void *)rxb->skb->data;
 
-	if (param_hwcrypto)
-		iwl_set_decrypted_flag(priv, rxb->skb,
+	if (iwl3945_param_hwcrypto)
+		iwl3945_set_decrypted_flag(priv, rxb->skb,
 				       le32_to_cpu(rx_end->status), stats);
 
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	rxb->skb = NULL;
 }
 
-static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+
+static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	struct ieee80211_hdr *header;
 	u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
 	struct ieee80211_rx_status stats = {
-		.mactime = le32_to_cpu(rx_end->beacon_timestamp),
+		.mactime = le64_to_cpu(rx_end->timestamp),
 		.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),
 		.channel = le16_to_cpu(rx_hdr->channel),
 		.phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
@@ -305,7 +308,6 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		.rate = rx_hdr->rate,
 		.flag = 0,
 	};
-
 	u8 network_packet;
 	int snr;
 
@@ -316,9 +318,8 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		return;
 	}
 
-	if (!(le32_to_cpu(rx_end->status) & RX_RES_STATUS_NO_CRC32_ERROR)
-	    || !(le32_to_cpu(rx_end->status) &
-		 RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)
+	    || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
 		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
 		return;
 	}
@@ -331,12 +332,9 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 	/* Convert 3945's rssi indicator to dBm */
 	stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
 
-	/* Set default noise value to -127 ... this works better than 0 when
-	 *   averaging frames with/without noise info; measured values are
-	 *   always negative ... using a negative value as the default value
-	 *   keeps all averages within an s8's range of negative values. */
+	/* Set default noise value to -127 */
 	if (priv->last_rx_noise == 0)
-		priv->last_rx_noise = -127;
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
 	/* 3945 provides noise info for OFDM frames only.
 	 * sig_avg and noise_diff are measured by the 3945's digital signal
@@ -349,43 +347,43 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 	 * Convert linear SNR to dB SNR, then subtract that from rssi dBm
 	 *   to obtain noise level in dBm.
 	 * Calculate stats.signal (quality indicator in %) based on SNR. */
-	if (rx_stats->noise_diff) {
-		snr = rx_stats->sig_avg / rx_stats->noise_diff;
-		stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);
-		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+	if (rx_stats_noise_diff) {
+		snr = rx_stats_sig_avg / rx_stats_noise_diff;
+		stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr);
+		stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise);
 
 	/* If noise info not available, calculate signal quality indicator (%)
 	 *   using just the dBm signal level. */
 	} else {
 		stats.noise = priv->last_rx_noise;
-		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+		stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0);
 	}
 
 
 	IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
 			stats.ssi, stats.noise, stats.signal,
-			rx_stats->sig_avg, rx_stats->noise_diff);
+			rx_stats_sig_avg, rx_stats_noise_diff);
 
 	stats.freq = ieee80211chan2mhz(stats.channel);
 
-	/* can be covered by iwl_report_frame() in most cases */
+	/* can be covered by iwl3945_report_frame() in most cases */
 /*      IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
 
 	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 
-	network_packet = iwl_is_network_packet(priv, header);
+	network_packet = iwl3945_is_network_packet(priv, header);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit())
 		IWL_DEBUG_STATS
 		    ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
 		     network_packet ? '*' : ' ',
 		     stats.channel, stats.ssi, stats.ssi,
 		     stats.ssi, stats.rate);
 
-	if (iwl_debug_level & (IWL_DL_RX))
+	if (iwl3945_debug_level & (IWL_DL_RX))
 		/* Set "1" to report good data frames in groups of 100 */
-		iwl_report_frame(priv, pkt, header, 1);
+		iwl3945_report_frame(priv, pkt, header, 1);
 #endif
 
 	if (network_packet) {
@@ -395,9 +393,10 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		priv->last_rx_noise = stats.noise;
 	}
 
-	switch (WLAN_FC_GET_TYPE(le16_to_cpu(header->frame_control))) {
+	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
-		switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_control))) {
+		switch (le16_to_cpu(header->frame_control) &
+			IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_PROBE_RESP:
 		case IEEE80211_STYPE_BEACON:{
 				/* If this is a beacon or probe response for
@@ -415,7 +414,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 					pos =
 					    (__le32 *) & mgmt->u.beacon.
 					    timestamp;
-					priv->timestamp0 = le64_to_cpu(pos[0]);
+					priv->timestamp0 = le32_to_cpu(pos[0]);
 					priv->timestamp1 = le32_to_cpu(pos[1]);
 					priv->beacon_int = le16_to_cpu(
 					    mgmt->u.beacon.beacon_int);
@@ -445,6 +444,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		case IEEE80211_STYPE_REASSOC_RESP:{
 				struct ieee80211_mgmt *mgnt =
 				    (struct ieee80211_mgmt *)header;
+
+				/* We have just associated, give some
+				 * time for the 4-way handshake if
+				 * any. Don't start scan too early. */
+				priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+
 				priv->assoc_id = (~((1 << 15) | (1 << 14)) &
 						  le16_to_cpu(mgnt->u.
 							      assoc_resp.aid));
@@ -459,13 +465,16 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 			}
 
 		case IEEE80211_STYPE_PROBE_REQ:{
+				DECLARE_MAC_BUF(mac1);
+				DECLARE_MAC_BUF(mac2);
+				DECLARE_MAC_BUF(mac3);
 				if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
 					IWL_DEBUG_DROP
-					    ("Dropping (non network): " MAC_FMT
-					     ", " MAC_FMT ", " MAC_FMT "\n",
-					     MAC_ARG(header->addr1),
-					     MAC_ARG(header->addr2),
-					     MAC_ARG(header->addr3));
+					    ("Dropping (non network): %s"
+					     ", %s, %s\n",
+					     print_mac(mac1, header->addr1),
+					     print_mac(mac2, header->addr2),
+					     print_mac(mac3, header->addr3));
 				return;
 			}
 		}
@@ -476,26 +485,30 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 	case IEEE80211_FTYPE_CTL:
 		break;
 
-	case IEEE80211_FTYPE_DATA:
-		if (unlikely(is_duplicate_packet(priv, header)))
-			IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", "
-				       MAC_FMT ", " MAC_FMT "\n",
-				       MAC_ARG(header->addr1),
-				       MAC_ARG(header->addr2),
-				       MAC_ARG(header->addr3));
+	case IEEE80211_FTYPE_DATA: {
+		DECLARE_MAC_BUF(mac1);
+		DECLARE_MAC_BUF(mac2);
+		DECLARE_MAC_BUF(mac3);
+
+		if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
+			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
 		else
 			iwl3945_handle_data_packet(priv, 1, rxb, &stats,
 						   phy_flags);
 		break;
 	}
+	}
 }
 
-int iwl_hw_tx_queue_attach_buffer_to_tfd(struct iwl_priv *priv,
-					 void *ptr, dma_addr_t addr, u16 len)
+int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
+				 dma_addr_t addr, u16 len)
 {
 	int count;
 	u32 pad;
-	struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr;
+	struct iwl3945_tfd_frame *tfd = (struct iwl3945_tfd_frame *)ptr;
 
 	count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
 	pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));
@@ -518,14 +531,14 @@ int iwl_hw_tx_queue_attach_buffer_to_tfd(struct iwl_priv *priv,
 }
 
 /**
- * iwl_hw_tx_queue_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ * iwl3945_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr]
  *
  * Does NOT advance any indexes
  */
-int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
 {
-	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
-	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct iwl3945_tfd_frame *bd_tmp = (struct iwl3945_tfd_frame *)&txq->bd[0];
+	struct iwl3945_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 	int counter;
@@ -548,46 +561,47 @@ int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 	for (i = 1; i < counter; i++) {
 		pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
 				 le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
-		if (txq->txb[txq->q.last_used].skb[0]) {
-			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0];
-			if (txq->txb[txq->q.last_used].skb[0]) {
+		if (txq->txb[txq->q.read_ptr].skb[0]) {
+			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
+			if (txq->txb[txq->q.read_ptr].skb[0]) {
 				/* Can be called from interrupt context */
 				dev_kfree_skb_any(skb);
-				txq->txb[txq->q.last_used].skb[0] = NULL;
+				txq->txb[txq->q.read_ptr].skb[0] = NULL;
 			}
 		}
 	}
 	return 0;
 }
 
-u8 iwl_hw_find_station(struct iwl_priv * priv, const u8 * bssid)
+u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
 {
 	int i;
 	int ret = IWL_INVALID_STATION;
 	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	for (i = IWL_STA_ID; i < (IWL_STA_ID + priv->num_stations); i++)
+	for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
 		if ((priv->stations[i].used) &&
 		    (!compare_ether_addr
-		     (priv->stations[i].sta.sta.addr, bssid))) {
+		     (priv->stations[i].sta.sta.addr, addr))) {
 			ret = i;
 			goto out;
 		}
 
-	IWL_DEBUG_INFO("can not find STA " MAC_FMT " (total %d)\n",
-		       MAC_ARG(bssid), priv->num_stations);
+	IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
+		       print_mac(mac, addr), priv->num_stations);
  out:
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 	return ret;
 }
 
 /**
- * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD
+ * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
  *
 */
-void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-			      struct iwl_cmd *cmd,
+void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
+			      struct iwl3945_cmd *cmd,
 			      struct ieee80211_tx_control *ctrl,
 			      struct ieee80211_hdr *hdr, int sta_id, int tx_id)
 {
@@ -597,10 +611,10 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	int rate;
 	u8 rts_retry_limit;
 	u8 data_retry_limit;
-	u32 tx_flags;
+	__le32 tx_flags;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 
-	rate = iwl_rates[rate_index].plcp;
+	rate = iwl3945_rates[rate_index].plcp;
 	tx_flags = cmd->cmd.tx.tx_flags;
 
 	/* We need to figure out how to get the sta->supp_rates while
@@ -612,7 +626,8 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	priv->stations[sta_id].current_rate.rate_n_flags = rate;
 
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-	    (sta_id != IWL_BROADCAST_ID) && (sta_id != IWL_MULTICAST_ID))
+	    (sta_id != IWL3945_BROADCAST_ID) &&
+		(sta_id != IWL_MULTICAST_ID))
 		priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -632,8 +647,8 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	if (priv->data_retry_limit != -1)
 		data_retry_limit = priv->data_retry_limit;
 
-	if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) {
-		switch (WLAN_FC_GET_STYPE(fc)) {
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_AUTH:
 		case IEEE80211_STYPE_DEAUTH:
 		case IEEE80211_STYPE_ASSOC_REQ:
@@ -654,41 +669,49 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	cmd->cmd.tx.tx_flags = tx_flags;
 
 	/* OFDM */
-	cmd->cmd.tx.supp_rates[0] = rate_mask & IWL_OFDM_RATES_MASK;
+	cmd->cmd.tx.supp_rates[0] =
+	   ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
 
 	/* CCK */
-	cmd->cmd.tx.supp_rates[1] = (rate_mask >> 8) & 0xF;
+	cmd->cmd.tx.supp_rates[1] = (rate_mask & 0xF);
 
-	IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: " BIT_FMT16 " "
-		       "cck/ofdm mask: 0x%x/0x%x\n",
-		       sta_id,
-		       cmd->cmd.tx.rate,
-		       BIT_ARG16(cmd->cmd.tx.tx_flags),
+	IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
+		       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
+		       cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags),
 		       cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
 }
 
-void iwl_hw_card_show_info(struct iwl_priv *priv)
+u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id, u16 tx_rate, u8 flags)
 {
-	IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n",
-		       ((priv->eeprom.board_revision >> 8) & 0x0F),
-		       ((priv->eeprom.board_revision >> 8) >> 4),
-		       (priv->eeprom.board_revision & 0x00FF));
+	unsigned long flags_spin;
+	struct iwl3945_station_entry *station;
+
+	if (sta_id == IWL_INVALID_STATION)
+		return IWL_INVALID_STATION;
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	station = &priv->stations[sta_id];
 
-	IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n",
-		       (int)sizeof(priv->eeprom.board_pba_number),
-		       priv->eeprom.board_pba_number);
+	station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
+	station->sta.rate_n_flags = cpu_to_le16(tx_rate);
+	station->current_rate.rate_n_flags = tx_rate;
+	station->sta.mode = STA_CONTROL_MODIFY_MSK;
 
-	IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n",
-		       priv->eeprom.antenna_switch_type);
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+	iwl3945_send_add_station(priv, &station->sta, flags);
+	IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
+			sta_id, tx_rate);
+	return sta_id;
 }
 
-static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+static int iwl3945_nic_set_pwr_src(struct iwl3945_priv *priv, int pwr_max)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
@@ -696,28 +719,27 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
 
 	if (!pwr_max) {
 		u32 val;
-		rc = pci_read_config_dword(priv->pci_dev, 0x0C8, &val);
+
+		rc = pci_read_config_dword(priv->pci_dev,
+				PCI_POWER_SOURCE, &val);
 		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
-			iwl_set_bits_mask_restricted_reg(
-				priv, ALM_APMG_PS_CTL,
-				APMG_PS_CTRL_REG_VAL_POWER_SRC_VAUX,
-				~APMG_PS_CTRL_REG_MSK_POWER_SRC);
-			iwl_release_restricted_access(priv);
+			iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+					~APMG_PS_CTRL_MSK_PWR_SRC);
+			iwl3945_release_nic_access(priv);
 
-			iwl_poll_bit(priv, CSR_GPIO_IN,
+			iwl3945_poll_bit(priv, CSR_GPIO_IN,
 				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
 				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
 		} else
-			iwl_release_restricted_access(priv);
-
+			iwl3945_release_nic_access(priv);
 	} else {
-		iwl_set_bits_mask_restricted_reg(
-			priv, ALM_APMG_PS_CTL,
-			APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN,
-			~APMG_PS_CTRL_REG_MSK_POWER_SRC);
+		iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+				~APMG_PS_CTRL_MSK_PWR_SRC);
 
-		iwl_release_restricted_access(priv);
-		iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+		iwl3945_release_nic_access(priv);
+		iwl3945_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
 			     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -725,76 +747,72 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
 	return rc;
 }
 
-static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static int iwl3945_rx_init(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
-	iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0),
+	iwl3945_write_direct32(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
+	iwl3945_write_direct32(priv, FH_RCSR_RPTR_ADDR(0),
 			     priv->hw_setting.shared_phys +
-			     offsetof(struct iwl_shared, rx_read_ptr[0]));
-	iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0);
-	iwl_write_restricted(
-		priv, FH_RCSR_CONFIG(0),
+			     offsetof(struct iwl3945_shared, rx_read_ptr[0]));
+	iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), 0);
+	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0),
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
 		ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
-		(RX_QUEUE_SIZE_LOG <<
-		 ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
+		(RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
 		(1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
 
 	/* fake read to flush all prev I/O */
-	iwl_read_restricted(priv, FH_RSSR_CTRL);
-
-	iwl_release_restricted_access(priv);
+	iwl3945_read_direct32(priv, FH_RSSR_CTRL);
 
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-static int iwl3945_tx_reset(struct iwl_priv *priv)
+static int iwl3945_tx_reset(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
 	/* bypass mode */
-	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2);
+	iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
 
 	/* RA 0 is active */
-	iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01);
+	iwl3945_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01);
 
 	/* all 6 fifo are active */
-	iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f);
+	iwl3945_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f);
 
-	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000);
-	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002);
-	iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004);
-	iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005);
+	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
+	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
+	iwl3945_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004);
+	iwl3945_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
 
-	iwl_write_restricted(priv, FH_TSSR_CBB_BASE,
+	iwl3945_write_direct32(priv, FH_TSSR_CBB_BASE,
 			     priv->hw_setting.shared_phys);
 
-	iwl_write_restricted(
-		priv, FH_TSSR_MSG_CONFIG,
+	iwl3945_write_direct32(priv, FH_TSSR_MSG_CONFIG,
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
@@ -803,8 +821,7 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
 
-	iwl_release_restricted_access(priv);
-
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -815,12 +832,12 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
  *
  * Destroys all DMA structures and initialize them again
  */
-static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
+static int iwl3945_txq_ctx_reset(struct iwl3945_priv *priv)
 {
 	int rc;
-	int i, num_slots;
+	int txq_id, slots_num;
 
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 
 	/* Tx CMD queue */
 	rc = iwl3945_tx_reset(priv);
@@ -828,13 +845,13 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 		goto error;
 
 	/* Tx queue(s) */
-	for (i = 0; i < TFD_QUEUE_MAX; i++) {
-		num_slots =
-		    (i == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS :
-			TFD_TX_CMD_SLOTS;
-		rc = iwl_tx_queue_init(priv, &priv->txq[i], num_slots, i);
+	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
+		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+				TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		rc = iwl3945_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+				txq_id);
 		if (rc) {
-			IWL_ERROR("Tx %d queue init failed\n", i);
+			IWL_ERROR("Tx %d queue init failed\n", txq_id);
 			goto error;
 		}
 	}
@@ -842,26 +859,26 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 	return rc;
 
  error:
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 	return rc;
 }
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
+int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
 {
 	u8 rev_id;
 	int rc;
 	unsigned long flags;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 
-	iwl_power_init_handle(priv);
+	iwl3945_power_init_handle(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
-	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+	iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (rc < 0) {
@@ -870,18 +887,18 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		return rc;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN,
-				 APMG_CLK_REG_VAL_DMA_CLK_RQT |
-				 APMG_CLK_REG_VAL_BSM_CLK_RQT);
+	iwl3945_write_prph(priv, APMG_CLK_EN_REG,
+				 APMG_CLK_VAL_DMA_CLK_RQT |
+				 APMG_CLK_VAL_BSM_CLK_RQT);
 	udelay(20);
-	iwl_set_bits_restricted_reg(priv, ALM_APMG_PCIDEV_STT,
-				    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
-	iwl_release_restricted_access(priv);
+	iwl3945_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Determine HW type */
@@ -897,51 +914,50 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		IWL_DEBUG_INFO("RTP type \n");
 	else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
 		IWL_DEBUG_INFO("ALM-MB type\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
 	} else {
 		IWL_DEBUG_INFO("ALM-MM type\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Initialize the EEPROM */
-	rc = iwl_eeprom_init(priv);
+	rc = iwl3945_eeprom_init(priv);
 	if (rc)
 		return rc;
 
 	spin_lock_irqsave(&priv->lock, flags);
 	if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
 		IWL_DEBUG_INFO("SKU OP mode is mrc\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
-	} else {
+	} else
 		IWL_DEBUG_INFO("SKU OP mode is basic\n");
-	}
 
 	if ((priv->eeprom.board_revision & 0xF0) == 0xD0) {
 		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
 			       priv->eeprom.board_revision);
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
 	} else {
 		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
 			       priv->eeprom.board_revision);
-		iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
 			      CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
 	}
 
 	if (priv->eeprom.almgor_m_version <= 1) {
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
 		IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
 			       priv->eeprom.almgor_m_version);
 	} else {
 		IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
 			       priv->eeprom.almgor_m_version);
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -954,33 +970,32 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
-		rc = iwl_rx_queue_alloc(priv);
+		rc = iwl3945_rx_queue_alloc(priv);
 		if (rc) {
 			IWL_ERROR("Unable to initialize Rx queue\n");
 			return -ENOMEM;
 		}
 	} else
-		iwl_rx_queue_reset(priv, rxq);
+		iwl3945_rx_queue_reset(priv, rxq);
 
-	iwl_rx_replenish(priv, 1);
+	iwl3945_rx_replenish(priv);
 
 	iwl3945_rx_init(priv, rxq);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-/*
- * Look at using this instead :::
+	/* Look at using this instead:
 	rxq->need_update = 1;
-	iwl_rx_queue_update_write_ptr(priv, rxq);
-*/
+	iwl3945_rx_queue_update_write_ptr(priv, rxq);
+	*/
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
-	iwl_release_restricted_access(priv);
+	iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
+	iwl3945_release_nic_access(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -988,55 +1003,55 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 	if (rc)
 		return rc;
 
-	priv->status |= STATUS_INIT;
+	set_bit(STATUS_INIT, &priv->status);
 
 	return 0;
 }
 
 /**
- * iwl_hw_txq_ctx_free - Free TXQ Context
+ * iwl3945_hw_txq_ctx_free - Free TXQ Context
  *
  * Destroy all TX DMA queues and structures
  */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv)
 {
 	int txq_id;
 
 	/* Tx queues */
 	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
-		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+		iwl3945_tx_queue_free(priv, &priv->txq[txq_id]);
 }
 
-void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv)
 {
 	int queue;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_grab_restricted_access(priv)) {
+	if (iwl3945_grab_nic_access(priv)) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		iwl_hw_txq_ctx_free(priv);
+		iwl3945_hw_txq_ctx_free(priv);
 		return;
 	}
 
 	/* stop SCD */
-	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0);
+	iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0);
 
 	/* reset TFD queues */
 	for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) {
-		iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0);
-		iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS,
-					ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
-					(queue), 1000);
+		iwl3945_write_direct32(priv, FH_TCSR_CONFIG(queue), 0x0);
+		iwl3945_poll_direct_bit(priv, FH_TSSR_TX_STATUS,
+				ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue),
+				1000);
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 }
 
-int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv)
 {
 	int rc = 0;
 	u32 reg_val;
@@ -1045,17 +1060,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* set stop master bit */
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+	reg_val = iwl3945_read32(priv, CSR_GP_CNTRL);
 
 	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
-	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) {
-		IWL_DEBUG_INFO
-		    ("Card in power save, master is already stopped\n");
-	} else {
-		rc = iwl_poll_bit(priv,
-				  CSR_RESET,
+	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+		IWL_DEBUG_INFO("Card in power save, master is already "
+			       "stopped\n");
+	else {
+		rc = iwl3945_poll_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 		if (rc < 0) {
@@ -1070,52 +1084,51 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	return rc;
 }
 
-int iwl_hw_nic_reset(struct iwl_priv *priv)
+int iwl3945_hw_nic_reset(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
-	iwl_hw_nic_stop_master(priv);
+	iwl3945_hw_nic_stop_master(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
-		iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
-					 APMG_CLK_REG_VAL_BSM_CLK_RQT);
+	rc = iwl3945_grab_nic_access(priv);
+	if (!rc) {
+		iwl3945_write_prph(priv, APMG_CLK_CTRL_REG,
+					 APMG_CLK_VAL_BSM_CLK_RQT);
 
 		udelay(10);
 
-		iwl_set_bit(priv, CSR_GP_CNTRL,
+		iwl3945_set_bit(priv, CSR_GP_CNTRL,
 			    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-		iwl_write_restricted_reg(priv, ALM_APMG_LARC_INT_MSK, 0x0);
-		iwl_write_restricted_reg(priv, ALM_APMG_LARC_INT, 0xFFFFFFFF);
+		iwl3945_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
+		iwl3945_write_prph(priv, APMG_RTC_INT_STT_REG,
+					0xFFFFFFFF);
 
 		/* enable DMA */
-		iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN,
-					 APMG_CLK_REG_VAL_DMA_CLK_RQT |
-					 APMG_CLK_REG_VAL_BSM_CLK_RQT);
+		iwl3945_write_prph(priv, APMG_CLK_EN_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT |
+					 APMG_CLK_VAL_BSM_CLK_RQT);
 		udelay(10);
 
-		iwl_set_bits_restricted_reg(
-			priv, ALM_APMG_PS_CTL,
-			APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ);
+		iwl3945_set_bits_prph(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_RESET_REQ);
 		udelay(5);
-		iwl_clear_bits_restricted_reg(
-			priv, ALM_APMG_PS_CTL,
-			APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ);
-		iwl_release_restricted_access(priv);
+		iwl3945_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_RESET_REQ);
+		iwl3945_release_nic_access(priv);
 	}
 
 	/* Clear the 'host command active' bit... */
-	priv->status &= ~STATUS_HCMD_ACTIVE;
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
 	wake_up_interruptible(&priv->wait_command_queue);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -1124,48 +1137,49 @@ int iwl_hw_nic_reset(struct iwl_priv *priv)
 }
 
 /**
- * reg_adjust_power_by_temp - return index delta into power gain settings table
- */
-static int reg_adjust_power_by_temp(int new_reading, int old_reading)
+ * iwl3945_hw_reg_adjust_power_by_temp
+ * return index delta into power gain settings table
+*/
+static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
 {
 	return (new_reading - old_reading) * (-11) / 100;
 }
 
 /**
- * reg_temp_out_of_range - Keep temperature in sane range
+ * iwl3945_hw_reg_temp_out_of_range - Keep temperature in sane range
  */
-static inline int reg_temp_out_of_range(int temperature)
+static inline int iwl3945_hw_reg_temp_out_of_range(int temperature)
 {
 	return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
 }
 
-int iwl_hw_get_temperature(struct iwl_priv *priv)
+int iwl3945_hw_get_temperature(struct iwl3945_priv *priv)
 {
-	return iwl_read32(priv, CSR_UCODE_DRV_GP2);
+	return iwl3945_read32(priv, CSR_UCODE_DRV_GP2);
 }
 
 /**
- * reg_txpower_get_temperature - get current temperature by reading from NIC
- */
-static int reg_txpower_get_temperature(struct iwl_priv *priv)
+ * iwl3945_hw_reg_txpower_get_temperature
+ * get the current temperature by reading from NIC
+*/
+static int iwl3945_hw_reg_txpower_get_temperature(struct iwl3945_priv *priv)
 {
 	int temperature;
 
-	temperature = iwl_hw_get_temperature(priv);
+	temperature = iwl3945_hw_get_temperature(priv);
 
 	/* driver's okay range is -260 to +25.
 	 *   human readable okay range is 0 to +285 */
 	IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT);
 
 	/* handle insane temp reading */
-	if (reg_temp_out_of_range(temperature)) {
+	if (iwl3945_hw_reg_temp_out_of_range(temperature)) {
 		IWL_ERROR("Error bad temperature value  %d\n", temperature);
 
 		/* if really really hot(?),
 		 *   substitute the 3rd band/group's temp measured at factory */
 		if (priv->last_temperature > 100)
-			temperature =
-				(s16)le16_to_cpu(priv->eeprom.groups[2].temperature);
+			temperature = priv->eeprom.groups[2].temperature;
 		else /* else use most recent "sane" value from driver */
 			temperature = priv->last_temperature;
 	}
@@ -1184,11 +1198,11 @@ static int reg_txpower_get_temperature(struct iwl_priv *priv)
  * records new temperature in tx_mgr->temperature.
  * replaces tx_mgr->last_temperature *only* if calib needed
  *    (assumes caller will actually do the calibration!). */
-static int is_temp_calib_needed(struct iwl_priv *priv)
+static int is_temp_calib_needed(struct iwl3945_priv *priv)
 {
 	int temp_diff;
 
-	priv->temperature = reg_txpower_get_temperature(priv);
+	priv->temperature = iwl3945_hw_reg_txpower_get_temperature(priv);
 	temp_diff = priv->temperature - priv->last_temperature;
 
 	/* get absolute value */
@@ -1220,7 +1234,7 @@ static int is_temp_calib_needed(struct iwl_priv *priv)
 
 /* radio and DSP power table, each step is 1/2 dB.
  * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
-static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
+static struct iwl3945_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
 	{
 	 {251, 127},		/* 2.4 GHz, highest power */
 	 {251, 127},
@@ -1299,7 +1313,7 @@ static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
 	 {3, 113},
 	 {3, 106},
 	 {3, 102},
-	 {3, 95}},		/* 2.4 GHz, lowest power */
+	 {3, 95} },		/* 2.4 GHz, lowest power */
 	{
 	 {251, 127},		/* 5.x GHz, highest power */
 	 {251, 120},
@@ -1378,10 +1392,10 @@ static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
 	 {35, 113},
 	 {35, 107},
 	 {35, 99},
-	 {3, 120}}		/* 5.x GHz, lowest power */
+	 {3, 120} }		/* 5.x GHz, lowest power */
 };
 
-static inline u8 reg_fix_power_index(int index)
+static inline u8 iwl3945_hw_reg_fix_power_index(int index)
 {
 	if (index < 0)
 		return 0;
@@ -1394,17 +1408,17 @@ static inline u8 reg_fix_power_index(int index)
 #define REG_RECALIB_PERIOD (60)
 
 /**
- * reg_set_scan_power - Set Tx power for scan probe requests
+ * iwl3945_hw_reg_set_scan_power - Set Tx power for scan probe requests
  *
  * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
  * or 6 Mbit (OFDM) rates.
  */
-static void reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
-			       s32 rate_index, const s8 * clip_pwrs,
-			       struct iwl_channel_info *ch_info,
+static void iwl3945_hw_reg_set_scan_power(struct iwl3945_priv *priv, u32 scan_tbl_index,
+			       s32 rate_index, const s8 *clip_pwrs,
+			       struct iwl3945_channel_info *ch_info,
 			       int band_index)
 {
-	struct iwl_scan_power_info *scan_power_info;
+	struct iwl3945_scan_power_info *scan_power_info;
 	s8 power;
 	u8 power_index;
 
@@ -1413,7 +1427,7 @@ static void reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 	/* use this channel group's 6Mbit clipping/saturation pwr,
 	 *   but cap at regulatory scan power restriction (set during init
 	 *   based on eeprom channel data) for this channel.  */
-	power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX]);
+	power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX_TABLE]);
 
 	/* further limit to user's max power preference.
 	 * FIXME:  Other spectrum management power limitations do not
@@ -1428,12 +1442,7 @@ static void reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 	 *   *index*. */
 	power_index = ch_info->power_info[rate_index].power_table_index
 	    - (power - ch_info->power_info
-	       [IWL_RATE_6M_INDEX].requested_power) * 2;
-
-#if 0
-	IWL_DEBUG_POWER("chnl %d scan power index %d\n",
-			ch_info->channel, power_index);
-#endif
+	       [IWL_RATE_6M_INDEX_TABLE].requested_power) * 2;
 
 	/* store reference index that we use when adjusting *all* scan
 	 *   powers.  So we can accommodate user (all channel) or spectrum
@@ -1445,7 +1454,7 @@ static void reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 	 *   of the table. */
 
 	/* don't exceed table bounds for "real" setting */
-	power_index = reg_fix_power_index(power_index);
+	power_index = iwl3945_hw_reg_fix_power_index(power_index);
 
 	scan_power_info->power_table_index = power_index;
 	scan_power_info->tpc.tx_gain =
@@ -1455,21 +1464,21 @@ static void reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 }
 
 /**
- * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings
+ * iwl3945_hw_reg_send_txpower - fill in Tx Power command with gain settings
  *
  * Configures power settings for all rates for the current channel,
  * using values from channel info struct, and send to NIC
  */
-int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv)
 {
-	int rate_idx;
-	const struct iwl_channel_info *ch_info = NULL;
-	struct iwl_txpowertable_cmd txpower = {
+	int rate_idx, i;
+	const struct iwl3945_channel_info *ch_info = NULL;
+	struct iwl3945_txpowertable_cmd txpower = {
 		.channel = priv->active_rxon.channel,
 	};
 
 	txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
-	ch_info = iwl_get_channel_info(priv,
+	ch_info = iwl3945_get_channel_info(priv,
 				       priv->phymode,
 				       le16_to_cpu(priv->active_rxon.channel));
 	if (!ch_info) {
@@ -1486,25 +1495,41 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	}
 
 	/* fill cmd with power settings for all rates for current channel */
-	for (rate_idx = 0; rate_idx < IWL_RATE_COUNT; rate_idx++) {
-		txpower.power[rate_idx].tpc = ch_info->power_info[rate_idx].tpc;
-		txpower.power[rate_idx].rate = iwl_rates[rate_idx].plcp;
+	/* Fill OFDM rate */
+	for (rate_idx = IWL_FIRST_OFDM_RATE, i = 0;
+	     rate_idx <= IWL_LAST_OFDM_RATE; rate_idx++, i++) {
+
+		txpower.power[i].tpc = ch_info->power_info[i].tpc;
+		txpower.power[i].rate = iwl3945_rates[rate_idx].plcp;
+
+		IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
+				le16_to_cpu(txpower.channel),
+				txpower.band,
+				txpower.power[i].tpc.tx_gain,
+				txpower.power[i].tpc.dsp_atten,
+				txpower.power[i].rate);
+	}
+	/* Fill CCK rates */
+	for (rate_idx = IWL_FIRST_CCK_RATE;
+	     rate_idx <= IWL_LAST_CCK_RATE; rate_idx++, i++) {
+		txpower.power[i].tpc = ch_info->power_info[i].tpc;
+		txpower.power[i].rate = iwl3945_rates[rate_idx].plcp;
 
 		IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
 				le16_to_cpu(txpower.channel),
 				txpower.band,
-				txpower.power[rate_idx].tpc.tx_gain,
-				txpower.power[rate_idx].tpc.dsp_atten,
-				txpower.power[rate_idx].rate);
+				txpower.power[i].tpc.tx_gain,
+				txpower.power[i].tpc.dsp_atten,
+				txpower.power[i].rate);
 	}
 
-	return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
-				sizeof(struct iwl_txpowertable_cmd), &txpower);
+	return iwl3945_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
+			sizeof(struct iwl3945_txpowertable_cmd), &txpower);
 
 }
 
 /**
- * reg_set_new_power - Configures power tables at new levels
+ * iwl3945_hw_reg_set_new_power - Configures power tables at new levels
  * @ch_info: Channel to update.  Uses power_info.requested_power.
  *
  * Replace requested_power and base_power_index ch_info fields for
@@ -1515,14 +1540,14 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
  *
  * This does *not* send anything to NIC, just sets up ch_info for one channel.
  *
- * NOTE:reg_compensate_for_temperature_dif() *must* be run after this to
- *	properly fill out the scan powers, and actual h/w gain settings,
- *	and send changes to NIC
+ * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to
+ *	 properly fill out the scan powers, and actual h/w gain settings,
+ *	 and send changes to NIC
  */
-static int reg_set_new_power(struct iwl_priv *priv,
-			     struct iwl_channel_info *ch_info)
+static int iwl3945_hw_reg_set_new_power(struct iwl3945_priv *priv,
+			     struct iwl3945_channel_info *ch_info)
 {
-	struct iwl_channel_power_info *power_info;
+	struct iwl3945_channel_power_info *power_info;
 	int power_changed = 0;
 	int i;
 	const s8 *clip_pwrs;
@@ -1535,7 +1560,7 @@ static int reg_set_new_power(struct iwl_priv *priv,
 	power_info = ch_info->power_info;
 
 	/* update OFDM Txpower settings */
-	for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE;
+	for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE;
 	     i++, ++power_info) {
 		int delta_idx;
 
@@ -1559,14 +1584,14 @@ static int reg_set_new_power(struct iwl_priv *priv,
 	 *    ... all CCK power settings for a given channel are the *same*. */
 	if (power_changed) {
 		power =
-		    ch_info->power_info[IWL_RATE_12M_INDEX].
+		    ch_info->power_info[IWL_RATE_12M_INDEX_TABLE].
 		    requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF;
 
-		/* do all CCK rates' iwl_channel_power_info structures */
-		for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) {
+		/* do all CCK rates' iwl3945_channel_power_info structures */
+		for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) {
 			power_info->requested_power = power;
 			power_info->base_power_index =
-			    ch_info->power_info[IWL_RATE_12M_INDEX].
+			    ch_info->power_info[IWL_RATE_12M_INDEX_TABLE].
 			    base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF;
 			++power_info;
 		}
@@ -1576,12 +1601,13 @@ static int reg_set_new_power(struct iwl_priv *priv,
 }
 
 /**
- * reg_get_channel_txpower_limit - returns new power limit for channel
+ * iwl3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel
  *
- * NOTE:  Returned power limit may be less (but not more) than requested,
- *   based strictly on regulatory (eeprom and spectrum mgt) limitations
- *   (no consideration for h/w clipping limitations). */
-static int reg_get_channel_txpower_limit(struct iwl_channel_info *ch_info)
+ * NOTE: Returned power limit may be less (but not more) than requested,
+ *	 based strictly on regulatory (eeprom and spectrum mgt) limitations
+ *	 (no consideration for h/w clipping limitations).
+ */
+static int iwl3945_hw_reg_get_ch_txpower_limit(struct iwl3945_channel_info *ch_info)
 {
 	s8 max_power;
 
@@ -1595,11 +1621,12 @@ static int reg_get_channel_txpower_limit(struct iwl_channel_info *ch_info)
 	else
 #endif
 		max_power = ch_info->eeprom.max_power_avg;
+
 	return min(max_power, ch_info->max_power_avg);
 }
 
 /**
- * reg_txpower_compensate_for_temperature_dif - Compensate for temperature
+ * iwl3945_hw_reg_comp_txpower_temp - Compensate for temperature
  *
  * Compensate txpower settings of *all* channels for temperature.
  * This only accounts for the difference between current temperature
@@ -1608,9 +1635,9 @@ static int reg_get_channel_txpower_limit(struct iwl_channel_info *ch_info)
  *
  * If RxOn is "associated", this sends the new Txpower to NIC!
  */
-static int reg_txpower_compensate_for_temperature_dif(struct iwl_priv *priv)
+static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv)
 {
-	struct iwl_channel_info *ch_info = NULL;
+	struct iwl3945_channel_info *ch_info = NULL;
 	int delta_index;
 	const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
 	u8 a_band;
@@ -1631,7 +1658,8 @@ static int reg_txpower_compensate_for_temperature_dif(struct iwl_priv *priv)
 
 		/* get power index adjustment based on curr and factory
 		 * temps */
-		delta_index = reg_adjust_power_by_temp(temperature, ref_temp);
+		delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
+							      ref_temp);
 
 		/* set tx power value for all rates, OFDM and CCK */
 		for (rate_index = 0; rate_index < IWL_RATE_COUNT;
@@ -1643,7 +1671,7 @@ static int reg_txpower_compensate_for_temperature_dif(struct iwl_priv *priv)
 			power_idx += delta_index;
 
 			/* stay within table range */
-			power_idx = reg_fix_power_index(power_idx);
+			power_idx = iwl3945_hw_reg_fix_power_index(power_idx);
 			ch_info->power_info[rate_index].
 			    power_table_index = (u8) power_idx;
 			ch_info->power_info[rate_index].tpc =
@@ -1657,22 +1685,21 @@ static int reg_txpower_compensate_for_temperature_dif(struct iwl_priv *priv)
 		for (scan_tbl_index = 0;
 		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
 			s32 actual_index = (scan_tbl_index == 0) ?
-			    IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
-			reg_set_scan_power(priv, scan_tbl_index,
+			    IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
+			iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index,
 					   actual_index, clip_pwrs,
 					   ch_info, a_band);
 		}
 	}
 
 	/* send Txpower command for current channel to ucode */
-	return iwl_hw_reg_send_txpower(priv);
+	return iwl3945_hw_reg_send_txpower(priv);
 }
 
-int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power)
 {
-	struct iwl_channel_info *ch_info;
+	struct iwl3945_channel_info *ch_info;
 	s8 max_power;
-	u8 channel;
 	u8 a_band;
 	u8 i;
 
@@ -1690,28 +1717,33 @@ int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
 	for (i = 0; i < priv->channel_count; i++) {
 		ch_info = &priv->channel_info[i];
 		a_band = is_channel_a_band(ch_info);
-		channel = ch_info->channel;
 
 		/* find minimum power of all user and regulatory constraints
 		 *    (does not consider h/w clipping limitations) */
-		max_power = reg_get_channel_txpower_limit(ch_info);
+		max_power = iwl3945_hw_reg_get_ch_txpower_limit(ch_info);
 		max_power = min(power, max_power);
 		if (max_power != ch_info->curr_txpow) {
 			ch_info->curr_txpow = max_power;
 
 			/* this considers the h/w clipping limitations */
-			reg_set_new_power(priv, ch_info);
+			iwl3945_hw_reg_set_new_power(priv, ch_info);
 		}
 	}
 
 	/* update txpower settings for all channels,
 	 *   send to NIC if associated. */
 	is_temp_calib_needed(priv);
-	reg_txpower_compensate_for_temperature_dif(priv);
+	iwl3945_hw_reg_comp_txpower_temp(priv);
 
 	return 0;
 }
 
+/* will add 3945 channel switch cmd handling later */
+int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel)
+{
+	return 0;
+}
+
 /**
  * iwl3945_reg_txpower_periodic -  called when time to check our temperature.
  *
@@ -1722,28 +1754,28 @@ int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
  *     -- send new set of gain settings to NIC
  * NOTE:  This should continue working, even when we're not associated,
  *   so we can keep our internal table of scan powers current. */
-void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
+void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv)
 {
 	/* This will kick in the "brute force"
-	 *   reg_txpower_compensate_for_temperature_dif() below */
+	 * iwl3945_hw_reg_comp_txpower_temp() below */
 	if (!is_temp_calib_needed(priv))
 		goto reschedule;
 
 	/* Set up a new set of temp-adjusted TxPowers, send to NIC.
 	 * This is based *only* on current temperature,
 	 * ignoring any previous power measurements */
-	reg_txpower_compensate_for_temperature_dif(priv);
+	iwl3945_hw_reg_comp_txpower_temp(priv);
 
  reschedule:
 	queue_delayed_work(priv->workqueue,
 			   &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
 }
 
-void iwl3945_bg_reg_txpower_periodic(void *p)
+static void iwl3945_bg_reg_txpower_periodic(void *p)
 {
-	struct iwl_priv *priv = p;
+	struct iwl3945_priv *priv = p;
 
-	if (priv->status & STATUS_EXIT_PENDING)
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
@@ -1751,17 +1783,21 @@ void iwl3945_bg_reg_txpower_periodic(void *p)
 	mutex_unlock(&priv->mutex);
 }
 
-/* reg_get_chnl_grp_index - find the channel-group index (0-4) for the channel.
+/**
+ * iwl3945_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
+ * 				   for the channel.
+ *
+ * This function is used when initializing channel-info structs.
  *
- *  ... used when initializing channel-info structs.
- * NOTE:  These channel groups do *NOT* match the bands above!
- *   These channel groups are based on factory-tested channels;
- *   on A-band, EEPROM's "group frequency" entries represent the top channel
- *   in each group 1-4.  Group 5 All B/G channels are in group 0.  */
-static u16 reg_get_chnl_grp_index(struct iwl_priv *priv,
-				  const struct iwl_channel_info *ch_info)
+ * NOTE: These channel groups do *NOT* match the bands above!
+ *	 These channel groups are based on factory-tested channels;
+ *	 on A-band, EEPROM's "group frequency" entries represent the top
+ *	 channel in each group 1-4.  Group 5 All B/G channels are in group 0.
+ */
+static u16 iwl3945_hw_reg_get_ch_grp_index(struct iwl3945_priv *priv,
+				       const struct iwl3945_channel_info *ch_info)
 {
-	struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
+	struct iwl3945_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
 	u8 group;
 	u16 group_index = 0;	/* based on factory calib frequencies */
 	u8 grp_channel;
@@ -1787,20 +1823,20 @@ static u16 reg_get_chnl_grp_index(struct iwl_priv *priv,
 }
 
 /**
- * reg_get_matched_power_index - Interpolate to get nominal index
+ * iwl3945_hw_reg_get_matched_power_index - Interpolate to get nominal index
  *
  * Interpolate to get nominal (i.e. at factory calibration temperature) index
  *   into radio/DSP gain settings table for requested power.
  */
-static int reg_get_matched_power_index(struct iwl_priv *priv,
+static int iwl3945_hw_reg_get_matched_power_index(struct iwl3945_priv *priv,
 				       s8 requested_power,
-				       s32 setting_index, s32 * new_index)
+				       s32 setting_index, s32 *new_index)
 {
-	const struct iwl_eeprom_txpower_group *chnl_grp = NULL;
+	const struct iwl3945_eeprom_txpower_group *chnl_grp = NULL;
 	s32 index0, index1;
 	s32 power = 2 * requested_power;
 	s32 i;
-	const struct iwl_eeprom_txpower_sample *samples;
+	const struct iwl3945_eeprom_txpower_sample *samples;
 	s32 gains0, gains1;
 	s32 res;
 	s32 denominator;
@@ -1840,11 +1876,11 @@ static int reg_get_matched_power_index(struct iwl_priv *priv,
 	return 0;
 }
 
-static void reg_init_channel_groups(struct iwl_priv *priv)
+static void iwl3945_hw_reg_init_channel_groups(struct iwl3945_priv *priv)
 {
 	u32 i;
 	s32 rate_index;
-	const struct iwl_eeprom_txpower_group *group;
+	const struct iwl3945_eeprom_txpower_group *group;
 
 	IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n");
 
@@ -1879,19 +1915,19 @@ static void reg_init_channel_groups(struct iwl_priv *priv)
 		for (rate_index = 0;
 		     rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
 			switch (rate_index) {
-			case IWL_RATE_36M_INDEX:
+			case IWL_RATE_36M_INDEX_TABLE:
 				if (i == 0)	/* B/G */
 					*clip_pwrs = satur_pwr;
 				else	/* A */
 					*clip_pwrs = satur_pwr - 5;
 				break;
-			case IWL_RATE_48M_INDEX:
+			case IWL_RATE_48M_INDEX_TABLE:
 				if (i == 0)
 					*clip_pwrs = satur_pwr - 7;
 				else
 					*clip_pwrs = satur_pwr - 10;
 				break;
-			case IWL_RATE_54M_INDEX:
+			case IWL_RATE_54M_INDEX_TABLE:
 				if (i == 0)
 					*clip_pwrs = satur_pwr - 9;
 				else
@@ -1920,10 +1956,10 @@ static void reg_init_channel_groups(struct iwl_priv *priv)
  *
  * This does *not* write values to NIC, just sets up our internal table.
  */
-int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
+int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv)
 {
-	struct iwl_channel_info *ch_info = NULL;
-	struct iwl_channel_power_info *pwr_info;
+	struct iwl3945_channel_info *ch_info = NULL;
+	struct iwl3945_channel_power_info *pwr_info;
 	int delta_index;
 	u8 rate_index;
 	u8 scan_tbl_index;
@@ -1936,10 +1972,10 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 
 	/* save temperature reference,
 	 *   so we can determine next time to calibrate */
-	temperature = reg_txpower_get_temperature(priv);
+	temperature = iwl3945_hw_reg_txpower_get_temperature(priv);
 	priv->last_temperature = temperature;
 
-	reg_init_channel_groups(priv);
+	iwl3945_hw_reg_init_channel_groups(priv);
 
 	/* initialize Tx power info for each and every channel, 2.4 and 5.x */
 	for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
@@ -1949,17 +1985,17 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 			continue;
 
 		/* find this channel's channel group (*not* "band") index */
-		ch_info->group_index = reg_get_chnl_grp_index(priv, ch_info);
+		ch_info->group_index =
+			iwl3945_hw_reg_get_ch_grp_index(priv, ch_info);
 
 		/* Get this chnlgrp's rate->max/clip-powers table */
 		clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
 
 		/* calculate power index *adjustment* value according to
 		 *  diff between current temperature and factory temperature */
-		delta_index = reg_adjust_power_by_temp(
-			temperature,
-			(s16)le16_to_cpu(
-				priv->eeprom.groups[ch_info->group_index].temperature));
+		delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
+				priv->eeprom.groups[ch_info->group_index].
+				temperature);
 
 		IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n",
 				ch_info->channel, delta_index, temperature +
@@ -1980,7 +2016,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 
 			/* get base (i.e. at factory-measured temperature)
 			 *    power table index for this rate's power */
-			rc = reg_get_matched_power_index(priv, pwr,
+			rc = iwl3945_hw_reg_get_matched_power_index(priv, pwr,
 							 ch_info->group_index,
 							 &power_idx);
 			if (rc) {
@@ -1993,9 +2029,9 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 			power_idx += delta_index;
 
 			/* stay within range of gain table */
-			power_idx = reg_fix_power_index(power_idx);
+			power_idx = iwl3945_hw_reg_fix_power_index(power_idx);
 
-			/* fill 1 OFDM rate's iwl_channel_power_info struct */
+			/* fill 1 OFDM rate's iwl3945_channel_power_info struct */
 			pwr_info->requested_power = pwr;
 			pwr_info->power_table_index = (u8) power_idx;
 			pwr_info->tpc.tx_gain =
@@ -2005,25 +2041,25 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 		}
 
 		/* set tx power for CCK rates, based on OFDM 12 Mbit settings*/
-		pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX];
-		power = pwr_info->requested_power
-		    + IWL_CCK_FROM_OFDM_POWER_DIFF;
-		pwr_index = pwr_info->power_table_index
-		    + IWL_CCK_FROM_OFDM_INDEX_DIFF;
-		base_pwr_index = pwr_info->base_power_index
-		    + IWL_CCK_FROM_OFDM_INDEX_DIFF;
+		pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX_TABLE];
+		power = pwr_info->requested_power +
+			IWL_CCK_FROM_OFDM_POWER_DIFF;
+		pwr_index = pwr_info->power_table_index +
+			IWL_CCK_FROM_OFDM_INDEX_DIFF;
+		base_pwr_index = pwr_info->base_power_index +
+			IWL_CCK_FROM_OFDM_INDEX_DIFF;
 
 		/* stay within table range */
-		pwr_index = reg_fix_power_index(pwr_index);
+		pwr_index = iwl3945_hw_reg_fix_power_index(pwr_index);
 		gain = power_gain_table[a_band][pwr_index].tx_gain;
 		dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten;
 
-		/* fill each CCK rate's iwl_channel_power_info structure
+		/* fill each CCK rate's iwl3945_channel_power_info structure
 		 * NOTE:  All CCK-rate Txpwrs are the same for a given chnl!
 		 * NOTE:  CCK rates start at end of OFDM rates! */
-		for (rate_index = IWL_OFDM_RATES;
-		     rate_index < IWL_RATE_COUNT; rate_index++) {
-			pwr_info = &ch_info->power_info[rate_index];
+		for (rate_index = 0;
+		     rate_index < IWL_CCK_RATES; rate_index++) {
+			pwr_info = &ch_info->power_info[rate_index+IWL_OFDM_RATES];
 			pwr_info->requested_power = power;
 			pwr_info->power_table_index = pwr_index;
 			pwr_info->base_power_index = base_pwr_index;
@@ -2035,99 +2071,98 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 		for (scan_tbl_index = 0;
 		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
 			s32 actual_index = (scan_tbl_index == 0) ?
-			    IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
-			reg_set_scan_power(priv, scan_tbl_index,
-					   actual_index, clip_pwrs,
-					   ch_info, a_band);
+				IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
+			iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index,
+				actual_index, clip_pwrs, ch_info, a_band);
 		}
 	}
 
 	return 0;
 }
 
-int iwl_hw_rxq_stop(struct iwl_priv *priv)
+int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0);
-	rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0);
+	rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
 	if (rc < 0)
 		IWL_ERROR("Can't stop Rx DMA.\n");
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
 {
 	int rc;
 	unsigned long flags;
 	int txq_id = txq->q.id;
 
-	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+	struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt;
 
-	shared_data->tx_base_ptr[txq_id] = (u32) txq->q.dma_addr;
-
-	txq->q.element_size = sizeof(struct iwl_tfd_frame);
+	shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0);
-	iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0);
+	iwl3945_write_direct32(priv, FH_CBCC_CTRL(txq_id), 0);
+	iwl3945_write_direct32(priv, FH_CBCC_BASE(txq_id), 0);
 
-	iwl_write_restricted(
-		priv, FH_TCSR_CONFIG(txq_id),
+	iwl3945_write_direct32(priv, FH_TCSR_CONFIG(txq_id),
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	/* fake read to flush all prev. writes */
-	iwl_read32(priv, FH_TSSR_CBB_BASE);
-
+	iwl3945_read32(priv, FH_TSSR_CBB_BASE);
 	spin_unlock_irqrestore(&priv->lock, flags);
+
 	return 0;
 }
 
-int iwl_hw_get_rx_read(struct iwl_priv *priv)
+int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv)
 {
-	struct iwl_shared *shared_data =
-	    (struct iwl_shared *)priv->hw_setting.shared_virt;
+	struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt;
 
-	return shared_data->rx_read_ptr[0];
+	return le32_to_cpu(shared_data->rx_read_ptr[0]);
 }
 
 /**
  * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
  */
-int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
+int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv)
 {
-	int rc, i;
-	struct iwl_rate_scaling_cmd rate_cmd = {
+	int rc, i, index, prev_index;
+	struct iwl3945_rate_scaling_cmd rate_cmd = {
 		.reserved = {0, 0, 0},
 	};
-	struct iwl_rate_scaling_info *table = rate_cmd.table;
+	struct iwl3945_rate_scaling_info *table = rate_cmd.table;
+
+	for (i = 0; i < ARRAY_SIZE(iwl3945_rates); i++) {
+		index = iwl3945_rates[i].table_rs_index;
 
-	for (i = 0; i < GLOBAL_ARRAY_SIZE(iwl_rates); i++) {
-		table[i].rate_n_flags = iwl_rates[i].plcp;
-		table[i].try_cnt = priv->retry_rate;
-		table[i].next_rate_index = iwl_get_prev_ieee_rate(i);
+		table[index].rate_n_flags =
+			iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0);
+		table[index].try_cnt = priv->retry_rate;
+		prev_index = iwl3945_get_prev_ieee_rate(i);
+		table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index;
 	}
 
 	switch (priv->phymode) {
@@ -2135,26 +2170,26 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
 		IWL_DEBUG_RATE("Select A mode rate scale\n");
 		/* If one of the following CCK rates is used,
 		 * have it fall back to the 6M OFDM rate */
-		for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++)
-			table[i].next_rate_index = IWL_FIRST_OFDM_RATE;
+		for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++)
+			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
 
 		/* Don't fall back to CCK rates */
-		table[IWL_RATE_12M_INDEX].next_rate_index = IWL_RATE_9M_INDEX;
+		table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE;
 
 		/* Don't drop out of OFDM rates */
-		table[IWL_FIRST_OFDM_RATE].next_rate_index =
-		    IWL_FIRST_OFDM_RATE;
+		table[IWL_RATE_6M_INDEX_TABLE].next_rate_index =
+		    iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
 		break;
 
 	case MODE_IEEE80211B:
 		IWL_DEBUG_RATE("Select B mode rate scale\n");
 		/* If an OFDM rate is used, have it fall back to the
 		 * 1M CCK rates */
-		for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; i++)
-			table[i].next_rate_index = IWL_FIRST_CCK_RATE;
+		for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
+			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index;
 
 		/* CCK shouldn't fall back to OFDM... */
-		table[IWL_RATE_11M_INDEX].next_rate_index = IWL_RATE_5M_INDEX;
+		table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
 		break;
 
 	default:
@@ -2164,25 +2199,26 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
 
 	/* Update the rate scaling for control frame Tx */
 	rate_cmd.table_id = 0;
-	rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
 			      &rate_cmd);
 	if (rc)
 		return rc;
 
 	/* Update the rate scaling for data frame Tx */
 	rate_cmd.table_id = 1;
-	return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+	return iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
 				&rate_cmd);
 }
 
-int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+/* Called when initializing driver */
+int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv)
 {
 	memset((void *)&priv->hw_setting, 0,
-	       sizeof(struct iwl_driver_hw_info));
+	       sizeof(struct iwl3945_driver_hw_info));
 
 	priv->hw_setting.shared_virt =
 	    pci_alloc_consistent(priv->pci_dev,
-				 sizeof(struct iwl_shared),
+				 sizeof(struct iwl3945_shared),
 				 &priv->hw_setting.shared_phys);
 
 	if (!priv->hw_setting.shared_virt) {
@@ -2192,77 +2228,84 @@ int iwl_hw_set_hw_setting(struct iwl_priv *priv)
 	}
 
 	priv->hw_setting.ac_queue_count = AC_NUM;
-	priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
-	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE;
+	priv->hw_setting.max_pkt_size = 2342;
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd);
 	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
 	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
-	priv->hw_setting.cck_flag = 0;
+	priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
+	priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
 	return 0;
 }
 
-int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-			  struct iwl_frame *frame, u16 rate)
+unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
+			  struct iwl3945_frame *frame, u8 rate)
 {
-	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
-	int frame_size;
+	struct iwl3945_tx_beacon_cmd *tx_beacon_cmd;
+	unsigned int frame_size;
 
-	tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u;
+	tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
 	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-	tx_beacon_cmd->tx.sta_id = IWL_BROADCAST_ID;
-	tx_beacon_cmd->tx.stop_time.life_time = 0xFFFFFFFF;
+	tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
-	frame_size = iwl_fill_beacon_frame(priv,
+	frame_size = iwl3945_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
-				BROADCAST_ADDR,
+				iwl3945_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
-	tx_beacon_cmd->tx.len = frame_size;
+	BUG_ON(frame_size > MAX_MPDU_SIZE);
+	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
 
 	tx_beacon_cmd->tx.rate = rate;
 	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
 				      TX_CMD_FLG_TSF_MSK);
 
-	/* supp_rates[0] == OFDM  */
-	tx_beacon_cmd->tx.supp_rates[0] = IWL_OFDM_BASIC_RATES_MASK;
-
-	/* supp_rates[1] == CCK
-	 *
-	 * NOTE:  IWL_*_RATES_MASK are not in the order that supp_rates
-	 * expects so we have to shift them around.
-	 *
-	 * supp_rates expects:
-	 * CCK rates are bit0..3
-	 *
-	 * However IWL_*_RATES_MASK has:
-	 * CCK rates are bit8..11
-	 */
+	/* supp_rates[0] == OFDM start at IWL_FIRST_OFDM_RATE*/
+	tx_beacon_cmd->tx.supp_rates[0] =
+		(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+
 	tx_beacon_cmd->tx.supp_rates[1] =
-		(IWL_CCK_BASIC_RATES_MASK >> 8) & 0xF;
+		(IWL_CCK_BASIC_RATES_MASK & 0xF);
 
-	return (sizeof(struct iwl_tx_beacon_cmd) + frame_size);
+	return (sizeof(struct iwl3945_tx_beacon_cmd) + frame_size);
 }
 
-void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv)
 {
 	priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
 }
 
-void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv)
 {
 	INIT_WORK(&priv->thermal_periodic,
-			  iwl3945_bg_reg_txpower_periodic, priv);
+		  iwl3945_bg_reg_txpower_periodic, priv);
 }
 
-void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv)
 {
 	cancel_delayed_work(&priv->thermal_periodic);
 }
 
-struct pci_device_id iwl_hw_card_ids[] = {
-	{0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+struct pci_device_id iwl3945_hw_card_ids[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)},
 	{0}
 };
 
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+/*
+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
+ * embedded controller) as EEPROM reader; each read is a series of pulses
+ * to/from the EEPROM chip, not a single event, so even reads could conflict
+ * if they weren't arbitrated by some ownership mechanism.  Here, the driver
+ * simply claims ownership, which should be safe when this function is called
+ * (i.e. before loading uCode!).
+ */
+inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
+{
+	_iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index f99a49b..5ac46c9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -23,33 +23,967 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-3945.h) for driver implementation definitions.
+ * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-3945-hw.h for hardware-related definitions.
+ */
 
 #ifndef __iwl_3945_h__
 #define __iwl_3945_h__
 
-#if IWL != 3945
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl3945_hw_card_ids[];
+
+#define DRV_NAME	"iwl3945"
+#include "iwl-3945-hw.h"
+#include "iwl-prph.h"
+#include "iwl-3945-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl3945_param_hwcrypto;
+extern int iwl3945_param_queues_num;
+
+enum iwl3945_antenna {
+	IWL_ANTENNA_DIVERSITY,
+	IWL_ANTENNA_MAIN,
+	IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define IWL_RX_BUF_SIZE           3000U
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl3945_rx_mem_buffer {
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+struct iwl3945_rt_rx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	__le64 rt_tsf;		/* TSF */
+	u8 rt_flags;		/* radiotap packet flags */
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channelMHz;	/* channel in MHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	s8 rt_dbmnoise;
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+struct iwl3945_rt_tx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channel;	/* channel in mHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl3945_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int write_ptr;       /* 1-st empty entry (index) host_w*/
+	int read_ptr;         /* last used entry (index) host_r*/
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	int low_mark;	       /* low watermark, resume queue if free
+				* space more than this */
+	int high_mark;         /* high watermark, stop queue if free
+				* space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+/* One for each TFD */
+struct iwl3945_tx_info {
+	struct ieee80211_tx_status status;
+	struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl3945_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @bd: base of circular buffer of TFDs
+ * @cmd: array of command/Tx buffers
+ * @dma_addr_cmd: physical address of cmd/tx buffer array
+ * @txb: array of per-TFD driver data
+ * @need_update: indicates need to update read/write index
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl3945_tx_queue {
+	struct iwl3945_queue q;
+	struct iwl3945_tfd_frame *bd;
+	struct iwl3945_cmd *cmd;
+	dma_addr_t dma_addr_cmd;
+	struct iwl3945_tx_info *txb;
+	int need_update;
+	int active;
+};
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl3945_channel_tgd_info {
+	u8 type;
+	s8 max_power;
+};
+
+struct iwl3945_channel_tgh_info {
+	s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl3945_channel_power_info {
+	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 base_power_index;	/* gain index for power at factory temp. */
+	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl3945_scan_power_info {
+	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
+};
+
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl3945_channel_info {
+	struct iwl3945_channel_tgd_info tgd;
+	struct iwl3945_channel_tgh_info tgh;
+	struct iwl3945_eeprom_channel eeprom;	/* EEPROM regulatory limit */
+	struct iwl3945_eeprom_channel fat_eeprom;	/* EEPROM regulatory limit for
+						 * FAT channel */
+
+	u8 channel;	  /* channel number */
+	u8 flags;	  /* flags copied from EEPROM */
+	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 min_power;	  /* always 0 */
+	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
+
+	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
+	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
+	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
+
+	/* Radio/DSP gain settings for each "normal" data Tx rate.
+	 * These include, in addition to RF and DSP gain, a few fields for
+	 *   remembering/modifying gain settings (indexes). */
+	struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE];
+
+	/* Radio/DSP gain settings for each scan rate, for directed scans. */
+	struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl3945_clip_group {
+	/* maximum power level to prevent clipping for each rate, derived by
+	 *   us from this band's saturation power in EEPROM */
+	const s8 clip_powers[IWL_MAX_RATES];
+};
+
+#include "iwl-3945-rs.h"
+
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
+
+/* Power management (not Tx power) structures */
+
+struct iwl3945_power_vec_entry {
+	struct iwl3945_powertable_cmd cmd;
+	u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0  (0)
+#define IWL_POWER_RANGE_1  (1)
+
+#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3	0x03
+#define IWL_POWER_INDEX_5	0x05
+#define IWL_POWER_AC		0x06
+#define IWL_POWER_BATTERY	0x07
+#define IWL_POWER_LIMIT		0x07
+#define IWL_POWER_MASK		0x0F
+#define IWL_POWER_ENABLED	0x10
+#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
+
+struct iwl3945_power_mgr {
+	spinlock_t lock;
+	struct iwl3945_power_vec_entry pwr_range_0[IWL_POWER_AC];
+	struct iwl3945_power_vec_entry pwr_range_1[IWL_POWER_AC];
+	u8 active_index;
+	u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl3945_frame {
+	union {
+		struct ieee80211_hdr frame;
+		struct iwl3945_tx_beacon_cmd beacon;
+		u8 raw[IEEE80211_FRAME_LEN];
+		u8 cmd[360];
+	} u;
+	struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+	/* CMD_SIZE_NORMAL = 0, */
+	CMD_SIZE_HUGE = (1 << 0),
+	/* CMD_SYNC = 0, */
+	CMD_ASYNC = (1 << 1),
+	/* CMD_NO_SKB = 0, */
+	CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl3945_cmd;
+struct iwl3945_priv;
+
+struct iwl3945_cmd_meta {
+	struct iwl3945_cmd_meta *source;
+	union {
+		struct sk_buff *skb;
+		int (*callback)(struct iwl3945_priv *priv,
+				struct iwl3945_cmd *cmd, struct sk_buff *skb);
+	} __attribute__ ((packed)) u;
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for a scan command
+ * (which is relatively huge; space is allocated separately).
+ */
+struct iwl3945_cmd {
+	struct iwl3945_cmd_meta meta;
+	struct iwl3945_cmd_header hdr;
+	union {
+		struct iwl3945_addsta_cmd addsta;
+		struct iwl3945_led_cmd led;
+		u32 flags;
+		u8 val8;
+		u16 val16;
+		u32 val32;
+		struct iwl3945_bt_cmd bt;
+		struct iwl3945_rxon_time_cmd rxon_time;
+		struct iwl3945_powertable_cmd powertable;
+		struct iwl3945_qosparam_cmd qosparam;
+		struct iwl3945_tx_cmd tx;
+		struct iwl3945_tx_beacon_cmd tx_beacon;
+		struct iwl3945_rxon_assoc_cmd rxon_assoc;
+		u8 *indirect;
+		u8 payload[360];
+	} __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl3945_host_cmd {
+	u8 id;
+	u16 len;
+	struct iwl3945_cmd_meta meta;
+	const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \
+			      sizeof(struct iwl3945_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * struct iwl3945_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl3945_rx_mem_buffers
+ */
+struct iwl3945_rx_queue {
+	__le32 *bd;
+	dma_addr_t dma_addr;
+	struct iwl3945_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+	struct iwl3945_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+	u32 processed;
+	u32 read;
+	u32 write;
+	u32 free_count;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+struct iwl3945_tid_data {
+	u16 seq_number;
+};
+
+struct iwl3945_hw_key {
+	enum ieee80211_key_alg alg;
+	int keylen;
+	u8 key[32];
+};
+
+union iwl3945_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+#ifdef CONFIG_IWL3945_QOS
+
+union iwl3945_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS structures */
+struct iwl3945_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl3945_qos_capabity qos_cap;
+	struct iwl3945_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWL3945_QOS */
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl3945_station_entry {
+	struct iwl3945_addsta_cmd sta;
+	struct iwl3945_tid_data tid[MAX_TID_COUNT];
+	union {
+		struct {
+			u8 rate;
+			u8 flags;
+		} s;
+		u16 rate_n_flags;
+	} current_rate;
+	u8 used;
+	u8 ps_status;
+	struct iwl3945_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+	void *v_addr;		/* access by driver */
+	dma_addr_t p_addr;	/* access by card's busmaster DMA */
+	u32 len;		/* bytes */
+};
+
+/* uCode file layout */
+struct iwl3945_ucode {
+	__le32 ver;		/* major/minor/subminor */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
+	__le32 init_data_size;	/* bytes of initialization data */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
+	u8 data[0];		/* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl3945_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+/**
+ * struct iwl4965_driver_hw_info
+ * @max_txq_num: Max # Tx queues supported
+ * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
+ * @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
+ * @rx_buf_size:
+ * @max_pkt_size:
+ * @max_rxq_log: Log-base-2 of max_rxq_size
+ * @max_stations:
+ * @bcast_sta_id:
+ * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
+ * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
+ */
+struct iwl3945_driver_hw_info {
+	u16 max_txq_num;
+	u16 ac_queue_count;
+	u16 tx_cmd_len;
+	u16 max_rxq_size;
+	u32 rx_buf_size;
+	u32 max_pkt_size;
+	u16 max_rxq_log;
+	u8  max_stations;
+	u8  bcast_sta_id;
+	void *shared_virt;
+	dma_addr_t shared_phys;
+};
+
+#define IWL_RX_HDR(x) ((struct iwl3945_rx_frame_hdr *)(\
+		       x->u.rx_frame.stats.payload + \
+		       x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl3945_rx_frame_end *)(\
+		       IWL_RX_HDR(x)->payload + \
+		       le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl3945_addsta_cmd;
+extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
+				struct iwl3945_addsta_cmd *sta, u8 flags);
+extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
+			  int is_ap, u8 flags);
+extern int iwl3945_is_network_packet(struct iwl3945_priv *priv,
+				 struct ieee80211_hdr *header);
+extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
+extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
+#ifdef CONFIG_IWL3945_DEBUG
+extern void iwl3945_report_frame(struct iwl3945_priv *priv,
+			     struct iwl3945_rx_packet *pkt,
+			     struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl3945_report_frame(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_packet *pkt,
+				    struct ieee80211_hdr *header,
+				    int group100) {}
+#endif
+extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
+					   struct iwl3945_rx_mem_buffer *rxb,
+					   void *data, short len,
+					   struct ieee80211_rx_status *stats,
+					   u16 phy_flags);
+extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv,
+				       struct ieee80211_hdr *header);
+extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
+extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_queue *rxq);
+extern int iwl3945_calc_db_from_ratio(int sig_ratio);
+extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
+			     struct iwl3945_tx_queue *txq, int count, u32 id);
+extern void iwl3945_rx_replenish(void *data);
+extern void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq);
+extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len,
+			    const void *data);
+extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
+		struct iwl3945_host_cmd *cmd);
+extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
+extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
+					 struct iwl3945_rx_queue *q);
+extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
+extern void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
+				   u32 decrypt_res,
+				   struct ieee80211_rx_status *stats);
+extern const u8 iwl3945_broadcast_addr[ETH_ALEN];
+
 /*
- * In non IWL == 3945 builds, these must build to nothing in order to allow
- * the common code to not have several #if IWL == XXXX / #endif blocks
- */
-static inline int iwl3945_get_antenna_flags(const struct iwl_priv *priv)
-{ return 0; }
-static inline int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
-{ return 0; }
-static inline void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) {}
-static inline void iwl3945_bg_reg_txpower_periodic(void *p)
-{}
-static inline int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
-{ return 0; }
-#else				/* IWL == 3945 */
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl3945_sync_station(struct iwl3945_priv *priv, int sta_id,
+			   u16 tx_rate, u8 flags);
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl3945_         <-- Its part of iwlwifi (should be changed to iwl3945_)
+ * iwl3945_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl3945_bg_      <-- Called from work queue context
+ * iwl3945_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv);
+extern void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv);
+extern void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv);
+extern int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv);
+extern int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_init(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv);
+extern void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv);
+extern void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_reset(struct iwl3945_priv *priv);
+extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq);
+extern int iwl3945_hw_get_temperature(struct iwl3945_priv *priv);
+extern int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv,
+				struct iwl3945_tx_queue *txq);
+extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
+				 struct iwl3945_frame *frame, u8 rate);
+extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv);
+extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
+				     struct iwl3945_cmd *cmd,
+				     struct ieee80211_tx_control *ctrl,
+				     struct ieee80211_hdr *hdr,
+				     int sta_id, int tx_id);
+extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv);
+extern int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power);
+extern void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv,
+				 struct iwl3945_rx_mem_buffer *rxb);
+extern void iwl3945_disable_events(struct iwl3945_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl3945_priv *priv);
+
+/**
+ * iwl3945_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE:  This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *bssid);
+
+extern int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel);
+
 /*
- * Forward declare iwl-3945.c functions for base.c
- */
-extern int iwl3945_get_antenna_flags(const struct iwl_priv *priv);
-extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
-extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
-extern void iwl3945_bg_reg_txpower_periodic(void *p);
-extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
-#endif				/* IWL == 3945 */
+ * Forward declare iwl-3945.c functions for iwl-base.c
+ */
+extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv);
+extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv);
+extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv);
+extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv);
+extern int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv);
+extern u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id,
+		 u16 tx_rate, u8 flags);
+
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl3945_priv {
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+	struct ieee80211_channel *ieee_channels;
+	struct ieee80211_rate *ieee_rates;
+	struct ieee80211_conf *cache_conf;
+
+	/* temporary frame storage list */
+	struct list_head free_frames;
+	int frames_count;
+
+	u8 phymode;
+	int alloc_rxb_skb;
+
+	void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv,
+				       struct iwl3945_rx_mem_buffer *rxb);
+
+	const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+	/* spectrum measurement report caching */
+	struct iwl3945_spectrum_notification measure_report;
+	u8 measurement_status;
+#endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+
+	/* we allocate array of iwl3945_channel_info for NIC's valid channels.
+	 *    Access via channel # using indirect index array */
+	struct iwl3945_channel_info *channel_info;	/* channel info array */
+	u8 channel_count;	/* # of channels */
+
+	/* each calibration channel group in the EEPROM has a derived
+	 * clip setting for each rate. */
+	const struct iwl3945_clip_group clip_groups[5];
+
+	/* thermal calibration */
+	s32 temperature;	/* degrees Kelvin */
+	s32 last_temperature;
+
+	/* Scan related variables */
+	unsigned long last_scan_jiffies;
+	unsigned long next_scan_jiffies;
+	unsigned long scan_start;
+	unsigned long scan_pass_start;
+	unsigned long scan_start_tsf;
+	int scan_bands;
+	int one_direct_scan;
+	u8 direct_ssid_len;
+	u8 direct_ssid[IW_ESSID_MAX_SIZE];
+	struct iwl3945_scan_cmd *scan;
+	u8 only_active_channel;
+
+	/* spinlock */
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
+	struct mutex mutex;
+
+	/* basic pci-network driver stuff */
+	struct pci_dev *pci_dev;
+
+	/* pci hardware address support */
+	void __iomem *hw_base;
+
+	/* uCode images, save to reload in case of failure */
+	struct fw_desc ucode_code;	/* runtime inst */
+	struct fw_desc ucode_data;	/* runtime data original */
+	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
+	struct fw_desc ucode_init;	/* initialization inst */
+	struct fw_desc ucode_init_data;	/* initialization data */
+	struct fw_desc ucode_boot;	/* bootstrap inst */
+
+
+	struct iwl3945_rxon_time_cmd rxon_timing;
+
+	/* We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware */
+	const struct iwl3945_rxon_cmd active_rxon;
+	struct iwl3945_rxon_cmd staging_rxon;
+
+	int error_recovering;
+	struct iwl3945_rxon_cmd recovery_rxon;
+
+	/* 1st responses from initialize and runtime uCode images.
+	 * 4965's initialize alive response contains some calibration data. */
+	struct iwl3945_init_alive_resp card_alive_init;
+	struct iwl3945_alive_resp card_alive;
+
+#ifdef LED
+	/* LED related variables */
+	struct iwl3945_activity_blink activity;
+	unsigned long led_packets;
+	int led_state;
+#endif
+
+	u16 active_rate;
+	u16 active_rate_basic;
+
+	u8 call_post_assoc_from_beacon;
+	u8 assoc_station_added;
+	/* Rate scaling data */
+	s8 data_retry_limit;
+	u8 retry_rate;
+
+	wait_queue_head_t wait_command_queue;
+
+	int activity_timer_active;
+
+	/* Rx and Tx DMA processing queues */
+	struct iwl3945_rx_queue rxq;
+	struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES];
+
+	unsigned long status;
+	u32 config;
+
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
+
+	struct iwl3945_power_mgr power_data;
+
+	struct iwl3945_notif_statistics statistics;
+	unsigned long last_statistics_time;
+
+	/* context information */
+	u8 essid[IW_ESSID_MAX_SIZE];
+	u8 essid_len;
+	u16 rates_mask;
+
+	u32 power_mode;
+	u32 antenna;
+	u8 bssid[ETH_ALEN];
+	u16 rts_threshold;
+	u8 mac_addr[ETH_ALEN];
+
+	/*station table variables */
+	spinlock_t sta_lock;
+	int num_stations;
+	struct iwl3945_station_entry stations[IWL_STATION_COUNT];
+
+	/* Indication if ieee80211_ops->open has been called */
+	int is_open;
+
+	u8 mac80211_registered;
+	int is_abg;
+
+	u32 notif_missed_beacons;
+
+	/* Rx'd packet timing information */
+	u32 last_beacon_time;
+	u64 last_tsf;
+
+	/* Duplicate packet detection */
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+
+	/* Hash table for finding stations in IBSS network */
+	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+	/* eeprom */
+	struct iwl3945_eeprom eeprom;
+
+	int iw_mode;
+
+	struct sk_buff *ibss_beacon;
+
+	/* Last Rx'd beacon timestamp */
+	u32 timestamp0;
+	u32 timestamp1;
+	u16 beacon_int;
+	struct iwl3945_driver_hw_info hw_setting;
+	int interface_id;
+
+	/* Current association information needed to configure the
+	 * hardware */
+	u16 assoc_id;
+	u16 assoc_capability;
+	u8 ps_mode;
+
+#ifdef CONFIG_IWL3945_QOS
+	struct iwl3945_qos_info qos_data;
+#endif /*CONFIG_IWL3945_QOS */
+
+	struct workqueue_struct *workqueue;
+
+	struct work_struct up;
+	struct work_struct restart;
+	struct work_struct calibrated_work;
+	struct work_struct scan_completed;
+	struct work_struct rx_replenish;
+	struct work_struct rf_kill;
+	struct work_struct abort_scan;
+	struct work_struct update_link_led;
+	struct work_struct auth_work;
+	struct work_struct report_work;
+	struct work_struct request_scan;
+	struct work_struct beacon_update;
+
+	struct tasklet_struct irq_tasklet;
+
+	struct work_struct init_alive_start;
+	struct work_struct alive_start;
+	struct work_struct activity_timer;
+	struct work_struct thermal_periodic;
+	struct work_struct gather_stats;
+	struct work_struct scan_check;
+	struct work_struct post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+	s8 user_txpower_limit;
+	s8 max_channel_txpower_limit;
+
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWL3945_DEBUG
+	/* debugging info */
+	u32 framecnt_to_us;
+	atomic_t restrict_refcnt;
+#endif
+};				/*iwl3945_priv */
+
+static inline int iwl3945_is_associated(struct iwl3945_priv *priv)
+{
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info)
+{
+	if (ch_info == NULL)
+		return 0;
+	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info)
+{
+	return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info)
+{
+	return ((ch_info->phymode == MODE_IEEE80211B) ||
+		(ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl3945_channel_info *ch)
+{
+	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl3945_channel_info *ch)
+{
+	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
+	const struct iwl3945_priv *priv, int phymode, u16 channel);
+
+/* Requires full declaration of iwl3945_priv before including */
+#include "iwl-3945-io.h"
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
new file mode 100644
index 0000000..7988c75
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -0,0 +1,2562 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-4965-commands.h) only for uCode API definitions.
+ * Please use iwl-4965-hw.h for hardware-related definitions.
+ * Please use iwl-4965.h for driver implementation definitions.
+ */
+
+#ifndef __iwl4965_commands_h__
+#define __iwl4965_commands_h__
+
+enum {
+	REPLY_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+
+	/* RXON and QOS commands */
+	REPLY_RXON = 0x10,
+	REPLY_RXON_ASSOC = 0x11,
+	REPLY_QOS_PARAM = 0x13,
+	REPLY_RXON_TIMING = 0x14,
+
+	/* Multi-Station support */
+	REPLY_ADD_STA = 0x18,
+	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+
+	/* RX, TX, LEDs */
+	REPLY_TX = 0x1c,
+	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
+	REPLY_LEDS_CMD = 0x48,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+	/* 802.11h related */
+	RADAR_NOTIFICATION = 0x70,	/* not used */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
+	REPLY_CHANNEL_SWITCH = 0x72,
+	CHANNEL_SWITCH_NOTIFICATION = 0x73,
+	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+	/* Power Management */
+	POWER_TABLE_CMD = 0x77,
+	PM_SLEEP_NOTIFICATION = 0x7A,
+	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+	/* Scan commands and notifications */
+	REPLY_SCAN_CMD = 0x80,
+	REPLY_SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* IBSS/AP commands */
+	BEACON_NOTIFICATION = 0x90,
+	REPLY_TX_BEACON = 0x91,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
+
+	/* Miscellaneous commands */
+	QUIET_NOTIFICATION = 0x96,		/* not used */
+	REPLY_TX_PWR_TABLE_CMD = 0x97,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
+
+	/* Bluetooth device coexistance config command */
+	REPLY_BT_CONFIG = 0x9b,
+
+	/* Statistics */
+	REPLY_STATISTICS_CMD = 0x9c,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	REPLY_CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	/* Missed beacons notification */
+	MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+	SENSITIVITY_CMD = 0xa8,
+	REPLY_PHY_CALIBRATION_CMD = 0xb0,
+	REPLY_RX_PHY_CMD = 0xc0,
+	REPLY_RX_MPDU_CMD = 0xc1,
+	REPLY_4965_RX = 0xc3,
+	REPLY_COMPRESSED_BA = 0xc5,
+	REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, rate_n_flags, txpower
+ *
+ *****************************************************************************/
+
+/* iwl4965_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
+/**
+ * struct iwl4965_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl4965_cmd_header {
+	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
+	u8 flags;	/* IWL_CMD_* */
+	/*
+	 * The driver sets up the sequence number to values of its chosing.
+	 * uCode does not use this value, but passes it back to the driver
+	 * when sending the response to each driver-originated command, so
+	 * the driver can match the response to the command.  Since the values
+	 * don't get used by uCode, the driver may set up an arbitrary format.
+	 *
+	 * There is one exception:  uCode sets bit 15 when it originates
+	 * the response/notification, i.e. when the response/notification
+	 * is not a direct response to a command sent by the driver.  For
+	 * example, uCode issues REPLY_3945_RX when it sends a received frame
+	 * to the driver; it is not a direct response to any driver command.
+	 *
+	 * The Linux driver uses the following format:
+	 *
+	 *  0:7    index/position within Tx queue
+	 *  8:13   Tx queue selection
+	 * 14:14   driver sets this to indicate command is in the 'huge'
+	 *         storage at the end of the command buffers, i.e. scan cmd
+	 * 15:15   uCode sets this in uCode-originated response/notification
+	 */
+	__le16 sequence;
+
+	/* command or response/notification data follows immediately */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/**
+ * 4965 rate_n_flags bit fields
+ *
+ * rate_n_flags format is used in following 4965 commands:
+ *  REPLY_4965_RX (response only)
+ *  REPLY_TX (both command and response)
+ *  REPLY_TX_LINK_QUALITY_CMD
+ *
+ * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
+ *  2-0:  0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *
+ *    3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
+ *
+ * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ *
+ * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
+ *  3-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+
+/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+
+/* Bit 12: (1) Duplicate data on both 20MHz chnls.  FAT (bit 11) must be set. */
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+/**
+ * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
+ * bit14:15 01 B inactive, A active
+ *          10 B active, A inactive
+ *          11 Both active
+ */
+#define RATE_MCS_ANT_A_POS	14
+#define RATE_MCS_ANT_B_POS	15
+#define RATE_MCS_ANT_A_MSK	0x4000
+#define RATE_MCS_ANT_B_MSK	0x8000
+#define RATE_MCS_ANT_AB_MSK	0xc000
+
+
+/**
+ * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD
+ *
+ * Scan uses only one transmitter, so only one analog/dsp gain pair is needed.
+ */
+struct iwl4965_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
+
+#define POWER_TABLE_NUM_ENTRIES			33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
+#define POWER_TABLE_CCK_ENTRY			32
+
+/**
+ * union iwl4965_tx_power_dual_stream
+ *
+ * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ * Use __le32 version (struct tx_power_dual_stream) when building command.
+ *
+ * Driver provides radio gain and DSP attenuation settings to device in pairs,
+ * one value for each transmitter chain.  The first value is for transmitter A,
+ * second for transmitter B.
+ *
+ * For SISO bit rates, both values in a pair should be identical.
+ * For MIMO rates, one value may be different from the other,
+ * in order to balance the Tx output between the two transmitters.
+ *
+ * See more details in doc for TXPOWER in iwl-4965-hw.h.
+ */
+union iwl4965_tx_power_dual_stream {
+	struct {
+		u8 radio_tx_gain[2];
+		u8 dsp_predis_atten[2];
+	} s;
+	u32 dw;
+};
+
+/**
+ * struct tx_power_dual_stream
+ *
+ * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Same format as iwl_tx_power_dual_stream, but __le32
+ */
+struct tx_power_dual_stream {
+	__le32 dw;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_tx_power_db
+ *
+ * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ */
+struct iwl4965_tx_power_db {
+	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
+/*
+ * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "initialize alive" notification once the initialization
+ * uCode image has completed its work, and is ready to load the runtime image.
+ * This is the *first* "alive" notification that the driver will receive after
+ * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * For 4965, this notification contains important calibration data for
+ * calculating txpower settings:
+ *
+ * 1)  Power supply voltage indication.  The voltage sensor outputs higher
+ *     values for lower voltage, and vice versa.
+ *
+ * 2)  Temperature measurement parameters, for each of two channel widths
+ *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
+ *     is done via one of the receiver chains, and channel width influences
+ *     the results.
+ *
+ * 3)  Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
+ *     for each of 5 frequency ranges.
+ */
+struct iwl4965_init_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;		/* "9" for initialize alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+
+	/* calibration values from "initialize" uCode */
+	__le32 voltage;		/* signed, higher value is lower voltage */
+	__le32 therm_r1[2];	/* signed, 1st for normal, 2nd for FAT channel*/
+	__le32 therm_r2[2];	/* signed */
+	__le32 therm_r3[2];	/* signed */
+	__le32 therm_r4[2];	/* signed */
+	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
+				 * 2 Tx chains */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *     Its header format is:
+ *
+ *	__le32 log_size;     log capacity (in number of entries)
+ *	__le32 type;         (1) timestamp with each entry, (0) no timestamp
+ *	__le32 wraps;        # times uCode has wrapped to top of circular buffer
+ *      __le32 write_index;  next circular buffer entry that uCode would fill
+ *
+ *     The header is followed by the circular buffer of log entries.  Entries
+ *     with timestamps have the following format:
+ *
+ *	__le32 event_id;     range 0 - 1500
+ *	__le32 timestamp;    low 32 bits of TSF (of network, if associated)
+ *	__le32 data;         event_id-specific data value
+ *
+ *     Entries without timestamps contain only event_id and data.
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.  For 4965, the format
+ *     of the error log is:
+ *
+ *	__le32 valid;        (nonzero) valid, (0) log is empty
+ *	__le32 error_id;     type of error
+ *	__le32 pc;           program counter
+ *	__le32 blink1;       branch link
+ *	__le32 blink2;       branch link
+ *	__le32 ilink1;       interrupt link
+ *	__le32 ilink2;       interrupt link
+ *	__le32 data1;        error-specific data
+ *	__le32 data2;        error-specific data
+ *	__le32 line;         source code line of error
+ *	__le32 bcon_time;    beacon timer
+ *	__le32 tsf_low;      network timestamp function timer
+ *	__le32 tsf_hi;       network timestamp function timer
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+struct iwl4965_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;			/* not "9" for runtime alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
+
+
+union tsf {
+	u8 byte[8];
+	__le16 word[4];
+	__le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl4965_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+	__le32 error_info;
+	union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		__constant_cpu_to_le16(0x1<<0)
+#define RXON_RX_CHAIN_VALID_MSK			__constant_cpu_to_le16(0x7<<1)
+#define RXON_RX_CHAIN_VALID_POS			(1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK		__constant_cpu_to_le16(0x7<<4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	__constant_cpu_to_le16(0x7<<7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
+#define RXON_RX_CHAIN_CNT_MSK			__constant_cpu_to_le16(0x3<<10)
+#define RXON_RX_CHAIN_CNT_POS			(10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK		__constant_cpu_to_le16(0x3<<12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK		__constant_cpu_to_le16(0x1<<14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	__constant_cpu_to_le32(0x1<<22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
+
+#define RXON_FLG_HT_PROT_MSK			__constant_cpu_to_le32(0x1<<23)
+#define RXON_FLG_FAT_PROT_MSK			__constant_cpu_to_le32(0x2<<23)
+
+#define RXON_FLG_CHANNEL_MODE_POS		(25)
+#define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3<<25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1<<25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2<<25)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+struct iwl4965_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+	__le16 rx_chain;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl4965_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	__le16 rx_chain_select_flags;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl4965_rxon_time_cmd {
+	union tsf timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl4965_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+	struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl4965_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl4965_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl4965_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl4965_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define	IWL_AP_ID		0
+#define IWL_MULTICAST_ID	1
+#define	IWL_STA_ID		2
+#define IWL4965_BROADCAST_ID	31
+#define	IWL4965_STATION_COUNT	32
+
+#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
+#define	IWL_INVALID_STATION 	255
+
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1<<8);
+#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS	(19)
+#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+#define STA_MODIFY_ADDBA_TID_MSK	0x08
+#define STA_MODIFY_DELBA_TID_MSK	0x10
+
+/* Receiver address (actually, Rx station's index into station table),
+ * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
+#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
+
+struct iwl4965_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	__le16 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * 3945 uses REPLY_RATE_SCALE to set up rate tables).
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+struct iwl4965_addsta_cmd {
+	u8 mode;		/* 1: modify existing, 0: add new station */
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl4965_keyinfo key;
+	__le32 station_flags;		/* STA_FLG_* */
+	__le32 station_flags_msk;	/* STA_FLG_* */
+
+	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+	 * corresponding to bit (e.g. bit 5 controls TID 5).
+	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+	__le16 tid_disable_tx;
+
+	__le16	reserved1;
+
+	/* TID for which to add block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	u8 add_immediate_ba_tid;
+
+	/* TID for which to remove block-ack support.
+	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+	u8 remove_immediate_ba_tid;
+
+	/* Starting Sequence Number for added block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	__le16 add_immediate_ba_ssn;
+
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK		0x1
+#define ADD_STA_NO_ROOM_IN_TABLE	0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
+#define ADD_STA_MODIFY_NON_EXIST_STA	0x8
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl4965_add_sta_resp {
+	u8 status;	/* ADD_STA_* */
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl4965_rx_frame_stats {
+	u8 phy_count;
+	u8 id;
+	u8 rssi;
+	u8 agc;
+	__le16 sig_avg;
+	__le16 noise_diff;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl4965_rx_frame_hdr {
+	__le16 channel;
+	__le16 phy_flags;
+	u8 reserved1;
+	u8 rate;
+	__le16 len;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+#define	RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
+#define	RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+
+#define	RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
+#define	RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
+#define	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
+#define	RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
+#define	RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+
+#define	RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+
+#define	RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define	RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define	RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+struct iwl4965_rx_frame_end {
+	__le32 status;
+	__le64 timestamp;
+	__le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl4965_rx_frame {
+	struct iwl4965_rx_frame_stats stats;
+	struct iwl4965_rx_frame_hdr hdr;
+	struct iwl4965_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
+#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
+#define IWL_AGC_DB_POS		(7)
+struct iwl4965_rx_non_cfg_phy {
+	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
+	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
+	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
+	u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
+	__le32 reserved2;
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+	__le16 byte_count;	/* frame's byte-count */
+	__le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device (see comments for
+ * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
+ * are preparing to transmit, the device pulls the Tx command over the PCI
+ * bus via one of the device's Tx DMA channels, to fill an internal FIFO
+ * from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
+ * handle reception of block-acks; uCode updates the host driver via
+ * REPLY_COMPRESSED_BA (4965).
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_RATE_SCALE (for 3945) or
+ * REPLY_TX_LINK_QUALITY_CMD (4965).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/* 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+
+/* 1: Transmit Clear-To-Send to self before this frame.
+ * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+
+/* For 4965:
+ * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+
+/* 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set. */
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+
+/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+ * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * 4965 uCode updates these Tx attempt count values in host DRAM.
+ * Used for managing Tx retries when expecting block-acks.
+ * Driver should set these fields to 0.
+ */
+struct iwl4965_dram_scratch {
+	u8 try_cnt;		/* Tx attempts */
+	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl4965_tx_cmd {
+	/*
+	 * MPDU byte count:
+	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+	 * + 8 byte IV for CCM or TKIP (not used for WEP)
+	 * + Data payload
+	 * + 8-byte MIC (not used for CCM/WEP)
+	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+	 * Range: 14-2342 bytes.
+	 */
+	__le16 len;
+
+	/*
+	 * MPDU or MSDU byte count for next frame.
+	 * Used for fragmentation and bursting, but not 11n aggregation.
+	 * Same as "len", but for next frame.  Set to 0 if not applicable.
+	 */
+	__le16 next_frame_len;
+
+	__le32 tx_flags;	/* TX_CMD_FLG_* */
+
+	/* 4965's uCode may modify this field of the Tx command (in host DRAM!).
+	 * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
+	struct iwl4965_dram_scratch scratch;
+
+	/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+
+	/* Index of destination station in uCode's station table */
+	u8 sta_id;
+
+	/* Type of security encryption:  CCM or TKIP */
+	u8 sec_ctl;		/* TX_CMD_SEC_* */
+
+	/*
+	 * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
+	 * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
+	 * data frames, this field may be used to selectively reduce initial
+	 * rate (via non-0 value) for special frames (e.g. management), while
+	 * still supporting rate scaling for all frames.
+	 */
+	u8 initial_rate_index;
+	u8 reserved;
+	u8 key[16];
+	__le16 next_frame_flags;
+	__le16 reserved2;
+	union {
+		__le32 life_time;
+		__le32 attempt;
+	} stop_time;
+
+	/* Host DRAM physical address pointer to "scratch" in this command.
+	 * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
+	__le32 dram_lsb_ptr;
+	u8 dram_msb_ptr;
+
+	u8 rts_retry_limit;	/*byte 50 */
+	u8 data_retry_limit;	/*byte 51 */
+	u8 tid_tspec;
+	union {
+		__le16 pm_frame_timeout;
+		__le16 attempt_duration;
+	} timeout;
+
+	/*
+	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+	 */
+	__le16 driver_txop;
+
+	/*
+	 * MAC header goes here, followed by 2 bytes padding if MAC header
+	 * length is 26 or 30 bytes, followed by payload data
+	 */
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
+ */
+enum {
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+	TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_TX_LOCKED = 0x90,
+	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
+
+enum {
+	TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+	TX_STATUS_MSK = 0x000000ff,	/* bits 0:7 */
+	TX_STATUS_DELAY_MSK = 0x00000040,
+	TX_STATUS_ABORT_MSK = 0x00000080,
+	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
+	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
+	TX_RESERVED = 0x00780000,	/* bits 19:22 */
+	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
+	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation status
+ ******************************* */
+
+enum {
+	AGG_TX_STATE_TRANSMITTED = 0x00,
+	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+	AGG_TX_STATE_ABORT_MSK = 0x08,
+	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+	AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)  No aggregation (frame_count == 1).  This reports Tx results for
+ *     a single frame.  Multiple attempts, at various bit rates, may have
+ *     been made for this frame.
+ *
+ * 2)  Aggregation (frame_count > 1).  This reports Tx results for
+ *     2 or more frames that used block-acknowledge.  All frames were
+ *     transmitted at same rate.  Rate scaling may have been used if first
+ *     frame in this new agg block failed in previous agg block(s).
+ *
+ *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
+ *     block-ack has not been received by the time the 4965 records this status.
+ *     This status relates to reasons the tx might have been blocked or aborted
+ *     within the sending station (this 4965), rather than whether it was
+ *     received successfully by the destination station.
+ */
+struct iwl4965_tx_resp {
+	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
+	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
+	u8 failure_rts;		/* # failures due to unsuccessful RTS */
+	u8 failure_frame;	/* # failures due to no ACK (unused for agg) */
+
+	/* For non-agg:  Rate at which frame was successful.
+	 * For agg:  Rate at which all frames were transmitted. */
+	__le32 rate_n_flags;	/* RATE_MCS_*  */
+
+	/* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
+	__le16 wireless_media_time;	/* uSecs */
+
+	__le16 reserved;
+	__le32 pa_power1;	/* RF power amplifier measurement (not used) */
+	__le32 pa_power2;
+
+	/*
+	 * For non-agg:  frame status TX_STATUS_*
+	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+	 *           fields follow this one, up to frame_count.
+	 *           Bit fields:
+	 *           11- 0:  AGG_TX_STATE_* status code
+	 *           15-12:  Retry count for 1st frame in aggregation (retries
+	 *                   occur if tx failed for this frame when it was a
+	 *                   member of a previous aggregation block).  If rate
+	 *                   scaling is used, retry count indicates the rate
+	 *                   table entry used for all frames in the new agg.
+	 *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
+	 */
+	__le32 status;	/* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ *
+ * Reports Block-Acknowledge from recipient station
+ */
+struct iwl4965_compressed_ba_resp {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+
+	/* Index of recipient (BA-sending) station in uCode's station table */
+	u8 sta_id;
+	u8 tid;
+	__le16 ba_seq_ctl;
+	__le32 ba_bitmap0;
+	__le32 ba_bitmap1;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ *
+ * See details under "TXPOWER" in iwl-4965-hw.h.
+ */
+struct iwl4965_txpowertable_cmd {
+	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
+	u8 reserved;
+	__le16 channel;
+	struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1<<0)
+
+/* # of EDCA prioritized tx fifos */
+#define  LINK_QUAL_AC_NUM AC_NUM
+
+/* # entries in rate scale table to support Tx retries */
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+/* Tx antenna selection values */
+#define  LINK_QUAL_ANT_A_MSK (1<<0)
+#define  LINK_QUAL_ANT_B_MSK (1<<1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+
+/**
+ * struct iwl4965_link_qual_general_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl4965_link_qual_general_params {
+	u8 flags;
+
+	/* No entries at or above this (driver chosen) index contain MIMO */
+	u8 mimo_delimiter;
+
+	/* Best single antenna to use for single stream (legacy, SISO). */
+	u8 single_stream_ant_msk;	/* LINK_QUAL_ANT_* */
+
+	/* Best antennas to use for MIMO (unused for 4965, assumes both). */
+	u8 dual_stream_ant_msk;		/* LINK_QUAL_ANT_* */
+
+	/*
+	 * If driver needs to use different initial rates for different
+	 * EDCA QOS access categories (as implemented by tx fifos 0-3),
+	 * this table will set that up, by indicating the indexes in the
+	 * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
+	 * Otherwise, driver should set all entries to 0.
+	 *
+	 * Entry usage:
+	 * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
+	 * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
+	 */
+	u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_link_qual_agg_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl4965_link_qual_agg_params {
+
+	/* Maximum number of uSec in aggregation.
+	 * Driver should set this to 4000 (4 milliseconds). */
+	__le16 agg_time_limit;
+
+	/*
+	 * Number of Tx retries allowed for a frame, before that frame will
+	 * no longer be considered for the start of an aggregation sequence
+	 * (scheduler will then try to tx it as single frame).
+	 * Driver should set this to 3.
+	 */
+	u8 agg_dis_start_th;
+
+	/*
+	 * Maximum number of frames in aggregation.
+	 * 0 = no limit (default).  1 = no aggregation.
+	 * Other values = max # frames in aggregation.
+	 */
+	u8 agg_frame_cnt_limit;
+
+	__le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ *
+ * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ *
+ * Each station in the 4965's internal station table has its own table of 16
+ * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
+ * an ACK is not received.  This command replaces the entire table for
+ * one station.
+ *
+ * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
+ *
+ * The rate scaling procedures described below work well.  Of course, other
+ * procedures are possible, and may work better for particular environments.
+ *
+ *
+ * FILLING THE RATE TABLE
+ *
+ * Given a particular initial rate and mode, as determined by the rate
+ * scaling algorithm described below, the Linux driver uses the following
+ * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
+ * Link Quality command:
+ *
+ *
+ * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
+ *     a) Use this same initial rate for first 3 entries.
+ *     b) Find next lower available rate using same mode (SISO or MIMO),
+ *        use for next 3 entries.  If no lower rate available, switch to
+ *        legacy mode (no FAT channel, no MIMO, no short guard interval).
+ *     c) If using MIMO, set command's mimo_delimiter to number of entries
+ *        using MIMO (3 or 6).
+ *     d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
+ *        no MIMO, no short guard interval), at the next lower bit rate
+ *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
+ *        legacy procedure for remaining table entries.
+ *
+ * 2)  If using legacy initial rate:
+ *     a) Use the initial rate for only one entry.
+ *     b) For each following entry, reduce the rate to next lower available
+ *        rate, until reaching the lowest available rate.
+ *     c) When reducing rate, also switch antenna selection.
+ *     d) Once lowest available rate is reached, repeat this rate until
+ *        rate table is filled (16 entries), switching antenna each entry.
+ *
+ *
+ * ACCUMULATING HISTORY
+ *
+ * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
+ * two sets of frame Tx success history:  One for the current/active modulation
+ * mode, and one for a speculative/search mode that is being attempted.  If the
+ * speculative mode turns out to be more effective (i.e. actual transfer
+ * rate is better), then the driver continues to use the speculative mode
+ * as the new current active mode.
+ *
+ * Each history set contains, separately for each possible rate, data for a
+ * sliding window of the 62 most recent tx attempts at that rate.  The data
+ * includes a shifting bitmap of success(1)/failure(0), and sums of successful
+ * and attempted frames, from which the driver can additionally calculate a
+ * success ratio (success / attempted) and number of failures
+ * (attempted - success), and control the size of the window (attempted).
+ * The driver uses the bit map to remove successes from the success sum, as
+ * the oldest tx attempts fall out of the window.
+ *
+ * When the 4965 makes multiple tx attempts for a given frame, each attempt
+ * might be at a different rate, and have different modulation characteristics
+ * (e.g. antenna, fat channel, short guard interval), as set up in the rate
+ * scaling table in the Link Quality command.  The driver must determine
+ * which rate table entry was used for each tx attempt, to determine which
+ * rate-specific history to update, and record only those attempts that
+ * match the modulation characteristics of the history set.
+ *
+ * When using block-ack (aggregation), all frames are transmitted at the same
+ * rate, since there is no per-attempt acknowledgement from the destination
+ * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
+ * rate_n_flags field.  After receiving a block-ack, the driver can update
+ * history for the entire block all at once.
+ *
+ *
+ * FINDING BEST STARTING RATE:
+ *
+ * When working with a selected initial modulation mode (see below), the
+ * driver attempts to find a best initial rate.  The initial rate is the
+ * first entry in the Link Quality command's rate table.
+ *
+ * 1)  Calculate actual throughput (success ratio * expected throughput, see
+ *     table below) for current initial rate.  Do this only if enough frames
+ *     have been attempted to make the value meaningful:  at least 6 failed
+ *     tx attempts, or at least 8 successes.  If not enough, don't try rate
+ *     scaling yet.
+ *
+ * 2)  Find available rates adjacent to current initial rate.  Available means:
+ *     a)  supported by hardware &&
+ *     b)  supported by association &&
+ *     c)  within any constraints selected by user
+ *
+ * 3)  Gather measured throughputs for adjacent rates.  These might not have
+ *     enough history to calculate a throughput.  That's okay, we might try
+ *     using one of them anyway!
+ *
+ * 4)  Try decreasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  lower adjacent rate has better measured throughput ||
+ *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
+ *
+ *     As a sanity check, if decrease was determined above, leave rate
+ *     unchanged if:
+ *     a)  lower rate unavailable
+ *     b)  success ratio at current rate > 85% (very good)
+ *     c)  current measured throughput is better than expected throughput
+ *         of lower rate (under perfect 100% tx conditions, see table below)
+ *
+ * 5)  Try increasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
+ *     b)  higher adjacent rate has better measured throughput ||
+ *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
+ *
+ *     As a sanity check, if increase was determined above, leave rate
+ *     unchanged if:
+ *     a)  success ratio at current rate < 70%.  This is not particularly
+ *         good performance; higher rate is sure to have poorer success.
+ *
+ * 6)  Re-evaluate the rate after each tx frame.  If working with block-
+ *     acknowledge, history and statistics may be calculated for the entire
+ *     block (including prior history that fits within the history windows),
+ *     before re-evaluation.
+ *
+ * FINDING BEST STARTING MODULATION MODE:
+ *
+ * After working with a modulation mode for a "while" (and doing rate scaling),
+ * the driver searches for a new initial mode in an attempt to improve
+ * throughput.  The "while" is measured by numbers of attempted frames:
+ *
+ * For legacy mode, search for new mode after:
+ *   480 successful frames, or 160 failed frames
+ * For high-throughput modes (SISO or MIMO), search for new mode after:
+ *   4500 successful frames, or 400 failed frames
+ *
+ * Mode switch possibilities are (3 for each mode):
+ *
+ * For legacy:
+ *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
+ * For SISO:
+ *   Change antenna, try MIMO, try shortened guard interval (SGI)
+ * For MIMO:
+ *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
+ *
+ * When trying a new mode, use the same bit rate as the old/current mode when
+ * trying antenna switches and shortened guard interval.  When switching to
+ * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
+ * for which the expected throughput (under perfect conditions) is about the
+ * same or slightly better than the actual measured throughput delivered by
+ * the old/current mode.
+ *
+ * Actual throughput can be estimated by multiplying the expected throughput
+ * by the success ratio (successful / attempted tx frames).  Frame size is
+ * not considered in this calculation; it assumes that frame size will average
+ * out to be fairly consistent over several samples.  The following are
+ * metric values for expected throughput assuming 100% success ratio.
+ * Only G band has support for CCK rates:
+ *
+ *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
+ *
+ *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
+ *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
+ *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
+ * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
+ *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
+ * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
+ *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
+ * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
+ *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
+ * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
+ *
+ * After the new mode has been tried for a short while (minimum of 6 failed
+ * frames or 8 successful frames), compare success ratio and actual throughput
+ * estimate of the new mode with the old.  If either is better with the new
+ * mode, continue to use the new mode.
+ *
+ * Continue comparing modes until all 3 possibilities have been tried.
+ * If moving from legacy to HT, try all 3 possibilities from the new HT
+ * mode.  After trying all 3, a best mode is found.  Continue to use this mode
+ * for the longer "while" described above (e.g. 480 successful frames for
+ * legacy), and then repeat the search process.
+ *
+ */
+struct iwl4965_link_quality_cmd {
+
+	/* Index of destination/recipient station in uCode's station table */
+	u8 sta_id;
+	u8 reserved1;
+	__le16 control;		/* not used */
+	struct iwl4965_link_qual_general_params general_params;
+	struct iwl4965_link_qual_agg_params agg_params;
+
+	/*
+	 * Rate info; when using rate-scaling, Tx command's initial_rate_index
+	 * specifies 1st Tx rate attempted, via index into this table.
+	 * 4965 works its way through table when retrying Tx.
+	 */
+	struct {
+		__le32 rate_n_flags;	/* RATE_MCS_*, IWL_RATE_* */
+	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl4965_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl4965_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl4965_measure_type */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl4965_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl4965_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl4965_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl4965_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl4965_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl4965_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl4965_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __attribute__ ((packed));
+
+enum iwl4965_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl4965_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl4965_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl4965_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl4965_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl4965_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1<<3)
+
+struct iwl4965_powertable_cmd {
+	__le16 flags;
+	u8 keep_alive_seconds;
+	u8 debug_flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+	__le32 keep_alive_beacons;
+} __attribute__ ((packed));
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl4965_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl4965_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl4965_card_state_notif {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl4965_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+struct iwl4965_scan_channel {
+	/* type is defined as:
+	 * 0:0 active (0 - passive)
+	 * 1:4 SSID direct
+	 *     If 1 is set then corresponding SSID IE is transmitted in probe
+	 * 5:7 reserved
+	 */
+	u8 type;
+	u8 channel;
+	struct iwl4965_tx_power tpc;
+	__le16 active_dwell;
+	__le16 passive_dwell;
+} __attribute__ ((packed));
+
+struct iwl4965_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX        0x4
+#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
+struct iwl4965_scan_cmd {
+	__le16 len;
+	u8 reserved0;
+	u8 channel_count;
+	__le16 quiet_time;     /* dwell only this long on quiet chnl
+				* (active scan) */
+	__le16 quiet_plcp_th;  /* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;    /* passive -> active promotion threshold */
+	__le16 rx_chain;
+	__le32 max_out_time;   /* max usec to be out of associated (service)
+				* chnl */
+	__le32 suspend_time;   /* pause scan this long when returning to svc
+				* chnl.
+				* 3945 -- 31:24 # beacons, 19:0 additional usec,
+				* 4965 -- 31:22 # beacons, 21:0 additional usec.
+				*/
+	__le32 flags;
+	__le32 filter_flags;
+
+	struct iwl4965_tx_cmd tx_cmd;
+	struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+	u8 data[0];
+	/*
+	 * The channels start after the probe request payload and are of type:
+	 *
+	 * struct iwl4965_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * can not mix 2.4GHz channels and 5.2GHz channels and must
+	 * request a scan multiple times (not concurrently)
+	 *
+	 */
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl4965_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl4965_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __attribute__ ((packed));
+
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl4965_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl4965_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 reserved;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl4965_beacon_notif {
+	struct iwl4965_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl4965_tx_beacon_cmd {
+	struct iwl4965_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
+	u8 reserved1;
+	struct ieee80211_hdr frame[0];	/* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+	__le32 sent_ba_rsp_cnt;
+	__le32 dsp_self_kill;
+	__le32 mh_format_err;
+	__le32 re_acq_main_rssi_sum;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_rx_ht_phy {
+	__le32 plcp_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 crc32_err;
+	__le32 mh_format_err;
+	__le32 agg_crc32_good;
+	__le32 agg_mpdu_cnt;
+	__le32 agg_cnt;
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+	__le32 channel_beacons;	/* beacons with our bss id and in our
+				 * serving channel */
+	__le32 num_missed_bcon;	/* number of missed beacons */
+	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
+					 * ADC was in saturation */
+	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
+					  * for INA */
+	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
+	__le32 interference_data_flag;	/* flag for interference data
+					 * availability. 1 when data is
+					 * available. */
+	__le32 channel_load;	/* counts RX Enable time */
+	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
+					 * and CCK) counter */
+	__le32 beacon_rssi_a;
+	__le32 beacon_rssi_b;
+	__le32 beacon_rssi_c;
+	__le32 beacon_energy_a;
+	__le32 beacon_energy_b;
+	__le32 beacon_energy_c;
+} __attribute__ ((packed));
+
+struct statistics_rx {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy general;
+	struct statistics_rx_ht_phy ofdm_ht;
+} __attribute__ ((packed));
+
+struct statistics_tx_non_phy_agg {
+	__le32 ba_timeout;
+	__le32 ba_reschedule_frames;
+	__le32 scd_query_agg_frame_cnt;
+	__le32 scd_query_no_agg;
+	__le32 scd_query_agg;
+	__le32 scd_query_mismatch;
+	__le32 frame_not_ready;
+	__le32 underrun;
+	__le32 bt_prio_kill;
+	__le32 rx_ba_rsp_cnt;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+	__le32 dump_msdu_cnt;
+	__le32 burst_abort_next_frame_mismatch_cnt;
+	__le32 burst_abort_missing_next_frame_cnt;
+	__le32 cts_timeout_collision;
+	__le32 ack_or_ba_timeout_collision;
+	struct statistics_tx_non_phy_agg agg;
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
+	__le32 reserved1;
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_general {
+	__le32 temperature;
+	__le32 temperature_m;
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+	__le32 rx_enable_counter;
+	__le32 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl4965_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl4965_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl4965_missed_beacon_notif {
+	__le32 consequtive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ * With the uCode used for open source drivers, most Tx calibration (except
+ * for Tx Power) and most Rx calibration is done by uCode during the
+ * "initialize" phase of uCode boot.  Driver must calibrate only:
+ *
+ * 1)  Tx power (depends on temperature), described elsewhere
+ * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
+ * 3)  Receiver sensitivity (to optimize signal detection)
+ *
+ *****************************************************************************/
+
+/**
+ * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
+ *
+ * This command sets up the Rx signal detector for a sensitivity level that
+ * is high enough to lock onto all signals within the associated network,
+ * but low enough to ignore signals that are below a certain threshold, so as
+ * not to have too many "false alarms".  False alarms are signals that the
+ * Rx DSP tries to lock onto, but then discards after determining that they
+ * are noise.
+ *
+ * The optimum number of false alarms is between 5 and 50 per 200 TUs
+ * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
+ * time listening, not transmitting).  Driver must adjust sensitivity so that
+ * the ratio of actual false alarms to actual Rx time falls within this range.
+ *
+ * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
+ * received beacon.  These provide information to the driver to analyze the
+ * sensitivity.  Don't analyze statistics that come in from scanning, or any
+ * other non-associated-network source.  Pertinent statistics include:
+ *
+ * From "general" statistics (struct statistics_rx_non_phy):
+ *
+ * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
+ *   Measure of energy of desired signal.  Used for establishing a level
+ *   below which the device does not detect signals.
+ *
+ * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
+ *   Measure of background noise in silent period after beacon.
+ *
+ * channel_load
+ *   uSecs of actual Rx time during beacon period (varies according to
+ *   how much time was spent transmitting).
+ *
+ * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
+ *
+ * false_alarm_cnt
+ *   Signal locks abandoned early (before phy-level header).
+ *
+ * plcp_err
+ *   Signal locks abandoned late (during phy-level header).
+ *
+ * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
+ *        beacon to beacon, i.e. each value is an accumulation of all errors
+ *        before and including the latest beacon.  Values will wrap around to 0
+ *        after counting up to 2^32 - 1.  Driver must differentiate vs.
+ *        previous beacon's values to determine # false alarms in the current
+ *        beacon period.
+ *
+ * Total number of false alarms = false_alarms + plcp_errs
+ *
+ * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for OFDM are at or close to settings for
+ * maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
+ *
+ *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
+ *   by *adding* 1 to all 4 of the table entries above, up to the max for
+ *   each entry.  Conversely, if false alarm rate is too low (less than 5
+ *   for each 204.8 msecs listening), *subtract* 1 from each entry to
+ *   increase sensitivity.
+ *
+ * For CCK sensitivity, keep track of the following:
+ *
+ *   1).  20-beacon history of maximum background noise, indicated by
+ *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
+ *        3 receivers.  For any given beacon, the "silence reference" is
+ *        the maximum of last 60 samples (20 beacons * 3 receivers).
+ *
+ *   2).  10-beacon history of strongest signal level, as indicated
+ *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
+ *        i.e. the strength of the signal through the best receiver at the
+ *        moment.  These measurements are "upside down", with lower values
+ *        for stronger signals, so max energy will be *minimum* value.
+ *
+ *        Then for any given beacon, the driver must determine the *weakest*
+ *        of the strongest signals; this is the minimum level that needs to be
+ *        successfully detected, when using the best receiver at the moment.
+ *        "Max cck energy" is the maximum (higher value means lower energy!)
+ *        of the last 10 minima.  Once this is determined, driver must add
+ *        a little margin by adding "6" to it.
+ *
+ *   3).  Number of consecutive beacon periods with too few false alarms.
+ *        Reset this to 0 at the first beacon period that falls within the
+ *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
+ *
+ * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for CCK are at maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
+ *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), method for reducing
+ *   sensitivity is:
+ *
+ *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       up to max 400.
+ *
+ *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
+ *       sensitivity has been reduced a significant amount; bring it up to
+ *       a moderate 161.  Otherwise, *add* 3, up to max 200.
+ *
+ *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
+ *       sensitivity has been reduced only a moderate or small amount;
+ *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
+ *       down to min 0.  Otherwise (if gain has been significantly reduced),
+ *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
+ *
+ *       b)  Save a snapshot of the "silence reference".
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too low
+ *   (less than 5 for each 204.8 msecs listening), method for increasing
+ *   sensitivity is used only if:
+ *
+ *   1a)  Previous beacon did not have too many false alarms
+ *   1b)  AND difference between previous "silence reference" and current
+ *        "silence reference" (prev - current) is 2 or more,
+ *   OR 2)  100 or more consecutive beacon periods have had rate of
+ *          less than 5 false alarms per 204.8 milliseconds rx time.
+ *
+ *   Method for increasing sensitivity:
+ *
+ *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
+ *       down to min 125.
+ *
+ *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       down to min 200.
+ *
+ *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
+ *   (between 5 and 50 for each 204.8 msecs listening):
+ *
+ *   1)  Save a snapshot of the silence reference.
+ *
+ *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
+ *       give some extra margin to energy threshold by *subtracting* 8
+ *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
+ *
+ *   For all cases (too few, too many, good range), make sure that the CCK
+ *   detection threshold (energy) is below the energy level for robust
+ *   detection over the past 10 beacon periods, the "Max cck energy".
+ *   Lower values mean higher energy; this means making sure that the value
+ *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
+ *
+ * Driver should set the following entries to fixed values:
+ *
+ *   HD_MIN_ENERGY_OFDM_DET_INDEX               100
+ *   HD_BARKER_CORR_TH_ADD_MIN_INDEX            190
+ *   HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX        390
+ *   HD_OFDM_ENERGY_TH_IN_INDEX                  62
+ */
+
+/*
+ * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
+ */
+#define HD_TABLE_SIZE  (11)	/* number of entries */
+#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)	/* table indexes */
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
+
+/* Control field in struct iwl4965_sensitivity_cmd */
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	__constant_cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	__constant_cpu_to_le16(1)
+
+/**
+ * struct iwl4965_sensitivity_cmd
+ * @control:  (1) updates working table, (0) updates default table
+ * @table:  energy threshold values, use HD_* as index into table
+ *
+ * Always use "1" in "control" to update uCode's working table and DSP.
+ */
+struct iwl4965_sensitivity_cmd {
+	__le16 control;			/* always use "1" */
+	__le16 table[HD_TABLE_SIZE];	/* use HD_* as index */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
+ *
+ * This command sets the relative gains of 4965's 3 radio receiver chains.
+ *
+ * After the first association, driver should accumulate signal and noise
+ * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
+ * beacons from the associated network (don't collect statistics that come
+ * in from scanning, or any other non-network source).
+ *
+ * DISCONNECTED ANTENNA:
+ *
+ * Driver should determine which antennas are actually connected, by comparing
+ * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
+ * following values over 20 beacons, one accumulator for each of the chains
+ * a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the strongest signal from among a/b/c.  Compare the other two to the
+ * strongest.  If any signal is more than 15 dB (times 20, unless you
+ * divide the accumulated values by 20) below the strongest, the driver
+ * considers that antenna to be disconnected, and should not try to use that
+ * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
+ * driver should declare the stronger one as connected, and attempt to use it
+ * (A and B are the only 2 Tx chains!).
+ *
+ *
+ * RX BALANCE:
+ *
+ * Driver should balance the 3 receivers (but just the ones that are connected
+ * to antennas, see above) for gain, by comparing the average signal levels
+ * detected during the silence after each beacon (background noise).
+ * Accumulate (add) the following values over 20 beacons, one accumulator for
+ * each of the chains a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the weakest background noise level from among a/b/c.  This Rx chain
+ * will be the reference, with 0 gain adjustment.  Attenuate other channels by
+ * finding noise difference:
+ *
+ * (accum_noise[i] - accum_noise[reference]) / 30
+ *
+ * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
+ * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
+ * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
+ * and set bit 2 to indicate "reduce gain".  The value for the reference
+ * (weakest) chain should be "0".
+ *
+ * diff_gain_[abc] bit fields:
+ *   2: (1) reduce gain, (0) increase gain
+ * 1-0: amount of gain, units of 1.5 dB
+ */
+
+/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+
+struct iwl4965_calibration_cmd {
+	u8 opCode;		/* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
+	u8 flags;		/* not used */
+	__le16 reserved;
+	s8 diff_gain_a;		/* see above */
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl4965_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl4965_rx_packet {
+	__le32 len;
+	struct iwl4965_cmd_header hdr;
+	union {
+		struct iwl4965_alive_resp alive_frame;
+		struct iwl4965_rx_frame rx_frame;
+		struct iwl4965_tx_resp tx_resp;
+		struct iwl4965_spectrum_notification spectrum_notif;
+		struct iwl4965_csa_notification csa_notif;
+		struct iwl4965_error_resp err_resp;
+		struct iwl4965_card_state_notif card_state_notif;
+		struct iwl4965_beacon_notif beacon_status;
+		struct iwl4965_add_sta_resp add_sta;
+		struct iwl4965_sleep_notification sleep_notif;
+		struct iwl4965_spectrum_resp spectrum;
+		struct iwl4965_notif_statistics stats;
+		struct iwl4965_compressed_ba_resp compressed_ba;
+		struct iwl4965_missed_beacon_notif missed_beacon;
+		__le32 status;
+		u8 raw[0];
+	} u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
+
+#endif				/* __iwl4965_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h
new file mode 100644
index 0000000..00bc1fa
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl4965_debug_h__
+#define __iwl4965_debug_h__
+
+#ifdef CONFIG_IWL4965_DEBUG
+extern u32 iwl4965_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl4965_debug_level & (level)) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif				/* CONFIG_IWL4965_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IWL_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl4965_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWL4965_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO          (1<<0)
+#define IWL_DL_MAC80211      (1<<1)
+#define IWL_DL_HOST_COMMAND  (1<<2)
+#define IWL_DL_STATE         (1<<3)
+
+#define IWL_DL_RADIO         (1<<7)
+#define IWL_DL_POWER         (1<<8)
+#define IWL_DL_TEMP          (1<<9)
+
+#define IWL_DL_NOTIF         (1<<10)
+#define IWL_DL_SCAN          (1<<11)
+#define IWL_DL_ASSOC         (1<<12)
+#define IWL_DL_DROP          (1<<13)
+
+#define IWL_DL_TXPOWER       (1<<14)
+
+#define IWL_DL_AP            (1<<15)
+
+#define IWL_DL_FW            (1<<16)
+#define IWL_DL_RF_KILL       (1<<17)
+#define IWL_DL_FW_ERRORS     (1<<18)
+
+#define IWL_DL_LED           (1<<19)
+
+#define IWL_DL_RATE          (1<<20)
+
+#define IWL_DL_CALIB         (1<<21)
+#define IWL_DL_WEP           (1<<22)
+#define IWL_DL_TX            (1<<23)
+#define IWL_DL_RX            (1<<24)
+#define IWL_DL_ISR           (1<<25)
+#define IWL_DL_HT            (1<<26)
+#define IWL_DL_IO            (1<<27)
+#define IWL_DL_11H           (1<<28)
+
+#define IWL_DL_STATS         (1<<29)
+#define IWL_DL_TX_REPLY      (1<<30)
+#define IWL_DL_QOS           (1<<31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...)    IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...)     IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...)   IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...)   IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...)     IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...)     IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...)    IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...)    IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+	IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...)  IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index 5e958a7..7e7d6e4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -60,39 +60,618 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-4965-hw.h) only for hardware-related definitions.
+ * Use iwl-4965-commands.h for uCode API definitions.
+ * Use iwl-4965.h for driver implementation definitions.
+ */
 
 #ifndef __iwl_4965_hw_h__
 #define __iwl_4965_hw_h__
 
-#define IWL_RX_BUF_SIZE (4 * 1024)
-#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
-#define IWL_MAX_INST_SIZE (96 * 1024)
-#define IWL_MAX_DATA_SIZE (40 * 1024)
-
-/********************* START TXPOWER *****************************************/
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
+ * The first queue used for block-ack aggregation is #7 (4965 only).
+ * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7.
+ */
+#define IWL_CMD_QUEUE_NUM       4
+#define IWL_CMD_FIFO_NUM        4
+#define IWL_BACK_QUEUE_FIRST_ID 7
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+#define IWL_HT_RATES 16
+#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#define IWL_RSSI_OFFSET	44
+
+/*
+ * EEPROM related constants, enums, and structures.
+ */
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
+ *   then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
+ *   CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
+
+/*
+ * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
+ *
+ * IBSS and/or AP operation is allowed *only* on those channels with
+ * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
+ * RADAR detection is not supported by the 4965 driver, but is a
+ * requirement for establishing a new network for legal operation on channels
+ * requiring RADAR detection or restricting ACTIVE scanning.
+ *
+ * NOTE:  "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
+ *        It only indicates that 20 MHz channel use is supported; FAT channel
+ *        usage is indicated by a separate set of regulatory flags for each
+ *        FAT channel pair.
+ *
+ * NOTE:  Using a channel inappropriately will result in a uCode error!
+ */
 enum {
-	HT_IE_EXT_CHANNEL_NONE = 0,
-	HT_IE_EXT_CHANNEL_ABOVE,
-	HT_IE_EXT_CHANNEL_INVALID,
-	HT_IE_EXT_CHANNEL_BELOW,
-	HT_IE_EXT_CHANNEL_MAX
+	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
+	EEPROM_CHANNEL_IBSS = (1 << 1),		/* usable as an IBSS channel */
+	/* Bit 2 Reserved */
+	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
+	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
+	EEPROM_CHANNEL_WIDE = (1 << 5),		/* 20 MHz channel okay */
+	EEPROM_CHANNEL_NARROW = (1 << 6),	/* 10 MHz channel (not used) */
+	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
 };
 
-enum {
-	CALIB_CH_GROUP_1 = 0,
-	CALIB_CH_GROUP_2 = 1,
-	CALIB_CH_GROUP_3 = 2,
-	CALIB_CH_GROUP_4 = 3,
-	CALIB_CH_GROUP_5 = 4,
-	CALIB_CH_GROUP_MAX
-};
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
+
+/* *regulatory* channel data format in eeprom, one for each channel.
+ * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
+struct iwl4965_eeprom_channel {
+	u8 flags;		/* EEPROM_CHANNEL_* flags copied from EEPROM */
+	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/* 4965 has two radio transmitters (and 3 radio receivers) */
+#define EEPROM_TX_POWER_TX_CHAINS      (2)
+
+/* 4965 has room for up to 8 sets of txpower calibration data */
+#define EEPROM_TX_POWER_BANDS          (8)
+
+/* 4965 factory calibration measures txpower gain settings for
+ * each of 3 target output levels */
+#define EEPROM_TX_POWER_MEASUREMENTS   (3)
+
+/* 4965 driver does not work with txpower calibration version < 5.
+ * Look for this in calib_version member of struct iwl4965_eeprom. */
+#define EEPROM_TX_POWER_VERSION_NEW    (5)
+
+
+/*
+ * 4965 factory calibration data for one txpower level, on one channel,
+ * measured on one of the 2 tx chains (radio transmitter and associated
+ * antenna).  EEPROM contains:
+ *
+ * 1)  Temperature (degrees Celsius) of device when measurement was made.
+ *
+ * 2)  Gain table index used to achieve the target measurement power.
+ *     This refers to the "well-known" gain tables (see iwl-4965-hw.h).
+ *
+ * 3)  Actual measured output power, in half-dBm ("34" = 17 dBm).
+ *
+ * 4)  RF power amplifier detector level measurement (not used).
+ */
+struct iwl4965_eeprom_calib_measure {
+	u8 temperature;		/* Device temperature (Celsius) */
+	u8 gain_idx;		/* Index into gain table */
+	u8 actual_pow;		/* Measured RF output power, half-dBm */
+	s8 pa_det;		/* Power amp detector level (not used) */
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 measurement set for one channel.  EEPROM contains:
+ *
+ * 1)  Channel number measured
+ *
+ * 2)  Measurements for each of 3 power levels for each of 2 radio transmitters
+ *     (a.k.a. "tx chains") (6 measurements altogether)
+ */
+struct iwl4965_eeprom_calib_ch_info {
+	u8 ch_num;
+	struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+		[EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+/*
+ * 4965 txpower subband info.
+ *
+ * For each frequency subband, EEPROM contains the following:
+ *
+ * 1)  First and last channels within range of the subband.  "0" values
+ *     indicate that this sample set is not being used.
+ *
+ * 2)  Sample measurement sets for 2 channels close to the range endpoints.
+ */
+struct iwl4965_eeprom_calib_subband_info {
+	u8 ch_from;	/* channel number of lowest channel in subband */
+	u8 ch_to;	/* channel number of highest channel in subband */
+	struct iwl4965_eeprom_calib_ch_info ch1;
+	struct iwl4965_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 txpower calibration info.  EEPROM contains:
+ *
+ * 1)  Factory-measured saturation power levels (maximum levels at which
+ *     tx power amplifier can output a signal without too much distortion).
+ *     There is one level for 2.4 GHz band and one for 5 GHz band.  These
+ *     values apply to all channels within each of the bands.
+ *
+ * 2)  Factory-measured power supply voltage level.  This is assumed to be
+ *     constant (i.e. same value applies to all channels/bands) while the
+ *     factory measurements are being made.
+ *
+ * 3)  Up to 8 sets of factory-measured txpower calibration values.
+ *     These are for different frequency ranges, since txpower gain
+ *     characteristics of the analog radio circuitry vary with frequency.
+ *
+ *     Not all sets need to be filled with data;
+ *     struct iwl4965_eeprom_calib_subband_info contains range of channels
+ *     (0 if unused) for each set of data.
+ */
+struct iwl4965_eeprom_calib_info {
+	u8 saturation_power24;	/* half-dBm (e.g. "34" = 17 dBm) */
+	u8 saturation_power52;	/* half-dBm */
+	s16 voltage;		/* signed */
+	struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 EEPROM map
+ */
+struct iwl4965_eeprom {
+	u8 reserved0[16];
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+	u16 device_id;		/* abs.ofs: 16 */
+	u8 reserved1[2];
+#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
+	u16 pmc;		/* abs.ofs: 20 */
+	u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+	u8 mac_address[6];	/* abs.ofs: 42 */
+	u8 reserved3[58];
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+	u16 board_revision;	/* abs.ofs: 106 */
+	u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+	u8 board_pba_number[9];	/* abs.ofs: 119 */
+	u8 reserved5[8];
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+	u16 version;		/* abs.ofs: 136 */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
+	u8 sku_cap;		/* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
+	u8 leds_mode;		/* abs.ofs: 139 */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+	u16 oem_mode;
+#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
+	u8 leds_off_time;	/* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
+	u8 leds_on_time;	/* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
+	u8 almgor_m_version;	/* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
+	u8 antenna_switch_type;	/* abs.ofs: 149 */
+	u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION          (2*0x4F)	/* 2 bytes */
+	u16 board_revision_4965;	/* abs.ofs: 158 */
+	u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA               (2*0x56+1)	/* 9 bytes */
+	u8 board_pba_number_4965[9];	/* abs.ofs: 173 */
+	u8 reserved8[10];
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
+	u8 sku_id[4];		/* abs.ofs: 192 */
+
+/*
+ * Per-channel regulatory data.
+ *
+ * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
+ * txpower (MSB).
+ *
+ * Entries immediately below are for 20 MHz channel width.  FAT (40 MHz)
+ * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
+ *
+ * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
+	u16 band_1_count;	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
+	struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+
+/*
+ * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
+ * 5.0 GHz channels 7, 8, 11, 12, 16
+ * (4915-5080MHz) (none of these is ever supported)
+ */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
+	u16 band_2_count;	/* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
+	struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+
+/*
+ * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+ * (5170-5320MHz)
+ */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
+	u16 band_3_count;	/* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
+	struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+
+/*
+ * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+ * (5500-5700MHz)
+ */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
+	u16 band_4_count;	/* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
+	struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+
+/*
+ * 5.7 GHz channels 145, 149, 153, 157, 161, 165
+ * (5725-5825MHz)
+ */
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
+	u16 band_5_count;	/* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
+	struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
+
+	u8 reserved10[2];
+
+
+/*
+ * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
+ *
+ * The channel listed is the center of the lower 20 MHz half of the channel.
+ * The overall center frequency is actually 2 channels (10 MHz) above that,
+ * and the upper half of each FAT channel is centered 4 channels (20 MHz) away
+ * from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
+ * and the overall FAT channel width centers on channel 3.
+ *
+ * NOTE:  The RXON command uses 20 MHz channel numbers to specify the
+ *        control channel to which to tune.  RXON also specifies whether the
+ *        control channel is the upper or lower half of a FAT channel.
+ *
+ * NOTE:  4965 does not support FAT channels on 2.4 GHz.
+ */
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0)	/* 14 bytes */
+	struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
+	u8 reserved11[2];
+
+/*
+ * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
+ * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
+ */
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)	/* 22 bytes */
+	struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
+	u8 reserved12[6];
+
+/*
+ * 4965 driver requires txpower calibration format version 5 or greater.
+ * Driver does not work with txpower calibration version < 5.
+ * This value is simply a 16-bit number, no major/minor versions here.
+ */
+#define EEPROM_CALIB_VERSION_OFFSET            (2*0xB6)	/* 2 bytes */
+	u16 calib_version;	/* abs.ofs: 364 */
+	u8 reserved13[2];
+	u8 reserved14[96];	/* abs.ofs: 368 */
+
+/*
+ * 4965 Txpower calibration data.
+ */
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET        (2*0xE8)	/* 48  bytes */
+	struct iwl4965_eeprom_calib_info calib_info;	/* abs.ofs: 464 */
+
+	u8 reserved16[140];	/* fill out to full 1024 byte block */
 
-#define POWER_TABLE_NUM_HT_OFDM_ENTRIES           (32)
 
-/* Temperature calibration offset is 3% 0C in Kelvin */
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+/* End of EEPROM */
+
+#include "iwl-4965-commands.h"
+
+#define PCI_LINK_CTRL      0x0F0
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
+
+#define CSR_SW_VER              (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL            (CSR_BASE+0x024)
+
+/*
+ * Hardware revision info
+ * Bit fields:
+ * 31-8:  Reserved
+ *  7-4:  Type of device:  0x0 = 4965, 0xd = 3945
+ *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
+ *  1-0:  "Dash" value, as in A-1, etc.
+ *
+ * NOTE:  Revision step affects calculation of CCK txpower for 4965.
+ */
+#define CSR_HW_REV              (CSR_BASE+0x028)
+
+/* EEPROM reads */
+#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+
+/*
+ * Indicates hardware rev, to determine CCK backoff for txpower calculation.
+ * Bit fields:
+ *  3-2:  0 = A, 1 = B, 2 = C, 3 = D step
+ */
+#define CSR_HW_REV_WA_REG	(CSR_BASE+0x22C)
+
+/* Hardware interface configuration bits */
+#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R	(0x00000010)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0)
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
+
+/*
+ * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
+ * structures, error log, event log, verifying uCode load).
+ * First write to address register, then read from or write to data register
+ * to complete the job.  Once the address register is set up, accesses to
+ * data registers auto-increment the address by one dword.
+ * Bit usage for address registers (read or write):
+ *  0-31:  memory address within device
+ */
+#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
+
+/*
+ * Registers for accessing device's internal peripheral registers
+ * (e.g. SCD, BSM, etc.).  First write to address register,
+ * then read from or write to data register to complete the job.
+ * Bit usage for address registers (read or write):
+ *  0-15:  register address (offset) within device
+ * 24-25:  (# bytes - 1) to read or write (e.g. 3 for dword)
+ */
+#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
+
+/*
+ * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Driver sets this to indicate index to next TFD that driver will fill
+ * (1 past latest filled).
+ * Bit usage:
+ *  0-7:  queue write index (0-255)
+ * 11-8:  queue selector (0-15)
+ */
+#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
+
+#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
+
+#define TFD_QUEUE_SIZE_MAX      (256)
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+#define IWL_DEFAULT_TX_RETRY  15
+
+#define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
+#define RX_QUEUE_SIZE_LOG                     8
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \
+			      sizeof(struct iwl4965_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+/* Size of one Rx buffer in host DRAM */
+#define IWL_RX_BUF_SIZE_4K (4 * 1024)
+#define IWL_RX_BUF_SIZE_8K (8 * 1024)
+
+/* Sizes and addresses for instruction and data memory (SRAM) in
+ * 4965's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
+#define RTC_INST_LOWER_BOUND			(0x000000)
+#define KDR_RTC_INST_UPPER_BOUND		(0x018000)
+
+#define RTC_DATA_LOWER_BOUND			(0x800000)
+#define KDR_RTC_DATA_UPPER_BOUND		(0x80A000)
+
+#define KDR_RTC_INST_SIZE    (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define KDR_RTC_DATA_SIZE    (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE
+
+/* Size of uCode instruction memory in bootstrap state machine */
+#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+
+static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
+{
+	return (addr >= RTC_DATA_LOWER_BOUND) &&
+	       (addr < KDR_RTC_DATA_UPPER_BOUND);
+}
+
+/********************* START TEMPERATURE *************************************/
+
+/**
+ * 4965 temperature calculation.
+ *
+ * The driver must calculate the device temperature before calculating
+ * a txpower setting (amplifier gain is temperature dependent).  The
+ * calculation uses 4 measurements, 3 of which (R1, R2, R3) are calibration
+ * values used for the life of the driver, and one of which (R4) is the
+ * real-time temperature indicator.
+ *
+ * uCode provides all 4 values to the driver via the "initialize alive"
+ * notification (see struct iwl4965_init_alive_resp).  After the runtime uCode
+ * image loads, uCode updates the R4 value via statistics notifications
+ * (see STATISTICS_NOTIFICATION), which occur after each received beacon
+ * when associated, or can be requested via REPLY_STATISTICS_CMD.
+ *
+ * NOTE:  uCode provides the R4 value as a 23-bit signed value.  Driver
+ *        must sign-extend to 32 bits before applying formula below.
+ *
+ * Formula:
+ *
+ * degrees Kelvin = ((97 * 259 * (R4 - R2) / (R3 - R1)) / 100) + 8
+ *
+ * NOTE:  The basic formula is 259 * (R4-R2) / (R3-R1).  The 97/100 is
+ * an additional correction, which should be centered around 0 degrees
+ * Celsius (273 degrees Kelvin).  The 8 (3 percent of 273) compensates for
+ * centering the 97/100 correction around 0 degrees K.
+ *
+ * Add 273 to Kelvin value to find degrees Celsius, for comparing current
+ * temperature with factory-measured temperatures when calculating txpower
+ * settings.
+ */
 #define TEMPERATURE_CALIB_KELVIN_OFFSET 8
 #define TEMPERATURE_CALIB_A_VAL 259
 
+/* Limit range of calculated temperature to be between these Kelvin values */
 #define IWL_TX_POWER_TEMPERATURE_MIN  (263)
 #define IWL_TX_POWER_TEMPERATURE_MAX  (410)
 
@@ -100,383 +679,875 @@ enum {
 	(((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \
 	 ((t) > IWL_TX_POWER_TEMPERATURE_MAX))
 
-#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300)
+/********************* END TEMPERATURE ***************************************/
 
-#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2)
+/********************* START TXPOWER *****************************************/
 
-#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
+/**
+ * 4965 txpower calculations rely on information from three sources:
+ *
+ *     1) EEPROM
+ *     2) "initialize" alive notification
+ *     3) statistics notifications
+ *
+ * EEPROM data consists of:
+ *
+ * 1)  Regulatory information (max txpower and channel usage flags) is provided
+ *     separately for each channel that can possibly supported by 4965.
+ *     40 MHz wide (.11n fat) channels are listed separately from 20 MHz
+ *     (legacy) channels.
+ *
+ *     See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom
+ *     for locations in EEPROM.
+ *
+ * 2)  Factory txpower calibration information is provided separately for
+ *     sub-bands of contiguous channels.  2.4GHz has just one sub-band,
+ *     but 5 GHz has several sub-bands.
+ *
+ *     In addition, per-band (2.4 and 5 Ghz) saturation txpowers are provided.
+ *
+ *     See struct iwl4965_eeprom_calib_info (and the tree of structures
+ *     contained within it) for format, and struct iwl4965_eeprom for
+ *     locations in EEPROM.
+ *
+ * "Initialization alive" notification (see struct iwl4965_init_alive_resp)
+ * consists of:
+ *
+ * 1)  Temperature calculation parameters.
+ *
+ * 2)  Power supply voltage measurement.
+ *
+ * 3)  Tx gain compensation to balance 2 transmitters for MIMO use.
+ *
+ * Statistics notifications deliver:
+ *
+ * 1)  Current values for temperature param R4.
+ */
 
+/**
+ * To calculate a txpower setting for a given desired target txpower, channel,
+ * modulation bit rate, and transmitter chain (4965 has 2 transmitters to
+ * support MIMO and transmit diversity), driver must do the following:
+ *
+ * 1)  Compare desired txpower vs. (EEPROM) regulatory limit for this channel.
+ *     Do not exceed regulatory limit; reduce target txpower if necessary.
+ *
+ *     If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31),
+ *     2 transmitters will be used simultaneously; driver must reduce the
+ *     regulatory limit by 3 dB (half-power) for each transmitter, so the
+ *     combined total output of the 2 transmitters is within regulatory limits.
+ *
+ *
+ * 2)  Compare target txpower vs. (EEPROM) saturation txpower *reduced by
+ *     backoff for this bit rate*.  Do not exceed (saturation - backoff[rate]);
+ *     reduce target txpower if necessary.
+ *
+ *     Backoff values below are in 1/2 dB units (equivalent to steps in
+ *     txpower gain tables):
+ *
+ *     OFDM 6 - 36 MBit:  10 steps (5 dB)
+ *     OFDM 48 MBit:      15 steps (7.5 dB)
+ *     OFDM 54 MBit:      17 steps (8.5 dB)
+ *     OFDM 60 MBit:      20 steps (10 dB)
+ *     CCK all rates:     10 steps (5 dB)
+ *
+ *     Backoff values apply to saturation txpower on a per-transmitter basis;
+ *     when using MIMO (2 transmitters), each transmitter uses the same
+ *     saturation level provided in EEPROM, and the same backoff values;
+ *     no reduction (such as with regulatory txpower limits) is required.
+ *
+ *     Saturation and Backoff values apply equally to 20 Mhz (legacy) channel
+ *     widths and 40 Mhz (.11n fat) channel widths; there is no separate
+ *     factory measurement for fat channels.
+ *
+ *     The result of this step is the final target txpower.  The rest of
+ *     the steps figure out the proper settings for the device to achieve
+ *     that target txpower.
+ *
+ *
+ * 3)  Determine (EEPROM) calibration subband for the target channel, by
+ *     comparing against first and last channels in each subband
+ *     (see struct iwl4965_eeprom_calib_subband_info).
+ *
+ *
+ * 4)  Linearly interpolate (EEPROM) factory calibration measurement sets,
+ *     referencing the 2 factory-measured (sample) channels within the subband.
+ *
+ *     Interpolation is based on difference between target channel's frequency
+ *     and the sample channels' frequencies.  Since channel numbers are based
+ *     on frequency (5 MHz between each channel number), this is equivalent
+ *     to interpolating based on channel number differences.
+ *
+ *     Note that the sample channels may or may not be the channels at the
+ *     edges of the subband.  The target channel may be "outside" of the
+ *     span of the sampled channels.
+ *
+ *     Driver may choose the pair (for 2 Tx chains) of measurements (see
+ *     struct iwl4965_eeprom_calib_ch_info) for which the actual measured
+ *     txpower comes closest to the desired txpower.  Usually, though,
+ *     the middle set of measurements is closest to the regulatory limits,
+ *     and is therefore a good choice for all txpower calculations (this
+ *     assumes that high accuracy is needed for maximizing legal txpower,
+ *     while lower txpower configurations do not need as much accuracy).
+ *
+ *     Driver should interpolate both members of the chosen measurement pair,
+ *     i.e. for both Tx chains (radio transmitters), unless the driver knows
+ *     that only one of the chains will be used (e.g. only one tx antenna
+ *     connected, but this should be unusual).  The rate scaling algorithm
+ *     switches antennas to find best performance, so both Tx chains will
+ *     be used (although only one at a time) even for non-MIMO transmissions.
+ *
+ *     Driver should interpolate factory values for temperature, gain table
+ *     index, and actual power.  The power amplifier detector values are
+ *     not used by the driver.
+ *
+ *     Sanity check:  If the target channel happens to be one of the sample
+ *     channels, the results should agree with the sample channel's
+ *     measurements!
+ *
+ *
+ * 5)  Find difference between desired txpower and (interpolated)
+ *     factory-measured txpower.  Using (interpolated) factory gain table index
+ *     (shown elsewhere) as a starting point, adjust this index lower to
+ *     increase txpower, or higher to decrease txpower, until the target
+ *     txpower is reached.  Each step in the gain table is 1/2 dB.
+ *
+ *     For example, if factory measured txpower is 16 dBm, and target txpower
+ *     is 13 dBm, add 6 steps to the factory gain index to reduce txpower
+ *     by 3 dB.
+ *
+ *
+ * 6)  Find difference between current device temperature and (interpolated)
+ *     factory-measured temperature for sub-band.  Factory values are in
+ *     degrees Celsius.  To calculate current temperature, see comments for
+ *     "4965 temperature calculation".
+ *
+ *     If current temperature is higher than factory temperature, driver must
+ *     increase gain (lower gain table index), and vice versa.
+ *
+ *     Temperature affects gain differently for different channels:
+ *
+ *     2.4 GHz all channels:  3.5 degrees per half-dB step
+ *     5 GHz channels 34-43:  4.5 degrees per half-dB step
+ *     5 GHz channels >= 44:  4.0 degrees per half-dB step
+ *
+ *     NOTE:  Temperature can increase rapidly when transmitting, especially
+ *            with heavy traffic at high txpowers.  Driver should update
+ *            temperature calculations often under these conditions to
+ *            maintain strong txpower in the face of rising temperature.
+ *
+ *
+ * 7)  Find difference between current power supply voltage indicator
+ *     (from "initialize alive") and factory-measured power supply voltage
+ *     indicator (EEPROM).
+ *
+ *     If the current voltage is higher (indicator is lower) than factory
+ *     voltage, gain should be reduced (gain table index increased) by:
+ *
+ *     (eeprom - current) / 7
+ *
+ *     If the current voltage is lower (indicator is higher) than factory
+ *     voltage, gain should be increased (gain table index decreased) by:
+ *
+ *     2 * (current - eeprom) / 7
+ *
+ *     If number of index steps in either direction turns out to be > 2,
+ *     something is wrong ... just use 0.
+ *
+ *     NOTE:  Voltage compensation is independent of band/channel.
+ *
+ *     NOTE:  "Initialize" uCode measures current voltage, which is assumed
+ *            to be constant after this initial measurement.  Voltage
+ *            compensation for txpower (number of steps in gain table)
+ *            may be calculated once and used until the next uCode bootload.
+ *
+ *
+ * 8)  If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31),
+ *     adjust txpower for each transmitter chain, so txpower is balanced
+ *     between the two chains.  There are 5 pairs of tx_atten[group][chain]
+ *     values in "initialize alive", one pair for each of 5 channel ranges:
+ *
+ *     Group 0:  5 GHz channel 34-43
+ *     Group 1:  5 GHz channel 44-70
+ *     Group 2:  5 GHz channel 71-124
+ *     Group 3:  5 GHz channel 125-200
+ *     Group 4:  2.4 GHz all channels
+ *
+ *     Add the tx_atten[group][chain] value to the index for the target chain.
+ *     The values are signed, but are in pairs of 0 and a non-negative number,
+ *     so as to reduce gain (if necessary) of the "hotter" channel.  This
+ *     avoids any need to double-check for regulatory compliance after
+ *     this step.
+ *
+ *
+ * 9)  If setting up for a CCK rate, lower the gain by adding a CCK compensation
+ *     value to the index:
+ *
+ *     Hardware rev B:  9 steps (4.5 dB)
+ *     Hardware rev C:  5 steps (2.5 dB)
+ *
+ *     Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG,
+ *     bits [3:2], 1 = B, 2 = C.
+ *
+ *     NOTE:  This compensation is in addition to any saturation backoff that
+ *            might have been applied in an earlier step.
+ *
+ *
+ * 10) Select the gain table, based on band (2.4 vs 5 GHz).
+ *
+ *     Limit the adjusted index to stay within the table!
+ *
+ *
+ * 11) Read gain table entries for DSP and radio gain, place into appropriate
+ *     location(s) in command (struct iwl4965_txpowertable_cmd).
+ */
+
+/* Limit range of txpower output target to be between these values */
 #define IWL_TX_POWER_TARGET_POWER_MIN       (0)	/* 0 dBm = 1 milliwatt */
 #define IWL_TX_POWER_TARGET_POWER_MAX      (16)	/* 16 dBm */
 
-/* timeout equivalent to 3 minutes */
-#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000
-
-#define IWL_TX_POWER_CCK_COMPENSATION (9)
-
-#define MIN_TX_GAIN_INDEX		(0)
-#define MIN_TX_GAIN_INDEX_52GHZ_EXT	(-9)
-#define MAX_TX_GAIN_INDEX_52GHZ		(98)
-#define MIN_TX_GAIN_52GHZ		(98)
-#define MAX_TX_GAIN_INDEX_24GHZ		(98)
-#define MIN_TX_GAIN_24GHZ		(98)
-#define MAX_TX_GAIN			(0)
-#define MAX_TX_GAIN_52GHZ_EXT		(-9)
+/**
+ * When MIMO is used (2 transmitters operating simultaneously), driver should
+ * limit each transmitter to deliver a max of 3 dB below the regulatory limit
+ * for the device.  That is, use half power for each transmitter, so total
+ * txpower is within regulatory limits.
+ *
+ * The value "6" represents number of steps in gain table to reduce power 3 dB.
+ * Each step is 1/2 dB.
+ */
+#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
 
+/**
+ * CCK gain compensation.
+ *
+ * When calculating txpowers for CCK, after making sure that the target power
+ * is within regulatory and saturation limits, driver must additionally
+ * back off gain by adding these values to the gain table index.
+ *
+ * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG,
+ * bits [3:2], 1 = B, 2 = C.
+ */
+#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
+#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
+
+/*
+ * 4965 power supply voltage compensation for txpower
+ */
+#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V   (7)
+
+/**
+ * Gain tables.
+ *
+ * The following tables contain pair of values for setting txpower, i.e.
+ * gain settings for the output of the device's digital signal processor (DSP),
+ * and for the analog gain structure of the transmitter.
+ *
+ * Each entry in the gain tables represents a step of 1/2 dB.  Note that these
+ * are *relative* steps, not indications of absolute output power.  Output
+ * power varies with temperature, voltage, and channel frequency, and also
+ * requires consideration of average power (to satisfy regulatory constraints),
+ * and peak power (to avoid distortion of the output signal).
+ *
+ * Each entry contains two values:
+ * 1)  DSP gain (or sometimes called DSP attenuation).  This is a fine-grained
+ *     linear value that multiplies the output of the digital signal processor,
+ *     before being sent to the analog radio.
+ * 2)  Radio gain.  This sets the analog gain of the radio Tx path.
+ *     It is a coarser setting, and behaves in a logarithmic (dB) fashion.
+ *
+ * EEPROM contains factory calibration data for txpower.  This maps actual
+ * measured txpower levels to gain settings in the "well known" tables
+ * below ("well-known" means here that both factory calibration *and* the
+ * driver work with the same table).
+ *
+ * There are separate tables for 2.4 GHz and 5 GHz bands.  The 5 GHz table
+ * has an extension (into negative indexes), in case the driver needs to
+ * boost power setting for high device temperatures (higher than would be
+ * present during factory calibration).  A 5 Ghz EEPROM index of "40"
+ * corresponds to the 49th entry in the table used by the driver.
+ */
+#define MIN_TX_GAIN_INDEX		(0)  /* highest gain, lowest idx, 2.4 */
+#define MIN_TX_GAIN_INDEX_52GHZ_EXT	(-9) /* highest gain, lowest idx, 5 */
+
+/**
+ * 2.4 GHz gain table
+ *
+ * Index    Dsp gain   Radio gain
+ *   0        110         0x3f      (highest gain)
+ *   1        104         0x3f
+ *   2         98         0x3f
+ *   3        110         0x3e
+ *   4        104         0x3e
+ *   5         98         0x3e
+ *   6        110         0x3d
+ *   7        104         0x3d
+ *   8         98         0x3d
+ *   9        110         0x3c
+ *  10        104         0x3c
+ *  11         98         0x3c
+ *  12        110         0x3b
+ *  13        104         0x3b
+ *  14         98         0x3b
+ *  15        110         0x3a
+ *  16        104         0x3a
+ *  17         98         0x3a
+ *  18        110         0x39
+ *  19        104         0x39
+ *  20         98         0x39
+ *  21        110         0x38
+ *  22        104         0x38
+ *  23         98         0x38
+ *  24        110         0x37
+ *  25        104         0x37
+ *  26         98         0x37
+ *  27        110         0x36
+ *  28        104         0x36
+ *  29         98         0x36
+ *  30        110         0x35
+ *  31        104         0x35
+ *  32         98         0x35
+ *  33        110         0x34
+ *  34        104         0x34
+ *  35         98         0x34
+ *  36        110         0x33
+ *  37        104         0x33
+ *  38         98         0x33
+ *  39        110         0x32
+ *  40        104         0x32
+ *  41         98         0x32
+ *  42        110         0x31
+ *  43        104         0x31
+ *  44         98         0x31
+ *  45        110         0x30
+ *  46        104         0x30
+ *  47         98         0x30
+ *  48        110          0x6
+ *  49        104          0x6
+ *  50         98          0x6
+ *  51        110          0x5
+ *  52        104          0x5
+ *  53         98          0x5
+ *  54        110          0x4
+ *  55        104          0x4
+ *  56         98          0x4
+ *  57        110          0x3
+ *  58        104          0x3
+ *  59         98          0x3
+ *  60        110          0x2
+ *  61        104          0x2
+ *  62         98          0x2
+ *  63        110          0x1
+ *  64        104          0x1
+ *  65         98          0x1
+ *  66        110          0x0
+ *  67        104          0x0
+ *  68         98          0x0
+ *  69         97            0
+ *  70         96            0
+ *  71         95            0
+ *  72         94            0
+ *  73         93            0
+ *  74         92            0
+ *  75         91            0
+ *  76         90            0
+ *  77         89            0
+ *  78         88            0
+ *  79         87            0
+ *  80         86            0
+ *  81         85            0
+ *  82         84            0
+ *  83         83            0
+ *  84         82            0
+ *  85         81            0
+ *  86         80            0
+ *  87         79            0
+ *  88         78            0
+ *  89         77            0
+ *  90         76            0
+ *  91         75            0
+ *  92         74            0
+ *  93         73            0
+ *  94         72            0
+ *  95         71            0
+ *  96         70            0
+ *  97         69            0
+ *  98         68            0
+ */
+
+/**
+ * 5 GHz gain table
+ *
+ * Index    Dsp gain   Radio gain
+ *  -9 	      123         0x3F      (highest gain)
+ *  -8 	      117         0x3F
+ *  -7        110         0x3F
+ *  -6        104         0x3F
+ *  -5         98         0x3F
+ *  -4        110         0x3E
+ *  -3        104         0x3E
+ *  -2         98         0x3E
+ *  -1        110         0x3D
+ *   0        104         0x3D
+ *   1         98         0x3D
+ *   2        110         0x3C
+ *   3        104         0x3C
+ *   4         98         0x3C
+ *   5        110         0x3B
+ *   6        104         0x3B
+ *   7         98         0x3B
+ *   8        110         0x3A
+ *   9        104         0x3A
+ *  10         98         0x3A
+ *  11        110         0x39
+ *  12        104         0x39
+ *  13         98         0x39
+ *  14        110         0x38
+ *  15        104         0x38
+ *  16         98         0x38
+ *  17        110         0x37
+ *  18        104         0x37
+ *  19         98         0x37
+ *  20        110         0x36
+ *  21        104         0x36
+ *  22         98         0x36
+ *  23        110         0x35
+ *  24        104         0x35
+ *  25         98         0x35
+ *  26        110         0x34
+ *  27        104         0x34
+ *  28         98         0x34
+ *  29        110         0x33
+ *  30        104         0x33
+ *  31         98         0x33
+ *  32        110         0x32
+ *  33        104         0x32
+ *  34         98         0x32
+ *  35        110         0x31
+ *  36        104         0x31
+ *  37         98         0x31
+ *  38        110         0x30
+ *  39        104         0x30
+ *  40         98         0x30
+ *  41        110         0x25
+ *  42        104         0x25
+ *  43         98         0x25
+ *  44        110         0x24
+ *  45        104         0x24
+ *  46         98         0x24
+ *  47        110         0x23
+ *  48        104         0x23
+ *  49         98         0x23
+ *  50        110         0x22
+ *  51        104         0x18
+ *  52         98         0x18
+ *  53        110         0x17
+ *  54        104         0x17
+ *  55         98         0x17
+ *  56        110         0x16
+ *  57        104         0x16
+ *  58         98         0x16
+ *  59        110         0x15
+ *  60        104         0x15
+ *  61         98         0x15
+ *  62        110         0x14
+ *  63        104         0x14
+ *  64         98         0x14
+ *  65        110         0x13
+ *  66        104         0x13
+ *  67         98         0x13
+ *  68        110         0x12
+ *  69        104         0x08
+ *  70         98         0x08
+ *  71        110         0x07
+ *  72        104         0x07
+ *  73         98         0x07
+ *  74        110         0x06
+ *  75        104         0x06
+ *  76         98         0x06
+ *  77        110         0x05
+ *  78        104         0x05
+ *  79         98         0x05
+ *  80        110         0x04
+ *  81        104         0x04
+ *  82         98         0x04
+ *  83        110         0x03
+ *  84        104         0x03
+ *  85         98         0x03
+ *  86        110         0x02
+ *  87        104         0x02
+ *  88         98         0x02
+ *  89        110         0x01
+ *  90        104         0x01
+ *  91         98         0x01
+ *  92        110         0x00
+ *  93        104         0x00
+ *  94         98         0x00
+ *  95         93         0x00
+ *  96         88         0x00
+ *  97         83         0x00
+ *  98         78         0x00
+ */
+
+
+/**
+ * Sanity checks and default values for EEPROM regulatory levels.
+ * If EEPROM values fall outside MIN/MAX range, use default values.
+ *
+ * Regulatory limits refer to the maximum average txpower allowed by
+ * regulatory agencies in the geographies in which the device is meant
+ * to be operated.  These limits are SKU-specific (i.e. geography-specific),
+ * and channel-specific; each channel has an individual regulatory limit
+ * listed in the EEPROM.
+ *
+ * Units are in half-dBm (i.e. "34" means 17 dBm).
+ */
 #define IWL_TX_POWER_DEFAULT_REGULATORY_24   (34)
 #define IWL_TX_POWER_DEFAULT_REGULATORY_52   (34)
 #define IWL_TX_POWER_REGULATORY_MIN          (0)
 #define IWL_TX_POWER_REGULATORY_MAX          (34)
+
+/**
+ * Sanity checks and default values for EEPROM saturation levels.
+ * If EEPROM values fall outside MIN/MAX range, use default values.
+ *
+ * Saturation is the highest level that the output power amplifier can produce
+ * without significant clipping distortion.  This is a "peak" power level.
+ * Different types of modulation (i.e. various "rates", and OFDM vs. CCK)
+ * require differing amounts of backoff, relative to their average power output,
+ * in order to avoid clipping distortion.
+ *
+ * Driver must make sure that it is violating neither the saturation limit,
+ * nor the regulatory limit, when calculating Tx power settings for various
+ * rates.
+ *
+ * Units are in half-dBm (i.e. "38" means 19 dBm).
+ */
 #define IWL_TX_POWER_DEFAULT_SATURATION_24   (38)
 #define IWL_TX_POWER_DEFAULT_SATURATION_52   (38)
 #define IWL_TX_POWER_SATURATION_MIN          (20)
 #define IWL_TX_POWER_SATURATION_MAX          (50)
 
-/* dv *0.4 = dt; so that 5 degrees temperature diff equals
- * 12.5 in voltage diff */
-#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9
-
-#define IWL_INVALID_CHANNEL                 (0xffffffff)
-#define IWL_TX_POWER_REGITRY_BIT            (2)
-
-#define MIN_IWL_TX_POWER_CALIB_DUR          (100)
-#define IWL_CCK_FROM_OFDM_POWER_DIFF        (-5)
-#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9)
-
-/* Number of entries in the gain table */
-#define POWER_GAIN_NUM_ENTRIES 78
-#define TX_POW_MAX_SESSION_NUM 5
-/*  timeout equivalent to 3 minutes */
-#define TX_IWL_TIMELIMIT_NOCALIB 1800000000
-
-/* Kedron TX_CALIB_STATES */
-#define IWL_TX_CALIB_STATE_SEND_TX        0x00000001
-#define IWL_TX_CALIB_WAIT_TX_RESPONSE     0x00000002
-#define IWL_TX_CALIB_ENABLED              0x00000004
-#define IWL_TX_CALIB_XVT_ON               0x00000008
-#define IWL_TX_CALIB_TEMPERATURE_CORRECT  0x00000010
-#define IWL_TX_CALIB_WORKING_WITH_XVT     0x00000020
-#define IWL_TX_CALIB_XVT_PERIODICAL       0x00000040
-
-#define NUM_IWL_TX_CALIB_SETTINS 5	/* Number of tx correction groups */
-
-#define IWL_MIN_POWER_IN_VP_TABLE 1	/* 0.5dBm multiplied by 2 */
-#define IWL_MAX_POWER_IN_VP_TABLE 40	/* 20dBm - multiplied by 2 (because
-					 * entries are for each 0.5dBm) */
-#define IWL_STEP_IN_VP_TABLE 1	/* 0.5dB - multiplied by 2 */
-#define IWL_NUM_POINTS_IN_VPTABLE \
-	(1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE)
-
-#define MIN_TX_GAIN_INDEX         (0)
-#define MAX_TX_GAIN_INDEX_52GHZ   (98)
-#define MIN_TX_GAIN_52GHZ         (98)
-#define MAX_TX_GAIN_INDEX_24GHZ   (98)
-#define MIN_TX_GAIN_24GHZ         (98)
-#define MAX_TX_GAIN               (0)
-
-/* First and last channels of all groups */
+/**
+ * Channel groups used for Tx Attenuation calibration (MIMO tx channel balance)
+ * and thermal Txpower calibration.
+ *
+ * When calculating txpower, driver must compensate for current device
+ * temperature; higher temperature requires higher gain.  Driver must calculate
+ * current temperature (see "4965 temperature calculation"), then compare vs.
+ * factory calibration temperature in EEPROM; if current temperature is higher
+ * than factory temperature, driver must *increase* gain by proportions shown
+ * in table below.  If current temperature is lower than factory, driver must
+ * *decrease* gain.
+ *
+ * Different frequency ranges require different compensation, as shown below.
+ */
+/* Group 0, 5.2 GHz ch 34-43:  4.5 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR1_FCH 34
 #define CALIB_IWL_TX_ATTEN_GR1_LCH 43
+
+/* Group 1, 5.3 GHz ch 44-70:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR2_FCH 44
 #define CALIB_IWL_TX_ATTEN_GR2_LCH 70
+
+/* Group 2, 5.5 GHz ch 71-124:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR3_FCH 71
 #define CALIB_IWL_TX_ATTEN_GR3_LCH 124
+
+/* Group 3, 5.7 GHz ch 125-200:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR4_FCH 125
 #define CALIB_IWL_TX_ATTEN_GR4_LCH 200
+
+/* Group 4, 2.4 GHz all channels:  3.5 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR5_FCH 1
 #define CALIB_IWL_TX_ATTEN_GR5_LCH 20
 
-struct tx_power_dual_stream {
-	__le16 ramon_tx_gain;
-	__le16 dsp_predis_atten;
-} __attribute__ ((packed));
-
-union tx_power_dual_stream_u {
-	struct tx_power_dual_stream s;
-	__le32 dw;
-} __attribute__ ((packed));
-
-struct iwl_tx_power_db {
-	union tx_power_dual_stream_u
-	 ht_ofdm_power[POWER_TABLE_NUM_HT_OFDM_ENTRIES];
-	union tx_power_dual_stream_u legacy_cck_power;
-
-} __attribute__ ((packed));
-
-struct iwl_tx_power_table_cmd {
-	u8 band;
-	u8 channel_normal_width;
-	__le16 channel;
-	struct iwl_tx_power_db tx_power;
-} __attribute__ ((packed));
+enum {
+	CALIB_CH_GROUP_1 = 0,
+	CALIB_CH_GROUP_2 = 1,
+	CALIB_CH_GROUP_3 = 2,
+	CALIB_CH_GROUP_4 = 3,
+	CALIB_CH_GROUP_5 = 4,
+	CALIB_CH_GROUP_MAX
+};
 
 /********************* END TXPOWER *****************************************/
 
-/* HT flags */
-#define RXON_FLG_CONTROL_CHANNEL_LOCATION_MSK	0x400000
-#define RXON_FLG_CONTROL_CHANNEL_LOC_LOW_MSK	0x000000
-#define RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK	0x400000
-
-#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
-/*yshevet - bug fix */
-#define RXON_FLG_HT_PROT_MSK			0x800000
-#define RXON_FLG_FAT_PROT_MSK			0x1000000
-
-#define RXON_FLG_CHANNEL_MODE_POS		(25)
-#define RXON_FLG_CHANNEL_MODE_MSK		0x06000000
-#define RXON_FLG_CHANNEL_MODE_LEGACY_MSK	0x00000000
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	0x02000000
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		0x04000000
-
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		(0x1<<0)
-#define RXON_RX_CHAIN_VALID_MSK			(0x7<<1)
-#define RXON_RX_CHAIN_VALID_POS			(1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK		(0x7<<4)
-#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	(0x7<<7)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
-#define RXON_RX_CHAIN_CNT_MSK			(0x3<<10)
-#define RXON_RX_CHAIN_CNT_POS			(10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK		(0x3<<12)
-#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK		(0x1<<14)
-#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
-
-
-#define MCS_DUP_6M_PLCP 0x20
-
-/* OFDM HT rate masks */
-/* ***************************************** */
-#define R_MCS_6M_MSK 0x1
-#define R_MCS_12M_MSK 0x2
-#define R_MCS_18M_MSK 0x4
-#define R_MCS_24M_MSK 0x8
-#define R_MCS_36M_MSK 0x10
-#define R_MCS_48M_MSK 0x20
-#define R_MCS_54M_MSK 0x40
-#define R_MCS_60M_MSK 0x80
-#define R_MCS_12M_DUAL_MSK 0x100
-#define R_MCS_24M_DUAL_MSK 0x200
-#define R_MCS_36M_DUAL_MSK 0x400
-#define R_MCS_48M_DUAL_MSK 0x800
-
-#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) (((tbl) == LQ_SISO))
-#define is_mimo(tbl) (((tbl) == LQ_MIMO))
-#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) (((tbl) == LQ_A))
-#define is_g_and(tbl) (((tbl) == LQ_G))
-
-/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
-#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1<<0)
-
-#define  LINK_QUAL_AC_NUM AC_NUM
-#define  LINK_QUAL_MAX_RETRY_NUM 16
-
-#define  LINK_QUAL_ANT_A_MSK (1<<0)
-#define  LINK_QUAL_ANT_B_MSK (1<<1)
-#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
-
-struct iwl_link_qual_general_params {
-	u8 flags;
-	u8 mimo_delimiter;
-	u8 single_stream_ant_msk;
-	u8 dual_stream_ant_msk;
-	u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
-
-struct iwl_link_qual_agg_params {
-	__le16 agg_time_limit;
-	u8 agg_dis_start_th;
-	u8 agg_frame_cnt_limit;
-	__le32 reserved;
-} __attribute__ ((packed));
-
-struct iwl_link_quality_cmd {
-	u8 sta_id;
-	u8 reserved1;
-	__le16 control;
-	struct iwl_link_qual_general_params general_params;
-	struct iwl_link_qual_agg_params agg_params;
-	struct iwl_rate rate_scale_table[LINK_QUAL_MAX_RETRY_NUM];
-	__le32 reserved2;
-} __attribute__ ((packed));
-
-#define STA_FLG_PWR_SAVE_MSK                0x100
-
+/****************************/
 /* Flow Handler Definitions */
+/****************************/
 
-/**********************/
-/*     Addresses      */
-/**********************/
-
+/**
+ * This I/O area is directly read/writable by driver (e.g. Linux uses writel())
+ * Addresses are offsets from device's PCI hardware base address.
+ */
 #define FH_MEM_LOWER_BOUND                   (0x1000)
 #define FH_MEM_UPPER_BOUND                   (0x1EF0)
 
-#define IWL_FH_REGS_LOWER_BOUND		     (0x1000)
-#define IWL_FH_REGS_UPPER_BOUND		     (0x2000)
-
-/* TFDB  Area - TFDs buffer table */
-#define FH_MEM_TFDB_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0x000)
-#define FH_MEM_TFDB_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0x900)
-/* channels 0 - 8 */
-#define FH_MEM_TFDB_CHNL_BUF0(x) (FH_MEM_TFDB_LOWER_BOUND + (x) * 0x100)
-#define FH_MEM_TFDB_CHNL_BUF1(x) (FH_MEM_TFDB_LOWER_BOUND + 0x80 + (x) * 0x100)
-
-/* TFDIB Area - TFD Immediate Buffer */
-#define FH_MEM_TFDIB_LOWER_BOUND	     (FH_MEM_LOWER_BOUND + 0x900)
-#define FH_MEM_TFDIB_UPPER_BOUND	     (FH_MEM_LOWER_BOUND + 0x958)
-/* channels 0 - 10 */
-#define FH_MEM_TFDIB_CHNL(x)     (FH_MEM_TFDIB_LOWER_BOUND + (x) * 0x8)
-
-/* TFDIB registers used in Service Mode */
-#define FH_MEM_TFDIB_CHNL9_REG0		     (FH_MEM_TFDIB_CHNL(9))
-#define FH_MEM_TFDIB_CHNL9_REG1		     (FH_MEM_TFDIB_CHNL(9) + 4)
-#define FH_MEM_TFDIB_CHNL10_REG0	     (FH_MEM_TFDIB_CHNL(10))
-#define FH_MEM_TFDIB_CHNL10_REG1	     (FH_MEM_TFDIB_CHNL(10) + 4)
-
-/* Tx service channels */
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MASK	     (0xFFFFFFFF)
-#define FH_MEM_TFDIB_DRAM_ADDR_MSB_MASK	     (0xF00000000)
-#define FH_MEM_TFDIB_TB_LENGTH_MASK	     (0x0001FFFF)	/* bits 16:0 */
-
-#define FH_MEM_TFDIB_DRAM_ADDR_LSB_BITSHIFT  (0)
-#define FH_MEM_TFDIB_DRAM_ADDR_MSB_BITSHIFT  (32)
-#define FH_MEM_TFDIB_TB_LENGTH_BITSHIFT	     (0)
-
-#define FH_MEM_TFDIB_REG0_ADDR_MASK	     (0xFFFFFFFF)
-#define FH_MEM_TFDIB_REG1_ADDR_MASK	     (0xF0000000)
-#define FH_MEM_TFDIB_REG1_LENGTH_MASK	     (0x0001FFFF)
-
-#define FH_MEM_TFDIB_REG0_ADDR_BITSHIFT	     (0)
-#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT	     (28)
-#define FH_MEM_TFDIB_REG1_LENGTH_BITSHIFT    (0)
-
-/* TRB Area - Transmit Request Buffers */
-#define FH_MEM_TRB_LOWER_BOUND		     (FH_MEM_LOWER_BOUND + 0x0958)
-#define FH_MEM_TRB_UPPER_BOUND		     (FH_MEM_LOWER_BOUND + 0x0980)
-/* channels 0 - 8 */
-#define FH_MEM_TRB_CHNL(x)	   (FH_MEM_TRB_LOWER_BOUND + (x) * 0x4)
-
+/**
+ * Keep-Warm (KW) buffer base address.
+ *
+ * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
+ * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
+ * DRAM access when 4965 is Txing or Rxing.  The dummy accesses prevent host
+ * from going into a power-savings mode that would cause higher DRAM latency,
+ * and possible data over/under-runs, before all Tx/Rx is complete.
+ *
+ * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
+ * of the buffer, which must be 4K aligned.  Once this is set up, the 4965
+ * automatically invokes keep-warm accesses when normal accesses might not
+ * be sufficient to maintain fast DRAM response.
+ *
+ * Bit fields:
+ *  31-0:  Keep-warm buffer physical base address [35:4], must be 4K aligned
+ */
 #define IWL_FH_KW_MEM_ADDR_REG		     (FH_MEM_LOWER_BOUND + 0x97C)
-/* STAGB Area - Scheduler TAG Buffer */
-#define FH_MEM_STAGB_LOWER_BOUND	     (FH_MEM_LOWER_BOUND + 0x980)
-#define FH_MEM_STAGB_UPPER_BOUND	     (FH_MEM_LOWER_BOUND + 0x9D0)
-/* channels 0 - 8 */
-#define FH_MEM_STAGB_0(x)     (FH_MEM_STAGB_LOWER_BOUND + (x) * 0x8)
-#define FH_MEM_STAGB_1(x)     (FH_MEM_STAGB_LOWER_BOUND + 0x4 + (x) * 0x8)
-
-/* Tx service channels */
-#define FH_MEM_SRAM_ADDR_9	     (FH_MEM_STAGB_LOWER_BOUND + 0x048)
-#define FH_MEM_SRAM_ADDR_10	     (FH_MEM_STAGB_LOWER_BOUND + 0x04C)
 
-#define FH_MEM_STAGB_SRAM_ADDR_MASK	     (0x00FFFFFF)
 
-/* CBBC Area - Circular buffers base address cache pointers table */
+/**
+ * TFD Circular Buffers Base (CBBC) addresses
+ *
+ * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
+ * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
+ * (see struct iwl_tfd_frame).  These 16 pointer registers are offset by 0x04
+ * bytes from one another.  Each TFD circular buffer in DRAM must be 256-byte
+ * aligned (address bits 0-7 must be 0).
+ *
+ * Bit fields in each pointer register:
+ *  27-0: TFD CB physical base address [35:8], must be 256-byte aligned
+ */
 #define FH_MEM_CBBC_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0x9D0)
 #define FH_MEM_CBBC_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0xA10)
-/* queues 0 - 15 */
-#define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
 
-/* TAGR Area - TAG reconstruct table */
-#define FH_MEM_TAGR_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0xA10)
-#define FH_MEM_TAGR_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0xA70)
-
-/* TDBGR Area - Tx Debug Registers */
-#define FH_MEM_TDBGR_LOWER_BOUND             (FH_MEM_LOWER_BOUND + 0x0A70)
-#define FH_MEM_TDBGR_UPPER_BOUND             (FH_MEM_LOWER_BOUND + 0x0B20)
-/* channels 0 - 10 */
-#define FH_MEM_TDBGR_CHNL(x)      (FH_MEM_TDBGR_LOWER_BOUND + (x) * 0x10)
-
-#define FH_MEM_TDBGR_CHNL_REG_0(x)	     (FH_MEM_TDBGR_CHNL(x))
-#define FH_MEM_TDBGR_CHNL_REG_1(x)	     (FH_MEM_TDBGR_CHNL_REG_0(x) + 0x4)
-
-#define FH_MEM_TDBGR_CHNL_BYTES_TO_FIFO_MASK		(0x000FFFFF)
-#define FH_MEM_TDBGR_CHNL_BYTES_TO_FIFO_BITSHIFT	(0)
+/* Find TFD CB base pointer for given queue (range 0-15). */
+#define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
 
-/* RDBUF Area */
-#define FH_MEM_RDBUF_LOWER_BOUND             (FH_MEM_LOWER_BOUND + 0xB80)
-#define FH_MEM_RDBUF_UPPER_BOUND             (FH_MEM_LOWER_BOUND + 0xBC0)
-#define FH_MEM_RDBUF_CHNL0		     (FH_MEM_RDBUF_LOWER_BOUND)
 
-/* RSCSR Area */
+/**
+ * Rx SRAM Control and Status Registers (RSCSR)
+ *
+ * These registers provide handshake between driver and 4965 for the Rx queue
+ * (this queue handles *all* command responses, notifications, Rx data, etc.
+ * sent from 4965 uCode to host driver).  Unlike Tx, there is only one Rx
+ * queue, and only one Rx DMA/FIFO channel.  Also unlike Tx, which can
+ * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
+ * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
+ * mapping between RBDs and RBs.
+ *
+ * Driver must allocate host DRAM memory for the following, and set the
+ * physical address of each into 4965 registers:
+ *
+ * 1)  Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
+ *     entries (although any power of 2, up to 4096, is selectable by driver).
+ *     Each entry (1 dword) points to a receive buffer (RB) of consistent size
+ *     (typically 4K, although 8K or 16K are also selectable by driver).
+ *     Driver sets up RB size and number of RBDs in the CB via Rx config
+ *     register FH_MEM_RCSR_CHNL0_CONFIG_REG.
+ *
+ *     Bit fields within one RBD:
+ *     27-0:  Receive Buffer physical address bits [35:8], 256-byte aligned
+ *
+ *     Driver sets physical address [35:8] of base of RBD circular buffer
+ *     into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
+ *
+ * 2)  Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
+ *     (RBs) have been filled, via a "write pointer", actually the index of
+ *     the RB's corresponding RBD within the circular buffer.  Driver sets
+ *     physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
+ *
+ *     Bit fields in lower dword of Rx status buffer (upper dword not used
+ *     by driver; see struct iwl4965_shared, val0):
+ *     31-12:  Not used by driver
+ *     11- 0:  Index of last filled Rx buffer descriptor
+ *             (4965 writes, driver reads this value)
+ *
+ * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
+ * enter pointers to these RBs into contiguous RBD circular buffer entries,
+ * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
+ *
+ * This "write" index corresponds to the *next* RBD that the driver will make
+ * available, i.e. one RBD past the tail of the ready-to-fill RBDs within
+ * the circular buffer.  This value should initially be 0 (before preparing any
+ * RBs), should be 8 after preparing the first 8 RBs (for example), and must
+ * wrap back to 0 at the end of the circular buffer (but don't wrap before
+ * "read" index has advanced past 1!  See below).
+ * NOTE:  4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
+ *
+ * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
+ * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
+ * to tell the driver the index of the latest filled RBD.  The driver must
+ * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
+ *
+ * The driver must also internally keep track of a third index, which is the
+ * next RBD to process.  When receiving an Rx interrupt, driver should process
+ * all filled but unprocessed RBs up to, but not including, the RB
+ * corresponding to the "read" index.  For example, if "read" index becomes "1",
+ * driver may process the RB pointed to by RBD 0.  Depending on volume of
+ * traffic, there may be many RBs to process.
+ *
+ * If read index == write index, 4965 thinks there is no room to put new data.
+ * Due to this, the maximum number of filled RBs is 255, instead of 256.  To
+ * be safe, make sure that there is a gap of at least 2 RBDs between "write"
+ * and "read" indexes; that is, make sure that there are no more than 254
+ * buffers waiting to be filled.
+ */
 #define FH_MEM_RSCSR_LOWER_BOUND	(FH_MEM_LOWER_BOUND + 0xBC0)
 #define FH_MEM_RSCSR_UPPER_BOUND	(FH_MEM_LOWER_BOUND + 0xC00)
 #define FH_MEM_RSCSR_CHNL0		(FH_MEM_RSCSR_LOWER_BOUND)
-#define FH_MEM_RSCSR_CHNL1		(FH_MEM_RSCSR_LOWER_BOUND + 0x020)
 
-/* RSCSR registers used in Normal mode*/
+/**
+ * Physical base address of 8-byte Rx Status buffer.
+ * Bit fields:
+ *  31-0: Rx status buffer physical base address [35:4], must 16-byte aligned.
+ */
 #define FH_RSCSR_CHNL0_STTS_WPTR_REG		(FH_MEM_RSCSR_CHNL0)
+
+/**
+ * Physical base address of Rx Buffer Descriptor Circular Buffer.
+ * Bit fields:
+ *  27-0:  RBD CD physical base address [35:8], must be 256-byte aligned.
+ */
 #define FH_RSCSR_CHNL0_RBDCB_BASE_REG		(FH_MEM_RSCSR_CHNL0 + 0x004)
+
+/**
+ * Rx write pointer (index, really!).
+ * Bit fields:
+ *  11-0:  Index of driver's most recent prepared-to-be-filled RBD, + 1.
+ *         NOTE:  For 256-entry circular buffer, use only bits [7:0].
+ */
 #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG		(FH_MEM_RSCSR_CHNL0 + 0x008)
-#define FH_RSCSR_CHNL0_RBDCB_RPTR_REG		(FH_MEM_RSCSR_CHNL0 + 0x00c)
+#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
 
-#define FH_RSCSR_FRAME_SIZE_MASK	(0x00003FFF)	/* bits 0-13 */
-/* RSCSR registers used in Service mode*/
-#define FH_RSCSR_CHNL1_RB_WPTR_REG		(FH_MEM_RSCSR_CHNL1)
-#define FH_RSCSR_CHNL1_RB_WPTR_OFFSET_REG	(FH_MEM_RSCSR_CHNL1 + 0x004)
-#define FH_RSCSR_CHNL1_RB_CHUNK_NUM_REG		(FH_MEM_RSCSR_CHNL1 + 0x008)
-#define FH_RSCSR_CHNL1_SRAM_ADDR_REG		(FH_MEM_RSCSR_CHNL1 + 0x00C)
 
-/* RCSR Area - Registers address map */
+/**
+ * Rx Config/Status Registers (RCSR)
+ * Rx Config Reg for channel 0 (only channel used)
+ *
+ * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for
+ * normal operation (see bit fields).
+ *
+ * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA.
+ * Driver should poll FH_MEM_RSSR_RX_STATUS_REG	for
+ * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing.
+ *
+ * Bit fields:
+ * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29-24: reserved
+ * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal),
+ *        min "5" for 32 RBDs, max "12" for 4096 RBDs.
+ * 19-18: reserved
+ * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K,
+ *        '10' 12K, '11' 16K.
+ * 15-14: reserved
+ * 13-12: IRQ destination; '00' none, '01' host driver (normal operation)
+ * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec)
+ *        typical value 0x10 (about 1/2 msec)
+ *  3- 0: reserved
+ */
 #define FH_MEM_RCSR_LOWER_BOUND      (FH_MEM_LOWER_BOUND + 0xC00)
 #define FH_MEM_RCSR_UPPER_BOUND      (FH_MEM_LOWER_BOUND + 0xCC0)
 #define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
-#define FH_MEM_RCSR_CHNL1            (FH_MEM_RCSR_LOWER_BOUND + 0x020)
 
 #define FH_MEM_RCSR_CHNL0_CONFIG_REG	(FH_MEM_RCSR_CHNL0)
-#define FH_MEM_RCSR_CHNL0_CREDIT_REG	(FH_MEM_RCSR_CHNL0 + 0x004)
-#define FH_MEM_RCSR_CHNL0_RBD_STTS_REG	(FH_MEM_RCSR_CHNL0 + 0x008)
-#define FH_MEM_RCSR_CHNL0_RB_STTS_REG	(FH_MEM_RCSR_CHNL0 + 0x00C)
-#define FH_MEM_RCSR_CHNL0_RXPD_STTS_REG	(FH_MEM_RCSR_CHNL0 + 0x010)
 
-#define FH_MEM_RCSR_CHNL0_RBD_STTS_FRAME_RB_CNT_MASK (0x7FFFFFF0) /* bits4:30 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK	  (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT	(20)
+#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT	(4)
+#define RX_RB_TIMEOUT	(0x10)
 
-/* RCSR registers used in Service mode*/
-#define FH_MEM_RCSR_CHNL1_CONFIG_REG		(FH_MEM_RCSR_CHNL1)
-#define FH_MEM_RCSR_CHNL1_RB_STTS_REG         	(FH_MEM_RCSR_CHNL1 + 0x00C)
-#define FH_MEM_RCSR_CHNL1_RX_PD_STTS_REG       	(FH_MEM_RCSR_CHNL1 + 0x010)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
+
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K    (0x00010000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
 
-/* RSSR Area - Rx shared ctrl & status registers */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
+
+
+/**
+ * Rx Shared Status Registers (RSSR)
+ *
+ * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG),
+ * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle.
+ *
+ * Bit fields:
+ *  24:  1 = Channel 0 is idle
+ *
+ * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain
+ * default values that should not be altered by the driver.
+ */
 #define FH_MEM_RSSR_LOWER_BOUND                	(FH_MEM_LOWER_BOUND + 0xC40)
 #define FH_MEM_RSSR_UPPER_BOUND               	(FH_MEM_LOWER_BOUND + 0xD00)
+
 #define FH_MEM_RSSR_SHARED_CTRL_REG           	(FH_MEM_RSSR_LOWER_BOUND)
 #define FH_MEM_RSSR_RX_STATUS_REG	(FH_MEM_RSSR_LOWER_BOUND + 0x004)
 #define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV  (FH_MEM_RSSR_LOWER_BOUND + 0x008)
 
-/* TCSR */
-#define IWL_FH_TCSR_LOWER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xD00)
-#define IWL_FH_TCSR_UPPER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xE60)
+#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE	(0x01000000)
+
 
-#define IWL_FH_TCSR_CHNL_NUM                            (7)
+/**
+ * Transmit DMA Channel Control/Status Registers (TCSR)
+ *
+ * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
+ * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
+ * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
+ *
+ * To use a Tx DMA channel, driver must initialize its
+ * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with:
+ *
+ * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL
+ *
+ * All other bits should be 0.
+ *
+ * Bit fields:
+ * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29- 4: Reserved, set to "0"
+ *     3: Enable internal DMA requests (1, normal operation), disable (0)
+ *  2- 0: Reserved, set to "0"
+ */
+#define IWL_FH_TCSR_LOWER_BOUND  (FH_MEM_LOWER_BOUND + 0xD00)
+#define IWL_FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
+
+/* Find Control/Status reg for given Tx DMA/FIFO channel */
 #define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
 	(IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-#define IWL_FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
-	  (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
-	 (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
 
-/* TSSR Area - Tx shared status registers */
-/* TSSR */
-#define IWL_FH_TSSR_LOWER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEA0)
-#define IWL_FH_TSSR_UPPER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEC0)
-
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x008)
-#define IWL_FH_TSSR_TX_STATUS_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x010)
-
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON	(0xFF000000)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON	(0x00FF0000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B	(0x00000000)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B	(0x00000400)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B	(0x00000800)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B	(0x00000C00)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON	(0x00000100)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON	(0x00000080)
+/**
+ * Tx Shared Status Registers (TSSR)
+ *
+ * After stopping Tx DMA channel (writing 0 to
+ * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll
+ * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle
+ * (channel's buffers empty | no pending requests).
+ *
+ * Bit fields:
+ * 31-24:  1 = Channel buffers empty (channel 7:0)
+ * 23-16:  1 = No pending requests (channel 7:0)
+ */
+#define IWL_FH_TSSR_LOWER_BOUND		(FH_MEM_LOWER_BOUND + 0xEA0)
+#define IWL_FH_TSSR_UPPER_BOUND		(FH_MEM_LOWER_BOUND + 0xEC0)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH	(0x00000020)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH		(0x00000005)
+#define IWL_FH_TSSR_TX_STATUS_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x010)
 
 #define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl)	\
 	((1 << (_chnl)) << 24)
@@ -487,327 +1558,347 @@ struct iwl_link_quality_cmd {
 	(IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
 	IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
 
-/* SRVC */
-#define IWL_FH_SRVC_LOWER_BOUND          (IWL_FH_REGS_LOWER_BOUND + 0x9C8)
-#define IWL_FH_SRVC_UPPER_BOUND          (IWL_FH_REGS_LOWER_BOUND + 0x9D0)
-
-#define IWL_FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
-	  (IWL_FH_SRVC_LOWER_BOUND + (_chnl - 9) * 0x4)
-
-/* TFDIB */
-#define IWL_FH_TFDIB_LOWER_BOUND         (IWL_FH_REGS_LOWER_BOUND + 0x900)
-#define IWL_FH_TFDIB_UPPER_BOUND         (IWL_FH_REGS_LOWER_BOUND + 0x958)
-
-#define IWL_FH_TFDIB_CTRL0_REG(_chnl)    \
-	(IWL_FH_TFDIB_LOWER_BOUND + 0x8 * _chnl)
-#define IWL_FH_TFDIB_CTRL1_REG(_chnl)    \
-	(IWL_FH_TFDIB_LOWER_BOUND + 0x8 * _chnl + 0x4)
-
-#define IWL_FH_SRVC_CHNL                                (9)
-#define IWL_FH_TFDIB_CTRL1_REG_POS_MSB                  (28)
-
-/* Debug Monitor Area */
-#define FH_MEM_DM_LOWER_BOUND            (FH_MEM_LOWER_BOUND + 0xEE0)
-#define FH_MEM_DM_UPPER_BOUND            (FH_MEM_LOWER_BOUND + 0xEF0)
-#define FH_MEM_DM_CONTROL_MASK_REG       (FH_MEM_DM_LOWER_BOUND)
-#define FH_MEM_DM_CONTROL_START_REG      (FH_MEM_DM_LOWER_BOUND + 0x004)
-#define FH_MEM_DM_CONTROL_STATUS_REG     (FH_MEM_DM_LOWER_BOUND + 0x008)
-#define FH_MEM_DM_MONITOR_REG            (FH_MEM_DM_LOWER_BOUND + 0x00C)
-
-#define FH_TB1_ADDR_LOW_MASK	(0xFFFFFFFF)	/* bits 31:0 */
-#define FH_TB1_ADDR_HIGH_MASK	(0xF00000000)	/* bits 35:32 */
-#define FH_TB2_ADDR_LOW_MASK	(0x0000FFFF)	/* bits 15:0 */
-#define FH_TB2_ADDR_HIGH_MASK	(0xFFFFF0000)	/* bits 35:16 */
-
-#define FH_TB1_ADDR_LOW_BITSHIFT	(0)
-#define FH_TB1_ADDR_HIGH_BITSHIFT	(32)
-#define FH_TB2_ADDR_LOW_BITSHIFT	(0)
-#define FH_TB2_ADDR_HIGH_BITSHIFT	(16)
-
-#define FH_TB1_LENGTH_MASK         (0x00000FFF)	/* bits 11:0 */
-#define FH_TB2_LENGTH_MASK         (0x00000FFF)	/* bits 11:0 */
 
-/* number of FH channels including 2 service mode */
-#define NUM_OF_FH_CHANNELS (10)
-
-/* ctrl field bitology */
-#define FH_TFD_CTRL_PADDING_MASK     (0xC0000000)	/* bits 31:30 */
-#define FH_TFD_CTRL_NUMTB_MASK       (0x1F000000)	/* bits 28:24 */
-
-#define FH_TFD_CTRL_PADDING_BITSHIFT                (30)
-#define FH_TFD_CTRL_NUMTB_BITSHIFT                  (24)
-
-#define FH_TFD_GET_NUM_TBS(ctrl) \
-	((ctrl & FH_TFD_CTRL_NUMTB_MASK) >> FH_TFD_CTRL_NUMTB_BITSHIFT)
-#define FH_TFD_GET_PADDING(ctrl) \
-	((ctrl & FH_TFD_CTRL_PADDING_MASK) >> FH_TFD_CTRL_PADDING_BITSHIFT)
-
-/* TCSR: tx_config register values */
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC              (0x00000002)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD           (0x00400000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD            (0x00800000)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM              (20)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX              (12)
-
-/* CBB table */
-#define FH_CBB_ADDR_MASK	0x0FFFFFFF	/* bits 27:0 */
-#define FH_CBB_ADDR_BIT_SHIFT		(8)
-
-/* RCSR:  channel 0 rx_config register defines */
-#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK	  (0x00030000) /* bits 16-17 */
-#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
-
-#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT       (20)
-#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT			(16)
-
-#define FH_RCSR_GET_RDBC_SIZE(reg) \
-	 ((reg & FH_RCSR_RX_CONFIG_RDBC_SIZE_MASK) >> \
-	  FH_RCSR_RX_CONFIG_RDBC_SIZE_BITSHIFT)
-
-/* RCSR:  channel 1 rx_config register defines */
-#define FH_RCSR_CHNL1_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
-#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_MASK	  (0x00003000) /* bits 12-13 */
-
-/* RCSR: rx_config register values */
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
-#define FH_RCSR_RX_CONFIG_SINGLE_FRAME_MODE	    (0x00008000)
-
-#define FH_RCSR_RX_CONFIG_RDRBD_DISABLE_VAL         (0x00000000)
-#define FH_RCSR_RX_CONFIG_RDRBD_ENABLE_VAL          (0x20000000)
-
-#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
-
-/* RCSR channel 0 config register values */
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
-
-/* RCSR channel 1 config register values */
-#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
-#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
-#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_RTC_VAL      (0x00002000)
-#define FH_RCSR_CHNL1_RX_CONFIG_IRQ_DEST_INT_HOST_RTC_VAL (0x00003000)
-
-/* RCSR: rb status register defines */
-#define FH_RCSR_RB_BYTE_TO_SEND_MASK		(0x0001FFFF)	/* bits 0-16 */
-
-/* RSCSR: defs used in normal mode */
-#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK		(0x00000FFF)	/* bits 0-11 */
-
-/* RSCSR: defs used in service mode */
-#define FH_RSCSR_CHNL1_SRAM_ADDR_MASK		(0x00FFFFFF)	/* bits 0-23 */
-#define FH_RSCSR_CHNL1_RB_WPTR_MASK		(0x0FFFFFFF)	/* bits 0-27 */
-#define FH_RSCSR_CHNL1_RB_WPTR_OFFSET_MASK	(0x000000FF)	/* bits 0-7 */
-
-/* RSSR: RX Enable Error IRQ to Driver register defines */
-#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV_NO_RBD (0x00400000)	/* bit 22 */
-
-#define FH_DRAM2SRAM_DRAM_ADDR_HIGH_MASK	(0xFFFFFFF00)	/* bits 8-35 */
-#define FH_DRAM2SRAM_DRAM_ADDR_LOW_MASK		(0x000000FF)	/* bits 0-7 */
-
-#define FH_DRAM2SRAM_DRAM_ADDR_HIGH_BITSHIFT	(8)	/* bits 8-35 */
-
-/* RX DRAM status regs definitions  */
-#define FH_RX_RB_NUM_MASK			(0x00000FFF)	/* bits 0-11 */
-#define FH_RX_FRAME_NUM_MASK			(0x0FFF0000) /* bits 16-27 */
-
-#define FH_RX_RB_NUM_BITSHIFT			(0)
-#define FH_RX_FRAME_NUM_BITSHIFT		(16)
+/********************* START TX SCHEDULER *************************************/
 
+/**
+ * 4965 Tx Scheduler
+ *
+ * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
+ * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
+ * host DRAM.  It steers each frame's Tx command (which contains the frame
+ * data) into one of up to 7 prioritized Tx DMA FIFO channels within the
+ * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
+ * but one DMA channel may take input from several queues.
+ *
+ * Tx DMA channels have dedicated purposes.  For 4965, they are used as follows:
+ *
+ * 0 -- EDCA BK (background) frames, lowest priority
+ * 1 -- EDCA BE (best effort) frames, normal priority
+ * 2 -- EDCA VI (video) frames, higher priority
+ * 3 -- EDCA VO (voice) and management frames, highest priority
+ * 4 -- Commands (e.g. RXON, etc.)
+ * 5 -- HCCA short frames
+ * 6 -- HCCA long frames
+ * 7 -- not used by driver (device-internal only)
+ *
+ * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
+ * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to
+ * support 11n aggregation via EDCA DMA channels.
+ *
+ * The driver sets up each queue to work in one of two modes:
+ *
+ * 1)  Scheduler-Ack, in which the scheduler automatically supports a
+ *     block-ack (BA) window of up to 64 TFDs.  In this mode, each queue
+ *     contains TFDs for a unique combination of Recipient Address (RA)
+ *     and Traffic Identifier (TID), that is, traffic of a given
+ *     Quality-Of-Service (QOS) priority, destined for a single station.
+ *
+ *     In scheduler-ack mode, the scheduler keeps track of the Tx status of
+ *     each frame within the BA window, including whether it's been transmitted,
+ *     and whether it's been acknowledged by the receiving station.  The device
+ *     automatically processes block-acks received from the receiving STA,
+ *     and reschedules un-acked frames to be retransmitted (successful
+ *     Tx completion may end up being out-of-order).
+ *
+ *     The driver must maintain the queue's Byte Count table in host DRAM
+ *     (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
+ *     This mode does not support fragmentation.
+ *
+ * 2)  FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
+ *     The device may automatically retry Tx, but will retry only one frame
+ *     at a time, until receiving ACK from receiving station, or reaching
+ *     retry limit and giving up.
+ *
+ *     The command queue (#4) must use this mode!
+ *     This mode does not require use of the Byte Count table in host DRAM.
+ *
+ * Driver controls scheduler operation via 3 means:
+ * 1)  Scheduler registers
+ * 2)  Shared scheduler data base in internal 4956 SRAM
+ * 3)  Shared data in host DRAM
+ *
+ * Initialization:
+ *
+ * When loading, driver should allocate memory for:
+ * 1)  16 TFD circular buffers, each with space for (typically) 256 TFDs.
+ * 2)  16 Byte Count circular buffers in 16 KBytes contiguous memory
+ *     (1024 bytes for each queue).
+ *
+ * After receiving "Alive" response from uCode, driver must initialize
+ * the scheduler (especially for queue #4, the command queue, otherwise
+ * the driver can't issue commands!):
+ */
+
+/**
+ * Max Tx window size is the max number of contiguous TFDs that the scheduler
+ * can keep track of at one time when creating block-ack chains of frames.
+ * Note that "64" matches the number of ack bits in a block-ack packet.
+ * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
+ * SCD_CONTEXT_QUEUE_OFFSET(x) values.
+ */
 #define SCD_WIN_SIZE				64
-#define SCD_FRAME_LIMIT				10
+#define SCD_FRAME_LIMIT				64
 
-/* memory mapped registers */
+/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
 #define SCD_START_OFFSET		0xa02c00
 
+/*
+ * 4965 tells driver SRAM address for internal scheduler structs via this reg.
+ * Value is valid only after "Alive" response from uCode.
+ */
 #define SCD_SRAM_BASE_ADDR           (SCD_START_OFFSET + 0x0)
+
+/*
+ * Driver may need to update queue-empty bits after changing queue's
+ * write and read pointers (indexes) during (re-)initialization (i.e. when
+ * scheduler is not tracking what's happening).
+ * Bit fields:
+ * 31-16:  Write mask -- 1: update empty bit, 0: don't change empty bit
+ * 15-00:  Empty state, one for each queue -- 1: empty, 0: non-empty
+ * NOTE:  This register is not used by Linux driver.
+ */
 #define SCD_EMPTY_BITS               (SCD_START_OFFSET + 0x4)
+
+/*
+ * Physical base address of array of byte count (BC) circular buffers (CBs).
+ * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
+ * This register points to BC CB for queue 0, must be on 1024-byte boundary.
+ * Others are spaced by 1024 bytes.
+ * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
+ * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
+ * Bit fields:
+ * 25-00:  Byte Count CB physical address [35:10], must be 1024-byte aligned.
+ */
 #define SCD_DRAM_BASE_ADDR           (SCD_START_OFFSET + 0x10)
-#define SCD_AIT                      (SCD_START_OFFSET + 0x18)
-#define SCD_TXFACT                   (SCD_START_OFFSET + 0x1c)
-#define SCD_QUEUE_WRPTR(x)           (SCD_START_OFFSET + 0x24 + (x) * 4)
-#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
-#define SCD_SETQUEUENUM              (SCD_START_OFFSET + 0xa4)
-#define SCD_SET_TXSTAT_TXED          (SCD_START_OFFSET + 0xa8)
-#define SCD_SET_TXSTAT_DONE          (SCD_START_OFFSET + 0xac)
-#define SCD_SET_TXSTAT_NOT_SCHD      (SCD_START_OFFSET + 0xb0)
-#define SCD_DECREASE_CREDIT          (SCD_START_OFFSET + 0xb4)
-#define SCD_DECREASE_SCREDIT         (SCD_START_OFFSET + 0xb8)
-#define SCD_LOAD_CREDIT              (SCD_START_OFFSET + 0xbc)
-#define SCD_LOAD_SCREDIT             (SCD_START_OFFSET + 0xc0)
-#define SCD_BAR                      (SCD_START_OFFSET + 0xc4)
-#define SCD_BAR_DW0                  (SCD_START_OFFSET + 0xc8)
-#define SCD_BAR_DW1                  (SCD_START_OFFSET + 0xcc)
-#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
-#define SCD_QUERY_REQ                (SCD_START_OFFSET + 0xd8)
-#define SCD_QUERY_RES                (SCD_START_OFFSET + 0xdc)
-#define SCD_PENDING_FRAMES           (SCD_START_OFFSET + 0xe0)
-#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
-#define SCD_INTERRUPT_THRESHOLD      (SCD_START_OFFSET + 0xe8)
-#define SCD_QUERY_MIN_FRAME_SIZE     (SCD_START_OFFSET + 0x100)
-#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
 
-/* SRAM structures */
-#define SCD_CONTEXT_DATA_OFFSET			0x380
-#define SCD_TX_STTS_BITMAP_OFFSET		0x400
-#define SCD_TRANSLATE_TBL_OFFSET		0x500
-#define SCD_CONTEXT_QUEUE_OFFSET(x)	(SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-	((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+/*
+ * Enables any/all Tx DMA/FIFO channels.
+ * Scheduler generates requests for only the active channels.
+ * Set this to 0xff to enable all 8 channels (normal usage).
+ * Bit fields:
+ *  7- 0:  Enable (1), disable (0), one bit for each channel 0-7
+ */
+#define SCD_TXFACT                   (SCD_START_OFFSET + 0x1c)
 
+/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */
 #define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
        ((1<<(hi))|((1<<(hi))-(1<<(lo))))
 
+/*
+ * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
+ * Initialized and updated by driver as new TFDs are added to queue.
+ * NOTE:  If using Block Ack, index must correspond to frame's
+ *        Start Sequence Number; index = (SSN & 0xff)
+ * NOTE:  Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
+ */
+#define SCD_QUEUE_WRPTR(x)           (SCD_START_OFFSET + 0x24 + (x) * 4)
 
-#define SCD_MODE_REG_BIT_SEARCH_MODE		(1<<0)
-#define SCD_MODE_REG_BIT_SBYP_MODE		(1<<1)
+/*
+ * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
+ * For FIFO mode, index indicates next frame to transmit.
+ * For Scheduler-ACK mode, index indicates first frame in Tx window.
+ * Initialized by driver, updated by scheduler.
+ */
+#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
 
-#define SCD_TXFIFO_POS_TID			(0)
-#define SCD_TXFIFO_POS_RA			(4)
+/*
+ * Select which queues work in chain mode (1) vs. not (0).
+ * Use chain mode to build chains of aggregated frames.
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
+ * NOTE:  If driver sets up queue for chain mode, it should be also set up
+ *        Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
+ */
+#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
+
+/*
+ * Select which queues interrupt driver when scheduler increments
+ * a queue's read pointer (index).
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
+ * NOTE:  This functionality is apparently a no-op; driver relies on interrupts
+ *        from Rx queue to read Tx command responses and update Tx queues.
+ */
+#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
+
+/*
+ * Queue search status registers.  One for each queue.
+ * Sets up queue mode and assigns queue to Tx DMA channel.
+ * Bit fields:
+ * 19-10: Write mask/enable bits for bits 0-9
+ *     9: Driver should init to "0"
+ *     8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
+ *        Driver should init to "1" for aggregation mode, or "0" otherwise.
+ *   7-6: Driver should init to "0"
+ *     5: Window Size Left; indicates whether scheduler can request
+ *        another TFD, based on window size, etc.  Driver should init
+ *        this bit to "1" for aggregation mode, or "0" for non-agg.
+ *   4-1: Tx FIFO to use (range 0-7).
+ *     0: Queue is active (1), not active (0).
+ * Other bits should be written as "0"
+ *
+ * NOTE:  If enabling Scheduler-ACK mode, chain mode should also be enabled
+ *        via SCD_QUEUECHAIN_SEL.
+ */
+#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
+
+/* Bit field positions */
 #define SCD_QUEUE_STTS_REG_POS_ACTIVE		(0)
 #define SCD_QUEUE_STTS_REG_POS_TXF		(1)
 #define SCD_QUEUE_STTS_REG_POS_WSL		(5)
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACK		(8)
+
+/* Write masks */
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN	(10)
 #define SCD_QUEUE_STTS_REG_MSK			(0x0007FC00)
 
-#define SCD_QUEUE_RA_TID_MAP_RATID_MSK		(0x01FF)
+/**
+ * 4965 internal SRAM structures for scheduler, shared with driver ...
+ *
+ * Driver should clear and initialize the following areas after receiving
+ * "Alive" response from 4965 uCode, i.e. after initial
+ * uCode load, or after a uCode load done for error recovery:
+ *
+ * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
+ * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
+ * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
+ *
+ * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
+ * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
+ * All OFFSET values must be added to this base address.
+ */
+
+/*
+ * Queue context.  One 8-byte entry for each of 16 queues.
+ *
+ * Driver should clear this entire area (size 0x80) to 0 after receiving
+ * "Alive" notification from uCode.  Additionally, driver should init
+ * each queue's entry as follows:
+ *
+ * LS Dword bit fields:
+ *  0-06:  Max Tx window size for Scheduler-ACK.  Driver should init to 64.
+ *
+ * MS Dword bit fields:
+ * 16-22:  Frame limit.  Driver should init to 10 (0xa).
+ *
+ * Driver should init all other bits to 0.
+ *
+ * Init must be done after driver receives "Alive" response from 4965 uCode,
+ * and when setting up queue for aggregation.
+ */
+#define SCD_CONTEXT_DATA_OFFSET			0x380
+#define SCD_CONTEXT_QUEUE_OFFSET(x)	(SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
 
 #define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS		(0)
 #define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK		(0x0000007F)
-#define SCD_QUEUE_CTX_REG1_CREDIT_POS		(8)
-#define SCD_QUEUE_CTX_REG1_CREDIT_MSK		(0x00FFFF00)
-#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS	(24)
-#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK	(0xFF000000)
 #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
 #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
 
-#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R	(0x00000010)
-#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
-#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
-
-
- /*IWL4965-END */
-
-#define IWL4965_BROADCAST_ID    (31)
-
-#define RX_RES_PHY_CNT 14
-
-#define STATISTICS_FLG_CLEAR                      (0x1)
-#define STATISTICS_FLG_DISABLE_NOTIFICATION       (0x2)
-
-#define STATISTICS_REPLY_FLG_CLEAR                (0x1)
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         (0x2)
-#define STATISTICS_REPLY_FLG_TGJ_NARROW_BAND_MSK  (0x4)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         (0x8)
-#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
-#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
-
-struct iwl4965_rx_phy_res {
-	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
-	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
-	u8 stat_id;		/* configurable DSP phy data set ID */
-	u8 reserved1;
-	__le64 timestamp;	/* TSF at on air rise */
-	__le32 beacon_time_stamp; /* beacon at on-air rise */
-	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
-	__le16 channel;		/* channel number */
-	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
-	__le32 reserved2;
-	struct iwl_rate rate;	/* rate in ucode internal format */
-	__le16 byte_count;		/* frame's byte-count */
-	__le16 reserved3;
-} __attribute__ ((packed));
+/*
+ * Tx Status Bitmap
+ *
+ * Driver should clear this entire area (size 0x100) to 0 after receiving
+ * "Alive" notification from uCode.  Area is used only by device itself;
+ * no other support (besides clearing) is required from driver.
+ */
+#define SCD_TX_STTS_BITMAP_OFFSET		0x400
 
-struct iwl4965_rx_mpdu_res_start {
-	__le16 byte_count;
-	__le16 reserved;
-} __attribute__ ((packed));
+/*
+ * RAxTID to queue translation mapping.
+ *
+ * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
+ * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
+ * one QOS priority level destined for one station (for this wireless link,
+ * not final destination).  The SCD_TRANSLATE_TABLE area provides 16 16-bit
+ * mappings, one for each of the 16 queues.  If queue is not in Scheduler-ACK
+ * mode, the device ignores the mapping value.
+ *
+ * Bit fields, for each 16-bit map:
+ * 15-9:  Reserved, set to 0
+ *  8-4:  Index into device's station table for recipient station
+ *  3-0:  Traffic ID (tid), range 0-15
+ *
+ * Driver should clear this entire area (size 32 bytes) to 0 after receiving
+ * "Alive" notification from uCode.  To update a 16-bit map value, driver
+ * must read a dword-aligned value from device SRAM, replace the 16-bit map
+ * value of interest, and write the dword value back into device SRAM.
+ */
+#define SCD_TRANSLATE_TBL_OFFSET		0x500
 
-#if 0
+/* Find translation table dword to read/write for given queue */
+#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+	((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
 
-union iwl_dram_scratch_union {
-	struct iwl_dram_scratch s;
-	__le32 dw;
-};
+#define SCD_TXFIFO_POS_TID			(0)
+#define SCD_TXFIFO_POS_RA			(4)
+#define SCD_QUEUE_RA_TID_MAP_RATID_MSK		(0x01FF)
 
-struct iwl4965_beacon_notify {
-	struct iwl_tx_resp beacon_notify_hdr;	/*15:4 */
-	__le32 low_tsf;		/*19:16 */
-	__le32 high_tsf;		/*23:20 */
-	__le32 ibss_mgr_status;	/*27:24 */
-} __attribute__ ((packed));
+/*********************** END TX SCHEDULER *************************************/
 
-struct iwl4965_tx_beacon_cmd {
-	struct iwl_tx_cmd tx;	/*byte 55:4 */
-	__le16 tim_idx;		/*byte 57:56 */
-	u8 tim_size;		/*byte 58 */
-	u8 reserved1;		/*byte 59 */
-	struct ieee80211_hdr frame[0];
-	/* Beacon Frame */
-} __attribute__ ((packed));
+static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags)
+{
+	return le32_to_cpu(rate_n_flags) & 0xFF;
+}
+static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags)
+{
+	return le32_to_cpu(rate_n_flags) & 0xFFFF;
+}
+static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+	return cpu_to_le32(flags|(u16)rate);
+}
 
-struct iwl4965_powertable_cmd {
-	__le16 flags;
-	u8 keep_alive_seconds;
-	u8 debug_flags;
-	__le32 rx_data_timeout;
-	__le32 tx_data_timeout;
-	__le32 sleep_interval[PMC_TCMD_SLEEP_INTRVL_TABLE_SIZE];
-	__le32 keep_alive_beacons;
-} __attribute__ ((packed));
 
-#define IWL_NUM_OF_STATIONS  ( 32 )
-#define BYTE_CNT_AREA_OFFSET            0
+/**
+ * Tx/Rx Queues
+ *
+ * Most communication between driver and 4965 is via queues of data buffers.
+ * For example, all commands that the driver issues to device's embedded
+ * controller (uCode) are via the command queue (one of the Tx queues).  All
+ * uCode command responses/replies/notifications, including Rx frames, are
+ * conveyed from uCode to driver via the Rx queue.
+ *
+ * Most support for these queues, including handshake support, resides in
+ * structures in host DRAM, shared between the driver and the device.  When
+ * allocating this memory, the driver must make sure that data written by
+ * the host CPU updates DRAM immediately (and does not get "stuck" in CPU's
+ * cache memory), so DRAM and cache are consistent, and the device can
+ * immediately see changes made by the driver.
+ *
+ * 4965 supports up to 16 DRAM-based Tx queues, and services these queues via
+ * up to 7 DMA channels (FIFOs).  Each Tx queue is supported by a circular array
+ * in DRAM containing 256 Transmit Frame Descriptors (TFDs).
+ */
+#define IWL4965_MAX_WIN_SIZE              64
+#define IWL4965_QUEUE_SIZE               256
+#define IWL4965_NUM_FIFOS                  7
+#define IWL_MAX_NUM_QUEUES                16
 
-enum HT_STATUS {
-	BA_STATUS_FAILURE = 0,
-	BA_STATUS_INITIATOR_DELBA,
-	BA_STATUS_RECIPIENT_DELBA,
-	BA_STATUS_RENEW_ADDBA_REQUEST,
-	BA_STATUS_ACTIVE,
-};
-#endif
-
-#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
-#define IWL_AGC_DB_POS		(7)
-/* Fixed (non-configurable) rx data from phy */
-struct iwl4965_rx_non_cfg_phy {
-	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
-	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
-	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
-	u8 pad[0];
-} __attribute__ ((packed));
 
-struct iwl_tfd_frame_data {
+/**
+ * struct iwl4965_tfd_frame_data
+ *
+ * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
+ * Each buffer must be on dword boundary.
+ * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers,
+ * may be filled within a TFD (iwl_tfd_frame).
+ *
+ * Bit fields in tb1_addr:
+ * 31- 0: Tx buffer 1 address bits [31:0]
+ *
+ * Bit fields in val1:
+ * 31-16: Tx buffer 2 address bits [15:0]
+ * 15- 4: Tx buffer 1 length (bytes)
+ *  3- 0: Tx buffer 1 address bits [32:32]
+ *
+ * Bit fields in val2:
+ * 31-20: Tx buffer 2 length (bytes)
+ * 19- 0: Tx buffer 2 address bits [35:16]
+ */
+struct iwl4965_tfd_frame_data {
 	__le32 tb1_addr;
 
 	__le32 val1;
@@ -835,7 +1926,36 @@ struct iwl_tfd_frame_data {
 #define IWL_tb2_len_SYM val2
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame {
+
+/**
+ * struct iwl4965_tfd_frame
+ *
+ * Transmit Frame Descriptor (TFD)
+ *
+ * 4965 supports up to 16 Tx queues resident in host DRAM.
+ * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
+ * Both driver and device share these circular buffers, each of which must be
+ * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965.
+ *
+ * Driver must indicate the physical address of the base of each
+ * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers.
+ *
+ * Each TFD contains pointer/size information for up to 20 data buffers
+ * in host DRAM.  These buffers collectively contain the (one) frame described
+ * by the TFD.  Each buffer must be a single contiguous block of memory within
+ * itself, but buffers may be scattered in host DRAM.  Each buffer has max size
+ * of (4K - 4).  The 4965 concatenates all of a TFD's buffers into a single
+ * Tx frame, up to 8 KBytes in size.
+ *
+ * Bit fields in the control dword (val0):
+ * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound
+ *    29: reserved
+ * 28-24: # Transmit Buffer Descriptors in TFD
+ * 23- 0: reserved
+ *
+ * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
+ */
+struct iwl4965_tfd_frame {
 	__le32 val0;
 	/* __le32 rsvd1:24; */
 	/* __le32 num_tbs:5; */
@@ -844,15 +1964,20 @@ struct iwl_tfd_frame {
 #define IWL_num_tbs_SYM val0
 	/* __le32 rsvd2:1; */
 	/* __le32 padding:2; */
-	struct iwl_tfd_frame_data pa[10];
+	struct iwl4965_tfd_frame_data pa[10];
 	__le32 reserved;
 } __attribute__ ((packed));
 
-#define IWL4965_MAX_WIN_SIZE              64
-#define IWL4965_QUEUE_SIZE               256
-#define IWL4965_NUM_FIFOS                  7
-#define IWL4965_NUM_QUEUES                16
 
+/**
+ * struct iwl4965_queue_byte_cnt_entry
+ *
+ * Byte Count Table Entry
+ *
+ * Bit fields:
+ * 15-12: reserved
+ * 11- 0: total to-be-transmitted byte count of frame (does not include command)
+ */
 struct iwl4965_queue_byte_cnt_entry {
 	__le16 val;
 	/* __le16 byte_cnt:12; */
@@ -862,6 +1987,25 @@ struct iwl4965_queue_byte_cnt_entry {
 	/* __le16 rsvd:4; */
 } __attribute__ ((packed));
 
+
+/**
+ * struct iwl4965_sched_queue_byte_cnt_tbl
+ *
+ * Byte Count table
+ *
+ * Each Tx queue uses a byte-count table containing 320 entries:
+ * one 16-bit entry for each of 256 TFDs, plus an additional 64 entries that
+ * duplicate the first 64 entries (to avoid wrap-around within a Tx window;
+ * max Tx window is 64 TFDs).
+ *
+ * When driver sets up a new TFD, it must also enter the total byte count
+ * of the frame to be transmitted into the corresponding entry in the byte
+ * count table for the chosen Tx queue.  If the TFD index is 0-63, the driver
+ * must duplicate the byte count entry in corresponding index 256-319.
+ *
+ * "dont_care" padding puts each byte count table on a 1024-byte boundary;
+ * 4965 assumes tables are separated by 1024 bytes.
+ */
 struct iwl4965_sched_queue_byte_cnt_tbl {
 	struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
 						       IWL4965_MAX_WIN_SIZE];
@@ -870,11 +2014,33 @@ struct iwl4965_sched_queue_byte_cnt_tbl {
 		     sizeof(__le16)];
 } __attribute__ ((packed));
 
-/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR
- * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
-struct iwl_shared {
+
+/**
+ * struct iwl4965_shared - handshake area for Tx and Rx
+ *
+ * For convenience in allocating memory, this structure combines 2 areas of
+ * DRAM which must be shared between driver and 4965.  These do not need to
+ * be combined, if better allocation would result from keeping them separate:
+ *
+ * 1)  The Tx byte count tables occupy 1024 bytes each (16 KBytes total for
+ *     16 queues).  Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find
+ *     the first of these tables.  4965 assumes tables are 1024 bytes apart.
+ *
+ * 2)  The Rx status (val0 and val1) occupies only 8 bytes.  Driver uses
+ *     FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area.
+ *     Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD)
+ *     that has been filled by the 4965.
+ *
+ * Bit fields val0:
+ * 31-12:  Not used
+ * 11- 0:  Index of last filled Rx buffer descriptor (4965 writes, driver reads)
+ *
+ * Bit fields val1:
+ * 31- 0:  Not used
+ */
+struct iwl4965_shared {
 	struct iwl4965_sched_queue_byte_cnt_tbl
-	 queues_byte_cnt_tbls[IWL4965_NUM_QUEUES];
+	 queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
 	__le32 val0;
 
 	/* __le32 rb_closed_stts_rb_num:12; */
@@ -904,4 +2070,4 @@ struct iwl_shared {
 	__le32 padding2;
 } __attribute__ ((packed));
 
-#endif /* __iwl_4965_hw_h__ */
+#endif /* __iwl4965_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-io.h b/drivers/net/wireless/iwlwifi/iwl-4965-io.h
new file mode 100644
index 0000000..34a0b57
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-io.h
@@ -0,0 +1,431 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl4965_io_h__
+#define __iwl4965_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-4965-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * and the current line number is printed in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl4965_read_direct32 calls the non-check version of
+ * _iwl4965_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O.  In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl4965_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *iwl,
+				 u32 ofs, u32 val)
+{
+	IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
+	_iwl4965_write32(iwl, ofs, val);
+}
+#define iwl4965_write32(iwl, ofs, val) \
+	__iwl4965_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl4965_write32(iwl, ofs, val) _iwl4965_write32(iwl, ofs, val)
+#endif
+
+#define _iwl4965_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *iwl, u32 ofs)
+{
+	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+	return _iwl4965_read32(iwl, ofs);
+}
+#define iwl4965_read32(iwl, ofs) __iwl4965_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl4965_read32(p, o) _iwl4965_read32(p, o)
+#endif
+
+static inline int _iwl4965_poll_bit(struct iwl4965_priv *priv, u32 addr,
+				u32 bits, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl4965_read32(priv, addr) & mask) == (bits & mask))
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_poll_bit(const char *f, u32 l,
+				 struct iwl4965_priv *priv, u32 addr,
+				 u32 bits, u32 mask, int timeout)
+{
+	int ret = _iwl4965_poll_bit(priv, addr, bits, mask, timeout);
+	if (unlikely(ret  == -ETIMEDOUT))
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+		     addr, bits, mask, f, l);
+	else
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+		     addr, bits, mask, ret, f, l);
+	return ret;
+}
+#define iwl4965_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl4965_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl4965_poll_bit(p, a, b, m, t) _iwl4965_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl4965_set_bit(struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	_iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bit(const char *f, u32 l,
+				 struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read32(priv, reg) | mask;
+	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl4965_write32(priv, reg, val);
+}
+#define iwl4965_set_bit(p, r, m) __iwl4965_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl4965_set_bit(p, r, m) _iwl4965_set_bit(p, r, m)
+#endif
+
+static inline void _iwl4965_clear_bit(struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	_iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_clear_bit(const char *f, u32 l,
+				   struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read32(priv, reg) & ~mask;
+	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl4965_write32(priv, reg, val);
+}
+#define iwl4965_clear_bit(p, r, m) __iwl4965_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl4965_clear_bit(p, r, m) _iwl4965_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl4965_grab_nic_access(struct iwl4965_priv *priv)
+{
+	int ret;
+	u32 gp_ctl;
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+			"wakes up NIC\n");
+
+		/* 10 msec allows time for NIC to complete its data save */
+		gp_ctl = _iwl4965_read32(priv, CSR_GP_CNTRL);
+		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+				"gpctl = 0x%08x\n", gp_ctl);
+			mdelay(10);
+		} else
+			IWL_DEBUG_RF_KILL("power-down complete, "
+					  "gpctl = 0x%08x\n", gp_ctl);
+	}
+
+	/* this bit wakes up the NIC */
+	_iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	ret = _iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+	if (ret < 0) {
+		IWL_ERROR("MAC is in deep sleep!\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IWL4965_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_grab_nic_access(const char *f, u32 l,
+					       struct iwl4965_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
+
+	IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l);
+	return _iwl4965_grab_nic_access(priv);
+}
+#define iwl4965_grab_nic_access(priv) \
+	__iwl4965_grab_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl4965_grab_nic_access(priv) \
+	_iwl4965_grab_nic_access(priv)
+#endif
+
+static inline void _iwl4965_release_nic_access(struct iwl4965_priv *priv)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_release_nic_access(const char *f, u32 l,
+					    struct iwl4965_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld nic access at line %d.\n", l);
+
+	IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l);
+	_iwl4965_release_nic_access(priv);
+}
+#define iwl4965_release_nic_access(priv) \
+	__iwl4965_release_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl4965_release_nic_access(priv) \
+	_iwl4965_release_nic_access(priv)
+#endif
+
+static inline u32 _iwl4965_read_direct32(struct iwl4965_priv *priv, u32 reg)
+{
+	return _iwl4965_read32(priv, reg);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read_direct32(const char *f, u32 l,
+					struct iwl4965_priv *priv, u32 reg)
+{
+	u32 value = _iwl4965_read_direct32(priv, reg);
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from %s %d\n", f, l);
+	IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+		     f, l);
+	return value;
+}
+#define iwl4965_read_direct32(priv, reg) \
+	__iwl4965_read_direct32(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl4965_read_direct32 _iwl4965_read_direct32
+#endif
+
+static inline void _iwl4965_write_direct32(struct iwl4965_priv *priv,
+					 u32 reg, u32 value)
+{
+	_iwl4965_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static void __iwl4965_write_direct32(u32 line,
+				   struct iwl4965_priv *priv, u32 reg, u32 value)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl4965_write_direct32(priv, reg, value);
+}
+#define iwl4965_write_direct32(priv, reg, value) \
+	__iwl4965_write_direct32(__LINE__, priv, reg, value)
+#else
+#define iwl4965_write_direct32 _iwl4965_write_direct32
+#endif
+
+static inline void iwl4965_write_reg_buf(struct iwl4965_priv *priv,
+					       u32 reg, u32 len, u32 *values)
+{
+	u32 count = sizeof(u32);
+
+	if ((priv != NULL) && (values != NULL)) {
+		for (; 0 < len; len -= count, reg += count, values++)
+			_iwl4965_write_direct32(priv, reg, *values);
+	}
+}
+
+static inline int _iwl4965_poll_direct_bit(struct iwl4965_priv *priv,
+					   u32 addr, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl4965_read_direct32(priv, addr) & mask) == mask)
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_poll_direct_bit(const char *f, u32 l,
+					    struct iwl4965_priv *priv,
+					    u32 addr, u32 mask, int timeout)
+{
+	int ret  = _iwl4965_poll_direct_bit(priv, addr, mask, timeout);
+
+	if (unlikely(ret == -ETIMEDOUT))
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
+	else
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, ret, f, l);
+	return ret;
+}
+#define iwl4965_poll_direct_bit(iwl, addr, mask, timeout) \
+	__iwl4965_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl4965_poll_direct_bit _iwl4965_poll_direct_bit
+#endif
+
+static inline u32 _iwl4965_read_prph(struct iwl4965_priv *priv, u32 reg)
+{
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	return _iwl4965_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read_prph(u32 line, struct iwl4965_priv *priv, u32 reg)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	return _iwl4965_read_prph(priv, reg);
+}
+
+#define iwl4965_read_prph(priv, reg) \
+	__iwl4965_read_prph(__LINE__, priv, reg)
+#else
+#define iwl4965_read_prph _iwl4965_read_prph
+#endif
+
+static inline void _iwl4965_write_prph(struct iwl4965_priv *priv,
+					     u32 addr, u32 val)
+{
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
+			      ((addr & 0x0000FFFF) | (3 << 24)));
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_write_prph(u32 line, struct iwl4965_priv *priv,
+					      u32 addr, u32 val)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access from line %d\n", line);
+	_iwl4965_write_prph(priv, addr, val);
+}
+
+#define iwl4965_write_prph(priv, addr, val) \
+	__iwl4965_write_prph(__LINE__, priv, addr, val);
+#else
+#define iwl4965_write_prph _iwl4965_write_prph
+#endif
+
+#define _iwl4965_set_bits_prph(priv, reg, mask) \
+	_iwl4965_write_prph(priv, reg, (_iwl4965_read_prph(priv, reg) | mask))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bits_prph(u32 line, struct iwl4965_priv *priv,
+					u32 reg, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+
+	_iwl4965_set_bits_prph(priv, reg, mask);
+}
+#define iwl4965_set_bits_prph(priv, reg, mask) \
+	__iwl4965_set_bits_prph(__LINE__, priv, reg, mask)
+#else
+#define iwl4965_set_bits_prph _iwl4965_set_bits_prph
+#endif
+
+#define _iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \
+	_iwl4965_write_prph(priv, reg, ((_iwl4965_read_prph(priv, reg) & mask) | bits))
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bits_mask_prph(u32 line,
+		struct iwl4965_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl4965_set_bits_mask_prph(priv, reg, bits, mask);
+}
+#define iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \
+	__iwl4965_set_bits_mask_prph(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl4965_set_bits_mask_prph _iwl4965_set_bits_mask_prph
+#endif
+
+static inline void iwl4965_clear_bits_prph(struct iwl4965_priv
+						 *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read_prph(priv, reg);
+	_iwl4965_write_prph(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl4965_read_targ_mem(struct iwl4965_priv *priv, u32 addr)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	return iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl4965_write_targ_mem(struct iwl4965_priv *priv, u32 addr, u32 val)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl4965_write_targ_mem_buf(struct iwl4965_priv *priv, u32 addr,
+					  u32 len, u32 *values)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	for (; 0 < len; len -= sizeof(u32), values++)
+		iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 1c5b50b..60fc9ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -36,28 +36,23 @@
 
 #include <linux/workqueue.h>
 
-#include <net/mac80211.h>
-#include <linux/wireless.h>
-
 #include "../net/mac80211/ieee80211_rate.h"
 
-#include "iwlwifi.h"
-#include "iwl-4965-rs.h"
+#include "iwl-4965.h"
 #include "iwl-helpers.h"
 
 #define RS_NAME "iwl-4965-rs"
 
 #define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
 #define IWL_NUMBER_TRY      1
-#define IWL_HT_NUMBER_TRY   1
+#define IWL_HT_NUMBER_TRY   3
 
-#define IWL_RATE_MAX_WINDOW		62
-#define IWL_RATE_HIGH_TH		10880
-#define IWL_RATE_MIN_FAILURE_TH		6
-#define IWL_RATE_MIN_SUCCESS_TH		8
-#define IWL_RATE_DECREASE_TH		1920
-#define IWL_RATE_INCREASE_TH            8960
-#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)        /*2 seconds */
+#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */
+
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)
 
 static u8 rs_ht_to_legacy[] = {
 	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
@@ -69,65 +64,109 @@ static u8 rs_ht_to_legacy[] = {
 	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
 };
 
-struct iwl_rate_scale_data {
-	u64 data;
-	s32 success_counter;
-	s32 success_ratio;
-	s32 counter;
-	s32 average_tpt;
+struct iwl4965_rate {
+	u32 rate_n_flags;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_rate_scale_data -- tx success history for one rate
+ */
+struct iwl4965_rate_scale_data {
+	u64 data;		/* bitmap of successful frames */
+	s32 success_counter;	/* number of frames successful */
+	s32 success_ratio;	/* per-cent * 128  */
+	s32 counter;		/* number of frames attempted */
+	s32 average_tpt;	/* success ratio * expected throughput */
 	unsigned long stamp;
 };
 
-struct iwl_scale_tbl_info {
-	enum iwl_table_type lq_type;
-	enum iwl_antenna_type antenna_type;
-	u8 is_SGI;
-	u8 is_fat;
-	u8 is_dup;
-	s32 *expected_tpt;
-	u8 action;
-	struct iwl_rate current_rate;
-	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+/**
+ * struct iwl4965_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_rate_scale_priv,
+ * one for "active", and one for "search".
+ */
+struct iwl4965_scale_tbl_info {
+	enum iwl4965_table_type lq_type;
+	enum iwl4965_antenna_type antenna_type;
+	u8 is_SGI;	/* 1 = short guard interval */
+	u8 is_fat;	/* 1 = 40 MHz channel width */
+	u8 is_dup;	/* 1 = duplicated data streams */
+	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
+	struct iwl4965_rate current_rate;  /* rate_n_flags, uCode API format */
+	struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
 };
 
-struct iwl_rate_scale_priv {
-	u8 active_tbl;
-	u8 enable_counter;
-	u8 stay_in_tbl;
-	u8 search_better_tbl;
+/**
+ * struct iwl_rate_scale_priv -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl4965_rate_scale_priv {
+	u8 active_tbl;		/* index of active table, range 0-1 */
+	u8 enable_counter;	/* indicates HT mode */
+	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
+	u8 search_better_tbl;	/* 1: currently trying alternate mode */
 	s32 last_tpt;
+
+	/* The following determine when to search for a new mode */
 	u32 table_count_limit;
-	u32 max_failure_limit;
-	u32 max_success_limit;
+	u32 max_failure_limit;	/* # failed frames before new search */
+	u32 max_success_limit;	/* # successful frames before new search */
 	u32 table_count;
-	u32 total_failed;
-	u32 total_success;
-	u8 action_counter;
-	u32 flush_timer;
-	u8 commit_lq;
+	u32 total_failed;	/* total failed frames, any/all rates */
+	u32 total_success;	/* total successful frames, any/all rates */
+	u32 flush_timer;	/* time staying in mode before new search */
+
+	u8 action_counter;	/* # mode-switch actions tried */
 	u8 antenna;
 	u8 valid_antenna;
 	u8 is_green;
 	u8 is_dup;
 	u8 phymode;
-	u8 ready;
+	u8 ibss_sta_added;
+
+	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
+	u32 supp_rates;
 	u16 active_rate;
 	u16 active_siso_rate;
 	u16 active_mimo_rate;
 	u16 active_rate_basic;
-	struct iwl_link_quality_cmd lq;
-	struct iwl_scale_tbl_info lq_info[LQ_SIZE];
+
+	struct iwl4965_link_quality_cmd lq;
+	struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *rs_sta_dbgfs_scale_table_file;
+	struct dentry *rs_sta_dbgfs_stats_table_file;
+	struct iwl4965_rate dbg_fixed;
+	struct iwl4965_priv *drv;
+#endif
 };
 
-static void rs_rate_scale_perform(struct iwl_priv *priv,
+static void rs_rate_scale_perform(struct iwl4965_priv *priv,
 				   struct net_device *dev,
 				   struct ieee80211_hdr *hdr,
 				   struct sta_info *sta);
-static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_rate *tx_mcs,
-			     struct iwl_link_quality_cmd *tbl);
-
+static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data,
+			     struct iwl4965_rate *tx_mcs,
+			     struct iwl4965_link_quality_cmd *tbl);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
+				struct iwl4965_rate *mcs, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
+				struct iwl4965_rate *mcs, int index)
+{}
+#endif
 
+/*
+ * Expected throughput metrics for following rates:
+ * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ * "G" is the only table that supports CCK (the first 4 rates).
+ */
 static s32 expected_tpt_A[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
 };
@@ -168,31 +207,34 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
 };
 
-static int iwl_lq_sync_callback(struct iwl_priv *priv,
-				struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl4965_lq_sync_callback(struct iwl4965_priv *priv,
+				struct iwl4965_cmd *cmd, struct sk_buff *skb)
 {
 	/*We didn't cache the SKB; let the caller free it */
 	return 1;
 }
 
-static int rs_send_lq_cmd(struct iwl_priv *priv,
-			  struct iwl_link_quality_cmd *lq, u8 flags)
+static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
+	return (u8)(rate_n_flags & 0xFF);
+}
+
+static int rs_send_lq_cmd(struct iwl4965_priv *priv,
+			  struct iwl4965_link_quality_cmd *lq, u8 flags)
+{
+#ifdef CONFIG_IWL4965_DEBUG
 	int i;
 #endif
-	int rc = -1;
-
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_TX_LINK_QUALITY_CMD,
-		.len = sizeof(struct iwl_link_quality_cmd),
+		.len = sizeof(struct iwl4965_link_quality_cmd),
 		.meta.flags = flags,
 		.data = lq,
 	};
 
 	if ((lq->sta_id == 0xFF) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
-		return rc;
+		return -EINVAL;
 
 	if (lq->sta_id == 0xFF)
 		lq->sta_id = IWL_AP_ID;
@@ -201,54 +243,62 @@ static int rs_send_lq_cmd(struct iwl_priv *priv,
 	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
 		       lq->general_params.single_stream_ant_msk,
 		       lq->general_params.dual_stream_ant_msk);
-#ifdef CONFIG_IWLWIFI_DEBUG
-	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+#ifdef CONFIG_IWL4965_DEBUG
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
 		IWL_DEBUG_RATE("lq index %d 0x%X\n",
-			       i, lq->rate_scale_table[i].rate_n_flags);
-	}
+				i, lq->rs_table[i].rate_n_flags);
 #endif
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_lq_sync_callback;
+		cmd.meta.u.callback = iwl4965_lq_sync_callback;
 
-	if (priv->assoc_station_added)
-		rc = iwl_send_cmd(priv, &cmd);
+	if (iwl4965_is_associated(priv) && priv->assoc_station_added &&
+	    priv->lq_mngr.lq_ready)
+		return  iwl4965_send_cmd(priv, &cmd);
 
-	return rc;
+	return 0;
 }
 
-static int rs_rate_scale_clear_window(struct iwl_rate_scale_data
-				      *window)
+static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
 {
-
 	window->data = 0;
 	window->success_counter = 0;
 	window->success_ratio = IWL_INVALID_VALUE;
 	window->counter = 0;
 	window->average_tpt = IWL_INVALID_VALUE;
 	window->stamp = 0;
-	return 0;
 }
 
-static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
 			      int scale_index, s32 tpt, u32 status)
 {
-	int rc = 0;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *window = NULL;
 	u64 mask;
 	u8 win_size = IWL_RATE_MAX_WINDOW;
 	s32 fail_count;
 
-	if (scale_index < 0)
-		return -1;
-
-	if (scale_index >= IWL_RATE_COUNT)
-		return -1;
+	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+		return -EINVAL;
 
+	/* Select data for current tx bit rate */
 	window = &(windows[scale_index]);
 
+	/*
+	 * Keep track of only the latest 62 tx frame attempts in this rate's
+	 * history window; anything older isn't really relevant any more.
+	 * If we have filled up the sliding window, drop the oldest attempt;
+	 * if the oldest attempt (highest bit in bitmap) shows "success",
+	 * subtract "1" from the success counter (this is the main reason
+	 * we keep these bitmaps!).
+	 */
 	if (window->counter >= win_size) {
-
 		window->counter = win_size - 1;
 		mask = 1;
 		mask = (mask << (win_size - 1));
@@ -258,7 +308,11 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
 		}
 	}
 
+	/* Increment frames-attempted counter */
 	window->counter = window->counter + 1;
+
+	/* Shift bitmap by one frame (throw away oldest history),
+	 * OR in "1", and increment "success" if this frame was successful. */
 	mask = window->data;
 	window->data = (mask << 1);
 	if (status != 0) {
@@ -266,46 +320,49 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
 		window->data |= 0x1;
 	}
 
-	if (window->counter > 0) {
+	/* Calculate current success ratio, avoid divide-by-0! */
+	if (window->counter > 0)
 		window->success_ratio = 128 * (100 * window->success_counter)
 					/ window->counter;
-	} else
+	else
 		window->success_ratio = IWL_INVALID_VALUE;
 
-
 	fail_count = window->counter - window->success_counter;
+
+	/* Calculate average throughput, if we have enough history. */
 	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
 	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
-		window->average_tpt = ((window->success_ratio *
-					tpt + 64) / 128);
+		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
 	else
-		 window->average_tpt = IWL_INVALID_VALUE;
+		window->average_tpt = IWL_INVALID_VALUE;
 
+	/* Tag this window as having been updated */
 	window->stamp = jiffies;
 
-	return rc;
+	return 0;
 }
 
-int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
-			   struct iwl_scale_tbl_info *tbl,
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate,
+			   struct iwl4965_scale_tbl_info *tbl,
 			   int index, u8 use_green)
 {
-	int rc = 0;
-
 	if (is_legacy(tbl->lq_type)) {
-		mcs_rate->rate_n_flags = iwl_rates[index].plcp;
+		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp;
 		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
 			mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
 
 	} else if (is_siso(tbl->lq_type)) {
 		if (index > IWL_LAST_OFDM_RATE)
 			index = IWL_LAST_OFDM_RATE;
-		 mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |
+		 mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
 					  RATE_MCS_HT_MSK;
 	} else {
 		if (index > IWL_LAST_OFDM_RATE)
 			index = IWL_LAST_OFDM_RATE;
-		mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |
+		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
 					 RATE_MCS_HT_MSK;
 	}
 
@@ -324,7 +381,7 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
 	}
 
 	if (is_legacy(tbl->lq_type))
-		return rc;
+		return;
 
 	if (tbl->is_fat) {
 		if (tbl->is_dup)
@@ -340,27 +397,31 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
 		if (is_siso(tbl->lq_type))
 			mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
 	}
-	return rc;
 }
 
-static int rs_get_tbl_info_from_mcs(struct iwl_rate *mcs_rate, int phymode,
-				    struct iwl_scale_tbl_info *tbl,
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate,
+				    int phymode, struct iwl4965_scale_tbl_info *tbl,
 				    int *rate_idx)
 {
 	int index;
 	u32 ant_msk;
 
-	index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);
+	index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags);
 
 	if (index  == IWL_RATE_INVALID) {
 		*rate_idx = -1;
-		return -1;
+		return -EINVAL;
 	}
-	tbl->is_SGI = 0;
+	tbl->is_SGI = 0;	/* default legacy setup */
 	tbl->is_fat = 0;
 	tbl->is_dup = 0;
-	tbl->antenna_type = ANT_BOTH;
+	tbl->antenna_type = ANT_BOTH;	/* default MIMO setup */
 
+	/* legacy rate format */
 	if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
 		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
 
@@ -368,8 +429,7 @@ static int rs_get_tbl_info_from_mcs(struct iwl_rate *mcs_rate, int phymode,
 			tbl->lq_type = LQ_NONE;
 		else {
 
-			if ((phymode == MODE_ATHEROS_TURBO) ||
-			    (phymode == MODE_IEEE80211A))
+			if (phymode == MODE_IEEE80211A)
 				tbl->lq_type = LQ_A;
 			else
 				tbl->lq_type = LQ_G;
@@ -381,7 +441,9 @@ static int rs_get_tbl_info_from_mcs(struct iwl_rate *mcs_rate, int phymode,
 		}
 		*rate_idx = index;
 
-	} else if (mcs_rate->s.rate <= IWL_RATE_SISO_60M_PLCP) {
+	/* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */
+	} else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags)
+					<= IWL_RATE_SISO_60M_PLCP) {
 		tbl->lq_type = LQ_SISO;
 
 		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
@@ -404,6 +466,8 @@ static int rs_get_tbl_info_from_mcs(struct iwl_rate *mcs_rate, int phymode,
 			tbl->is_dup = 1;
 
 		*rate_idx = index;
+
+	/* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */
 	} else {
 		tbl->lq_type = LQ_MIMO;
 		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
@@ -420,8 +484,8 @@ static int rs_get_tbl_info_from_mcs(struct iwl_rate *mcs_rate, int phymode,
 	return 0;
 }
 
-static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
-				     struct iwl_scale_tbl_info *tbl)
+static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate,
+				     struct iwl4965_scale_tbl_info *tbl)
 {
 	if (tbl->antenna_type == ANT_AUX) {
 		tbl->antenna_type = ANT_MAIN;
@@ -434,18 +498,15 @@ static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
 	}
 }
 
-static inline s8 rs_use_green(struct iwl_priv *priv)
+static inline u8 rs_use_green(struct iwl4965_priv *priv,
+			      struct ieee80211_conf *conf)
 {
-	s8 rc = 0;
-#ifdef CONFIG_IWLWIFI_HT
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
-		return 0;
-
-	if ((priv->current_assoc_ht.is_green_field) &&
-	    !(priv->current_assoc_ht.operating_mode & 0x4))
-		rc = 1;
-#endif	/*CONFIG_IWLWIFI_HT */
-	return rc;
+#ifdef CONFIG_IWL4965_HT
+	return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+		priv->current_ht_config.is_green_field &&
+		!priv->current_ht_config.non_GF_STA_present);
+#endif	/* CONFIG_IWL4965_HT */
+	return 0;
 }
 
 /**
@@ -455,10 +516,10 @@ static inline s8 rs_use_green(struct iwl_priv *priv)
  * basic available rates.
  *
  */
-static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
-				    struct ieee80211_hdr *hdr,
-				    enum iwl_table_type rate_type,
-				    u16 * data_rate)
+static void rs_get_supported_rates(struct iwl4965_rate_scale_priv *lq_data,
+				   struct ieee80211_hdr *hdr,
+				   enum iwl4965_table_type rate_type,
+				   u16 *data_rate)
 {
 	if (is_legacy(rate_type))
 		*data_rate = lq_data->active_rate;
@@ -469,8 +530,8 @@ static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
 			*data_rate = lq_data->active_mimo_rate;
 	}
 
-	if (hdr && (is_multicast_ether_addr(hdr->addr1))
-	    && (lq_data->active_rate_basic))
+	if (hdr && is_multicast_ether_addr(hdr->addr1) &&
+	    lq_data->active_rate_basic)
 		*data_rate = lq_data->active_rate_basic;
 }
 
@@ -479,7 +540,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 	u8 high = IWL_RATE_INVALID;
 	u8 low = IWL_RATE_INVALID;
 
-	/* 802.11A or ht walks to the next literal adjascent rate in
+	/* 802.11A or ht walks to the next literal adjacent rate in
 	 * the rate table */
 	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
 		int i;
@@ -508,7 +569,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
 	low = index;
 	while (low != IWL_RATE_INVALID) {
-		low = iwl_rates[low].prev_rs;
+		low = iwl4965_rates[low].prev_rs;
 		if (low == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << low))
@@ -518,7 +579,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
 	high = index;
 	while (high != IWL_RATE_INVALID) {
-		high = iwl_rates[high].next_rs;
+		high = iwl4965_rates[high].next_rs;
 		if (high == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << high))
@@ -529,54 +590,65 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 	return (high << 8) | low;
 }
 
-static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, u8 scale_index,
-			     u8 ht_possible, struct iwl_rate *msc_rate)
+static void rs_get_lower_rate(struct iwl4965_rate_scale_priv *lq_data,
+			     struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
+			     u8 ht_possible, struct iwl4965_rate *mcs_rate)
 {
-	u8 is_green = lq_data->is_green;
-	s32 low, high;
+	s32 low;
 	u16 rate_mask;
 	u16 high_low;
+	u8 switch_to_legacy = 0;
+	u8 is_green = lq_data->is_green;
 
-	if (is_legacy(tbl->lq_type) || (ht_possible && scale_index)) {
-		rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
-					&rate_mask);
+	/* check if we need to switch from HT to legacy rates.
+	 * assumption is that mandatory rates (1Mbps or 6Mbps)
+	 * are always supported (spec demand) */
+	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+		switch_to_legacy = 1;
+		scale_index = rs_ht_to_legacy[scale_index];
+		if (lq_data->phymode == MODE_IEEE80211A)
+			tbl->lq_type = LQ_A;
+		else
+			tbl->lq_type = LQ_G;
 
-		high_low = rs_get_adjacent_rate(scale_index,
-						 rate_mask, tbl->lq_type);
-		low = high_low & 0xff;
-		high = (high_low >> 8) & 0xff;
+		if ((tbl->antenna_type == ANT_BOTH) ||
+		    (tbl->antenna_type == ANT_NONE))
+			tbl->antenna_type = ANT_MAIN;
 
-		if (low == IWL_RATE_INVALID) {
-			if (is_legacy(tbl->lq_type)) {
-				low = scale_index;
-				rs_mcs_from_tbl(msc_rate, tbl,
-						     low, is_green);
-				return 0;
-			}
-		} else {
-			rs_mcs_from_tbl(msc_rate, tbl, low, is_green);
-			return 0;
-		}
+		tbl->is_fat = 0;
+		tbl->is_SGI = 0;
 	}
 
-	low = rs_ht_to_legacy[scale_index];
-	if ((lq_data->phymode == MODE_IEEE80211A) ||
-	    (lq_data->phymode == MODE_ATHEROS_TURBO))
-		tbl->lq_type = LQ_A;
-	else
-		tbl->lq_type = LQ_G;
+	rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);
 
-	if ((tbl->antenna_type == ANT_BOTH) || (tbl->antenna_type == ANT_NONE))
-		tbl->antenna_type = ANT_MAIN;
+	/* Mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		/* supp_rates has no CCK bits in A mode */
+		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+			rate_mask  = (u16)(rate_mask &
+			   (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_mask = (u16)(rate_mask & lq_data->supp_rates);
+	}
 
-	tbl->is_fat = 0;
-	tbl->is_SGI = 0;
+	/* If we switched from HT to legacy, check current rate */
+	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
+		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+		return;
+	}
 
-	rs_mcs_from_tbl(msc_rate, tbl, low, is_green);
-	return 0;
+	high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+	low = high_low & 0xff;
+
+	if (low != IWL_RATE_INVALID)
+		rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
+	else
+		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
 }
 
+/*
+ * mac80211 sends us Tx status
+ */
 static void rs_tx_status(void *priv_rate,
 			 struct net_device *dev,
 			 struct sk_buff *skb,
@@ -585,23 +657,22 @@ static void rs_tx_status(void *priv_rate,
 	int status;
 	u8 retries;
 	int rs_index, index = 0;
-	struct iwl_rate_scale_priv *lq;
-	struct iwl_link_quality_cmd *table;
+	struct iwl4965_rate_scale_priv *lq;
+	struct iwl4965_link_quality_cmd *table;
 	struct sta_info *sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iwl_rate_scale_data *window = NULL;
-	struct iwl_rate_scale_data *search_win = NULL;
-	struct iwl_rate tx_mcs;
-	struct iwl_scale_tbl_info tbl_type;
-	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
+	struct iwl4965_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *search_win = NULL;
+	struct iwl4965_rate tx_mcs;
+	struct iwl4965_scale_tbl_info tbl_type;
+	struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
 	u8 active_index = 0;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	s32 tpt = 0;
 
-	IWL_DEBUG_RATE("getting frame ack response, update rate "
-		       "scale window\n");
+	IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
 
 	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
 		return;
@@ -620,20 +691,30 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
+
+	if (!priv->lq_mngr.lq_ready)
+		return;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
+		return;
+
 	table = &lq->lq;
 	active_index = lq->active_tbl;
 
+	/* Get mac80211 antenna info */
 	lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
 	if (!lq->antenna)
 		lq->antenna = lq->valid_antenna;
 
+	/* Ignore mac80211 antenna info for now */
 	lq->antenna = lq->valid_antenna;
+
 	curr_tbl = &(lq->lq_info[active_index]);
 	search_tbl = &(lq->lq_info[(1 - active_index)]);
-	window = (struct iwl_rate_scale_data *)
+	window = (struct iwl4965_rate_scale_data *)
 	    &(curr_tbl->win[0]);
-	search_win = (struct iwl_rate_scale_data *)
+	search_win = (struct iwl4965_rate_scale_data *)
 	    &(search_tbl->win[0]);
 
 	tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
@@ -647,21 +728,35 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
+	/*
+	 * Ignore this Tx frame response if its initial rate doesn't match
+	 * that of latest Link Quality command.  There may be stragglers
+	 * from a previous Link Quality command, but we're no longer interested
+	 * in those; they're either from the "active" mode while we're trying
+	 * to check "search" mode, or a prior "search" mode after we've moved
+	 * to a new "search" mode (which might become the new "active" mode).
+	 */
 	if (retries &&
-	    (tx_mcs.rate_n_flags != table->rate_scale_table[0].rate_n_flags)) {
+	    (tx_mcs.rate_n_flags !=
+				le32_to_cpu(table->rs_table[0].rate_n_flags))) {
 		IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
 				tx_mcs.rate_n_flags,
-				table->rate_scale_table[0].rate_n_flags);
+				le32_to_cpu(table->rs_table[0].rate_n_flags));
 		sta_info_put(sta);
 		return;
 	}
 
+	/* Update frame history window with "failure" for each Tx retry. */
 	while (retries) {
+		/* Look up the rate and other info used for each tx attempt.
+		 * Each tx attempt steps one entry deeper in the rate table. */
 		tx_mcs.rate_n_flags =
-		    table->rate_scale_table[index].rate_n_flags;
+		    le32_to_cpu(table->rs_table[index].rate_n_flags);
 		rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
 					  &tbl_type, &rs_index);
 
+		/* If type matches "search" table,
+		 * add failure to "search" history */
 		if ((tbl_type.lq_type == search_tbl->lq_type) &&
 		    (tbl_type.antenna_type == search_tbl->antenna_type) &&
 		    (tbl_type.is_SGI == search_tbl->is_SGI)) {
@@ -669,8 +764,10 @@ static void rs_tx_status(void *priv_rate,
 				tpt = search_tbl->expected_tpt[rs_index];
 			else
 				tpt = 0;
-			rs_collect_tx_data(search_win,
-					    rs_index, tpt, 0);
+			rs_collect_tx_data(search_win, rs_index, tpt, 0);
+
+		/* Else if type matches "current/active" table,
+		 * add failure to "current/active" history */
 		} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
 			   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
 			   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
@@ -680,6 +777,9 @@ static void rs_tx_status(void *priv_rate,
 				tpt = 0;
 			rs_collect_tx_data(window, rs_index, tpt, 0);
 		}
+
+		/* If not searching for a new mode, increment failed counter
+		 * ... this helps determine when to start searching again */
 		if (lq->stay_in_tbl)
 			lq->total_failed++;
 		--retries;
@@ -687,20 +787,28 @@ static void rs_tx_status(void *priv_rate,
 
 	}
 
-	if (!tx_resp->retry_count )
+	/*
+	 * Find (by rate) the history window to update with final Tx attempt;
+	 * if Tx was successful first try, use original rate,
+	 * else look up the rate that was, finally, successful.
+	 */
+	if (!tx_resp->retry_count)
 		tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
 	else
 		tx_mcs.rate_n_flags =
-			table->rate_scale_table[index].rate_n_flags;
+			le32_to_cpu(table->rs_table[index].rate_n_flags);
 
 	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
 				  &tbl_type, &rs_index);
 
+	/* Update frame history window with "success" if Tx got ACKed ... */
 	if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
 		status = 1;
 	else
 		status = 0;
 
+	/* If type matches "search" table,
+	 * add final tx status to "search" history */
 	if ((tbl_type.lq_type == search_tbl->lq_type) &&
 	    (tbl_type.antenna_type == search_tbl->antenna_type) &&
 	    (tbl_type.is_SGI == search_tbl->is_SGI)) {
@@ -710,6 +818,9 @@ static void rs_tx_status(void *priv_rate,
 			tpt = 0;
 		rs_collect_tx_data(search_win,
 				    rs_index, tpt, status);
+
+	/* Else if type matches "current/active" table,
+	 * add final tx status to "current/active" history */
 	} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
 		   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
 		   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
@@ -720,6 +831,8 @@ static void rs_tx_status(void *priv_rate,
 		rs_collect_tx_data(window, rs_index, tpt, status);
 	}
 
+	/* If not searching for new mode, increment success/failed counter
+	 * ... these help determine when to start searching again */
 	if (lq->stay_in_tbl) {
 		if (status)
 			lq->total_success++;
@@ -727,65 +840,53 @@ static void rs_tx_status(void *priv_rate,
 			lq->total_failed++;
 	}
 
+	/* See if there's a better rate or modulation mode to try. */
 	rs_rate_scale_perform(priv, dev, hdr, sta);
 	sta_info_put(sta);
 	return;
 }
 
 static u8 rs_is_ant_connected(u8 valid_antenna,
-			      enum iwl_antenna_type antenna_type)
+			      enum iwl4965_antenna_type antenna_type)
 {
 	if (antenna_type == ANT_AUX)
 		return ((valid_antenna & 0x2) ? 1:0);
 	else if (antenna_type == ANT_MAIN)
 		return ((valid_antenna & 0x1) ? 1:0);
-	else if (antenna_type == ANT_BOTH) {
-		if ((valid_antenna & 0x3) == 0x3)
-			return 1;
-		else
-			return 0;
-	}
+	else if (antenna_type == ANT_BOTH)
+		return ((valid_antenna & 0x3) == 0x3);
 
 	return 1;
 }
 
 static u8 rs_is_other_ant_connected(u8 valid_antenna,
-				    enum iwl_antenna_type antenna_type)
+				    enum iwl4965_antenna_type antenna_type)
 {
 	if (antenna_type == ANT_AUX)
-		return (rs_is_ant_connected(valid_antenna, ANT_MAIN));
+		return rs_is_ant_connected(valid_antenna, ANT_MAIN);
 	else
-		return (rs_is_ant_connected(valid_antenna, ANT_AUX));
+		return rs_is_ant_connected(valid_antenna, ANT_AUX);
 
 	return 0;
 }
 
-#define IWL_LEGACY_SWITCH_ANTENNA	0
-#define IWL_LECACY_SWITCH_SISO		1
-#define IWL_LEGACY_SWITCH_MIMO	        2
-
-#define IWL_RS_GOOD_RATIO		12800
-
-#define IWL_ACTION_LIMIT		3
-#define IWL_LEGACY_FAILURE_LIMIT	160
-#define IWL_LEGACY_SUCCESS_LIMIT	480
-#define IWL_LEGACY_TABLE_COUNT		160
-
-#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
-#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
-#define IWL_NONE_LEGACY_TABLE_COUNT	1500
-
-#define IWL_RATE_SCALE_SWITCH		(10880)
-
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
 static void rs_set_stay_in_table(u8 is_legacy,
-				 struct iwl_rate_scale_priv *lq_data)
+				 struct iwl4965_rate_scale_priv *lq_data)
 {
 	IWL_DEBUG_HT("we are staying in the same table\n");
-	lq_data->stay_in_tbl = 1;
+	lq_data->stay_in_tbl = 1;	/* only place this gets set */
 	if (is_legacy) {
 		lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
 		lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
-		lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_data->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
 	} else {
 		lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
 		lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
@@ -796,8 +897,11 @@ static void rs_set_stay_in_table(u8 is_legacy,
 	lq_data->total_success = 0;
 }
 
-static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
-				      struct iwl_scale_tbl_info *tbl)
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+static void rs_get_expected_tpt_table(struct iwl4965_rate_scale_priv *lq_data,
+				      struct iwl4965_scale_tbl_info *tbl)
 {
 	if (is_legacy(tbl->lq_type)) {
 		if (!is_a_band(tbl->lq_type))
@@ -829,72 +933,130 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
 		tbl->expected_tpt = expected_tpt_G;
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-static s32 rs_get_best_rate(struct iwl_priv *priv,
-			    struct iwl_rate_scale_priv *lq_data,
-			    struct iwl_scale_tbl_info *tbl,
+#ifdef CONFIG_IWL4965_HT
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput.  When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl4965_priv *priv,
+			    struct iwl4965_rate_scale_priv *lq_data,
+			    struct iwl4965_scale_tbl_info *tbl,	/* "search" */
 			    u16 rate_mask, s8 index, s8 rate)
 {
-	struct iwl_scale_tbl_info *active_tbl =
+	/* "active" values */
+	struct iwl4965_scale_tbl_info *active_tbl =
 	    &(lq_data->lq_info[lq_data->active_tbl]);
-	s32 new_rate, high, low;
 	s32 active_sr = active_tbl->win[index].success_ratio;
-	s32 *tpt_tbl = tbl->expected_tpt;
 	s32 active_tpt = active_tbl->expected_tpt[index];
+
+	/* expected "search" throughput */
+	s32 *tpt_tbl = tbl->expected_tpt;
+
+	s32 new_rate, high, low, start_hi;
 	u16 high_low;
 
-	new_rate = high = low = IWL_RATE_INVALID;
+	new_rate = high = low = start_hi = IWL_RATE_INVALID;
 
-	for (;;) {
-		high_low = rs_get_adjacent_rate(rate,
-						 rate_mask, tbl->lq_type);
+	for (; ;) {
+		high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
 
 		low = high_low & 0xff;
 		high = (high_low >> 8) & 0xff;
 
+		/*
+		 * Lower the "search" bit rate, to give new "search" mode
+		 * approximately the same throughput as "active" if:
+		 *
+		 * 1) "Active" mode has been working modestly well (but not
+		 *    great), and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above the actual
+		 *    measured "active" throughput (but less than expected
+		 *    "active" throughput under perfect conditions).
+		 * OR
+		 * 2) "Active" mode has been working perfectly or very well
+		 *    and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above expected
+		 *    "active" throughput (under perfect conditions).
+		 */
 		if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
 		     ((active_sr > IWL_RATE_DECREASE_TH) &&
 		      (active_sr <= IWL_RATE_HIGH_TH) &&
 		      (tpt_tbl[rate] <= active_tpt))) ||
 		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
 		     (tpt_tbl[rate] > active_tpt))) {
+
+			/* (2nd or later pass)
+			 * If we've already tried to raise the rate, and are
+			 * now trying to lower it, use the higher rate. */
+			if (start_hi != IWL_RATE_INVALID) {
+				new_rate = start_hi;
+				break;
+			}
+
 			new_rate = rate;
+
+			/* Loop again with lower rate */
 			if (low != IWL_RATE_INVALID)
 				rate = low;
+
+			/* Lower rate not available, use the original */
 			else
 				break;
+
+		/* Else try to raise the "search" rate to match "active" */
 		} else {
+			/* (2nd or later pass)
+			 * If we've already tried to lower the rate, and are
+			 * now trying to raise it, use the lower rate. */
 			if (new_rate != IWL_RATE_INVALID)
 				break;
-			else if (high != IWL_RATE_INVALID)
+
+			/* Loop again with higher rate */
+			else if (high != IWL_RATE_INVALID) {
+				start_hi = high;
 				rate = high;
-			else
+
+			/* Higher rate not available, use the original */
+			} else {
+				new_rate = rate;
 				break;
+			}
 		}
 	}
-	if (new_rate == IWL_RATE_INVALID)
-		new_rate = rate;
 
 	return new_rate;
 }
-#endif				/* CONFIG_IWLWIFI_HT */
+#endif				/* CONFIG_IWL4965_HT */
 
 static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
 {
 	return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
 }
 
-static int rs_switch_to_mimo(struct iwl_priv *priv,
-			     struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, int index)
+/*
+ * Set up search table for MIMO
+ */
+static int rs_switch_to_mimo(struct iwl4965_priv *priv,
+			     struct iwl4965_rate_scale_priv *lq_data,
+			     struct ieee80211_conf *conf,
+			     struct sta_info *sta,
+			     struct iwl4965_scale_tbl_info *tbl, int index)
 {
-	int rc = -1;
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	u16 rate_mask;
 	s32 rate;
 	s8 is_green = lq_data->is_green;
 
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+	    !sta->ht_info.ht_supported)
 		return -1;
 
 	IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
@@ -902,36 +1064,34 @@ static int rs_switch_to_mimo(struct iwl_priv *priv,
 	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
 				&rate_mask);
 
-	if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+	if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
 		return -1;
 
+	/* Need both Tx chains/antennas to support MIMO */
 	if (!rs_is_both_ant_supp(lq_data->antenna))
 		return -1;
 
-	rc = 0;
 	tbl->is_dup = lq_data->is_dup;
 	tbl->action = 0;
-	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+	if (priv->current_ht_config.supported_chan_width
+	    == IWL_CHANNEL_WIDTH_40MHZ)
 		tbl->is_fat = 1;
 	else
 		tbl->is_fat = 0;
 
 	if (tbl->is_fat) {
-		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
 			tbl->is_SGI = 1;
 		else
 			tbl->is_SGI = 0;
-	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
 		tbl->is_SGI = 1;
 	else
 		tbl->is_SGI = 0;
 
 	rs_get_expected_tpt_table(lq_data, tbl);
 
-	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, 4);
-
-	if ((rate == IWL_RATE_INVALID) || (rate == 1))
-		rate = IWL_RATE_48M_INDEX;
+	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
 
 	IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
 	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
@@ -940,43 +1100,49 @@ static int rs_switch_to_mimo(struct iwl_priv *priv,
 
 	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
 		     tbl->current_rate.rate_n_flags, is_green);
-
-#endif				/*CONFIG_IWLWIFI_HT */
-	return rc;
+	return 0;
+#else
+	return -1;
+#endif				/*CONFIG_IWL4965_HT */
 }
 
-static int rs_switch_to_siso(struct iwl_priv *priv,
-			     struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, int index)
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl4965_priv *priv,
+			     struct iwl4965_rate_scale_priv *lq_data,
+			     struct ieee80211_conf *conf,
+			     struct sta_info *sta,
+			     struct iwl4965_scale_tbl_info *tbl, int index)
 {
-	int rc = -1;
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	u16 rate_mask;
 	u8 is_green = lq_data->is_green;
 	s32 rate;
 
 	IWL_DEBUG_HT("LQ: try to switch to SISO\n");
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+	    !sta->ht_info.ht_supported)
 		return -1;
 
-	rc = 0;
 	tbl->is_dup = lq_data->is_dup;
 	tbl->lq_type = LQ_SISO;
 	tbl->action = 0;
 	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
 				&rate_mask);
 
-	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+	if (priv->current_ht_config.supported_chan_width
+	    == IWL_CHANNEL_WIDTH_40MHZ)
 		tbl->is_fat = 1;
 	else
 		tbl->is_fat = 0;
 
 	if (tbl->is_fat) {
-		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
 			tbl->is_SGI = 1;
 		else
 			tbl->is_SGI = 0;
-	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
 		tbl->is_SGI = 1;
 	else
 		tbl->is_SGI = 0;
@@ -985,9 +1151,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 		tbl->is_SGI = 0;
 
 	rs_get_expected_tpt_table(lq_data, tbl);
-	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, 4);
-	if ((rate == IWL_RATE_INVALID) || (rate == 1))
-		rate = IWL_RATE_48M_INDEX;
+	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
 	IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
 	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
 		IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
@@ -997,37 +1162,50 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
 	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
 		     tbl->current_rate.rate_n_flags, is_green);
+	return 0;
+#else
+	return -1;
 
-#endif				/*CONFIG_IWLWIFI_HT */
-	return rc;
+#endif				/*CONFIG_IWL4965_HT */
 }
 
-static int rs_move_legacy_other(struct iwl_priv *priv,
-				struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl4965_priv *priv,
+				struct iwl4965_rate_scale_priv *lq_data,
+				struct ieee80211_conf *conf,
+				struct sta_info *sta,
 				int index)
 {
-	int rc = 0;
-	struct iwl_scale_tbl_info *tbl =
+	int ret = 0;
+	struct iwl4965_scale_tbl_info *tbl =
 	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
+	struct iwl4965_scale_tbl_info *search_tbl =
 	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
-	for (;;) {
+
+	for (; ;) {
 		switch (tbl->action) {
 		case IWL_LEGACY_SWITCH_ANTENNA:
 			IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
 
 			search_tbl->lq_type = LQ_NONE;
 			lq_data->action_counter++;
+
+			/* Don't change antenna if success has been great */
 			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
 				break;
+
+			/* Don't change antenna if other one is not connected */
 			if (!rs_is_other_ant_connected(lq_data->antenna,
 							tbl->antenna_type))
 				break;
 
+			/* Set up search table to try other antenna */
 			memcpy(search_tbl, tbl, sz);
 
 			rs_toggle_antenna(&(search_tbl->current_rate),
@@ -1036,37 +1214,39 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 			lq_data->search_better_tbl = 1;
 			goto out;
 
-		case IWL_LECACY_SWITCH_SISO:
+		case IWL_LEGACY_SWITCH_SISO:
 			IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+
+			/* Set up search table to try SISO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_SISO;
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
-			rc = rs_switch_to_siso(priv, lq_data,
+			ret = rs_switch_to_siso(priv, lq_data, conf, sta,
 						 search_tbl, index);
-			if (!rc) {
+			if (!ret) {
 				lq_data->search_better_tbl = 1;
 				lq_data->action_counter = 0;
-			}
-			if (!rc)
 				goto out;
+			}
 
 			break;
 		case IWL_LEGACY_SWITCH_MIMO:
 			IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+
+			/* Set up search table to try MIMO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_MIMO;
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
 			search_tbl->antenna_type = ANT_BOTH;
-			rc = rs_switch_to_mimo(priv, lq_data,
+			ret = rs_switch_to_mimo(priv, lq_data, conf, sta,
 						 search_tbl, index);
-			if (!rc) {
+			if (!ret) {
 				lq_data->search_better_tbl = 1;
 				lq_data->action_counter = 0;
-			}
-			if (!rc)
 				goto out;
+			}
 			break;
 		}
 		tbl->action++;
@@ -1087,23 +1267,24 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 
 }
 
-#define IWL_SISO_SWITCH_ANTENNA  0
-#define IWL_SISO_SWITCH_MIMO     1
-#define IWL_SISO_SWITCH_GI       2
-
-static int rs_move_siso_to_other(struct iwl_priv *priv,
-				 struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl4965_priv *priv,
+				 struct iwl4965_rate_scale_priv *lq_data,
+				 struct ieee80211_conf *conf,
+				 struct sta_info *sta,
 				 int index)
 {
-	int rc = -1;
+	int ret;
 	u8 is_green = lq_data->is_green;
-	struct iwl_scale_tbl_info *tbl =
+	struct iwl4965_scale_tbl_info *tbl =
 	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
+	struct iwl4965_scale_tbl_info *search_tbl =
 	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 
 	for (;;) {
@@ -1133,13 +1314,12 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
 			search_tbl->antenna_type = ANT_BOTH;
-			rc = rs_switch_to_mimo(priv, lq_data,
+			ret = rs_switch_to_mimo(priv, lq_data, conf, sta,
 						 search_tbl, index);
-			if (!rc)
+			if (!ret) {
 				lq_data->search_better_tbl = 1;
-
-			if (!rc)
 				goto out;
+			}
 			break;
 		case IWL_SISO_SWITCH_GI:
 			IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
@@ -1151,8 +1331,17 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 				search_tbl->is_SGI = 1;
 			else
 				break;
-			rs_get_expected_tpt_table(lq_data, search_tbl);
 			lq_data->search_better_tbl = 1;
+			if ((tbl->lq_type == LQ_SISO) &&
+			    (tbl->is_SGI)) {
+				s32 tpt = lq_data->last_tpt / 100;
+				if (((!tbl->is_fat) &&
+				     (tpt >= expected_tpt_siso20MHz[index])) ||
+				    ((tbl->is_fat) &&
+				     (tpt >= expected_tpt_siso40MHz[index])))
+					lq_data->search_better_tbl = 0;
+			}
+			rs_get_expected_tpt_table(lq_data, search_tbl);
 			rs_mcs_from_tbl(&search_tbl->current_rate,
 					     search_tbl, index, is_green);
 			goto out;
@@ -1173,22 +1362,23 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 	return 0;
 }
 
-#define IWL_MIMO_SWITCH_ANTENNA_A	0
-#define IWL_MIMO_SWITCH_ANTENNA_B	1
-#define IWL_MIMO_SWITCH_GI		2
-
-static int rs_move_mimo_to_other(struct iwl_priv *priv,
-				 struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from MIMO
+ */
+static int rs_move_mimo_to_other(struct iwl4965_priv *priv,
+				 struct iwl4965_rate_scale_priv *lq_data,
+				 struct ieee80211_conf *conf,
+				 struct sta_info *sta,
 				 int index)
 {
-	int rc = -1;
+	int ret;
 	s8 is_green = lq_data->is_green;
-	struct iwl_scale_tbl_info *tbl =
+	struct iwl4965_scale_tbl_info *tbl =
 	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
+	struct iwl4965_scale_tbl_info *search_tbl =
 	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 
 	for (;;) {
@@ -1197,6 +1387,8 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 		case IWL_MIMO_SWITCH_ANTENNA_A:
 		case IWL_MIMO_SWITCH_ANTENNA_B:
 			IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+
+			/* Set up new search table for SISO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_SISO;
 			search_tbl->is_SGI = 0;
@@ -1206,9 +1398,9 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 			else
 				search_tbl->antenna_type = ANT_AUX;
 
-			rc = rs_switch_to_siso(priv, lq_data,
+			ret = rs_switch_to_siso(priv, lq_data, conf, sta,
 						 search_tbl, index);
-			if (!rc) {
+			if (!ret) {
 				lq_data->search_better_tbl = 1;
 				goto out;
 			}
@@ -1216,6 +1408,8 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 
 		case IWL_MIMO_SWITCH_GI:
 			IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+
+			/* Set up new search table for MIMO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_MIMO;
 			search_tbl->antenna_type = ANT_BOTH;
@@ -1225,6 +1419,22 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 			else
 				search_tbl->is_SGI = 1;
 			lq_data->search_better_tbl = 1;
+
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
+			if ((tbl->lq_type == LQ_MIMO) &&
+			    (tbl->is_SGI)) {
+				s32 tpt = lq_data->last_tpt / 100;
+				if (((!tbl->is_fat) &&
+				     (tpt >= expected_tpt_mimo20MHz[index])) ||
+				    ((tbl->is_fat) &&
+				     (tpt >= expected_tpt_mimo40MHz[index])))
+					lq_data->search_better_tbl = 0;
+			}
 			rs_get_expected_tpt_table(lq_data, search_tbl);
 			rs_mcs_from_tbl(&search_tbl->current_rate,
 					     search_tbl, index, is_green);
@@ -1232,7 +1442,7 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 
 		}
 		tbl->action++;
-		if (tbl->action > IWL_MIMO_SWITCH_ANTENNA_B)
+		if (tbl->action > IWL_MIMO_SWITCH_GI)
 			tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
 
 		if (tbl->action == start_action)
@@ -1242,15 +1452,22 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 	return 0;
  out:
 	tbl->action++;
-	if (tbl->action > IWL_MIMO_SWITCH_ANTENNA_B)
+	if (tbl->action > IWL_MIMO_SWITCH_GI)
 		tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
 	return 0;
 
 }
 
-static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl4965_rate_scale_priv *lq_data)
 {
-	struct iwl_scale_tbl_info *tbl;
+	struct iwl4965_scale_tbl_info *tbl;
 	int i;
 	int active_tbl;
 	int flush_interval_passed = 0;
@@ -1259,27 +1476,49 @@ static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
 
 	tbl = &(lq_data->lq_info[active_tbl]);
 
+	/* If we've been disallowing search, see if we should now allow it */
 	if (lq_data->stay_in_tbl) {
 
+		/* Elapsed time using current modulation mode */
 		if (lq_data->flush_timer)
 			flush_interval_passed =
 			    time_after(jiffies,
 				       (unsigned long)(lq_data->flush_timer +
 					IWL_RATE_SCALE_FLUSH_INTVL));
 
+		/* For now, disable the elapsed time criterion */
 		flush_interval_passed = 0;
+
+		/*
+		 * Check if we should allow search for new modulation mode.
+		 * If many frames have failed or succeeded, or we've used
+		 * this same modulation for a long time, allow search, and
+		 * reset history stats that keep track of whether we should
+		 * allow a new search.  Also (below) reset all bitmaps and
+		 * stats in active history.
+		 */
 		if ((lq_data->total_failed > lq_data->max_failure_limit) ||
 		    (lq_data->total_success > lq_data->max_success_limit) ||
 		    ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
 		     && (flush_interval_passed))) {
-			IWL_DEBUG_HT("LQ: stay is expired %d %d \n:",
+			IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
 				     lq_data->total_failed,
-				     lq_data->total_success);
-			lq_data->stay_in_tbl = 0;
+				     lq_data->total_success,
+				     flush_interval_passed);
+
+			/* Allow search for new mode */
+			lq_data->stay_in_tbl = 0;	/* only place reset */
 			lq_data->total_failed = 0;
 			lq_data->total_success = 0;
 			lq_data->flush_timer = 0;
-		} else if (lq_data->table_count > 0) {
+
+		/*
+		 * Else if we've used this modulation mode enough repetitions
+		 * (regardless of elapsed time or success/failure), reset
+		 * history bitmaps and rate-specific stats for all rates in
+		 * active table.
+		 */
+		} else {
 			lq_data->table_count++;
 			if (lq_data->table_count >=
 			    lq_data->table_count_limit) {
@@ -1292,6 +1531,9 @@ static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
 			}
 		}
 
+		/* If transitioning to allow "search", reset all history
+		 * bitmaps and stats in active table (this will become the new
+		 * "search" table). */
 		if (!lq_data->stay_in_tbl) {
 			for (i = 0; i < IWL_RATE_COUNT; i++)
 				rs_rate_scale_clear_window(&(tbl->win[i]));
@@ -1299,16 +1541,22 @@ static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
 	}
 }
 
-static void rs_rate_scale_perform(struct iwl_priv *priv,
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl4965_priv *priv,
 				  struct net_device *dev,
 				  struct ieee80211_hdr *hdr,
 				  struct sta_info *sta)
 {
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = local_to_hw(local);
+	struct ieee80211_conf *conf = &hw->conf;
 	int low = IWL_RATE_INVALID;
 	int high = IWL_RATE_INVALID;
 	int index;
 	int i;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *window = NULL;
 	int current_tpt = IWL_INVALID_VALUE;
 	int low_tpt = IWL_INVALID_VALUE;
 	int high_tpt = IWL_INVALID_VALUE;
@@ -1316,10 +1564,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	s8 scale_action = 0;
 	u16 fc, rate_mask;
 	u8 update_lq = 0;
-	struct iwl_rate_scale_priv *lq_data;
-	struct iwl_scale_tbl_info *tbl, *tbl1;
+	struct iwl4965_rate_scale_priv *lq_data;
+	struct iwl4965_scale_tbl_info *tbl, *tbl1;
 	u16 rate_scale_index_msk = 0;
-	struct iwl_rate mcs_rate;
+	struct iwl4965_rate mcs_rate;
 	u8 is_green = 0;
 	u8 active_tbl = 0;
 	u8 done_search = 0;
@@ -1338,12 +1586,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	if (!sta || !sta->rate_ctrl_priv)
 		return;
 
-	lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
-	if (!lq_data->ready) {
+	if (!priv->lq_mngr.lq_ready) {
 		IWL_DEBUG_RATE("still rate scaling not ready\n");
 		return;
 	}
+	lq_data = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
 
+	/*
+	 * Select rate-scale / modulation-mode table to work with in
+	 * the rest of this function:  "search" if searching for better
+	 * modulation mode, or "active" if doing rate scaling within a mode.
+	 */
 	if (!lq_data->search_better_tbl)
 		active_tbl = lq_data->active_tbl;
 	else
@@ -1352,11 +1605,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	tbl = &(lq_data->lq_info[active_tbl]);
 	is_green = lq_data->is_green;
 
+	/* current tx rate */
 	index = sta->last_txrate;
 
 	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
 		       tbl->lq_type);
 
+	/* rates available for this association, and for modulation mode */
 	rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
 				&rate_mask);
 
@@ -1364,13 +1619,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
 	/* mask with station rate restriction */
 	if (is_legacy(tbl->lq_type)) {
-		if ((lq_data->phymode == (u8) MODE_IEEE80211A) ||
-		    (lq_data->phymode == (u8) MODE_ATHEROS_TURBO))
+		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+			/* supp_rates has no CCK bits in A mode */
 			rate_scale_index_msk = (u16) (rate_mask &
-				(sta->supp_rates << IWL_FIRST_OFDM_RATE));
+				(lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
 		else
 			rate_scale_index_msk = (u16) (rate_mask &
-						      sta->supp_rates);
+						      lq_data->supp_rates);
 
 	} else
 		rate_scale_index_msk = rate_mask;
@@ -1378,11 +1633,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	if (!rate_scale_index_msk)
 		rate_scale_index_msk = rate_mask;
 
+	/* If current rate is no longer supported on current association,
+	 * or user changed preferences for rates, find a new supported rate. */
 	if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
 		index = IWL_INVALID_VALUE;
 		update_lq = 1;
 
-		/* get the lowest availabe rate */
+		/* get the highest available rate */
 		for (i = 0; i <= IWL_RATE_COUNT; i++) {
 			if ((1 << i) & rate_scale_index_msk)
 				index = i;
@@ -1394,36 +1651,55 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		}
 	}
 
+	/* Get expected throughput table and history window for current rate */
 	if (!tbl->expected_tpt)
 		rs_get_expected_tpt_table(lq_data, tbl);
 
 	window = &(tbl->win[index]);
 
+	/*
+	 * If there is not enough history to calculate actual average
+	 * throughput, keep analyzing results of more tx frames, without
+	 * changing rate or mode (bypass most of the rest of this function).
+	 * Set up new rate table in uCode only if old rate is not supported
+	 * in current association (use new rate found above).
+	 */
 	fail_count = window->counter - window->success_counter;
 	if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
 	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
 	    || (tbl->expected_tpt == NULL)) {
-		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d\n",
-			       window->success_counter, window->counter);
+		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+			       "for index %d\n",
+			       window->success_counter, window->counter, index);
+
+		/* Can't calculate this yet; not enough history */
 		window->average_tpt = IWL_INVALID_VALUE;
+
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
 		rs_stay_in_table(lq_data);
+
+		/* Set up new rate table in uCode, if needed */
 		if (update_lq) {
 			rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-			rs_fill_link_cmd(lq_data, &mcs_rate, &(lq_data->lq));
-			if (!rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC))
-				lq_data->commit_lq = 0;
-			else
-				lq_data->commit_lq = 1;
+			rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
 		}
 		goto out;
 
+	/* Else we have enough samples; calculate estimate of
+	 * actual average throughput */
 	} else
 		window->average_tpt = ((window->success_ratio *
 					tbl->expected_tpt[index] + 64) / 128);
 
+	/* If we are searching for better modulation mode, check success. */
 	if (lq_data->search_better_tbl) {
 		int success_limit = IWL_RATE_SCALE_SWITCH;
 
+		/* If good success, continue using the "search" mode;
+		 * no need to send new link quality command, since we're
+		 * continuing to use the setup that we've been trying. */
 		if ((window->success_ratio > success_limit) ||
 		    (window->average_tpt > lq_data->last_tpt)) {
 			if (!is_legacy(tbl->lq_type)) {
@@ -1435,55 +1711,78 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 					     lq_data->last_tpt);
 				lq_data->enable_counter = 1;
 			}
+			/* Swap tables; "search" becomes "active" */
 			lq_data->active_tbl = active_tbl;
 			current_tpt = window->average_tpt;
+
+		/* Else poor success; go back to mode in "active" table */
 		} else {
+			/* Nullify "search" table */
 			tbl->lq_type = LQ_NONE;
+
+			/* Revert to "active" table */
 			active_tbl = lq_data->active_tbl;
 			tbl = &(lq_data->lq_info[active_tbl]);
 
-			index = iwl_rate_index_from_plcp(
+			/* Revert to "active" rate and throughput info */
+			index = iwl4965_rate_index_from_plcp(
 				tbl->current_rate.rate_n_flags);
+			current_tpt = lq_data->last_tpt;
 
+			/* Need to set up a new rate table in uCode */
 			update_lq = 1;
-			current_tpt = lq_data->last_tpt;
 			IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
 		}
+
+		/* Either way, we've made a decision; modulation mode
+		 * search is done, allow rate adjustment next time. */
 		lq_data->search_better_tbl = 0;
-		done_search = 1;
+		done_search = 1;	/* Don't switch modes below! */
 		goto lq_update;
 	}
 
+	/* (Else) not in search of better modulation mode, try for better
+	 * starting rate, while staying in this mode. */
 	high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
 					tbl->lq_type);
 	low = high_low & 0xff;
 	high = (high_low >> 8) & 0xff;
 
+	/* Collect measured throughputs for current and adjacent rates */
 	current_tpt = window->average_tpt;
-
-	if (low != IWL_RATE_INVALID) {
+	if (low != IWL_RATE_INVALID)
 		low_tpt = tbl->win[low].average_tpt;
-	}
 	if (high != IWL_RATE_INVALID)
 		high_tpt = tbl->win[high].average_tpt;
 
-
+	/* Assume rate increase */
 	scale_action = 1;
 
+	/* Too many failures, decrease rate */
 	if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
 	    (current_tpt == 0)) {
 		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
 		scale_action = -1;
+
+	/* No throughput measured yet for adjacent rates; try increase. */
 	} else if ((low_tpt == IWL_INVALID_VALUE) &&
-		   (high_tpt == IWL_INVALID_VALUE)) {
+		   (high_tpt == IWL_INVALID_VALUE))
 		scale_action = 1;
-	} else if ((low_tpt != IWL_INVALID_VALUE) &&
-		   (high_tpt != IWL_INVALID_VALUE)
-		   && (low_tpt < current_tpt)
-		   && (high_tpt < current_tpt)) {
+
+	/* Both adjacent throughputs are measured, but neither one has better
+	 * throughput; we're using the best rate, don't change it! */
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
+		 (high_tpt != IWL_INVALID_VALUE) &&
+		 (low_tpt < current_tpt) &&
+		 (high_tpt < current_tpt))
 		scale_action = 0;
-	} else {
+
+	/* At least one adjacent rate's throughput is measured,
+	 * and may have better performance. */
+	else {
+		/* Higher adjacent rate's throughput is measured */
 		if (high_tpt != IWL_INVALID_VALUE) {
+			/* Higher rate has better throughput */
 			if (high_tpt > current_tpt)
 				scale_action = 1;
 			else {
@@ -1491,7 +1790,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 				    ("decrease rate because of high tpt\n");
 				scale_action = -1;
 			}
+
+		/* Lower adjacent rate's throughput is measured */
 		} else if (low_tpt != IWL_INVALID_VALUE) {
+			/* Lower rate has better throughput */
 			if (low_tpt > current_tpt) {
 				IWL_DEBUG_RATE
 				    ("decrease rate because of low tpt\n");
@@ -1501,82 +1803,103 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		}
 	}
 
+	/* Sanity check; asked for decrease, but success rate or throughput
+	 * has been good at old rate.  Don't change it. */
 	if (scale_action == -1) {
 		if ((low != IWL_RATE_INVALID) &&
 		    ((window->success_ratio > IWL_RATE_HIGH_TH) ||
 		     (current_tpt > (100 * tbl->expected_tpt[low]))))
 			scale_action = 0;
+
+	/* Sanity check; asked for increase, but success rate has not been great
+	 * even at old rate, higher rate will be worse.  Don't change it. */
 	} else if ((scale_action == 1) &&
 		   (window->success_ratio < IWL_RATE_INCREASE_TH))
 		scale_action = 0;
 
 	switch (scale_action) {
 	case -1:
+		/* Decrease starting rate, update uCode's rate table */
 		if (low != IWL_RATE_INVALID) {
 			update_lq = 1;
 			index = low;
 		}
 		break;
-
 	case 1:
+		/* Increase starting rate, update uCode's rate table */
 		if (high != IWL_RATE_INVALID) {
 			update_lq = 1;
 			index = high;
 		}
 
 		break;
-
 	case 0:
-
+		/* No change */
 	default:
 		break;
 	}
 
-	IWL_DEBUG_HT
-	    ("choose rate scale index %d action %d low %d high %d\n",
-	     index, scale_action, low, high);
+	IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+		    "high %d type %d\n",
+		     index, scale_action, low, high, tbl->lq_type);
 
  lq_update:
+	/* Replace uCode's rate table for the destination station. */
 	if (update_lq) {
 		rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-		rs_fill_link_cmd(lq_data, &mcs_rate, &(lq_data->lq));
-		if (!rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC))
-			lq_data->commit_lq = 0;
-		else
-			lq_data->commit_lq = 1;
+		rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+		rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
 	}
+
+	/* Should we stay with this modulation mode, or search for a new one? */
 	rs_stay_in_table(lq_data);
-	if (!update_lq
-	    && !done_search && !lq_data->stay_in_tbl) {
+
+	/*
+	 * Search for new modulation mode if we're:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  Allowing a new search
+	 */
+	if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
+		/* Save current throughput to compare with "search" throughput*/
 		lq_data->last_tpt = current_tpt;
+
+		/* Select a new "search" modulation mode to try.
+		 * If one is found, set up the new "search" table. */
 		if (is_legacy(tbl->lq_type))
-			rs_move_legacy_other(priv, lq_data, index);
+			rs_move_legacy_other(priv, lq_data, conf, sta, index);
 		else if (is_siso(tbl->lq_type))
-			rs_move_siso_to_other(priv, lq_data, index);
+			rs_move_siso_to_other(priv, lq_data, conf, sta, index);
 		else
-			rs_move_mimo_to_other(priv, lq_data, index);
+			rs_move_mimo_to_other(priv, lq_data, conf, sta, index);
 
+		/* If new "search" mode was selected, set up in uCode table */
 		if (lq_data->search_better_tbl) {
+			/* Access the "search" table, clear its history. */
 			tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
 			for (i = 0; i < IWL_RATE_COUNT; i++)
 				rs_rate_scale_clear_window(&(tbl->win[i]));
 
-			index = iwl_rate_index_from_plcp(
-				tbl->current_rate.rate_n_flags);
+			/* Use new "search" start rate */
+			index = iwl4965_rate_index_from_plcp(
+					tbl->current_rate.rate_n_flags);
 
 			IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",
 				     tbl->current_rate.rate_n_flags, index);
 			rs_fill_link_cmd(lq_data, &tbl->current_rate,
-					   &(lq_data->lq));
-			if (!rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC))
-				lq_data->commit_lq = 0;
-			else
-				lq_data->commit_lq = 1;
+					 &lq_data->lq);
+			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
 		}
+
+		/* If the "active" (non-search) mode was legacy,
+		 * and we've tried switching antennas,
+		 * but we haven't been able to try HT modes (not available),
+		 * stay with best antenna legacy modulation for a while
+		 * before next round of mode comparisons. */
 		tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
 		if (is_legacy(tbl1->lq_type) &&
-#ifdef CONFIG_IWLWIFI_HT
-		    !priv->current_assoc_ht.is_ht &&
+#ifdef CONFIG_IWL4965_HT
+		   (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) &&
 #endif
 		    (lq_data->action_counter >= 1)) {
 			lq_data->action_counter = 0;
@@ -1584,48 +1907,69 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 			rs_set_stay_in_table(1, lq_data);
 		}
 
+		/* If we're in an HT mode, and all 3 mode switch actions
+		 * have been tried and compared, stay in this best modulation
+		 * mode for a while before next round of mode comparisons. */
 		if (lq_data->enable_counter &&
 		    (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
+#ifdef CONFIG_IWL4965_HT_AGG
+			/* If appropriate, set up aggregation! */
+			if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
+			    (priv->lq_mngr.agg_ctrl.auto_agg)) {
+				priv->lq_mngr.agg_ctrl.tid_retry =
+				    TID_ALL_SPECIFIED;
+				schedule_work(&priv->agg_work);
+			}
+#endif /*CONFIG_IWL4965_HT_AGG */
 			lq_data->action_counter = 0;
 			rs_set_stay_in_table(0, lq_data);
 		}
+
+	/*
+	 * Else, don't search for a new modulation mode.
+	 * Put new timestamp in stay-in-modulation-mode flush timer if:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  flush timer is empty
+	 */
 	} else {
 		if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
 			lq_data->flush_timer = jiffies;
 	}
 
- out:
+out:
 	rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
 	i = index;
 	sta->last_txrate = i;
+
 	/* sta->txrate is an index to A mode rates which start
-	*  at IWL_FIRST_OFDM_RATE  */
-	if ((lq_data->phymode == (u8) MODE_IEEE80211A) ||
-	    (lq_data->phymode == (u8) MODE_ATHEROS_TURBO))
+	 * at IWL_FIRST_OFDM_RATE
+	 */
+	if (lq_data->phymode == (u8) MODE_IEEE80211A)
 		sta->txrate = i - IWL_FIRST_OFDM_RATE;
-
-	sta->antenna_sel_tx = tbl->lq_type;
+	else
+		sta->txrate = i;
 
 	return;
 }
 
 
-static void rs_initialize_lq(struct iwl_priv *priv,
-			     struct sta_info *sta,
-			     int flg)
+static void rs_initialize_lq(struct iwl4965_priv *priv,
+			     struct ieee80211_conf *conf,
+			     struct sta_info *sta)
 {
 	int i;
-	struct iwl_rate_scale_priv *lq;
-	struct iwl_scale_tbl_info *tbl;
+	struct iwl4965_rate_scale_priv *lq;
+	struct iwl4965_scale_tbl_info *tbl;
 	u8 active_tbl = 0;
 	int rate_idx;
-	u8 use_green = rs_use_green(priv);
-	struct iwl_rate mcs_rate;
+	u8 use_green = rs_use_green(priv, conf);
+	struct iwl4965_rate mcs_rate;
 
 	if (!sta || !sta->rate_ctrl_priv)
 		goto out;
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
 	i = sta->last_txrate;
 
 	if ((lq->lq.sta_id == 0xff) &&
@@ -1642,7 +1986,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 	if ((i < 0) || (i >= IWL_RATE_COUNT))
 		i = 0;
 
-	mcs_rate.rate_n_flags = iwl_rates[i].plcp ;
+	mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ;
 	mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
 	mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
 
@@ -1652,13 +1996,13 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 	tbl->antenna_type = ANT_AUX;
 	rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
 	if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
-	    rs_toggle_antenna(&mcs_rate, tbl),
+	    rs_toggle_antenna(&mcs_rate, tbl);
 
 	rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
 	tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
 	rs_get_expected_tpt_table(lq, tbl);
-	rs_fill_link_cmd(lq, &mcs_rate, &(lq->lq));
-	lq->commit_lq = 1;
+	rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
+	rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
  out:
 	return;
 }
@@ -1688,13 +2032,14 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 
 	int i;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct sta_info *sta;
 	u16 fc;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
-	struct iwl_rate_scale_priv *lq;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
+	struct iwl4965_rate_scale_priv *lq;
 
-	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
+	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
 	memset(extra, 0, sizeof(*extra));
 
@@ -1714,37 +2059,51 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 		return rs_get_lowest_rate(local);
 	}
 
+	lq = (struct iwl4965_rate_scale_priv *)sta->rate_ctrl_priv;
 	i = sta->last_txrate;
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
-	if (lq->commit_lq && lq->ready) {
-		lq->commit_lq = 0;
-		if (rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC))
-			lq->commit_lq = 1;
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
+		u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
+		DECLARE_MAC_BUF(mac);
+
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, hdr->addr1));
+			sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+							0, CMD_ASYNC, NULL);
+		}
+		if ((sta_id != IWL_INVALID_STATION)) {
+			lq->lq.sta_id = sta_id;
+			lq->lq.rs_table[0].rate_n_flags = 0;
+			lq->ibss_sta_added = 1;
+			rs_initialize_lq(priv, conf, sta);
+		}
+		if (!lq->ibss_sta_added)
+			goto done;
 	}
 
+ done:
 	sta_info_put(sta);
-	if ((i < 0) || (i > IWL_RATE_COUNT)) {
+	if ((i < 0) || (i > IWL_RATE_COUNT))
 		return rs_get_lowest_rate(local);
-	}
 
 	return &priv->ieee_rates[i];
 }
 
 static void *rs_alloc_sta(void *priv, gfp_t gfp)
 {
-	struct iwl_rate_scale_priv *crl;
+	struct iwl4965_rate_scale_priv *crl;
 	int i, j;
 
 	IWL_DEBUG_RATE("create station rate scale window\n");
-	crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+
+	crl = kzalloc(sizeof(struct iwl4965_rate_scale_priv), gfp);
 
 	if (crl == NULL)
 		return NULL;
-
-	memset(crl, 0, sizeof(struct iwl_rate_scale_priv));
 	crl->lq.sta_id = 0xff;
 
+
 	for (j = 0; j < LQ_SIZE; j++)
 		for (i = 0; i < IWL_RATE_COUNT; i++)
 			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
@@ -1757,17 +2116,13 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 			 struct sta_info *sta)
 {
 	int i, j;
+	struct ieee80211_conf *conf = &local->hw.conf;
 	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
-	struct iwl_rate_scale_priv *crl = priv_sta;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
+	struct iwl4965_rate_scale_priv *crl = priv_sta;
 
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-		mutex_lock(&priv->mutex);
-
-	memset(crl, 0, sizeof(struct iwl_rate_scale_priv));
-
-	crl->lq.sta_id = 0xff;
 	crl->flush_timer = 0;
+	crl->supp_rates = sta->supp_rates;
 	sta->txrate = 3;
 	for (j = 0; j < LQ_SIZE; j++)
 		for (i = 0; i < IWL_RATE_COUNT; i++)
@@ -1779,129 +2134,162 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
 	 * after assoc.. */
 
-	if (((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
-		(priv->iw_mode == IEEE80211_IF_TYPE_AP))) {
-		u8 sta_id = iwl_hw_find_station(priv, sta->addr);
+	crl->ibss_sta_added = 0;
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		u8 sta_id = iwl4965_hw_find_station(priv, sta->addr);
+		DECLARE_MAC_BUF(mac);
+
 		/* for IBSS the call are from tasklet */
-		IWL_DEBUG_HT("LQ: ADD station " MAC_FMT " \n",
-			     MAC_ARG(sta->addr));
+		IWL_DEBUG_HT("LQ: ADD station %s\n",
+			     print_mac(mac, sta->addr));
 
 		if (sta_id == IWL_INVALID_STATION) {
-			IWL_DEBUG_RATE("LQ: ADD station " MAC_FMT "\n",
-					MAC_ARG(sta->addr));
-					sta_id = iwl_add_station(priv,
-						 sta->addr, 0, CMD_ASYNC);
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, sta->addr));
+			sta_id = iwl4965_add_station_flags(priv, sta->addr,
+							0, CMD_ASYNC, NULL);
 		}
 		if ((sta_id != IWL_INVALID_STATION)) {
 			crl->lq.sta_id = sta_id;
-			crl->lq.rate_scale_table[0].rate_n_flags = 0;
+			crl->lq.rs_table[0].rate_n_flags = 0;
 		}
-		crl->ready = 1;
+		/* FIXME: this is w/a remove it later */
+		priv->assoc_station_added = 1;
 	}
 
+	/* Find highest tx rate supported by hardware and destination station */
 	for (i = 0; i < mode->num_rates; i++) {
 		if ((sta->supp_rates & BIT(i)) &&
 		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
 			sta->txrate = i;
 	}
 	sta->last_txrate = sta->txrate;
-	/* For MODE_IEEE80211A mode cck rate are at end
-	 * rate table
-	 */
-	if ((local->hw.conf.phymode == MODE_IEEE80211A) ||
-	    (local->hw.conf.phymode == MODE_ATHEROS_TURBO))
+	/* For MODE_IEEE80211A, cck rates are at end of rate table */
+	if (local->hw.conf.phymode == MODE_IEEE80211A)
 		sta->last_txrate += IWL_FIRST_OFDM_RATE;
 
-	crl->is_dup = priv->is_dup;
+	crl->is_dup = 0;
 	crl->valid_antenna = priv->valid_antenna;
 	crl->antenna = priv->antenna;
-	crl->is_green = rs_use_green(priv);
+	crl->is_green = rs_use_green(priv, conf);
 	crl->active_rate = priv->active_rate;
 	crl->active_rate &= ~(0x1000);
 	crl->active_rate_basic = priv->active_rate_basic;
 	crl->phymode = priv->phymode;
-#ifdef CONFIG_IWLWIFI_HT
-	crl->active_siso_rate = (priv->active_rate_ht[0] << 1);
-	crl->active_siso_rate |= (priv->active_rate_ht[0] & 0x1);
+#ifdef CONFIG_IWL4965_HT
+	/*
+	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
+	 */
+	crl->active_siso_rate = (priv->current_ht_config.supp_mcs_set[0] << 1);
+	crl->active_siso_rate |=
+			(priv->current_ht_config.supp_mcs_set[0] & 0x1);
 	crl->active_siso_rate &= ~((u16)0x2);
 	crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;
 
-	crl->active_mimo_rate = (priv->active_rate_ht[1] << 1);
-	crl->active_mimo_rate |= (priv->active_rate_ht[1] & 0x1);
+	/* Same here */
+	crl->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1);
+	crl->active_mimo_rate |=
+			(priv->current_ht_config.supp_mcs_set[1] & 0x1);
 	crl->active_mimo_rate &= ~((u16)0x2);
 	crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
-#endif /*CONFIG_IWLWIFI_HT*/
+	IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
+		     crl->active_mimo_rate);
+#endif /*CONFIG_IWL4965_HT*/
+#ifdef CONFIG_MAC80211_DEBUGFS
+	crl->drv = priv;
+#endif
 
 	if (priv->assoc_station_added)
-		crl->ready = 1;
-
-	if (priv && (priv->iw_mode != IEEE80211_IF_TYPE_IBSS))
-		rs_initialize_lq(priv, sta, 0);
-	else
-		rs_initialize_lq(priv, sta, CMD_ASYNC);
+		priv->lq_mngr.lq_ready = 1;
 
-	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-		mutex_unlock(&priv->mutex);
+	rs_initialize_lq(priv, conf, sta);
 }
 
-static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
-			    struct iwl_rate *tx_mcs,
-			    struct iwl_link_quality_cmd *lq_cmd)
+static void rs_fill_link_cmd(struct iwl4965_rate_scale_priv *lq_data,
+			    struct iwl4965_rate *tx_mcs,
+			    struct iwl4965_link_quality_cmd *lq_cmd)
 {
 	int index = 0;
-	int rc = 0;
 	int rate_idx;
+	int repeat_rate = 0;
 	u8 ant_toggle_count = 0;
 	u8 use_ht_possible = 1;
-	u8 repeat_cur_rate = 0;
-	struct iwl_rate new_rate;
-	struct iwl_scale_tbl_info tbl_type = { 0 };
+	struct iwl4965_rate new_rate;
+	struct iwl4965_scale_tbl_info tbl_type = { 0 };
 
+	/* Override starting rate (index 0) if needed for debug purposes */
+	rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+
+	/* Interpret rate_n_flags */
 	rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
 				  &tbl_type, &rate_idx);
 
+	/* How many times should we repeat the initial rate? */
 	if (is_legacy(tbl_type.lq_type)) {
 		ant_toggle_count = 1;
-		repeat_cur_rate = IWL_NUMBER_TRY;
+		repeat_rate = IWL_NUMBER_TRY;
 	} else
-		repeat_cur_rate = IWL_HT_NUMBER_TRY;
+		repeat_rate = IWL_HT_NUMBER_TRY;
+
+	lq_cmd->general_params.mimo_delimiter =
+			is_mimo(tbl_type.lq_type) ? 1 : 0;
 
-	lq_cmd->rate_scale_table[index].rate_n_flags = tx_mcs->rate_n_flags;
-	lq_cmd->general_params.mimo_delimiter = is_mimo(tbl_type.lq_type) ? 1 : 0;
+	/* Fill 1st table entry (index 0) */
+	lq_cmd->rs_table[index].rate_n_flags =
+			cpu_to_le32(tx_mcs->rate_n_flags);
 	new_rate.rate_n_flags = tx_mcs->rate_n_flags;
 
 	if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
-		lq_cmd->general_params.single_stream_ant_msk = 1;
+		lq_cmd->general_params.single_stream_ant_msk
+			= LINK_QUAL_ANT_A_MSK;
 	else
-		lq_cmd->general_params.single_stream_ant_msk = 2;
+		lq_cmd->general_params.single_stream_ant_msk
+			= LINK_QUAL_ANT_B_MSK;
 
 	index++;
-	repeat_cur_rate--;
+	repeat_rate--;
 
+	/* Fill rest of rate table */
 	while (index < LINK_QUAL_MAX_RETRY_NUM) {
-		while (repeat_cur_rate && (index < LINK_QUAL_MAX_RETRY_NUM)) {
-			if (is_legacy(tbl_type.lq_type)){
-				if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+		/* Repeat initial/next rate.
+		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
+		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+			if (is_legacy(tbl_type.lq_type)) {
+				if (ant_toggle_count <
+				    NUM_TRY_BEFORE_ANTENNA_TOGGLE)
 					ant_toggle_count++;
 				else {
 					rs_toggle_antenna(&new_rate, &tbl_type);
 					ant_toggle_count = 1;
 				}
 			}
-			lq_cmd->rate_scale_table[index].rate_n_flags =
-				    new_rate.rate_n_flags;
-			repeat_cur_rate--;
+
+			/* Override next rate if needed for debug purposes */
+			rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+
+			/* Fill next table entry */
+			lq_cmd->rs_table[index].rate_n_flags =
+					cpu_to_le32(new_rate.rate_n_flags);
+			repeat_rate--;
 			index++;
 		}
-		rs_get_tbl_info_from_mcs(&lq_cmd->rate_scale_table[index - 1],
-					  lq_data->phymode,
-					  &tbl_type, &rate_idx);
+
+		rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
+						&rate_idx);
+
+		/* Indicate to uCode which entries might be MIMO.
+		 * If initial rate was MIMO, this will finally end up
+		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
 		if (is_mimo(tbl_type.lq_type))
 			lq_cmd->general_params.mimo_delimiter = index;
 
-		rs_get_lower_rate(lq_data, &tbl_type,
-				  rate_idx, use_ht_possible, &new_rate);
+		/* Get next rate */
+		rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
+				  use_ht_possible, &new_rate);
 
+		/* How many times should we repeat the next rate? */
 		if (is_legacy(tbl_type.lq_type)) {
 			if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
 				ant_toggle_count++;
@@ -1909,55 +2297,228 @@ static int rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
 				rs_toggle_antenna(&new_rate, &tbl_type);
 				ant_toggle_count = 1;
 			}
-			repeat_cur_rate = IWL_NUMBER_TRY;
-		} else {
-			repeat_cur_rate = IWL_HT_NUMBER_TRY;
-		}
+			repeat_rate = IWL_NUMBER_TRY;
+		} else
+			repeat_rate = IWL_HT_NUMBER_TRY;
 
+		/* Don't allow HT rates after next pass.
+		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
 		use_ht_possible = 0;
 
-		lq_cmd->rate_scale_table[index].rate_n_flags =
-		    new_rate.rate_n_flags;
-		/*lq_cmd->rate_scale_table[index].rate_n_flags = 0x800d; */
+		/* Override next rate if needed for debug purposes */
+		rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+
+		/* Fill next table entry */
+		lq_cmd->rs_table[index].rate_n_flags =
+				cpu_to_le32(new_rate.rate_n_flags);
 
 		index++;
-		repeat_cur_rate--;
+		repeat_rate--;
 	}
 
-	/*lq_cmd->rate_scale_table[0].rate_n_flags = 0x800d; */
-
 	lq_cmd->general_params.dual_stream_ant_msk = 3;
 	lq_cmd->agg_params.agg_dis_start_th = 3;
-	lq_cmd->agg_params.agg_time_limit = 4000;
-	return rc;
+	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
 }
 
 static void *rs_alloc(struct ieee80211_local *local)
 {
-	IWL_DEBUG_RATE("enter\n");
-	IWL_DEBUG_RATE("leave\n");
 	return local->hw.priv;
 }
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+	return;
+}
 
-static void rs_free(void *data)
+static void rs_clear(void *priv_rate)
 {
+	struct iwl4965_priv *priv = (struct iwl4965_priv *) priv_rate;
+
 	IWL_DEBUG_RATE("enter\n");
+
+	priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	if (priv->lq_mngr.agg_ctrl.granted_ba)
+		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
 	IWL_DEBUG_RATE("leave\n");
 }
 
 static void rs_free_sta(void *priv, void *priv_sta)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
 
 	IWL_DEBUG_RATE("enter\n");
 	kfree(rs_priv);
 	IWL_DEBUG_RATE("leave\n");
 }
 
-static void rs_clear(void *priv)
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int open_file_generic(struct inode *inode, struct file *file)
 {
-	IWL_DEBUG_RATE("NOP\n");
+	file->private_data = inode->i_private;
+	return 0;
 }
+static void rs_dbgfs_set_mcs(struct iwl4965_rate_scale_priv *rs_priv,
+				struct iwl4965_rate *mcs, int index)
+{
+	u32 base_rate;
+
+	if (rs_priv->phymode == (u8) MODE_IEEE80211A)
+		base_rate = 0x800D;
+	else
+		base_rate = 0x820A;
+
+	if (rs_priv->dbg_fixed.rate_n_flags) {
+		if (index < 12)
+			mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+		else
+			mcs->rate_n_flags = base_rate;
+		IWL_DEBUG_RATE("Fixed rate ON\n");
+		return;
+	}
+
+	IWL_DEBUG_RATE("Fixed rate OFF\n");
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+			const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
+	char buf[64];
+	int buf_size;
+	u32 parsed_rate;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x", &parsed_rate) == 1)
+		rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+	else
+		rs_priv->dbg_fixed.rate_n_flags = 0;
+
+	rs_priv->active_rate = 0x0FFF;		/* 1 - 54 MBits, includes CCK */
+	rs_priv->active_siso_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	rs_priv->active_mimo_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+
+	IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
+		rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+
+	if (rs_priv->dbg_fixed.rate_n_flags) {
+		rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
+		rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+	}
+
+	return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buff[1024];
+	int desc = 0;
+	int i = 0;
+
+	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
+
+	desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+			rs_priv->total_failed, rs_priv->total_success,
+			rs_priv->active_rate);
+	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+			rs_priv->dbg_fixed.rate_n_flags);
+	desc += sprintf(buff+desc, "general:"
+		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+		rs_priv->lq.general_params.flags,
+		rs_priv->lq.general_params.mimo_delimiter,
+		rs_priv->lq.general_params.single_stream_ant_msk,
+		rs_priv->lq.general_params.dual_stream_ant_msk);
+
+	desc += sprintf(buff+desc, "agg:"
+			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+			le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
+			rs_priv->lq.agg_params.agg_dis_start_th,
+			rs_priv->lq.agg_params.agg_frame_cnt_limit);
+
+	desc += sprintf(buff+desc,
+			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+			rs_priv->lq.general_params.start_rate_index[0],
+			rs_priv->lq.general_params.start_rate_index[1],
+			rs_priv->lq.general_params.start_rate_index[2],
+			rs_priv->lq.general_params.start_rate_index[3]);
+
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+		desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
+			i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+	.write = rs_sta_dbgfs_scale_table_write,
+	.read = rs_sta_dbgfs_scale_table_read,
+	.open = open_file_generic,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buff[1024];
+	int desc = 0;
+	int i, j;
+
+	struct iwl4965_rate_scale_priv *rs_priv = file->private_data;
+	for (i = 0; i < LQ_SIZE; i++) {
+		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+				"rate=0x%X\n",
+				rs_priv->active_tbl == i?"*":"x",
+				rs_priv->lq_info[i].lq_type,
+				rs_priv->lq_info[i].is_SGI,
+				rs_priv->lq_info[i].is_fat,
+				rs_priv->lq_info[i].is_dup,
+				rs_priv->lq_info[i].current_rate.rate_n_flags);
+		for (j = 0; j < IWL_RATE_COUNT; j++) {
+			desc += sprintf(buff+desc,
+					"counter=%d success=%d %%=%d\n",
+					rs_priv->lq_info[i].win[j].counter,
+					rs_priv->lq_info[i].win[j].success_counter,
+					rs_priv->lq_info[i].win[j].success_ratio);
+		}
+	}
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+	.read = rs_sta_dbgfs_stats_table_read,
+	.open = open_file_generic,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+					struct dentry *dir)
+{
+	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
+	rs_priv->rs_sta_dbgfs_scale_table_file =
+		debugfs_create_file("rate_scale_table", 0600, dir,
+				rs_priv, &rs_sta_dbgfs_scale_table_ops);
+	rs_priv->rs_sta_dbgfs_stats_table_file =
+		debugfs_create_file("rate_stats_table", 0600, dir,
+			rs_priv, &rs_sta_dbgfs_stats_table_ops);
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+	struct iwl4965_rate_scale_priv *rs_priv = priv_sta;
+	debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
+	debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+}
+#endif
 
 static struct rate_control_ops rs_ops = {
 	.module = NULL,
@@ -1970,13 +2531,17 @@ static struct rate_control_ops rs_ops = {
 	.free = rs_free,
 	.alloc_sta = rs_alloc_sta,
 	.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rs_add_debugfs,
+	.remove_sta_debugfs = rs_remove_debugfs,
+#endif
 };
 
-int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_priv *priv = hw->priv;
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl4965_priv *priv = hw->priv;
+	struct iwl4965_rate_scale_priv *rs_priv;
 	struct sta_info *sta;
 	int count = 0, i;
 	u32 samples = 0, success = 0, good = 0;
@@ -2009,7 +2574,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		int active = rs_priv->active_tbl;
 
 		count +=
-		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+		    sprintf(&buf[count], " %2dMbs: ", iwl4965_rates[i].ieee / 2);
 
 		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
 		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
@@ -2020,7 +2585,7 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		samples += rs_priv->lq_info[active].win[i].counter;
 		good += rs_priv->lq_info[active].win[i].success_counter;
 		success += rs_priv->lq_info[active].win[i].success_counter *
-			   iwl_rates[i].ieee;
+			   iwl4965_rates[i].ieee;
 
 		if (rs_priv->lq_info[active].win[i].stamp) {
 			int delta =
@@ -2034,60 +2599,45 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		} else
 			buf[count++] = '\n';
 
-		j = iwl_get_prev_ieee_rate(i);
+		j = iwl4965_get_prev_ieee_rate(i);
 		if (j == i)
 			break;
 		i = j;
 	}
-	sta_info_put(sta);
 
 	/* Display the average rate of all samples taken.
 	 *
-	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
-	 * added from iwl_rates is actually 2X the rate */
+	 * NOTE:  We multiply # of samples by 2 since the IEEE measurement
+	 * added from iwl4965_rates is actually 2X the rate */
 	if (samples)
-		count += sprintf(
-			 &buf[count],
+		count += sprintf(&buf[count],
 			 "\nAverage rate is %3d.%02dMbs over last %4dms\n"
 			 "%3d%% success (%d good packets over %d tries)\n",
 			 success / (2 * samples), (success * 5 / samples) % 10,
 			 max_time, good * 100 / samples, good, samples);
 	else
 		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
-	count += sprintf(&buf[count], "\nrate scale type %d anntena %d \n",
-			 lq_type, antenna);
+	count += sprintf(&buf[count], "\nrate scale type %d antenna %d "
+			 "active_search %d rate index %d\n", lq_type, antenna,
+			 rs_priv->search_better_tbl, sta->last_txrate);
 
+	sta_info_put(sta);
 	return count;
 }
 
-void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_priv *priv = hw->priv;
-	struct iwl_rate_scale_priv *rs_priv;
-	struct sta_info *sta;
-
-	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
-	if (!sta || !sta->rate_ctrl_priv) {
-		if (sta) {
-			sta_info_put(sta);
-			IWL_DEBUG_RATE("leave - no private rate data!\n");
-		} else
-			IWL_DEBUG_RATE("leave - no station!\n");
-		return;
-	}
+	struct iwl4965_priv *priv = hw->priv;
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
-	rs_priv->ready = 1;
-	sta_info_put(sta);
+	priv->lq_mngr.lq_ready = 1;
 }
 
-void iwl_rate_control_register(void)
+void iwl4965_rate_control_register(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_register(&rs_ops);
 }
 
-void iwl_rate_control_unregister(void)
+void iwl4965_rate_control_unregister(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_unregister(&rs_ops);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index b1fb0f0..31e21e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -27,14 +27,13 @@
 #ifndef __iwl_4965_rs_h__
 #define __iwl_4965_rs_h__
 
-#include "iwl-hw.h"
 #include "iwl-4965.h"
 
-struct iwl_rate_info {
-	u8 plcp;
-	u8 plcp_siso;
-	u8 plcp_mimo;
-	u8 ieee;
+struct iwl4965_rate_info {
+	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+	u8 plcp_mimo;	/* uCode API:  IWL_RATE_MIMO_6M_PLCP, etc. */
+	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
 	u8 prev_ieee;    /* previous rate in IEEE speeds */
 	u8 next_ieee;    /* next rate in IEEE speeds */
 	u8 prev_rs;      /* previous rate used in rs algo */
@@ -43,6 +42,10 @@ struct iwl_rate_info {
 	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
 };
 
+/*
+ * These serve as indexes into
+ * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+ */
 enum {
 	IWL_RATE_1M_INDEX = 0,
 	IWL_RATE_2M_INDEX,
@@ -84,6 +87,7 @@ enum {
 #define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
 #define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
 
+/* 4965 uCode API values for legacy bit rates, both OFDM and CCK */
 enum {
 	IWL_RATE_6M_PLCP  = 13,
 	IWL_RATE_9M_PLCP  = 15,
@@ -100,7 +104,7 @@ enum {
 	IWL_RATE_11M_PLCP = 110,
 };
 
-/* OFDM HT rate plcp */
+/* 4965 uCode API values for OFDM high-throughput (HT) bit rates */
 enum {
 	IWL_RATE_SISO_6M_PLCP = 0,
 	IWL_RATE_SISO_12M_PLCP = 1,
@@ -122,6 +126,7 @@ enum {
 	IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
 };
 
+/* MAC header values for bit rates */
 enum {
 	IWL_RATE_6M_IEEE  = 12,
 	IWL_RATE_9M_IEEE  = 18,
@@ -171,116 +176,114 @@ enum {
 #define IWL_MIN_RSSI_VAL                 -100
 #define IWL_MAX_RSSI_VAL                    0
 
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
+#define IWL_LEGACY_FAILURE_LIMIT	160
+#define IWL_LEGACY_SUCCESS_LIMIT	480
+#define IWL_LEGACY_TABLE_COUNT		160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
+#define IWL_NONE_LEGACY_TABLE_COUNT	1500
+
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO		12800	/* 100% */
+#define IWL_RATE_SCALE_SWITCH		10880	/*  85% */
+#define IWL_RATE_HIGH_TH		10880	/*  85% */
+#define IWL_RATE_INCREASE_TH            8960	/*  70% */
+#define IWL_RATE_DECREASE_TH		1920	/*  15% */
+
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA	0
+#define IWL_LEGACY_SWITCH_SISO		1
+#define IWL_LEGACY_SWITCH_MIMO	        2
+
+/* possible actions when in siso mode */
+#define IWL_SISO_SWITCH_ANTENNA		0
+#define IWL_SISO_SWITCH_MIMO		1
+#define IWL_SISO_SWITCH_GI		2
 
-#define LQ_SIZE		2
+/* possible actions when in mimo mode */
+#define IWL_MIMO_SWITCH_ANTENNA_A	0
+#define IWL_MIMO_SWITCH_ANTENNA_B	1
+#define IWL_MIMO_SWITCH_GI		2
 
-enum iwl_table_type {
+#define IWL_ACTION_LIMIT		3	/* # possible actions */
+
+#define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */
+
+extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+
+enum iwl4965_table_type {
 	LQ_NONE,
-	LQ_G,
+	LQ_G,		/* legacy types */
 	LQ_A,
-	LQ_SISO,
+	LQ_SISO,	/* high-throughput types */
 	LQ_MIMO,
 	LQ_MAX,
 };
 
-enum iwl_antenna_type {
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) (((tbl) == LQ_SISO))
+#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) (((tbl) == LQ_A))
+#define is_g_and(tbl) (((tbl) == LQ_G))
+
+/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */
+enum iwl4965_antenna_type {
 	ANT_NONE,
 	ANT_MAIN,
 	ANT_AUX,
 	ANT_BOTH,
 };
 
-static inline int iwl_rate_index_from_plcp(int plcp)
+static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 {
-	int i = 0;
-
-	if (plcp & RATE_MCS_HT_MSK) {
-		i = (plcp & 0xff);
-
-		if (i >= IWL_RATE_MIMO_6M_PLCP)
-			i = i - IWL_RATE_MIMO_6M_PLCP;
-
-		i += IWL_FIRST_OFDM_RATE;
-		/* skip 9M not supported in ht*/
-		if (i >= IWL_RATE_9M_INDEX)
-			i += 1;
-		if ((i >= IWL_FIRST_OFDM_RATE) &&
-		    (i <= IWL_LAST_OFDM_RATE))
-			return i;
-	} else {
-		for (i = 0; i < ARRAY_SIZE(iwl_rates); i++)
-			if (iwl_rates[i].plcp == (plcp &0xFF))
-				return i;
-	}
-	return -1;
-}
-
-static inline u8 iwl_rate_get_lowest_plcp(int rate_mask)
-{
-	u8 i;
-
-	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-	     i = iwl_rates[i].next_ieee) {
-		if (rate_mask & (1 << i))
-			return iwl_rates[i].plcp;
-	}
+	u8 rate = iwl4965_rates[rate_index].prev_ieee;
 
-	return IWL_RATE_INVALID;
-}
-
-static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
-{
-	u8 rate = iwl_rates[rate_index].prev_ieee;
 	if (rate == IWL_RATE_INVALID)
 		rate = rate_index;
 	return rate;
 }
 
-#if IWL == 4965
+extern int iwl4965_rate_index_from_plcp(int plcp);
+
 /**
- * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation
  *
  * NOTE:  This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control alogirthm and is not meant to be
+ * the performance of the rate control algorithm and is not meant to be
  * parsed software.
  */
-extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
 
 /**
- * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info
  *
- * The specific througput table used is based on the type of network
+ * The specific throughput table used is based on the type of network
  * the associated with, including A, B, G, and G w/ TGG protection
  */
-extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
 
 /**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
+ * iwl4965_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
+ * iwl4965_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
  */
-extern void iwl_rate_control_register(void);
+extern void iwl4965_rate_control_register(struct ieee80211_hw *hw);
 
 /**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
+ * iwl4965_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
  */
-extern void iwl_rate_control_unregister(void);
-#else
-static inline int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf,
-				   u8 sta_id)
-{ return -ENOTSUPP; }
-static inline void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) {}
-static inline void iwl_rate_control_register(void) {}
-static inline void iwl_rate_control_unregister(void) {}
-#endif /* IWL == 4965 */
+extern void iwl4965_rate_control_unregister(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d13ccc9..83cef93 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -35,14 +35,13 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/mac80211.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/delay.h>
 
-#include "iwlwifi.h"
 #include "iwl-4965.h"
 #include "iwl-helpers.h"
 
+static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv);
+
 #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
 	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
 				    IWL_RATE_SISO_##s##M_PLCP, \
@@ -63,13 +62,13 @@
  * maps to IWL_RATE_INVALID
  *
  */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
 	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
 	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 5, 12, 5, 18),      /* 11mbps */
+	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
 	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
-	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 5, 11, 5, 11),       /*  9mbps */
+	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
 	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
 	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
 	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
@@ -79,22 +78,22 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
 };
 
-static int is_fat_channel(struct iwl_priv *priv)
+static int is_fat_channel(__le32 rxon_flags)
 {
-	return ((priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
-		(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK));
+	return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
+		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
 }
 
-static u8 is_single_stream(struct iwl_priv *priv)
+static u8 is_single_stream(struct iwl4965_priv *priv)
 {
-#ifdef CONFIG_IWLWIFI_HT
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||
-	    (priv->active_rate_ht[1] == 0) ||
+#ifdef CONFIG_IWL4965_HT
+	if (!priv->current_ht_config.is_ht ||
+	    (priv->current_ht_config.supp_mcs_set[1] == 0) ||
 	    (priv->ps_mode == IWL_MIMO_PS_STATIC))
 		return 1;
 #else
 	return 1;
-#endif	/*CONFIG_IWLWIFI_HT */
+#endif	/*CONFIG_IWL4965_HT */
 	return 0;
 }
 
@@ -104,11 +103,11 @@ static u8 is_single_stream(struct iwl_priv *priv)
  * MIMO (dual stream) requires at least 2, but works better with 3.
  * This does not determine *which* chains to use, just how many.
  */
-static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
-					u8 * idle_state, u8 * rx_state)
+static int iwl4965_get_rx_chain_counter(struct iwl4965_priv *priv,
+					u8 *idle_state, u8 *rx_state)
 {
 	u8 is_single = is_single_stream(priv);
-	u8 is_cam = (priv->status & STATUS_POWER_PMI) ? 0 : 1;
+	u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
 
 	/* # of Rx chains to use when expecting MIMO. */
 	if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
@@ -133,163 +132,172 @@ static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
 	return 0;
 }
 
-int iwl_hw_rxq_stop(struct iwl_priv *priv)
+int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	/* stop HW */
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-	rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+	/* stop Rx DMA */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
 				     (1 << 24), 1000);
 	if (rc < 0)
 		IWL_ERROR("Can't stop Rx DMA.\n");
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-u8 iwl_hw_find_station(struct iwl_priv * priv, const u8 * bssid)
+u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr)
 {
 	int i;
 	int start = 0;
 	int ret = IWL_INVALID_STATION;
 	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
 
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
 	    (priv->iw_mode == IEEE80211_IF_TYPE_AP))
 		start = IWL_STA_ID;
 
-	if (is_broadcast_ether_addr(bssid))
-		return IWL_BROADCAST_ID;
+	if (is_broadcast_ether_addr(addr))
+		return IWL4965_BROADCAST_ID;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	for (i = start; i < (start + priv->num_stations); i++)
+	for (i = start; i < priv->hw_setting.max_stations; i++)
 		if ((priv->stations[i].used) &&
 		    (!compare_ether_addr
-		     (priv->stations[i].sta.sta.addr, bssid))) {
+		     (priv->stations[i].sta.sta.addr, addr))) {
 			ret = i;
 			goto out;
 		}
 
-	IWL_DEBUG_ASSOC("can not find STA " MAC_FMT " total %d\n",
-			MAC_ARG(bssid), priv->num_stations);
+	IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+			print_mac(mac, addr), priv->num_stations);
 
  out:
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 	return ret;
 }
 
-static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+static int iwl4965_nic_set_pwr_src(struct iwl4965_priv *priv, int pwr_max)
 {
-	int rc = 0;
+	int ret;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
+	ret = iwl4965_grab_nic_access(priv);
+	if (ret) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
+		return ret;
 	}
 
 	if (!pwr_max) {
 		u32 val;
-		rc = pci_read_config_dword(priv->pci_dev, 0x0C8, &val);
 
-		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
-			iwl_set_bits_mask_restricted_reg(
-				priv, ALM_APMG_PS_CTL,
-				APMG_PS_CTRL_REG_VAL_POWER_SRC_VAUX,
-				~APMG_PS_CTRL_REG_MSK_POWER_SRC);
+		ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+					   &val);
 
-		}
-	} else {
-		iwl_set_bits_mask_restricted_reg(
-			priv, ALM_APMG_PS_CTL,
-			APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN,
-			~APMG_PS_CTRL_REG_MSK_POWER_SRC);
-
-	}
+		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+			iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+				~APMG_PS_CTRL_MSK_PWR_SRC);
+	} else
+		iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+			~APMG_PS_CTRL_MSK_PWR_SRC);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return rc;
+	return ret;
 }
 
-static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
 {
 	int rc;
 	unsigned long flags;
+	unsigned int rb_size;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	/* stop HW */
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	if (iwl4965_param_amsdu_size_8K)
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+	else
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+	/* Stop Rx DMA */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
 
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+	/* Reset driver's Rx queue write index */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+	/* Tell device where to find RBD circular buffer in DRAM */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
 			     rxq->dma_addr >> 8);
 
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+	/* Tell device where in DRAM to update its Rx status */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
 			     (priv->hw_setting.shared_phys +
-			      offsetof(struct iwl_shared, val0)) >> 4);
+			      offsetof(struct iwl4965_shared, val0)) >> 4);
 
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+	/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
 			     FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
 			     FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-			     IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+			     rb_size |
 			     /*0x10 << 4 | */
 			     (RX_QUEUE_SIZE_LOG <<
 			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
 
 	/*
-	 * iwl_write32(priv,CSR_INT_COAL_REG,0);
+	 * iwl4965_write32(priv,CSR_INT_COAL_REG,0);
 	 */
 
-	iwl_release_restricted_access(priv);
-
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-static int iwl4965_kw_init(struct iwl_priv *priv)
+/* Tell 4965 where to find the "keep warm" buffer */
+static int iwl4965_kw_init(struct iwl4965_priv *priv)
 {
 	unsigned long flags;
 	int rc;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc)
 		goto out;
 
-	iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,
-			     (priv->kw.dma_addr >> 4));
-	iwl_release_restricted_access(priv);
+	iwl4965_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
+			     priv->kw.dma_addr >> 4);
+	iwl4965_release_nic_access(priv);
 out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	return rc;
 }
 
-static int iwl4965_kw_alloc(struct iwl_priv *priv)
+static int iwl4965_kw_alloc(struct iwl4965_priv *priv)
 {
 	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
+	struct iwl4965_kw *kw = &priv->kw;
+
 	kw->size = IWL4965_KW_SIZE;	/* TBW need set somewhere else */
 	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
 	if (!kw->v_addr)
@@ -301,38 +309,39 @@ static int iwl4965_kw_alloc(struct iwl_priv *priv)
 #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
 			    ? # x " " : "")
 
-int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
-			      int channel,
-			      const struct iwl_eeprom_channel *eeprom_ch,
+/**
+ * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv.
+ *
+ * Does not set up a command, or touch hardware.
+ */
+int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel,
+			      const struct iwl4965_eeprom_channel *eeprom_ch,
 			      u8 fat_extension_channel)
 {
-	struct iwl_channel_info *ch_info;
+	struct iwl4965_channel_info *ch_info;
+
+	ch_info = (struct iwl4965_channel_info *)
+			iwl4965_get_channel_info(priv, phymode, channel);
 
-	ch_info = (struct iwl_channel_info *)iwl_get_channel_info(priv,
-						phymode,
-						channel);
 	if (!is_channel_valid(ch_info))
 		return -1;
 
-		IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(" BIT_FMT8
-				" %ddBm): Ad-Hoc %ssupported\n",
-				ch_info->channel,
-				is_channel_a_band(ch_info) ?
-				"5.2" : "2.4",
-				CHECK_AND_PRINT(IBSS),
-				CHECK_AND_PRINT(ACTIVE),
-				CHECK_AND_PRINT(RADAR),
-				CHECK_AND_PRINT(WIDE),
-				CHECK_AND_PRINT(NARROW),
-				CHECK_AND_PRINT(DFS),
-				BIT_ARG8(eeprom_ch->flags),
-				eeprom_ch->
-				max_power_avg,
-				((eeprom_ch->
-				flags & EEPROM_CHANNEL_IBSS)
-				&& !(eeprom_ch->
-				flags & EEPROM_CHANNEL_RADAR))
-				? "" : "not ");
+	IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+			" %ddBm): Ad-Hoc %ssupported\n",
+			ch_info->channel,
+			is_channel_a_band(ch_info) ?
+			"5.2" : "2.4",
+			CHECK_AND_PRINT(IBSS),
+			CHECK_AND_PRINT(ACTIVE),
+			CHECK_AND_PRINT(RADAR),
+			CHECK_AND_PRINT(WIDE),
+			CHECK_AND_PRINT(NARROW),
+			CHECK_AND_PRINT(DFS),
+			eeprom_ch->flags,
+			eeprom_ch->max_power_avg,
+			((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
+			 && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
+			"" : "not ");
 
 	ch_info->fat_eeprom = *eeprom_ch;
 	ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
@@ -345,15 +354,18 @@ int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
 	return 0;
 }
 
-static void iwl4965_kw_free(struct iwl_priv *priv)
+/**
+ * iwl4965_kw_free - Free the "keep warm" buffer
+ */
+static void iwl4965_kw_free(struct iwl4965_priv *priv)
 {
 	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
+	struct iwl4965_kw *kw = &priv->kw;
+
 	if (kw->v_addr) {
 		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
 		memset(kw, 0, sizeof(*kw));
 	}
-
 }
 
 /**
@@ -363,17 +375,18 @@ static void iwl4965_kw_free(struct iwl_priv *priv)
  * @param priv
  * @return error code
  */
-static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv)
 {
 	int rc = 0;
-	int txq_id, num_slots;
+	int txq_id, slots_num;
 	unsigned long flags;
 
 	iwl4965_kw_free(priv);
 
-	iwl_hw_txq_ctx_free(priv);
+	/* Free all tx/cmd queues and keep-warm buffer */
+	iwl4965_hw_txq_ctx_free(priv);
 
-	/* Tx CMD queue */
+	/* Alloc keep-warm buffer */
 	rc = iwl4965_kw_alloc(priv);
 	if (rc) {
 		IWL_ERROR("Keep Warm allocation failed");
@@ -382,28 +395,31 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (unlikely(rc)) {
 		IWL_ERROR("TX reset failed");
 		spin_unlock_irqrestore(&priv->lock, flags);
 		goto error_reset;
 	}
 
-	iwl_write_restricted_reg(priv, SCD_TXFACT, 0);
-	iwl_release_restricted_access(priv);
+	/* Turn off all Tx DMA channels */
+	iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	/* Tell 4965 where to find the keep-warm buffer */
 	rc = iwl4965_kw_init(priv);
 	if (rc) {
 		IWL_ERROR("kw_init failed\n");
 		goto error_reset;
 	}
 
-	/* Tx queue(s) */
-	for (txq_id = 0; txq_id < priv->hw_setting.max_queue_number; txq_id++) {
-		num_slots = (txq_id == IWL_CMD_QUEUE_NUM) ?
+	/* Alloc and init all (default 16) Tx queues,
+	 * including the command queue (#4) */
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
 					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], num_slots,
+		rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
 				       txq_id);
 		if (rc) {
 			IWL_ERROR("Tx %d queue init failed\n", txq_id);
@@ -414,32 +430,32 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
 	return rc;
 
  error:
-	iwl_hw_txq_ctx_free(priv);
+	iwl4965_hw_txq_ctx_free(priv);
  error_reset:
 	iwl4965_kw_free(priv);
  error_kw:
 	return rc;
 }
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
+int iwl4965_hw_nic_init(struct iwl4965_priv *priv)
 {
 	int rc;
 	unsigned long flags;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	u8 rev_id;
 	u32 val;
 	u8 val_link;
 
-	iwl_power_init_handle(priv);
+	iwl4965_power_init_handle(priv);
 
 	/* nic_init */
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+	iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (rc < 0) {
@@ -448,26 +464,26 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		return rc;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+	iwl4965_read_prph(priv, APMG_CLK_CTRL_REG);
 
-	iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
-				 APMG_CLK_REG_VAL_DMA_CLK_RQT |
-				 APMG_CLK_REG_VAL_BSM_CLK_RQT);
-	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+	iwl4965_write_prph(priv, APMG_CLK_CTRL_REG,
+				 APMG_CLK_VAL_DMA_CLK_RQT |
+				 APMG_CLK_VAL_BSM_CLK_RQT);
+	iwl4965_read_prph(priv, APMG_CLK_CTRL_REG);
 
 	udelay(20);
 
-	iwl_set_bits_restricted_reg(priv, ALM_APMG_PCIDEV_STT,
-				    APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
+	iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_restricted_access(priv);
-	iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+	iwl4965_release_nic_access(priv);
+	iwl4965_write32(priv, CSR_INT_COALESCING, 512 / 32);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Determine HW type */
@@ -481,15 +497,16 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
-		pci_read_config_dword(priv->pci_dev, 0xe8, &val);
+		pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
 		/* Enable No Snoop field */
-		pci_write_config_dword(priv->pci_dev, 0xe8, val & ~(1 << 11));
+		pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
+				       val & ~(1 << 11));
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Read the EEPROM */
-	rc = iwl_eeprom_init(priv);
+	rc = iwl4965_eeprom_init(priv);
 	if (rc)
 		return rc;
 
@@ -507,51 +524,53 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	/* set CSR_HW_CONFIG_REG for uCode use */
 
-	iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
+	iwl4965_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
 		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
 		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc < 0) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		return rc;
 	}
 
-	iwl_read_restricted_reg(priv, ALM_APMG_PS_CTL);
-	iwl_set_bits_restricted_reg(priv, ALM_APMG_PS_CTL,
-				    APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ);
+	iwl4965_read_prph(priv, APMG_PS_CTRL_REG);
+	iwl4965_set_bits_prph(priv, APMG_PS_CTRL_REG,
+				    APMG_PS_CTRL_VAL_RESET_REQ);
 	udelay(5);
-	iwl_clear_bits_restricted_reg(priv, ALM_APMG_PS_CTL,
-				      APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ);
+	iwl4965_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+				      APMG_PS_CTRL_VAL_RESET_REQ);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_card_show_info(priv);
+	iwl4965_hw_card_show_info(priv);
 
 	/* end nic_init */
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
-		rc = iwl_rx_queue_alloc(priv);
+		rc = iwl4965_rx_queue_alloc(priv);
 		if (rc) {
 			IWL_ERROR("Unable to initialize Rx queue\n");
 			return -ENOMEM;
 		}
 	} else
-		iwl_rx_queue_reset(priv, rxq);
+		iwl4965_rx_queue_reset(priv, rxq);
 
-	iwl_rx_replenish(priv, 1);
+	iwl4965_rx_replenish(priv);
 
 	iwl4965_rx_init(priv, rxq);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
 	rxq->need_update = 1;
-	iwl_rx_queue_update_write_ptr(priv, rxq);
+	iwl4965_rx_queue_update_write_ptr(priv, rxq);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Allocate and init all Tx and Command queues */
 	rc = iwl4965_txq_ctx_reset(priv);
 	if (rc)
 		return rc;
@@ -562,12 +581,12 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
 		IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
 
-	priv->status |= STATUS_INIT;
+	set_bit(STATUS_INIT, &priv->status);
 
 	return 0;
 }
 
-int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 	u32 reg_val;
@@ -576,17 +595,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* set stop master bit */
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+	iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+	reg_val = iwl4965_read32(priv, CSR_GP_CNTRL);
 
 	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
-	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) {
-		IWL_DEBUG_INFO
-		    ("Card in power save, master is already stopped\n");
-	} else {
-		rc = iwl_poll_bit(priv,
-				  CSR_RESET,
+	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+		IWL_DEBUG_INFO("Card in power save, master is already "
+			       "stopped\n");
+	else {
+		rc = iwl4965_poll_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 		if (rc < 0) {
@@ -601,73 +619,72 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	return rc;
 }
 
-void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+/**
+ * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
+ */
+void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv)
 {
 
 	int txq_id;
 	unsigned long flags;
 
-	/* reset TFD queues */
-	for (txq_id = 0; txq_id < IWL4965_NUM_QUEUES; txq_id++) {
+	/* Stop each Tx DMA channel, and wait for it to be idle */
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
 		spin_lock_irqsave(&priv->lock, flags);
-		if (iwl_grab_restricted_access(priv)) {
+		if (iwl4965_grab_nic_access(priv)) {
 			spin_unlock_irqrestore(&priv->lock, flags);
 			continue;
 		}
 
-		iwl_write_restricted(priv,
+		iwl4965_write_direct32(priv,
 				     IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
 				     0x0);
-		iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
+		iwl4965_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
 					IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
 					(txq_id), 200);
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	iwl_hw_txq_ctx_free(priv);
+	/* Deallocate memory for all Tx queues */
+	iwl4965_hw_txq_ctx_free(priv);
 }
 
-int iwl_hw_nic_reset(struct iwl_priv *priv)
+int iwl4965_hw_nic_reset(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 	unsigned long flags;
 
-	iwl_hw_nic_stop_master(priv);
+	iwl4965_hw_nic_stop_master(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
 	udelay(10);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_RESET,
+	iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl4965_poll_bit(priv, CSR_RESET,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
 
 	udelay(10);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (!rc) {
-		iwl_write_restricted_reg(priv, ALM_APMG_CLK_EN,
-					 APMG_CLK_REG_VAL_DMA_CLK_RQT |
-					 APMG_CLK_REG_VAL_BSM_CLK_RQT);
+		iwl4965_write_prph(priv, APMG_CLK_EN_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT |
+					 APMG_CLK_VAL_BSM_CLK_RQT);
 
 		udelay(10);
 
-		iwl_set_bits_restricted_reg(
-			priv, ALM_APMG_PCIDEV_STT,
-			APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE);
+		iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+				APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	priv->status &= ~STATUS_HCMD_ACTIVE;
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 	wake_up_interruptible(&priv->wait_command_queue);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -694,7 +711,7 @@ int iwl_hw_nic_reset(struct iwl_priv *priv)
  */
 static void iwl4965_bg_statistics_periodic(unsigned long data)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)data;
 
 	queue_work(priv->workqueue, &priv->statistics_work);
 }
@@ -702,60 +719,60 @@ static void iwl4965_bg_statistics_periodic(unsigned long data)
 /**
  * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
  *
- * This is queued by iwl_bg_statistics_periodic.
+ * This is queued by iwl4965_bg_statistics_periodic.
  */
 static void iwl4965_bg_statistics_work(void *p)
 {
-	struct iwl_priv *priv = p;
+	struct iwl4965_priv *priv = p;
 
-	if (priv->status & STATUS_EXIT_PENDING)
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_send_statistics_request(priv);
+	iwl4965_send_statistics_request(priv);
 	mutex_unlock(&priv->mutex);
 }
 
 #define CT_LIMIT_CONST		259
 #define TM_CT_KILL_THRESHOLD	110
 
-void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
+void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv)
 {
-	struct iwl_ct_kill_config cmd;
-	u32 R1 = 0, R2 = 0, R3 = 0;
-	u32 temp_th = 0;
+	struct iwl4965_ct_kill_config cmd;
+	u32 R1, R2, R3;
+	u32 temp_th;
+	u32 crit_temperature;
 	unsigned long flags;
 	int rc = 0;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
-		R1 = priv->card_alive_init.therm_r1[1];
-		R2 = priv->card_alive_init.therm_r2[1];
-		R3 = priv->card_alive_init.therm_r3[1];
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
 	} else {
-		R1 = priv->card_alive_init.therm_r1[0];
-		R2 = priv->card_alive_init.therm_r2[0];
-		R3 = priv->card_alive_init.therm_r3[0];
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
 	}
 
 	temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);
 
-	cmd.critical_temperature_R = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
-	rc = iwl_send_cmd_pdu(priv,
+	crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
+	cmd.critical_temperature_R =  cpu_to_le32(crit_temperature);
+	rc = iwl4965_send_cmd_pdu(priv,
 			      REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd);
 	if (rc)
 		IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
 	else
-		IWL_WARNING("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
-
-	return;
+		IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
 }
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 
 /* "false alarms" are signals that our DSP tries to lock onto,
  *   but then determines that they are either noise, or transmissions
@@ -765,7 +782,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
  *   enough to receive all of our own network traffic, but not so
  *   high that our DSP gets too busy trying to lock onto non-network
  *   activity/noise. */
-static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
+static int iwl4965_sens_energy_cck(struct iwl4965_priv *priv,
 				   u32 norm_fa,
 				   u32 rx_enable_time,
 				   struct statistics_general_data *rx_info)
@@ -791,7 +808,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 	u32 false_alarms = norm_fa * 200 * 1024;
 	u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
 	u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	data = &(priv->sensitivity_data);
 
@@ -922,10 +939,8 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 			data->auto_corr_cck_mrc =
 					 max((u32)AUTO_CORR_MIN_CCK_MRC, val);
 
-		} else {
+		} else
 			IWL_DEBUG_CALIB("... but not changing sensitivity\n");
-		}
-
 
 	/* Else we got a healthy number of false alarms, keep status quo */
 	} else {
@@ -945,9 +960,10 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 	}
 
 	/* Make sure the energy threshold does not go above the measured
-	 *   energy of the desired Rx signals (reduced by backoff margin),
-	 *   or else we might start missing Rx frames.
-	 * Lower value is higher energy, so we use max()! */
+	 * energy of the desired Rx signals (reduced by backoff margin),
+	 * or else we might start missing Rx frames.
+	 * Lower value is higher energy, so we use max()!
+	 */
 	data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
 	IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
 
@@ -957,7 +973,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 }
 
 
-static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
+static int iwl4965_sens_auto_corr_ofdm(struct iwl4965_priv *priv,
 				       u32 norm_fa,
 				       u32 rx_enable_time)
 {
@@ -965,7 +981,7 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
 	u32 false_alarms = norm_fa * 200 * 1024;
 	u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
 	u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	data = &(priv->sensitivity_data);
 
@@ -1015,30 +1031,29 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
 				max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val);
 	}
 
-	else {
+	else
 		IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
 			 min_false_alarms, false_alarms, max_false_alarms);
-	}
 
 	return 0;
 }
 
-static int iwl_sensitivity_callback(struct iwl_priv *priv,
-				    struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl4965_sensitivity_callback(struct iwl4965_priv *priv,
+				    struct iwl4965_cmd *cmd, struct sk_buff *skb)
 {
 	/* We didn't cache the SKB; let the caller free it */
 	return 1;
 }
 
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
+static int iwl4965_sensitivity_write(struct iwl4965_priv *priv, u8 flags)
 {
 	int rc = 0;
-	struct iwl_sensitivity_cmd cmd ;
-	struct iwl_sensitivity_data *data = NULL;
-	struct iwl_host_cmd cmd_out = {
+	struct iwl4965_sensitivity_cmd cmd ;
+	struct iwl4965_sensitivity_data *data = NULL;
+	struct iwl4965_host_cmd cmd_out = {
 		.id = SENSITIVITY_CMD,
-		.len = sizeof(struct iwl_sensitivity_cmd),
+		.len = sizeof(struct iwl4965_sensitivity_cmd),
 		.meta.flags = flags,
 		.data = &cmd,
 	};
@@ -1048,25 +1063,30 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 	memset(&cmd, 0, sizeof(cmd));
 
 	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
-					(u16)data->auto_corr_ofdm;
+				cpu_to_le16((u16)data->auto_corr_ofdm);
 	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
-					(u16)data->auto_corr_ofdm_mrc;
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
 	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
-					(u16)data->auto_corr_ofdm_x1;
+				cpu_to_le16((u16)data->auto_corr_ofdm_x1);
 	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
-					(u16)data->auto_corr_ofdm_mrc_x1;
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
 
 	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
-					(u16)data->auto_corr_cck;
+				cpu_to_le16((u16)data->auto_corr_cck);
 	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
-					(u16)data->auto_corr_cck_mrc;
+				cpu_to_le16((u16)data->auto_corr_cck_mrc);
 
-	cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] = (u16)data->nrg_th_cck;
-	cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] = (u16)data->nrg_th_ofdm;
+	cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_cck);
+	cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_ofdm);
 
-	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] = 190;
-	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] = 390;
-	cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] = 62;
+	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+				__constant_cpu_to_le16(190);
+	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+				__constant_cpu_to_le16(390);
+	cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+				__constant_cpu_to_le16(62);
 
 	IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
 			data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
@@ -1077,10 +1097,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 			data->auto_corr_cck, data->auto_corr_cck_mrc,
 			data->nrg_th_cck);
 
+	/* Update uCode's "work" table, and copy it to DSP */
 	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
 
 	if (flags & CMD_ASYNC)
-		cmd_out.meta.u.callback = iwl_sensitivity_callback;
+		cmd_out.meta.u.callback = iwl4965_sensitivity_callback;
 
 	/* Don't send command to uCode if nothing has changed */
 	if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
@@ -1093,7 +1114,7 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
 	       sizeof(u16)*HD_TABLE_SIZE);
 
-	rc = iwl_send_cmd(priv, &cmd_out);
+	rc = iwl4965_send_cmd(priv, &cmd_out);
 	if (!rc) {
 		IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n");
 		return rc;
@@ -1102,11 +1123,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 	return 0;
 }
 
-void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
+void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force)
 {
 	int rc = 0;
 	int i;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
 
@@ -1116,7 +1137,7 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
 
 	/* Clear driver's sensitivity algo data */
 	data = &(priv->sensitivity_data);
-	memset(data, 0, sizeof(struct iwl_sensitivity_data));
+	memset(data, 0, sizeof(struct iwl4965_sensitivity_data));
 
 	data->num_in_cck_no_fa = 0;
 	data->nrg_curr_state = IWL_FA_TOO_MANY;
@@ -1160,21 +1181,21 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
 /* Reset differential Rx gains in NIC to prepare for chain noise calibration.
  * Called after every association, but this runs only once!
  *  ... once chain noise is calibrated the first time, it's good forever.  */
-void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+void iwl4965_chain_noise_reset(struct iwl4965_priv *priv)
 {
-	struct iwl_chain_noise_data *data = NULL;
+	struct iwl4965_chain_noise_data *data = NULL;
 	int rc = 0;
 
 	data = &(priv->chain_noise_data);
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-		struct iwl_calibration_cmd cmd;
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) {
+		struct iwl4965_calibration_cmd cmd;
 
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
 		cmd.diff_gain_a = 0;
 		cmd.diff_gain_b = 0;
 		cmd.diff_gain_c = 0;
-		rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
 				 sizeof(cmd), &cmd);
 		msleep(4);
 		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
@@ -1189,10 +1210,10 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv)
  * 1)  Which antennas are connected.
  * 2)  Differential rx gain settings to balance the 3 receivers.
  */
-static void iwl4965_noise_calibration(struct iwl_priv *priv,
-				      struct iwl_notif_statistics *stat_resp)
+static void iwl4965_noise_calibration(struct iwl4965_priv *priv,
+				      struct iwl4965_notif_statistics *stat_resp)
 {
-	struct iwl_chain_noise_data *data = NULL;
+	struct iwl4965_chain_noise_data *data = NULL;
 	int rc = 0;
 
 	u32 chain_noise_a;
@@ -1218,46 +1239,48 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 
 	/* Accumulate just the first 20 beacons after the first association,
 	 *   then we're done forever. */
-	if (data->state != IWL_CHAIN_NOISE_ACCUMULATE ) {
+	if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
 		if (data->state == IWL_CHAIN_NOISE_ALIVE)
 			IWL_DEBUG_CALIB("Wait for noise calib reset\n");
 		return;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (rx_info->interference_data_flag != 1) {
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB(" << Interference data unavailable\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
 
 	band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1;
-	chan_num = priv->staging_rxon.channel;
+	chan_num = le16_to_cpu(priv->staging_rxon.channel);
 
 	/* Make sure we accumulate data for just the associated channel
 	 *   (even if scanning). */
-	if ((chan_num != (stat_resp->flag >> 16)) ||
-	   ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
-	     (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) &&
-	    band)) {
+	if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) ||
+	    ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
+	     (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) {
 		IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n",
-				 chan_num, band);
+				chan_num, band);
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
 
 	/* Accumulate beacon statistics values across 20 beacons */
-	chain_noise_a = (rx_info->beacon_silence_rssi_a & IN_BAND_FILTER);
-	chain_noise_b = (rx_info->beacon_silence_rssi_b & IN_BAND_FILTER);
-	chain_noise_c = (rx_info->beacon_silence_rssi_c & IN_BAND_FILTER);
+	chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+				IN_BAND_FILTER;
+	chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+				IN_BAND_FILTER;
+	chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+				IN_BAND_FILTER;
 
-	chain_sig_a = (rx_info->beacon_rssi_a & IN_BAND_FILTER);
-	chain_sig_b = (rx_info->beacon_rssi_b & IN_BAND_FILTER);
-	chain_sig_c = (rx_info->beacon_rssi_c & IN_BAND_FILTER);
+	chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+	chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+	chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	data->beacon_count ++;
+	data->beacon_count++;
 
 	data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
 	data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
@@ -1280,12 +1303,9 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 	if (data->beacon_count == CAL_NUM_OF_BEACONS) {
 
 		/* Analyze signal for disconnected antenna */
-		average_sig[0] = (data->chain_signal_a) /
-					CAL_NUM_OF_BEACONS;
-		average_sig[1] = (data->chain_signal_b) /
-					CAL_NUM_OF_BEACONS;
-		average_sig[2] = (data->chain_signal_c) /
-					CAL_NUM_OF_BEACONS;
+		average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+		average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+		average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
 
 		if (average_sig[0] >= average_sig[1]) {
 			max_average_sig = average_sig[0];
@@ -1311,26 +1331,25 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 		/* Compare signal strengths for all 3 receivers. */
 		for (i = 0; i < NUM_RX_CHAINS; i++) {
 			if (i != max_average_sig_antenna_i) {
-				s32 rssiDelta = (max_average_sig -
-						 average_sig[i]);
+				s32 rssi_delta = (max_average_sig -
+						  average_sig[i]);
 
 				/* If signal is very weak, compared with
 				 * strongest, mark it as disconnected. */
-				if (rssiDelta > MAXIMUM_ALLOWED_PATHLOSS)
+				if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
 					data->disconn_array[i] = 1;
 				else
 					active_chains |= (1 << i);
 			IWL_DEBUG_CALIB("i = %d  rssiDelta = %d  "
 				     "disconn_array[i] = %d\n",
-				     i, rssiDelta,
-				     data->disconn_array[i]);
+				     i, rssi_delta, data->disconn_array[i]);
 			}
 		}
 
 		/*If both chains A & B are disconnected -
 		 * connect B and leave A as is */
 		if (data->disconn_array[CHAIN_A] &&
-		   data->disconn_array[CHAIN_B]) {
+		    data->disconn_array[CHAIN_B]) {
 			data->disconn_array[CHAIN_B] = 0;
 			active_chains |= (1 << CHAIN_B);
 			IWL_DEBUG_CALIB("both A & B chains are disconnected! "
@@ -1383,9 +1402,8 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 
 				data->delta_gain_code[i] =
 					(data->delta_gain_code[i] | (1 << 2));
-			} else {
+			} else
 				data->delta_gain_code[i] = 0;
-			}
 		}
 		IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
 			     data->delta_gain_code[0],
@@ -1394,7 +1412,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 
 		/* Differential gain gets sent to uCode only once */
 		if (!data->radio_write) {
-			struct iwl_calibration_cmd cmd;
+			struct iwl4965_calibration_cmd cmd;
 			data->radio_write = 1;
 
 			memset(&cmd, 0, sizeof(cmd));
@@ -1402,7 +1420,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 			cmd.diff_gain_a = data->delta_gain_code[0];
 			cmd.diff_gain_b = data->delta_gain_code[1];
 			cmd.diff_gain_c = data->delta_gain_code[2];
-			rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+			rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
 					      sizeof(cmd), &cmd);
 			if (rc)
 				IWL_DEBUG_CALIB("fail sending cmd "
@@ -1425,8 +1443,8 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 	return;
 }
 
-static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
-					    struct iwl_notif_statistics *resp)
+static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv,
+					    struct iwl4965_notif_statistics *resp)
 {
 	int rc = 0;
 	u32 rx_enable_time;
@@ -1436,7 +1454,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 	u32 bad_plcp_ofdm;
 	u32 norm_fa_ofdm;
 	u32 norm_fa_cck;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 	struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
 	struct statistics_rx *statistics = &(resp->rx);
 	unsigned long flags;
@@ -1444,37 +1462,37 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 
 	data = &(priv->sensitivity_data);
 
-	if (!iwl_is_associated(priv)) {
+	if (!iwl4965_is_associated(priv)) {
 		IWL_DEBUG_CALIB("<< - not associated\n");
 		return;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (rx_info->interference_data_flag != 1) {
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
 		IWL_DEBUG_CALIB("<< invalid data.\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
 
 	/* Extract Statistics: */
-	rx_enable_time = rx_info->channel_load;
-	fa_cck = statistics->cck.false_alarm_cnt;
-	fa_ofdm = statistics->ofdm.false_alarm_cnt;
-	bad_plcp_cck = statistics->cck.plcp_err;
-	bad_plcp_ofdm = statistics->ofdm.plcp_err;
+	rx_enable_time = le32_to_cpu(rx_info->channel_load);
+	fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+	fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+	bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+	bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
 
 	statis.beacon_silence_rssi_a =
-			statistics->general.beacon_silence_rssi_a;
+			le32_to_cpu(statistics->general.beacon_silence_rssi_a);
 	statis.beacon_silence_rssi_b =
-			statistics->general.beacon_silence_rssi_b;
+			le32_to_cpu(statistics->general.beacon_silence_rssi_b);
 	statis.beacon_silence_rssi_c =
-			statistics->general.beacon_silence_rssi_c;
+			le32_to_cpu(statistics->general.beacon_silence_rssi_c);
 	statis.beacon_energy_a =
-			statistics->general.beacon_energy_a;
+			le32_to_cpu(statistics->general.beacon_energy_a);
 	statis.beacon_energy_b =
-			statistics->general.beacon_energy_b;
+			le32_to_cpu(statistics->general.beacon_energy_b);
 	statis.beacon_energy_c =
-			statistics->general.beacon_energy_c;
+			le32_to_cpu(statistics->general.beacon_energy_c);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1504,7 +1522,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 
 	if (data->last_fa_cnt_ofdm > fa_ofdm)
 		data->last_fa_cnt_ofdm = fa_ofdm;
-	else{
+	else {
 		fa_ofdm -= data->last_fa_cnt_ofdm;
 		data->last_fa_cnt_ofdm += fa_ofdm;
 	}
@@ -1524,22 +1542,20 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 			bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
 
 	iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
-
-	iwl4965_sens_energy_cck(priv, norm_fa_cck,
-					rx_enable_time, &statis);
-
+	iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
 	rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC);
+
 	return;
 }
 
 static void iwl4965_bg_sensitivity_work(void *p)
 {
-	struct iwl_priv *priv = p;
+	struct iwl4965_priv *priv = p;
 
 	mutex_lock(&priv->mutex);
 
-	if ((priv->status & STATUS_EXIT_PENDING) ||
-	    (priv->status & STATUS_SCANNING)) {
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status)) {
 		mutex_unlock(&priv->mutex);
 		return;
 	}
@@ -1551,37 +1567,34 @@ static void iwl4965_bg_sensitivity_work(void *p)
 					IWL_SENS_CALIB_NEED_REINIT) {
 			iwl4965_init_sensitivity(priv, CMD_ASYNC, 0);
 			priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED;
-		} else {
+		} else
 			iwl4965_sensitivity_calibration(priv,
-							&priv->statistics);
-		}
+					&priv->statistics);
 	}
 
 	mutex_unlock(&priv->mutex);
 	return;
 }
-#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
 
 static void iwl4965_bg_txpower_work(void *p)
 {
-	struct iwl_priv *priv = p;
-
-	mutex_lock(&priv->mutex);
+	struct iwl4965_priv *priv = p;
 
 	/* If a scan happened to start before we got here
 	 * then just return; the statistics notification will
 	 * kick off another scheduled work to compensate for
 	 * any temperature delta we missed here. */
-	if ((priv->status & STATUS_EXIT_PENDING) ||
-	    priv->status & STATUS_SCANNING) {
-		mutex_unlock(&priv->mutex);
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status))
 		return;
-	}
+
+	mutex_lock(&priv->mutex);
 
 	/* Regardless of if we are assocaited, we must reconfigure the
 	 * TX power since frames can be sent on non-radar channels while
 	 * not associated */
-	iwl_hw_reg_send_txpower(priv);
+	iwl4965_hw_reg_send_txpower(priv);
 
 	/* Update last_temperature to keep is_calib_needed from running
 	 * when it isn't needed... */
@@ -1590,43 +1603,68 @@ static void iwl4965_bg_txpower_work(void *p)
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index)
 {
-	iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+	iwl4965_write_direct32(priv, HBUS_TARG_WRPTR,
 			     (index & 0xff) | (txq_id << 8));
-	iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index);
+	iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index);
 }
 
-static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
-			    struct iwl_tx_queue *txq, int tx_fifo_id,
-			    int sched_retry, int active)
+/**
+ * iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue
+ * @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed
+ * @scd_retry: (1) Indicates queue will be used in aggregation mode
+ *
+ * NOTE:  Acquire priv->lock before calling this function !
+ */
+static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv,
+					struct iwl4965_tx_queue *txq,
+					int tx_fifo_id, int scd_retry)
 {
 	int txq_id = txq->q.id;
 
-	txq->sched_retry = sched_retry;
-	txq->sched_retry = active;
+	/* Find out whether to activate Tx queue */
+	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+	/* Set up and activate */
+	iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id),
+				 (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+				 (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
+				 (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
+				 (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+				 SCD_QUEUE_STTS_REG_MSK);
 
-	iwl_write_restricted_reg(priv,
-				SCD_QUEUE_STATUS_BITS(txq_id),
-				(active << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-				(tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF)|
-				(sched_retry << SCD_QUEUE_STTS_REG_POS_WSL)|
-				(sched_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK)|
-				SCD_QUEUE_STTS_REG_MSK);
+	txq->sched_retry = scd_retry;
 
 	IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
-		(active?"Activete":"Deactivate"),
-		sched_retry?"BA":"AC", txq_id, tx_fifo_id);
+		       active ? "Activate" : "Deactivate",
+		       scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
 }
 
-
-static const u16 default_ac_to_tx_fifo[] = {
-	IWL_TX_QUEUE_AC1, IWL_TX_QUEUE_AC0,
-	IWL_TX_QUEUE_AC2, IWL_TX_QUEUE_AC3,
-	IWL_TX_QUEUE_HCCA_1, IWL_TX_QUEUE_HCCA_2
+static const u16 default_queue_to_tx_fifo[] = {
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC0,
+	IWL_CMD_FIFO_NUM,
+	IWL_TX_FIFO_HCCA_1,
+	IWL_TX_FIFO_HCCA_2
 };
 
-int iwl4965_alive_notify(struct iwl_priv *priv)
+static inline void iwl4965_txq_ctx_activate(struct iwl4965_priv *priv, int txq_id)
+{
+	set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl4965_txq_ctx_deactivate(struct iwl4965_priv *priv, int txq_id)
+{
+	clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+int iwl4965_alive_notify(struct iwl4965_priv *priv)
 {
 	u32 a;
 	int i = 0;
@@ -1635,49 +1673,55 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	memset(&(priv->sensitivity_data), 0,
-	       sizeof(struct iwl_sensitivity_data));
+	       sizeof(struct iwl4965_sensitivity_data));
 	memset(&(priv->chain_noise_data), 0,
-	       sizeof(struct iwl_chain_noise_data));
+	       sizeof(struct iwl4965_chain_noise_data));
 	for (i = 0; i < NUM_RX_CHAINS; i++)
 		priv->chain_noise_data.delta_gain_code[i] =
 				CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-#endif /* CONFIG_IWLWIFI_SENSITIVITY*/
-	rc = iwl_grab_restricted_access(priv);
+#endif /* CONFIG_IWL4965_SENSITIVITY*/
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR);
+	/* Clear 4965's internal Tx Scheduler data base */
+	priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR);
 	a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
 	for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
+		iwl4965_write_targ_mem(priv, a, 0);
 	for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
-	for (;
-	     a < sizeof(u16) * IWL4965_NUM_QUEUES;
-	     a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
-
-	iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR,
-				 (priv->hw_setting.shared_phys +
-				  offsetof(struct iwl_shared,
-					   queues_byte_cnt_tbls))
-				 >> 10);
-	iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0);
-
-	/* initiate the queues */
-	for (i = 0; i < IWL4965_NUM_QUEUES; i++) {
-		iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0);
-		iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
-		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+		iwl4965_write_targ_mem(priv, a, 0);
+	for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
+		iwl4965_write_targ_mem(priv, a, 0);
+
+	/* Tel 4965 where to find Tx byte count tables */
+	iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR,
+		(priv->hw_setting.shared_phys +
+		 offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
+
+	/* Disable chain mode for all queues */
+	iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0);
+
+	/* Initialize each Tx queue (including the command queue) */
+	for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
+
+		/* TFD circular buffer read/write indexes */
+		iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0);
+		iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+
+		/* Max Tx Window size for Scheduler-ACK mode */
+		iwl4965_write_targ_mem(priv, priv->scd_base_addr +
 					SCD_CONTEXT_QUEUE_OFFSET(i),
 					(SCD_WIN_SIZE <<
 					SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
 					SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
-		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+
+		/* Frame limit */
+		iwl4965_write_targ_mem(priv, priv->scd_base_addr +
 					SCD_CONTEXT_QUEUE_OFFSET(i) +
 					sizeof(u32),
 					(SCD_FRAME_LIMIT <<
@@ -1685,85 +1729,98 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 					SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
 
 	}
-	iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK,
-				 (1 << IWL4965_NUM_QUEUES) - 1);
+	iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK,
+				 (1 << priv->hw_setting.max_txq_num) - 1);
 
-	iwl_write_restricted_reg(priv, SCD_TXFACT,
+	/* Activate all Tx DMA/FIFO channels */
+	iwl4965_write_prph(priv, KDR_SCD_TXFACT,
 				 SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
 
 	iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
-	iwl4965_tx_queue_set_status(priv, &priv->txq[IWL_CMD_QUEUE_NUM],
-				    IWL_CMD_FIFO_NUM, 0, 1);
-	/* map qos queues to fifos one-to-one */
-	for (i = 0; i < GLOBAL_ARRAY_SIZE(default_ac_to_tx_fifo); i++) {
-		int ac = default_ac_to_tx_fifo[i];
-		iwl4965_tx_queue_set_status(priv, &priv->txq[ac], ac, 0, 1);
+
+	/* Map each Tx/cmd queue to its corresponding fifo */
+	for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
+		int ac = default_queue_to_tx_fifo[i];
+		iwl4965_txq_ctx_activate(priv, i);
+		iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+/**
+ * iwl4965_hw_set_hw_setting
+ *
+ * Called when initializing driver
+ */
+int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv)
 {
+	/* Allocate area for Tx byte count tables and Rx queue status */
 	priv->hw_setting.shared_virt =
 	    pci_alloc_consistent(priv->pci_dev,
-				 sizeof(struct iwl_shared),
+				 sizeof(struct iwl4965_shared),
 				 &priv->hw_setting.shared_phys);
 
 	if (!priv->hw_setting.shared_virt)
 		return -1;
 
-	memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared));
+	memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared));
 
-	priv->hw_setting.max_queue_number = IWL4965_NUM_QUEUES;
+	priv->hw_setting.max_txq_num = iwl4965_param_queues_num;
 	priv->hw_setting.ac_queue_count = AC_NUM;
-
-	priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK;
-	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
 	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
 	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+	if (iwl4965_param_amsdu_size_8K)
+		priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+	else
+		priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+	priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
+	priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
+	priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
 	return 0;
 }
 
 /**
- * iwl_hw_txq_ctx_free - Free TXQ Context
+ * iwl4965_hw_txq_ctx_free - Free TXQ Context
  *
  * Destroy all TX DMA queues and structures
  */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv)
 {
 	int txq_id;
 
 	/* Tx queues */
-	for (txq_id = 0; txq_id < priv->hw_setting.max_queue_number; txq_id++)
-		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+		iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
 
+	/* Keep-warm buffer */
 	iwl4965_kw_free(priv);
 }
 
 /**
- * iwl_hw_tx_queue_free_tfd -  Free one TFD, those at index [txq->q.last_used]
+ * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
  *
- * Does NOT advance any indexes
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
  */
-int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
-	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
-	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0];
+	struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 	int counter = 0;
 	int index, is_odd;
 
-	/* classify bd */
+	/* Host command buffers stay mapped in memory, nothing to clean */
 	if (txq->q.id == IWL_CMD_QUEUE_NUM)
-		/* nothing to cleanup after for host commands */
 		return 0;
 
-	/* sanity check */
+	/* Sanity check on number of chunks */
 	counter = IWL_GET_BITS(*bd, num_tbs);
 	if (counter > MAX_NUM_OF_TBS) {
 		IWL_ERROR("Too many chunks: %i\n", counter);
@@ -1771,11 +1828,11 @@ int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 		return 0;
 	}
 
-	/* unmap chunks if any */
-
+	/* Unmap chunks, if any.
+	 * TFD info for odd chunks is different format than for even chunks. */
 	for (i = 0; i < counter; i++) {
 		index = i / 2;
-		is_odd = i % 2;
+		is_odd = i & 0x1;
 
 		if (is_odd)
 			pci_unmap_single(
@@ -1792,37 +1849,24 @@ int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 					 IWL_GET_BITS(bd->pa[index], tb1_len),
 					 PCI_DMA_TODEVICE);
 
-		if (txq->txb[txq->q.last_used].skb[i]) {
-			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i];
+		/* Free SKB, if any, for this chunk */
+		if (txq->txb[txq->q.read_ptr].skb[i]) {
+			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
 
 			dev_kfree_skb(skb);
-			txq->txb[txq->q.last_used].skb[i] = NULL;
+			txq->txb[txq->q.read_ptr].skb[i] = NULL;
 		}
 	}
 	return 0;
 }
 
-int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power)
 {
-	IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n");
+	IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n");
 	return -EINVAL;
 }
 
-#define TX_POWER_IWL_ILLEGAL_VDET    -100000
-#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18
-#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34
-#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17
-#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20
-#define TX_POWER_IWL_NOMINAL_POWER            26
-#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1
-#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V       7
-#define TX_POWER_IWL_DEGREES_PER_VDET_CODE       11
-#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1
-#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
-#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
-
-static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 * res)
+static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
 {
 	s32 sign = 1;
 
@@ -1840,8 +1884,19 @@ static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 * res)
 	return 1;
 }
 
-static s32 iwl4965_get_voltage_compensation(u32 eeprom_voltage,
-					    u32 current_voltage)
+/**
+ * iwl4965_get_voltage_compensation - Power supply voltage comp for txpower
+ *
+ * Determines power supply voltage compensation for txpower calculations.
+ * Returns number of 1/2-dB steps to subtract from gain table index,
+ * to compensate for difference between power supply voltage during
+ * factory measurements, vs. current power supply voltage.
+ *
+ * Voltage indication is higher for lower voltage.
+ * Lower voltage requires more gain (lower gain table index).
+ */
+static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
+					    s32 current_voltage)
 {
 	s32 comp = 0;
 
@@ -1860,35 +1915,20 @@ static s32 iwl4965_get_voltage_compensation(u32 eeprom_voltage,
 	return comp;
 }
 
-static const struct iwl_channel_info *iwl4965_get_current_txpower_info(
-	struct iwl_priv *priv, u8 *band, u8 *channel, u8 *is_fat,
-	u8 *ctrl_chan_high)
+static const struct iwl4965_channel_info *
+iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel)
 {
-	const struct iwl_channel_info *ch_info;
-
-	*ctrl_chan_high = 0;
-	*channel = priv->active_rxon.channel;
-	*band = ((priv->phymode == MODE_IEEE80211B) ||
-		 (priv->phymode == MODE_IEEE80211G) ||
-		 (priv->phymode == MODE_ATHEROS_TURBOG)) ? 1 : 0;
+	const struct iwl4965_channel_info *ch_info;
 
-	ch_info = iwl_get_channel_info(priv, priv->phymode,
-				       priv->active_rxon.channel);
+	ch_info = iwl4965_get_channel_info(priv, phymode, channel);
 
 	if (!is_channel_valid(ch_info))
 		return NULL;
 
-	*is_fat = is_fat_channel(priv);
-
-	if (*is_fat)
-		if (priv->active_rxon.flags &
-		    RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK)
-			*ctrl_chan_high = 1;
-
 	return ch_info;
 }
 
-static s32 iwl4965_get_txatten_group_from_channel(u32 channel)
+static s32 iwl4965_get_tx_atten_grp(u16 channel)
 {
 	if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH &&
 	    channel <= CALIB_IWL_TX_ATTEN_GR5_LCH)
@@ -1914,24 +1954,20 @@ static s32 iwl4965_get_txatten_group_from_channel(u32 channel)
 	return -1;
 }
 
-static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
+static u32 iwl4965_get_sub_band(const struct iwl4965_priv *priv, u32 channel)
 {
-	s32 sub_band = -1;
-
-	for (sub_band = 0; sub_band < EEPROM_TX_POWER_BANDS; sub_band++) {
+	s32 b = -1;
 
-		if (priv->eeprom.calib_info.band_info_tbl[sub_band].ch_from ==
-		    0)
+	for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
+		if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
 			continue;
 
-		if ((channel >=
-		     priv->eeprom.calib_info.band_info_tbl[sub_band].ch_from)
-		    && (channel <=
-			priv->eeprom.calib_info.band_info_tbl[sub_band].ch_to))
+		if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
+		    && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
 			break;
 	}
 
-	return sub_band;
+	return b;
 }
 
 static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
@@ -1946,16 +1982,23 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
 	}
 }
 
-static int iwl4965_interpolate_chan(
-	struct iwl_priv *priv, u32 channel,
-	struct iwl_eeprom_calib_channel_info *chan_info)
+/**
+ * iwl4965_interpolate_chan - Interpolate factory measurements for one channel
+ *
+ * Interpolates factory measurements from the two sample channels within a
+ * sub-band, to apply to channel of interest.  Interpolation is proportional to
+ * differences in channel frequencies, which is proportional to differences
+ * in channel number.
+ */
+static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel,
+				    struct iwl4965_eeprom_calib_ch_info *chan_info)
 {
 	s32 s = -1;
 	u32 c;
 	u32 m;
-	const struct iwl_eeprom_calib_measurement *m1;
-	const struct iwl_eeprom_calib_measurement *m2;
-	struct iwl_eeprom_calib_measurement *omeas;
+	const struct iwl4965_eeprom_calib_measure *m1;
+	const struct iwl4965_eeprom_calib_measure *m2;
+	struct iwl4965_eeprom_calib_measure *omeas;
 	u32 ch_i1;
 	u32 ch_i2;
 
@@ -1965,8 +2008,8 @@ static int iwl4965_interpolate_chan(
 		return -1;
 	}
 
-	ch_i1 = priv->eeprom.calib_info.band_info_tbl[s].ch1.ch_num;
-	ch_i2 = priv->eeprom.calib_info.band_info_tbl[s].ch2.ch_num;
+	ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
+	ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
 	chan_info->ch_num = (u8) channel;
 
 	IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
@@ -1974,9 +2017,9 @@ static int iwl4965_interpolate_chan(
 
 	for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
 		for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
-			m1 = &(priv->eeprom.calib_info.band_info_tbl[s].ch1.
+			m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
 			       measurements[c][m]);
-			m2 = &(priv->eeprom.calib_info.band_info_tbl[s].ch2.
+			m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
 			       measurements[c][m]);
 			omeas = &(chan_info->measurements[c][m]);
 
@@ -2030,7 +2073,7 @@ static s32 back_off_table[] = {
 
 /* Thermal compensation values for txpower for various frequency ranges ...
  *   ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
-static struct iwl_txpower_comp_entry {
+static struct iwl4965_txpower_comp_entry {
 	s32 degrees_per_05db_a;
 	s32 degrees_per_05db_a_denom;
 } tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
@@ -2044,7 +2087,7 @@ static struct iwl_txpower_comp_entry {
 static s32 get_min_power_index(s32 rate_power_index, u32 band)
 {
 	if (!band) {
-		if ((rate_power_index % 8) <= 4)
+		if ((rate_power_index & 7) <= 4)
 			return MIN_TX_GAIN_INDEX_52GHZ_EXT;
 	}
 	return MIN_TX_GAIN_INDEX;
@@ -2280,16 +2323,10 @@ static const struct gain_entry gain_table[2][108] = {
 	 }
 };
 
-/**
- * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit
- *
- * Uses the active RXON for channel, band, and characteristics (fat, high)
- * The power limit is taken from priv->user_txpower_limit.
- */
-int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 channel,
+				    u8 is_fat, u8 ctrl_chan_high,
+				    struct iwl4965_tx_power_db *tx_power_tbl)
 {
-	u16 radio_gain;
-	u16 dsp_atten;
 	u8 saturation_power;
 	s32 target_power;
 	s32 user_target_power;
@@ -2297,15 +2334,14 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	s32 current_temp;
 	s32 reg_limit;
 	s32 current_regulatory;
-	s32 txatten_group = CALIB_CH_GROUP_MAX;
-	int i = 0;
+	s32 txatten_grp = CALIB_CH_GROUP_MAX;
+	int i;
 	int c;
-	struct iwl_tx_power_table_cmd cmd = { 0 };
-	const struct iwl_channel_info *ch_info = NULL;
-	struct iwl_eeprom_calib_channel_info ch_eeprom_info;
-	const struct iwl_eeprom_calib_measurement *measurement;
-	int rc = 0;
+	const struct iwl4965_channel_info *ch_info = NULL;
+	struct iwl4965_eeprom_calib_ch_info ch_eeprom_info;
+	const struct iwl4965_eeprom_calib_measure *measurement;
 	s16 voltage;
+	s32 init_voltage;
 	s32 voltage_compensation;
 	s32 degrees_per_05db_num;
 	s32 degrees_per_05db_denom;
@@ -2314,18 +2350,6 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	s32 factory_gain_index[2];
 	s32 factory_actual_pwr[2];
 	s32 power_index;
-	u8 band = 0;
-	u8 channel = 0;
-	u8 is_fat = 0;
-	u8 ctrl_chan_high = 0;
-
-	if (priv->status & STATUS_SCANNING) {
-		/* If this gets hit a lot, switch it to a BUG() and catch
-		 * the stack trace to find out who is calling this during
-		 * a scan. */
-		IWL_WARNING("TX Power requested while scanning!\n");
-		return -EAGAIN;
-	}
 
 	/* Sanity check requested level (dBm) */
 	if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) {
@@ -2345,27 +2369,22 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 
 	/* Get current (RXON) channel, band, width */
 	ch_info =
-	    iwl4965_get_current_txpower_info(priv, &band, &channel, &is_fat,
-					     &ctrl_chan_high);
+		iwl4965_get_channel_txpower_info(priv, priv->phymode, channel);
 
 	IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band,
 			  is_fat);
 
 	if (!ch_info)
-		return -1;
-
-	cmd.band = band;
-	cmd.channel = channel;
-	cmd.channel_normal_width = 0;
+		return -EINVAL;
 
 	/* get txatten group, used to select 1) thermal txpower adjustment
 	 *   and 2) mimo txpower balance between Tx chains. */
-	txatten_group = iwl4965_get_txatten_group_from_channel(channel);
-	if (txatten_group < 0)
-		return -1;
+	txatten_grp = iwl4965_get_tx_atten_grp(channel);
+	if (txatten_grp < 0)
+		return -EINVAL;
 
 	IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n",
-			  channel, txatten_group);
+			  channel, txatten_grp);
 
 	if (is_fat) {
 		if (ctrl_chan_high)
@@ -2409,13 +2428,13 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
 
 	/* calculate tx gain adjustment based on power supply voltage */
-	voltage = (s16)le16_to_cpu(priv->eeprom.calib_info.voltage);
+	voltage = priv->eeprom.calib_info.voltage;
+	init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
 	voltage_compensation =
-	    iwl4965_get_voltage_compensation(voltage,
-					     priv->card_alive_init.voltage);
+	    iwl4965_get_voltage_compensation(voltage, init_voltage);
 
 	IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n",
-			  priv->card_alive_init.voltage,
+			  init_voltage,
 			  voltage, voltage_compensation);
 
 	/* get current temperature (Celsius) */
@@ -2423,18 +2442,12 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX);
 	current_temp = KELVIN_TO_CELSIUS(current_temp);
 
-	if (-40 > current_temp) {
-		IWL_WARNING("Invalid temperature %d, can't calculate "
-			    "txpower\n", current_temp);
-		return -EINVAL;
-	}
-
 	/* select thermal txpower adjustment params, based on channel group
 	 *   (same frequency group used for mimo txatten adjustment) */
 	degrees_per_05db_num =
-	    tx_power_cmp_tble[txatten_group].degrees_per_05db_a;
+	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
 	degrees_per_05db_denom =
-	    tx_power_cmp_tble[txatten_group].degrees_per_05db_a_denom;
+	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;
 
 	/* get per-chain txpower values from factory measurements */
 	for (c = 0; c < 2; c++) {
@@ -2463,9 +2476,9 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	}
 
 	/* for each of 33 bit-rates (including 1 for CCK) */
-	for (i = 0; i <= POWER_TABLE_NUM_HT_OFDM_ENTRIES; i++) {
+	for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) {
 		u8 is_mimo_rate;
-		union tx_power_dual_stream_u *tx_power;
+		union iwl4965_tx_power_dual_stream tx_power;
 
 		/* for mimo, reduce each chain's txpower by half
 		 * (3dB, 6 steps), so total output power is regulatory
@@ -2501,8 +2514,8 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 
 			if (is_mimo_rate)
 				atten_value =
-				    priv->card_alive_init.
-				    tx_atten[txatten_group][c];
+				    (s32)le32_to_cpu(priv->card_alive_init.
+				    tx_atten[txatten_grp][c]);
 			else
 				atten_value = 0;
 
@@ -2514,8 +2527,8 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 					    voltage_compensation +
 					    atten_value);
 
-/*                      IWL_DEBUG_TXPOWER("calculated txpower index %d\n", */
-/*                               power_index); */
+/*			IWL_DEBUG_TXPOWER("calculated txpower index %d\n",
+						power_index); */
 
 			if (power_index < get_min_power_index(i, band))
 				power_index = get_min_power_index(i, band);
@@ -2525,16 +2538,9 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 				power_index += 9;
 
 			/* CCK, rate 32, reduce txpower for CCK */
-			if (POWER_TABLE_NUM_HT_OFDM_ENTRIES == i) {
+			if (i == POWER_TABLE_CCK_ENTRY)
 				power_index +=
 				    IWL_TX_POWER_CCK_COMPENSATION_C_STEP;
-				tx_power = &(cmd.tx_power.legacy_cck_power);
-			}
-
-			/* OFDM, rates 0-31 */
-			else {
-				tx_power = &(cmd.tx_power.ht_ofdm_power[i]);
-			}
 
 			/* stay within the table! */
 			if (power_index > 107) {
@@ -2549,65 +2555,134 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 			}
 
 			/* fill txpower command for this rate/chain */
-			radio_gain = gain_table[band][power_index].radio;
-			dsp_atten = gain_table[band][power_index].dsp;
-
-			if (c == 0) {
-				tx_power->s.ramon_tx_gain = radio_gain;
-				tx_power->s.dsp_predis_atten = dsp_atten;
-			} else {
-				tx_power->s.ramon_tx_gain |= (radio_gain << 8);
-				tx_power->s.dsp_predis_atten |=
-				    (dsp_atten << 8);
-			}
+			tx_power.s.radio_tx_gain[c] =
+				gain_table[band][power_index].radio;
+			tx_power.s.dsp_predis_atten[c] =
+				gain_table[band][power_index].dsp;
 
 			IWL_DEBUG_TXPOWER("chain %d mimo %d index %d "
 					  "gain 0x%02x dsp %d\n",
 					  c, atten_value, power_index,
-					  radio_gain, dsp_atten);
+					tx_power.s.radio_tx_gain[c],
+					tx_power.s.dsp_predis_atten[c]);
+		}/* for each chain */
 
-		}		/* for each chain */
+		tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
 
-	}			/* for each rate */
+	}/* for each rate */
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+	return 0;
+}
 
+/**
+ * iwl4965_hw_reg_send_txpower - Configure the TXPOWER level user limit
+ *
+ * Uses the active RXON for channel, band, and characteristics (fat, high)
+ * The power limit is taken from priv->user_txpower_limit.
+ */
+int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv)
+{
+	struct iwl4965_txpowertable_cmd cmd = { 0 };
+	int rc = 0;
+	u8 band = 0;
+	u8 is_fat = 0;
+	u8 ctrl_chan_high = 0;
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		/* If this gets hit a lot, switch it to a BUG() and catch
+		 * the stack trace to find out who is calling this during
+		 * a scan. */
+		IWL_WARNING("TX Power requested while scanning!\n");
+		return -EAGAIN;
+	}
+
+	band = ((priv->phymode == MODE_IEEE80211B) ||
+		(priv->phymode == MODE_IEEE80211G));
+
+	is_fat =  is_fat_channel(priv->active_rxon.flags);
+
+	if (is_fat &&
+	    (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+		ctrl_chan_high = 1;
+
+	cmd.band = band;
+	cmd.channel = priv->active_rxon.channel;
+
+	rc = iwl4965_fill_txpower_tbl(priv, band,
+				le16_to_cpu(priv->active_rxon.channel),
+				is_fat, ctrl_chan_high, &cmd.tx_power);
+	if (rc)
+		return rc;
+
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+	return rc;
+}
+
+int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel)
+{
+	int rc;
+	u8 band = 0;
+	u8 is_fat = 0;
+	u8 ctrl_chan_high = 0;
+	struct iwl4965_channel_switch_cmd cmd = { 0 };
+	const struct iwl4965_channel_info *ch_info;
+
+	band = ((priv->phymode == MODE_IEEE80211B) ||
+		(priv->phymode == MODE_IEEE80211G));
+
+	ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel);
+
+	is_fat = is_fat_channel(priv->staging_rxon.flags);
+
+	if (is_fat &&
+	    (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+		ctrl_chan_high = 1;
+
+	cmd.band = band;
+	cmd.expect_beacon = 0;
+	cmd.channel = cpu_to_le16(channel);
+	cmd.rxon_flags = priv->active_rxon.flags;
+	cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+	cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	if (ch_info)
+		cmd.expect_beacon = is_channel_radar(ch_info);
+	else
+		cmd.expect_beacon = 1;
+
+	rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
+				      ctrl_chan_high, &cmd.tx_power);
+	if (rc) {
+		IWL_DEBUG_11H("error:%d  fill txpower_tbl\n", rc);
+		return rc;
+	}
+
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
 	return rc;
 }
 
 #define RTS_HCCA_RETRY_LIMIT		3
 #define RTS_DFAULT_RETRY_LIMIT		60
 
-void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-			      struct iwl_cmd *cmd,
+void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv,
+			      struct iwl4965_cmd *cmd,
 			      struct ieee80211_tx_control *ctrl,
 			      struct ieee80211_hdr *hdr, int sta_id,
 			      int is_hcca)
 {
-	unsigned long flags;
-	int rate = ctrl->tx_rate;
+	u8 rate;
 	u8 rts_retry_limit = 0;
 	u8 data_retry_limit = 0;
-	u32 tx_flags;
+	__le32 tx_flags;
+	u16 fc = le16_to_cpu(hdr->frame_control);
 
 	tx_flags = cmd->cmd.tx.tx_flags;
 
-	rate = iwl_rates[ctrl->tx_rate].plcp;
-
-	spin_lock_irqsave(&priv->sta_lock, flags);
-
-	priv->stations[sta_id].current_rate.rate_n_flags = rate;
-
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-	    (sta_id != IWL_BROADCAST_ID) && (sta_id != IWL_MULTICAST_ID))
-		priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
-
-	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	rate = iwl4965_rates[ctrl->tx_rate].plcp;
 
 	rts_retry_limit = (is_hcca) ?
 	    RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
 
-	if (ieee80211_is_probe_response(hdr->frame_control)) {
+	if (ieee80211_is_probe_response(fc)) {
 		data_retry_limit = 3;
 		if (data_retry_limit < rts_retry_limit)
 			rts_retry_limit = data_retry_limit;
@@ -2617,8 +2692,8 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	if (priv->data_retry_limit != -1)
 		data_retry_limit = priv->data_retry_limit;
 
-	if (WLAN_FC_GET_TYPE(hdr->frame_control) == IEEE80211_FTYPE_MGMT) {
-		switch (WLAN_FC_GET_STYPE(hdr->frame_control)) {
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_AUTH:
 		case IEEE80211_STYPE_DEAUTH:
 		case IEEE80211_STYPE_ASSOC_REQ:
@@ -2635,78 +2710,87 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 
 	cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
 	cmd->cmd.tx.data_retry_limit = data_retry_limit;
-	cmd->cmd.tx.rate.s.rate = rate;
+	cmd->cmd.tx.rate_n_flags = iwl4965_hw_set_rate_n_flags(rate, 0);
 	cmd->cmd.tx.tx_flags = tx_flags;
 }
 
-int iwl_hw_get_rx_read(struct iwl_priv *priv)
+int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv)
 {
-	struct iwl_shared *shared_data =
-	    (struct iwl_shared *)priv->hw_setting.shared_virt;
+	struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
 
 	return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
 }
 
-int iwl_hw_get_temperature(struct iwl_priv *priv)
+int iwl4965_hw_get_temperature(struct iwl4965_priv *priv)
 {
 	return priv->temperature;
 }
 
-int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-			  struct iwl_frame *frame, u16 rate)
+unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv,
+			  struct iwl4965_frame *frame, u8 rate)
 {
-	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
-	int frame_size;
-
-	if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
-		rate |= RATE_MCS_CCK_MSK;
+	struct iwl4965_tx_beacon_cmd *tx_beacon_cmd;
+	unsigned int frame_size;
 
 	tx_beacon_cmd = &frame->u.beacon;
 	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
-	tx_beacon_cmd->tx.sta_id = IWL_BROADCAST_ID;
-	tx_beacon_cmd->tx.stop_time.life_time = 0xFFFFFFFF;
+	tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
+	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
-	frame_size = iwl_fill_beacon_frame(priv,
+	frame_size = iwl4965_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
-				BROADCAST_ADDR,
+				iwl4965_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
-	tx_beacon_cmd->tx.len = frame_size;
+	BUG_ON(frame_size > MAX_MPDU_SIZE);
+	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+	if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
+		tx_beacon_cmd->tx.rate_n_flags =
+			iwl4965_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+	else
+		tx_beacon_cmd->tx.rate_n_flags =
+			iwl4965_hw_set_rate_n_flags(rate, 0);
 
-	tx_beacon_cmd->tx.rate.rate_n_flags = rate;
 	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
 				TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
 	return (sizeof(*tx_beacon_cmd) + frame_size);
 }
 
-int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+/*
+ * Tell 4965 where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
 	int rc;
 	unsigned long flags;
 	int txq_id = txq->q.id;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id),
+	/* Circular buffer (TFD queue in DRAM) physical base address */
+	iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
 			     txq->q.dma_addr >> 8);
-	iwl_write_restricted(
+
+	/* Enable DMA channel, using same id as for TFD queue */
+	iwl4965_write_direct32(
 		priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
 		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
 		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
-	return 0;
-}
 
-static inline u32 iwl4965_get_dma_lo_address(dma_addr_t addr)
-{
-	return (u32) (addr & 0xffffffff);
+	return 0;
 }
 
 static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
@@ -2714,13 +2798,14 @@ static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
 	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
 }
 
-int iwl_hw_tx_queue_attach_buffer_to_tfd(struct iwl_priv *priv,
-					 void *ptr, dma_addr_t addr, u16 len)
+int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr,
+				 dma_addr_t addr, u16 len)
 {
 	int index, is_odd;
-	struct iwl_tfd_frame *tfd = ptr;
+	struct iwl4965_tfd_frame *tfd = ptr;
 	u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
 
+	/* Each TFD can point to a maximum 20 Tx buffers */
 	if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
 		IWL_ERROR("Error can not send more than %d chunks\n",
 			  MAX_NUM_OF_TBS);
@@ -2728,11 +2813,10 @@ int iwl_hw_tx_queue_attach_buffer_to_tfd(struct iwl_priv *priv,
 	}
 
 	index = num_tbs / 2;
-	is_odd = num_tbs % 2;
+	is_odd = num_tbs & 0x1;
 
 	if (!is_odd) {
-		tfd->pa[index].tb1_addr = cpu_to_le32(
-			     iwl4965_get_dma_lo_address(addr));
+		tfd->pa[index].tb1_addr = cpu_to_le32(addr);
 		IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
 			     iwl4965_get_dma_hi_address(addr));
 		IWL_SET_BITS(tfd->pa[index], tb1_len, len);
@@ -2748,7 +2832,7 @@ int iwl_hw_tx_queue_attach_buffer_to_tfd(struct iwl_priv *priv,
 	return 0;
 }
 
-void iwl_hw_card_show_info(struct iwl_priv *priv)
+static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv)
 {
 	u16 hw_version = priv->eeprom.board_revision_4965;
 
@@ -2763,50 +2847,41 @@ void iwl_hw_card_show_info(struct iwl_priv *priv)
 #define IWL_TX_CRC_SIZE		4
 #define IWL_TX_DELIMITER_SIZE	4
 
-int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-				   struct iwl_tx_queue *txq, u16 byte_cnt)
+/**
+ * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array
+ */
+int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
+				   struct iwl4965_tx_queue *txq, u16 byte_cnt)
 {
 	int len;
 	int txq_id = txq->q.id;
-	struct iwl_shared *shared_data =
-	    (struct iwl_shared *)priv->hw_setting.shared_virt;
+	struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
 
 	if (txq->need_update == 0)
 		return 0;
 
 	len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
 
-	IWL_SET_BITS(shared_data->queues_byte_cnt_tbls[txq_id].
-		     tfd_offset[txq->q.first_empty], byte_cnt, len);
+	/* Set up byte count within first 256 entries */
+	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+		       tfd_offset[txq->q.write_ptr], byte_cnt, len);
 
-	if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE)
-		IWL_SET_BITS(shared_data->queues_byte_cnt_tbls[txq_id].
-			     tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty],
-			     byte_cnt, len);
+	/* If within first 64 entries, duplicate at end */
+	if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE)
+		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+			tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr],
+			byte_cnt, len);
 
 	return 0;
 }
 
-#define IWL4965_LEGACY_SWITCH_ANTENNA	0
-#define IWL4965_LECACY_SWITCH_SISO		1
-#define IWL4965_LEGACY_SWITCH_MIMO	        2
-
-#define IWL4965_GOOD_RATIO			12800
-
-#define IWL_ACTION_LIMIT		3
-#define IWL4965_LEGACY_FAILURE_LIMIT	160
-#define IWL4965_LEGACY_SUCCESS_LIMIT	480
-#define IWL4965_LEGACY_TABLE_COUNT		160
-
-#define IWL4965_NONE_LEGACY_FAILURE_LIMIT	400
-#define IWL4965_NONE_LEGACY_SUCCESS_LIMIT	4500
-#define IWL4965_NONE_LEGACY_TABLE_COUNT	1500
-
-#define IWL4965_RATE_SCALE_SWITCH  (10880)
-
-/* Set up Rx receiver/antenna/chain usage in "staging" RXON image.
- * This should not be used for scan command ... it puts data in wrong place.  */
-void iwl4965_set_rxon_chain(struct iwl_priv *priv)
+/**
+ * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwl4965_set_rxon_chain(struct iwl4965_priv *priv)
 {
 	u8 is_single = is_single_stream(priv);
 	u8 idle_state, rx_state;
@@ -2819,14 +2894,17 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv)
 	 * Just after first association, iwl4965_noise_calibration()
 	 *    checks which antennas actually *are* connected. */
 	priv->staging_rxon.rx_chain |=
-	    (priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
+	    cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
 
 	/* How many receivers should we use? */
 	iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state);
-	priv->staging_rxon.rx_chain |= (rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
-	priv->staging_rxon.rx_chain |= (idle_state << RXON_RX_CHAIN_CNT_POS);
+	priv->staging_rxon.rx_chain |=
+		cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+	priv->staging_rxon.rx_chain |=
+		cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
 
-	if (!is_single && !(priv->status & STATUS_POWER_PMI) && (rx_state >= 2))
+	if (!is_single && (rx_state >= 2) &&
+	    !test_bit(STATUS_POWER_PMI, &priv->status))
 		priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
 	else
 		priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
@@ -2834,27 +2912,378 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv)
 	IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
 }
 
-int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+/*
+	get the traffic load value for tid
+*/
+static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid)
+{
+	u32 load = 0;
+	u32 current_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	unsigned long flags;
+	struct iwl4965_traffic_load *tid_ptr = NULL;
+
+	if (tid >= TID_MAX_LOAD_COUNT)
+		return 0;
+
+	tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+	current_time -= current_time % TID_ROUND_VALUE;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (!(tid_ptr->queue_count))
+		goto out;
+
+	time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	if (index >= TID_QUEUE_MAX_SIZE) {
+		u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+		while (tid_ptr->queue_count &&
+		       (tid_ptr->time_stamp < oldest_time)) {
+			tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+			tid_ptr->packet_count[tid_ptr->head] = 0;
+			tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+			tid_ptr->queue_count--;
+			tid_ptr->head++;
+			if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+				tid_ptr->head = 0;
+		}
+	}
+	load = tid_ptr->total;
+
+ out:
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	return load;
+}
+
+/*
+	increment traffic load value for tid and also remove
+	any old values if passed the certian time period
+*/
+static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid)
+{
+	u32 current_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	unsigned long flags;
+	struct iwl4965_traffic_load *tid_ptr = NULL;
+
+	if (tid >= TID_MAX_LOAD_COUNT)
+		return;
+
+	tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+	current_time -= current_time % TID_ROUND_VALUE;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (!(tid_ptr->queue_count)) {
+		tid_ptr->total = 1;
+		tid_ptr->time_stamp = current_time;
+		tid_ptr->queue_count = 1;
+		tid_ptr->head = 0;
+		tid_ptr->packet_count[0] = 1;
+		goto out;
+	}
+
+	time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	if (index >= TID_QUEUE_MAX_SIZE) {
+		u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+		while (tid_ptr->queue_count &&
+		       (tid_ptr->time_stamp < oldest_time)) {
+			tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+			tid_ptr->packet_count[tid_ptr->head] = 0;
+			tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+			tid_ptr->queue_count--;
+			tid_ptr->head++;
+			if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+				tid_ptr->head = 0;
+		}
+	}
+
+	index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
+	tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
+	tid_ptr->total = tid_ptr->total + 1;
+
+	if ((index + 1) > tid_ptr->queue_count)
+		tid_ptr->queue_count = index + 1;
+ out:
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+}
+
+#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS   7
+enum HT_STATUS {
+	BA_STATUS_FAILURE = 0,
+	BA_STATUS_INITIATOR_DELBA,
+	BA_STATUS_RECIPIENT_DELBA,
+	BA_STATUS_RENEW_ADDBA_REQUEST,
+	BA_STATUS_ACTIVE,
+};
+
+/**
+ * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available
+ */
+static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv)
+{
+	int i;
+	struct iwl4965_lq_mngr *lq;
+	u8 count = 0;
+	u16 msk;
+
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	/* Find out how many agg queues are in use */
+	for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
+		msk = 1 << i;
+		if ((lq->agg_ctrl.granted_ba & msk) ||
+		    (lq->agg_ctrl.wait_for_agg_status & msk))
+			count++;
+	}
+
+	if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
+		return 1;
+
+	return 0;
+}
+
+static void iwl4965_ba_status(struct iwl4965_priv *priv,
+			      u8 tid, enum HT_STATUS status);
+
+static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length,
+				 u32 ba_timeout)
+{
+	int rc;
+
+	rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
+	if (rc)
+		iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+	return rc;
+}
+
+static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid)
+{
+	int rc;
+
+	rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
+	if (rc)
+		iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+	return rc;
+}
+
+static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv,
+					struct iwl4965_lq_mngr *lq,
+					u8 auto_agg, u8 tid)
+{
+	u32 tid_msk = (1 << tid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+/*
+	if ((auto_agg) && (!lq->enable_counter)){
+		lq->agg_ctrl.next_retry = 0;
+		lq->agg_ctrl.tid_retry = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		return;
+	}
+*/
+	if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
+	    (lq->agg_ctrl.requested_ba & tid_msk)) {
+		u8 available_queues;
+		u32 load;
+
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		available_queues = iwl4964_tl_ba_avail(priv);
+		load = iwl4965_tl_get_load(priv, tid);
+
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		if (!available_queues) {
+			if (auto_agg)
+				lq->agg_ctrl.tid_retry |= tid_msk;
+			else {
+				lq->agg_ctrl.requested_ba &= ~tid_msk;
+				lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+			}
+		} else if ((auto_agg) &&
+			   ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
+			    ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
+			lq->agg_ctrl.tid_retry |= tid_msk;
+		else {
+			lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+			iwl4965_perform_addba(priv, tid, 0x40,
+					      lq->agg_ctrl.ba_timeout);
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+}
+
+static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid)
+{
+	struct iwl4965_lq_mngr *lq;
+	unsigned long flags;
+
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid < TID_MAX_LOAD_COUNT))
+		iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
+					    tid);
+	else if (tid == TID_ALL_SPECIFIED) {
+		if (lq->agg_ctrl.requested_ba) {
+			for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
+				iwl4965_turn_on_agg_for_tid(priv, lq,
+					lq->agg_ctrl.auto_agg, tid);
+		} else {
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+			lq->agg_ctrl.tid_retry = 0;
+			lq->agg_ctrl.next_retry = 0;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		}
+	}
+
+}
+
+void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid)
+{
+	u32 tid_msk;
+	struct iwl4965_lq_mngr *lq;
+	unsigned long flags;
+
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid < TID_MAX_LOAD_COUNT)) {
+		tid_msk = 1 << tid;
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+		lq->agg_ctrl.requested_ba &= ~tid_msk;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		iwl4965_perform_delba(priv, tid);
+	} else if (tid == TID_ALL_SPECIFIED) {
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+			tid_msk = 1 << tid;
+			lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+			iwl4965_perform_delba(priv, tid);
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		}
+		lq->agg_ctrl.requested_ba = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	}
+}
+
+/**
+ * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status
+ */
+static void iwl4965_ba_status(struct iwl4965_priv *priv,
+				u8 tid, enum HT_STATUS status)
+{
+	struct iwl4965_lq_mngr *lq;
+	u32 tid_msk = (1 << tid);
+	unsigned long flags;
+
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid >= TID_MAX_LOAD_COUNT))
+		goto out;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	switch (status) {
+	case BA_STATUS_ACTIVE:
+		if (!(lq->agg_ctrl.granted_ba & tid_msk))
+			lq->agg_ctrl.granted_ba |= tid_msk;
+		break;
+	default:
+		if ((lq->agg_ctrl.granted_ba & tid_msk))
+			lq->agg_ctrl.granted_ba &= ~tid_msk;
+		break;
+	}
+
+	lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+	if (status != BA_STATUS_ACTIVE) {
+		if (lq->agg_ctrl.auto_agg) {
+			lq->agg_ctrl.tid_retry |= tid_msk;
+			lq->agg_ctrl.next_retry =
+			    jiffies + msecs_to_jiffies(500);
+		} else
+			lq->agg_ctrl.requested_ba &= ~tid_msk;
+	}
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ out:
+	return;
+}
+
+static void iwl4965_bg_agg_work(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	u32 tid;
+	u32 retry_tid;
+	u32 tid_msk;
+	unsigned long flags;
+	struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	retry_tid = lq->agg_ctrl.tid_retry;
+	lq->agg_ctrl.tid_retry = 0;
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+	if (retry_tid == TID_ALL_SPECIFIED)
+		iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
+	else {
+		for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+			tid_msk = (1 << tid);
+			if (retry_tid & tid_msk)
+				iwl4965_turn_on_agg(priv, tid);
+		}
+	}
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (lq->agg_ctrl.tid_retry)
+		lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	return;
+}
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+int iwl4965_tx_cmd(struct iwl4965_priv *priv, struct iwl4965_cmd *out_cmd,
 		   u8 sta_id, dma_addr_t txcmd_phys,
 		   struct ieee80211_hdr *hdr, u8 hdr_len,
 		   struct ieee80211_tx_control *ctrl, void *sta_in)
 {
-	struct iwl_tx_cmd cmd;
-	struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0];
+	struct iwl4965_tx_cmd cmd;
+	struct iwl4965_tx_cmd *tx = (struct iwl4965_tx_cmd *)&out_cmd->cmd.payload[0];
 	dma_addr_t scratch_phys;
 	u8 unicast = 0;
 	u8 is_data = 1;
 	u16 fc;
+	u16 rate_flags;
 	int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	__le16 *qc;
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 	unicast = !is_multicast_ether_addr(hdr->addr1);
 
 	fc = le16_to_cpu(hdr->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA)
+	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
 		is_data = 0;
 
-	memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd));
-	memset(tx, 0, sizeof(struct iwl_tx_cmd));
+	memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl4965_tx_cmd));
+	memset(tx, 0, sizeof(struct iwl4965_tx_cmd));
 	memcpy(tx->hdr, hdr, hdr_len);
 
 	tx->len = cmd.len;
@@ -2873,48 +3302,66 @@ int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
 	tx->rts_retry_limit = cmd.rts_retry_limit;
 	tx->data_retry_limit = cmd.data_retry_limit;
 
-	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-	    offsetof(struct iwl_tx_cmd, scratch);
-	tx->dram_lsb_ptr = iwl4965_get_dma_lo_address(scratch_phys);
+	scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) +
+	    offsetof(struct iwl4965_tx_cmd, scratch);
+	tx->dram_lsb_ptr = cpu_to_le32(scratch_phys);
 	tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys);
 
 	/* Hard coded to start at the highest retry fallback position
 	 * until the 4965 specific rate control algorithm is tied in */
 	tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
-	tx->rate.s.rate = iwl_rates[rate_index].plcp;
 
 	/* Alternate between antenna A and B for successive frames */
 	if (priv->use_ant_b_for_management_frame) {
 		priv->use_ant_b_for_management_frame = 0;
-		tx->rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
-		tx->rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+		rate_flags = RATE_MCS_ANT_B_MSK;
 	} else {
 		priv->use_ant_b_for_management_frame = 1;
-		tx->rate.rate_n_flags |= RATE_MCS_ANT_A_MSK;
-		tx->rate.rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
+		rate_flags = RATE_MCS_ANT_A_MSK;
 	}
 
-	if (!unicast || !is_data ) {
+	if (!unicast || !is_data) {
 		if ((rate_index >= IWL_FIRST_CCK_RATE) &&
 		    (rate_index <= IWL_LAST_CCK_RATE))
-			tx->rate.rate_n_flags |= RATE_MCS_CCK_MSK;
-
+			rate_flags |= RATE_MCS_CCK_MSK;
 	} else {
 		tx->initial_rate_index = 0;
 		tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
 	}
 
-	if (ieee80211_is_probe_request(fc))
-		tx->tx_flags |= TX_CMD_FLG_TSF_MSK;
-	else if (ieee80211_is_back_request(fc))
+	tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(iwl4965_rates[rate_index].plcp,
+						rate_flags);
+
+	if (ieee80211_is_back_request(fc))
 		tx->tx_flags |= TX_CMD_FLG_ACK_MSK |
 			TX_CMD_FLG_IMM_BA_RSP_MASK;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc &&
+	    (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
+		u8 tid = 0;
+		tid = (u8) (le16_to_cpu(*qc) & 0xF);
+		if (tid < TID_MAX_LOAD_COUNT)
+			iwl4965_tl_add_packet(priv, tid);
+	}
+
+	if (priv->lq_mngr.agg_ctrl.next_retry &&
+	    (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
+		unsigned long flags;
 
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		priv->lq_mngr.agg_ctrl.next_retry = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		schedule_work(&priv->agg_work);
+	}
+#endif
+#endif
 	return 0;
 }
 
 /**
- * iwl4965_sign_extend - Sign extend a value using specified bit as sign-bit
+ * sign_extend - Sign extend a value using specified bit as sign-bit
  *
  * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1
  * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7.
@@ -2922,25 +3369,11 @@ int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
  * @param oper value to sign extend
  * @param index 0 based bit index (0<=index<32) to sign bit
  */
-static s32 iwl4965_sign_extend(u32 oper, u8 index)
+static s32 sign_extend(u32 oper, int index)
 {
-	u32 bit;
-	u32 mask;
-
-	/* If the index is the MSB or higher then just return the
-	 * operand cast to a signed value */
-	if (index > 30)
-		return oper;
-
-	bit = 1 << index;
-	mask = ~(bit - 1);
+	u8 shift = 31 - index;
 
-	/* negative -- sign extend */
-	if (oper & bit)
-		return oper |= mask;
-
-	/* positive -- sign clear */
-	return oper &= ~mask;
+	return (s32)(oper << shift) >> shift;
 }
 
 /**
@@ -2949,38 +3382,40 @@ static s32 iwl4965_sign_extend(u32 oper, u8 index)
  *
  * A return of <0 indicates bogus data in the statistics
  */
-int iwl4965_get_temperature(const struct iwl_priv *priv)
+int iwl4965_get_temperature(const struct iwl4965_priv *priv)
 {
 	s32 temperature;
 	s32 vt;
-	s32 R1, R2, R3, R4;
+	s32 R1, R2, R3;
+	u32 R4;
 
-	if ((priv->status & STATUS_TEMPERATURE) &&
+	if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
 		(priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
 		IWL_DEBUG_TEMP("Running FAT temperature calibration\n");
-		R1 = priv->card_alive_init.therm_r1[1];
-		R2 = priv->card_alive_init.therm_r2[1];
-		R3 = priv->card_alive_init.therm_r3[1];
-		R4 = priv->card_alive_init.therm_r4[1];
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+		R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]);
 	} else {
 		IWL_DEBUG_TEMP("Running temperature calibration\n");
-		R1 = priv->card_alive_init.therm_r1[0];
-		R2 = priv->card_alive_init.therm_r2[0];
-		R3 = priv->card_alive_init.therm_r3[0];
-		R4 = priv->card_alive_init.therm_r4[0];
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+		R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]);
 	}
 
 	/*
-	 * Temperature is only 23 bits so sign extend out to 32
+	 * Temperature is only 23 bits, so sign extend out to 32.
 	 *
 	 * NOTE If we haven't received a statistics notification yet
 	 * with an updated temperature, use R4 provided to us in the
-	 * ALIVE response. */
-	if (!(priv->status & STATUS_TEMPERATURE))
-		vt = iwl4965_sign_extend(R4, 23);
+	 * "initialize" ALIVE response.
+	 */
+	if (!test_bit(STATUS_TEMPERATURE, &priv->status))
+		vt = sign_extend(R4, 23);
 	else
-		vt = iwl4965_sign_extend(priv->statistics.general.temperature,
-					 23);
+		vt = sign_extend(
+			le32_to_cpu(priv->statistics.general.temperature), 23);
 
 	IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n",
 		       R1, R2, R3, vt);
@@ -3015,11 +3450,11 @@ int iwl4965_get_temperature(const struct iwl_priv *priv)
  * Assumes caller will replace priv->last_temperature once calibration
  * executed.
  */
-static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
+static int iwl4965_is_temp_calib_needed(struct iwl4965_priv *priv)
 {
 	int temp_diff;
 
-	if (!(priv->status & STATUS_STATISTICS)) {
+	if (!test_bit(STATUS_STATISTICS, &priv->status)) {
 		IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n");
 		return 0;
 	}
@@ -3045,9 +3480,49 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
 	return 1;
 }
 
-void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+/* Calculate noise level, based on measurements during network silence just
+ *   before arriving beacon.  This measurement can be done only if we know
+ *   exactly when to expect beacons, therefore only when we're associated. */
+static void iwl4965_rx_calc_noise(struct iwl4965_priv *priv)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct statistics_rx_non_phy *rx_info
+				= &(priv->statistics.rx.general);
+	int num_active_rx = 0;
+	int total_silence = 0;
+	int bcn_silence_a =
+		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+	int bcn_silence_b =
+		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+	int bcn_silence_c =
+		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+	if (bcn_silence_a) {
+		total_silence += bcn_silence_a;
+		num_active_rx++;
+	}
+	if (bcn_silence_b) {
+		total_silence += bcn_silence_b;
+		num_active_rx++;
+	}
+	if (bcn_silence_c) {
+		total_silence += bcn_silence_c;
+		num_active_rx++;
+	}
+
+	/* Average among active antennas */
+	if (num_active_rx)
+		priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+	else
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+	IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n",
+			bcn_silence_a, bcn_silence_b, bcn_silence_c,
+			priv->last_rx_noise);
+}
+
+void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	int change;
 	s32 temp;
 
@@ -3062,7 +3537,7 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
 	memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
 
-	priv->status |= STATUS_STATISTICS;
+	set_bit(STATUS_STATISTICS, &priv->status);
 
 	/* Reschedule the statistics timer to occur in
 	 * REG_RECALIB_PERIOD seconds to ensure we get a
@@ -3071,11 +3546,14 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	mod_timer(&priv->statistics_periodic, jiffies +
 		  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	if (unlikely(!(priv->status & STATUS_SCANNING)) &&
-	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION))
+	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+		iwl4965_rx_calc_noise(priv);
+#ifdef CONFIG_IWL4965_SENSITIVITY
 		queue_work(priv->workqueue, &priv->sensitivity_work);
 #endif
+	}
+
 	/* If the hardware hasn't reported a change in
 	 * temperature then don't bother computing a
 	 * calibrated temperature value */
@@ -3099,26 +3577,26 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	}
 
 	priv->temperature = temp;
-	priv->status |= STATUS_TEMPERATURE;
+	set_bit(STATUS_TEMPERATURE, &priv->status);
 
-	if (unlikely(!(priv->status & STATUS_SCANNING) &&
-		     iwl4965_is_temp_calib_needed(priv)))
+	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+		     iwl4965_is_temp_calib_needed(priv))
 		queue_work(priv->workqueue, &priv->txpower_work);
 }
 
-static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
+static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data,
 				       int include_phy,
-				       struct iwl_rx_mem_buffer *rxb,
+				       struct iwl4965_rx_mem_buffer *rxb,
 				       struct ieee80211_rx_status *stats)
 {
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 	struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
 	    (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
 	struct ieee80211_hdr *hdr;
-	unsigned int len;
-	u32 *rx_end;
+	u16 len;
+	__le32 *rx_end;
 	unsigned int skblen;
-	u32 ampd_status;
+	u32 ampdu_status;
 
 	if (!include_phy && priv->last_phy_res[0])
 		rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
@@ -3131,9 +3609,9 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 		hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] +
 					       rx_start->cfg_phy_cnt);
 
-		len = rx_start->byte_count;
+		len = le16_to_cpu(rx_start->byte_count);
 
-		rx_end = (u32 *) ((u8 *) & pkt->u.raw[0] +
+		rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] +
 				  sizeof(struct iwl4965_rx_phy_res) +
 				  rx_start->cfg_phy_cnt + len);
 
@@ -3141,20 +3619,19 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 		struct iwl4965_rx_mpdu_res_start *amsdu =
 		    (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
 
-		hdr = (void *)(pkt->u.raw +
+		hdr = (struct ieee80211_hdr *)(pkt->u.raw +
 			       sizeof(struct iwl4965_rx_mpdu_res_start));
-		rx_end = (u32 *) (((u8 *) hdr) + amsdu->byte_count);
-		len = amsdu->byte_count;
-		rx_start->byte_count = len;
+		len =  le16_to_cpu(amsdu->byte_count);
+		rx_start->byte_count = amsdu->byte_count;
+		rx_end = (__le32 *) (((u8 *) hdr) + len);
 	}
-	if (len > 2342 || len < 16) {
-		IWL_DEBUG_DROP("byte count out of range [16,2342]"
+	if (len > priv->hw_setting.max_pkt_size || len < 16) {
+		IWL_WARNING("byte count out of range [16,4K]"
 			       " : %d\n", len);
 		return;
-
 	}
 
-	ampd_status = *rx_end;
+	ampdu_status = le32_to_cpu(*rx_end);
 	skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);
 
 	/* start from MAC */
@@ -3163,31 +3640,31 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 
 	/* We only process data packets if the interface is open */
 	if (unlikely(!priv->is_open)) {
-		IWL_DEBUG_DROP
+		IWL_DEBUG_DROP_LIMIT
 		    ("Dropping packet while interface is not open.\n");
 		return;
 	}
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		if (param_hwcrypto)
-			iwl_set_decrypted_flag(priv, rxb->skb,
-					       ampd_status, stats);
-		iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
+		if (iwl4965_param_hwcrypto)
+			iwl4965_set_decrypted_flag(priv, rxb->skb,
+					       ampdu_status, stats);
+		iwl4965_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
 		return;
 	}
 
 	stats->flag = 0;
 	hdr = (struct ieee80211_hdr *)rxb->skb->data;
 
-	if (param_hwcrypto)
-		iwl_set_decrypted_flag(priv, rxb->skb, ampd_status, stats);
+	if (iwl4965_param_hwcrypto)
+		iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
 
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	priv->alloc_rxb_skb--;
 	rxb->skb = NULL;
 #ifdef LED
 	priv->led_packets += len;
-	iwl_setup_activity_timer(priv);
+	iwl4965_setup_activity_timer(priv);
 #endif
 }
 
@@ -3198,11 +3675,12 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
 	 *   contents are always there, not configurable by host.  */
 	struct iwl4965_rx_non_cfg_phy *ncphy =
 	    (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy;
-	u32 agc = (ncphy->agc_info & IWL_AGC_DB_MASK) >> IWL_AGC_DB_POS;
+	u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK)
+			>> IWL_AGC_DB_POS;
 
 	u32 valid_antennae =
-	    (rx_resp->phy_flags & RX_PHY_FLAGS_ANTENNAE_MASK) >>
-	    RX_PHY_FLAGS_ANTENNAE_OFFSET;
+	    (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK)
+			>> RX_PHY_FLAGS_ANTENNAE_OFFSET;
 	u8 max_rssi = 0;
 	u32 i;
 
@@ -3224,7 +3702,7 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
 	return (max_rssi - agc - IWL_RSSI_OFFSET);
 }
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 
 /* Parsed Information Elements */
 struct ieee802_11_elems {
@@ -3242,7 +3720,7 @@ struct ieee802_11_elems {
 	u8 ht_extra_param_len;
 };
 
-static int parse_elems(u8 * start, size_t len, struct ieee802_11_elems *elems)
+static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
 {
 	size_t left = len;
 	u8 *pos = start;
@@ -3296,29 +3774,76 @@ static int parse_elems(u8 * start, size_t len, struct ieee802_11_elems *elems)
 
 	return 0;
 }
-#endif /* CONFIG_IWLWIFI_HT */
 
-static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode)
+{
+	ht_info->cap = 0;
+	memset(ht_info->supp_mcs_set, 0, 16);
+
+	ht_info->ht_supported = 1;
+
+	if (mode == MODE_IEEE80211A) {
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
+		ht_info->supp_mcs_set[4] = 0x01;
+	}
+	ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
+	ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
+	ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
+			     (IWL_MIMO_PS_NONE << 2));
+	if (iwl4965_param_amsdu_size_8K) {
+		printk(KERN_DEBUG "iwl4965 in A-MSDU 8K support mode\n");
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+	}
+
+	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+
+	ht_info->supp_mcs_set[0] = 0xFF;
+	ht_info->supp_mcs_set[1] = 0xFF;
+}
+#endif /* CONFIG_IWL4965_HT */
+
+static void iwl4965_sta_modify_ps_wake(struct iwl4965_priv *priv, int sta_id)
 {
-	unsigned long lock_flags;
-	spin_lock_irqsave(&priv->sta_lock, lock_flags);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
 	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
 	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
 	priv->stations[sta_id].sta.sta.modify_mask = 0;
-	priv->stations[sta_id].sta.mode |= STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, lock_flags);
-	/* assuming we are in rx flow and the lock is already locked */
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta,
-			     CMD_ASYNC | CMD_NO_LOCK);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
+static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *addr)
+{
+	/* FIXME: need locking over ps_status ??? */
+	u8 sta_id = iwl4965_hw_find_station(priv, addr);
+
+	if (sta_id != IWL_INVALID_STATION) {
+		u8 sta_awake = priv->stations[sta_id].
+				ps_status == STA_PS_STATUS_WAKE;
+
+		if (sta_awake && ps_bit)
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+		else if (!sta_awake && !ps_bit) {
+			iwl4965_sta_modify_ps_wake(priv, sta_id);
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+		}
+	}
+}
+
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+
 /* Called for REPLY_4965_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	/* Use phy data (Rx signal strength, etc.) contained within
 	 *   this rx packet for legacy frames,
 	 *   or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
@@ -3326,21 +3851,22 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 	struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
 		(struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) :
 		(struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
-
-	u32 *rx_end;
+	__le32 *rx_end;
 	unsigned int len = 0;
 	struct ieee80211_hdr *header;
 	u16 fc;
 	struct ieee80211_rx_status stats = {
-		.mactime = rx_start->beacon_time_stamp,
-		.freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)),
-		.channel = rx_start->channel,
+		.mactime = le64_to_cpu(rx_start->timestamp),
+		.channel = le16_to_cpu(rx_start->channel),
 		.phymode =
 			(rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
 			MODE_IEEE80211G : MODE_IEEE80211A,
 		.antenna = 0,
-		.rate = rx_start->rate.s.rate,
-		.flag = rx_start->phy_flags,
+		.rate = iwl4965_hw_get_rate(rx_start->rate_n_flags),
+		.flag = 0,
+#ifdef CONFIG_IWL4965_HT_AGG
+		.ordered = 0
+#endif /* CONFIG_IWL4965_HT_AGG */
 	};
 	u8 network_packet;
 
@@ -3367,83 +3893,78 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 		header = (struct ieee80211_hdr *)((u8 *) & rx_start[1]
 						  + rx_start->cfg_phy_cnt);
 
-		len = rx_start->byte_count;
-		rx_end = (u32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
-				  sizeof(struct iwl4965_rx_phy_res) +
-				  rx_start->byte_count);
+		len = le16_to_cpu(rx_start->byte_count);
+		rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
+				  sizeof(struct iwl4965_rx_phy_res) + len);
 	} else {
 		struct iwl4965_rx_mpdu_res_start *amsdu =
 			(struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
 
 		header = (void *)(pkt->u.raw +
-				  sizeof(struct iwl4965_rx_mpdu_res_start));
-		len = amsdu->byte_count;
-		rx_end =
-			(u32 *) (pkt->u.raw +
-				 sizeof(struct iwl4965_rx_mpdu_res_start) +
-				 amsdu->byte_count);
+			sizeof(struct iwl4965_rx_mpdu_res_start));
+		len = le16_to_cpu(amsdu->byte_count);
+		rx_end = (__le32 *) (pkt->u.raw +
+			sizeof(struct iwl4965_rx_mpdu_res_start) + len);
 	}
 
 	if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
 	    !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", *rx_end);
+		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n",
+				le32_to_cpu(*rx_end));
 		return;
 	}
 
-	stats.freq = ieee80211chan2mhz((stats.channel));
-	stats.flag = 0;
+	priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+
+	stats.freq = ieee80211chan2mhz(stats.channel);
 
 	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
 	stats.ssi = iwl4965_calc_rssi(rx_start);
 
-	IWL_DEBUG_RX("Rssi %d, TSF %lu\n", stats.ssi,
-		 (long unsigned int)le64_to_cpu(rx_start->timestamp));
-
-	/* Sensitivity algo, if used (only while associated, not scanning),
-	 * calculates signal-to-noise ratio in dB.  Use this if available,
-	 * else calculate signal quality using only the signal strength. */
-	if (priv->last_rx_snr && iwl_is_associated(priv) &&
-			!(priv->status & STATUS_SCANNING)) {
-		/* TODO:  Find better noise level reference, use
-		 *        in iwl_calc_sig_qual() */
-		stats.noise = stats.ssi - priv->last_rx_snr;
-		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+	/* Meaningful noise values are available only from beacon statistics,
+	 *   which are gathered only when associated, and indicate noise
+	 *   only for the associated network channel ...
+	 * Ignore these noise values while scanning (other channels) */
+	if (iwl4965_is_associated(priv) &&
+	    !test_bit(STATUS_SCANNING, &priv->status)) {
+		stats.noise = priv->last_rx_noise;
+		stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise);
 	} else {
-		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
-
-		/* Reset noise values if not associated or snr not available. */
-		/* Set default noise value to -127 ... this works better than
-		 *   0 when averaging frames with/without noise info;
-		 *   measured dBm values are always negative ... using a
-		 *   negative value as the default keeps all averages
-		 *   within an s8's (used in some apps) range of negative
-		 *   values. */
-		priv->last_rx_snr = 0;
-		priv->last_rx_noise = -127;
-		stats.noise = -127;
-	}
-	IWL_DEBUG_STATS("Rssi %d noise %d qual %d snr db %d\n", stats.ssi,
-			stats.noise, stats.signal, priv->last_rx_snr);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	/* TODO:  Parts of iwl_report_frame are broken for 4965 */
-	if (iwl_debug_level & (IWL_DL_RX))
+		stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+		stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0);
+	}
+
+	/* Reset beacon noise level if not associated. */
+	if (!iwl4965_is_associated(priv))
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+#ifdef CONFIG_IWL4965_DEBUG
+	/* TODO:  Parts of iwl4965_report_frame are broken for 4965 */
+	if (iwl4965_debug_level & (IWL_DL_RX))
 		/* Set "1" to report good data frames in groups of 100 */
-		iwl_report_frame(priv, pkt, header, 1);
+		iwl4965_report_frame(priv, pkt, header, 1);
+
+	if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS))
+	IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
+		stats.ssi, stats.noise, stats.signal,
+		 (long unsigned int)le64_to_cpu(rx_start->timestamp));
 #endif
 
-	network_packet = iwl_is_network_packet(priv, header);
+	network_packet = iwl4965_is_network_packet(priv, header);
 	if (network_packet) {
 		priv->last_rx_rssi = stats.ssi;
-		priv->last_rx_noise = stats.noise;
-		priv->last_beacon_time = rx_start->beacon_time_stamp;
-		priv->last_tsf = rx_start->timestamp;
+		priv->last_beacon_time =  priv->ucode_beacon_time;
+		priv->last_tsf = le64_to_cpu(rx_start->timestamp);
 	}
 
 	fc = le16_to_cpu(header->frame_control);
-	switch (WLAN_FC_GET_TYPE(fc)) {
+	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
-		switch (WLAN_FC_GET_STYPE(fc)) {
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl4965_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
+						header->addr2);
+		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_PROBE_RESP:
 		case IEEE80211_STYPE_BEACON:
 			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA &&
@@ -3452,11 +3973,12 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 			     !compare_ether_addr(header->addr3, priv->bssid))) {
 				struct ieee80211_mgmt *mgmt =
 					(struct ieee80211_mgmt *)header;
-				u32 *pos;
+				u64 timestamp =
+					le64_to_cpu(mgmt->u.beacon.timestamp);
 
-				pos = (u32 *) & mgmt->u.beacon.timestamp;
-				priv->timestamp0 = le32_to_cpu(pos[0]);
-				priv->timestamp1 = le32_to_cpu(pos[1]);
+				priv->timestamp0 = timestamp & 0xFFFFFFFF;
+				priv->timestamp1 =
+					(timestamp >> 32) & 0xFFFFFFFF;
 				priv->beacon_int = le16_to_cpu(
 				    mgmt->u.beacon.beacon_int);
 				if (priv->call_post_assoc_from_beacon &&
@@ -3479,20 +4001,26 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 			 */
 		case IEEE80211_STYPE_ASSOC_RESP:
 		case IEEE80211_STYPE_REASSOC_RESP:
-			if (network_packet && iwl_is_associated(priv)) {
-#ifdef CONFIG_IWLWIFI_HT
+			if (network_packet) {
+#ifdef CONFIG_IWL4965_HT
 				u8 *pos = NULL;
 				struct ieee802_11_elems elems;
-#endif				/*CONFIG_IWLWIFI_HT */
+#endif				/*CONFIG_IWL4965_HT */
 				struct ieee80211_mgmt *mgnt =
 					(struct ieee80211_mgmt *)header;
 
+				/* We have just associated, give some
+				 * time for the 4-way handshake if
+				 * any. Don't start scan too early. */
+				priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+
 				priv->assoc_id = (~((1 << 15) | (1 << 14))
-						  & mgnt->u.assoc_resp.aid);
+					& le16_to_cpu(mgnt->u.assoc_resp.aid));
 				priv->assoc_capability =
 					le16_to_cpu(
 						mgnt->u.assoc_resp.capab_info);
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 				pos = mgnt->u.assoc_resp.variable;
 				if (!parse_elems(pos,
 						 len - (pos - (u8 *) mgnt),
@@ -3501,7 +4029,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 					    elems.ht_cap_param)
 						break;
 				}
-#endif				/*CONFIG_IWLWIFI_HT */
+#endif				/*CONFIG_IWL4965_HT */
 				/* assoc_id is 0 no association */
 				if (!priv->assoc_id)
 					break;
@@ -3516,13 +4044,16 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
 		case IEEE80211_STYPE_PROBE_REQ:
 			if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-			    !iwl_is_associated(priv)) {
+			    !iwl4965_is_associated(priv)) {
+				DECLARE_MAC_BUF(mac1);
+				DECLARE_MAC_BUF(mac2);
+				DECLARE_MAC_BUF(mac3);
+
 				IWL_DEBUG_DROP("Dropping (non network): "
-					       MAC_FMT ", " MAC_FMT ", "
-					       MAC_FMT "\n",
-					       MAC_ARG(header->addr1),
-					       MAC_ARG(header->addr2),
-					       MAC_ARG(header->addr3));
+					       "%s, %s, %s\n",
+					       print_mac(mac1, header->addr1),
+					       print_mac(mac2, header->addr2),
+					       print_mac(mac3, header->addr3));
 				return;
 			}
 		}
@@ -3530,49 +4061,45 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 		break;
 
 	case IEEE80211_FTYPE_CTL:
+#ifdef CONFIG_IWL4965_HT_AGG
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_BACK_REQ:
+			IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
+			iwl4965_handle_data_packet(priv, 0, include_phy,
+						rxb, &stats);
+			break;
+		default:
+			break;
+		}
+#endif
+
 		break;
 
-	case IEEE80211_FTYPE_DATA:
-		/* FIXME - patch for PS in AP mode */
-		if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-			u8 sta_id = iwl_hw_find_station(priv, header->addr2);
-			u8 sta_awake;
-			u16 ps_bit;
-
-			if (sta_id == IWL_INVALID_STATION)
-				break;
-
-			sta_awake = (priv->stations[sta_id].ps_status ==
-				     STA_PS_STATUS_WAKE);
-			ps_bit = (header->frame_control  &
-				  cpu_to_le16(IEEE80211_FCTL_PM));
-			if (sta_awake && ps_bit) {
-				priv->stations[sta_id].ps_status =
-					STA_PS_STATUS_SLEEP;
-			} else if (!sta_awake && !ps_bit) {
-				iwl4965_sta_modify_ps_wake(priv, sta_id);
-				priv->stations[sta_id].ps_status =
-						STA_PS_STATUS_WAKE;
-			}
-		}
+	case IEEE80211_FTYPE_DATA: {
+		DECLARE_MAC_BUF(mac1);
+		DECLARE_MAC_BUF(mac2);
+		DECLARE_MAC_BUF(mac3);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl4965_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
+						header->addr2);
 
 		if (unlikely(!network_packet))
 			IWL_DEBUG_DROP("Dropping (non network): "
-				       MAC_FMT ", " MAC_FMT ", "
-				       MAC_FMT "\n",
-				       MAC_ARG(header->addr1),
-				       MAC_ARG(header->addr2),
-				       MAC_ARG(header->addr3));
-		else if (unlikely(is_duplicate_packet(priv, header)))
-			IWL_DEBUG_DROP("Dropping (dup): " MAC_FMT ", "
-				       MAC_FMT ", " MAC_FMT "\n",
-				       MAC_ARG(header->addr1),
-				       MAC_ARG(header->addr2),
-				       MAC_ARG(header->addr3));
+				       "%s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
+		else if (unlikely(iwl4965_is_duplicate_packet(priv, header)))
+			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
 		else
 			iwl4965_handle_data_packet(priv, 1, include_phy, rxb,
 						   &stats);
 		break;
+	}
 	default:
 		break;
 
@@ -3581,140 +4108,435 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
 /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
  * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_rx_phy(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	priv->last_phy_res[0] = 1;
 	memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
 	       sizeof(struct iwl4965_rx_phy_res));
 }
 
-static void iwl4965_rx_missed_beacon_notif (struct iwl_priv *priv,
-					   struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb)
 
 {
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_missed_beacon_notif *missed_beacon;
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_missed_beacon_notif *missed_beacon;
 
 	missed_beacon = &pkt->u.missed_beacon;
-	if (missed_beacon->consequtive_missed_beacons > 5) {
+	if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
 		IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-			    missed_beacon->consequtive_missed_beacons,
-			    missed_beacon->total_missed_becons,
-			    missed_beacon->num_recvd_beacons,
-			    missed_beacon->num_expected_beacons);
+		    le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+		    le32_to_cpu(missed_beacon->total_missed_becons),
+		    le32_to_cpu(missed_beacon->num_recvd_beacons),
+		    le32_to_cpu(missed_beacon->num_expected_beacons));
 		priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-		if (unlikely(!(priv->status & STATUS_SCANNING)))
+		if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
 			queue_work(priv->workqueue, &priv->sensitivity_work);
 	}
-#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
+}
+
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+
+/**
+ * iwl4965_set_tx_status - Update driver's record of one Tx frame's status
+ *
+ * This will get sent to mac80211.
+ */
+static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx,
+				  u32 status, u32 retry_count, u32 rate)
+{
+	struct ieee80211_tx_status *tx_status =
+		&(priv->txq[txq_id].txb[idx].status);
+
+	tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
+	tx_status->retry_count += retry_count;
+	tx_status->control.tx_rate = rate;
 }
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
 
-static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
-					   struct iwl_rx_mem_buffer *rxb)
+/**
+ * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ */
+static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv,
+					 int sta_id, int tid)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_compressed_ba_resp *compressed_ba = &pkt->u.compressed_ba;
-	int index = iwl_queue_dec_wrap(compressed_ba->scd_ssn & 0xff, 0xff);
-	struct iwl_tx_queue *txq = NULL;
+	unsigned long flags;
+
+	/* Remove "disable" flag, to enable Tx for this TID */
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+	priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+
+/**
+ * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack
+ *
+ * Go through block-ack's bitmap of ACK'd frames, update driver's record of
+ * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
+ */
+static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv,
+						 struct iwl4965_ht_agg *agg,
+						 struct iwl4965_compressed_ba_resp*
+						 ba_resp)
+
+{
+	int i, sh, ack;
+	u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl);
+	u32 bitmap0, bitmap1;
+	u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0);
+	u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1);
+
+	if (unlikely(!agg->wait_for_ba))  {
+		IWL_ERROR("Received BA when not expected\n");
+		return -EINVAL;
+	}
+
+	/* Mark that the expected block-ack response arrived */
+	agg->wait_for_ba = 0;
+	IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
+
+	/* Calculate shift to align block-ack bits with our Tx window bits */
+	sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4);
+	if (sh < 0) /* tbw something is wrong with indices */
+		sh += 0x100;
+
+	/* don't use 64-bit values for now */
+	bitmap0 = resp_bitmap0 >> sh;
+	bitmap1 = resp_bitmap1 >> sh;
+	bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh);
+
+	if (agg->frame_count > (64 - sh)) {
+		IWL_DEBUG_TX_REPLY("more frames than bitmap size");
+		return -1;
+	}
 
-	BUG_ON(compressed_ba->scd_flow >= ARRAY_SIZE(priv->txq));
-	txq = &priv->txq[compressed_ba->scd_flow];
+	/* check for success or failure according to the
+	 * transmitted bitmap and block-ack bitmap */
+	bitmap0 &= agg->bitmap0;
+	bitmap1 &= agg->bitmap1;
+
+	/* For each frame attempted in aggregation,
+	 * update driver's record of tx frame's status. */
+	for (i = 0; i < agg->frame_count ; i++) {
+		int idx = (agg->start_idx + i) & 0xff;
+		ack = bitmap0 & (1 << i);
+		IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
+			ack? "ACK":"NACK", i, idx, agg->start_idx + i);
+		iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0,
+			agg->rate_n_flags);
 
-	/* TODO: Need to get this copy more sefely - now good for debug */
-	IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA Received from " MAC_FMT
-			   " , sta_id = %d\n",
-			   MAC_ARG((u8 *) & compressed_ba->sta_addr_lo32),
-			   compressed_ba->sta_id);
-	IWL_DEBUG_TX_REPLY
-	    ("TID = %d, seq_ctl = %d, bitmap = 0x%x%x, scd_flow = %d, "
-	     "scd_ssn = %d\n",
-	     compressed_ba->tid, compressed_ba->ba_seq_ctl,
-	     compressed_ba->ba_bitmap0, compressed_ba->ba_bitmap1,
-	     compressed_ba->scd_flow, compressed_ba->scd_ssn);
+	}
 
-	/* releases all the TFDs until the SSN */
-	if (txq->q.last_used != (compressed_ba->scd_ssn & 0xff))
-		iwl_tx_queue_reclaim(priv, compressed_ba->scd_flow, index);
+	IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1);
 
+	return 0;
+}
+
+/**
+ * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (s/b power of 2)
+ */
+static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
+{
+	return (index == 0) ? n_bd - 1 : index - 1;
 }
-#endif	/* CONFIG_IWLWIFI_HT_AGG */
 
+/**
+ * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+	int index;
+	struct iwl4965_tx_queue *txq = NULL;
+	struct iwl4965_ht_agg *agg;
+
+	/* "flow" corresponds to Tx queue */
+	u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+	/* "ssn" is start of block-ack Tx window, corresponds to index
+	 * (in Tx queue's circular buffer) of first TFD/frame in window */
+	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+	if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
+		IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
+		return;
+	}
+
+	txq = &priv->txq[ba_resp_scd_flow];
+	agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+
+	/* Find index just before block-ack window */
+	index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+	/* TODO: Need to get this copy more safely - now good for debug */
 /*
- * RATE SCALE CODE
+	{
+	DECLARE_MAC_BUF(mac);
+	IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+			   "sta_id = %d\n",
+			   agg->wait_for_ba,
+			   print_mac(mac, (u8*) &ba_resp->sta_addr_lo32),
+			   ba_resp->sta_id);
+	IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = "
+			   "%d, scd_ssn = %d\n",
+			   ba_resp->tid,
+			   ba_resp->ba_seq_ctl,
+			   ba_resp->ba_bitmap1,
+			   ba_resp->ba_bitmap0,
+			   ba_resp->scd_flow,
+			   ba_resp->scd_ssn);
+	IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n",
+			   agg->start_idx,
+			   agg->bitmap1,
+			   agg->bitmap0);
+	}
+*/
+
+	/* Update driver's record of ACK vs. not for each frame in window */
+	iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+
+	/* Release all TFDs before the SSN, i.e. all TFDs in front of
+	 * block-ack window (we assume that they've been successfully
+	 * transmitted ... if not, it's too late anyway). */
+	if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff))
+		iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
+
+}
+
+
+/**
+ * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration
  */
-int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates)
+static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id)
 {
+	/* Simply stop the queue, but don't change any configuration;
+	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+	iwl4965_write_prph(priv,
+		KDR_SCD_QUEUE_STATUS_BITS(txq_id),
+		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+/**
+ * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue
+ */
+static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid,
+					u16 txq_id)
+{
+	u32 tbl_dw_addr;
+	u32 tbl_dw;
+	u16 scd_q2ratid;
+
+	scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+	tbl_dw_addr = priv->scd_base_addr +
+			SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+	tbl_dw = iwl4965_read_targ_mem(priv, tbl_dw_addr);
+
+	if (txq_id & 0x1)
+		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+	else
+		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+	iwl4965_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
+
+	return 0;
+}
+
+/**
+ * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue
+ *
+ * NOTE:  txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID,
+ *        i.e. it must be one of the higher queues used for aggregation
+ */
+static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id,
+				       int tx_fifo, int sta_id, int tid,
+				       u16 ssn_idx)
+{
+	unsigned long flags;
+	int rc;
+	u16 ra_tid;
+
+	if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
+		IWL_WARNING("queue number too small: %d, must be > %d\n",
+			txq_id, IWL_BACK_QUEUE_FIRST_ID);
+
+	ra_tid = BUILD_RAxTID(sta_id, tid);
+
+	/* Modify device's station table to Tx this TID */
+	iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl4965_grab_nic_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* Stop this Tx queue before configuring it */
+	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+	/* Map receiver-address / traffic-ID to this queue */
+	iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+	/* Set this queue as a chain-building queue */
+	iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+	/* Place first TFD at index corresponding to start sequence number.
+	 * Assumes that ssn_idx is valid (!= 0xFFF) */
+	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+	/* Set up Tx window size and frame limit for this queue */
+	iwl4965_write_targ_mem(priv,
+			priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+			(SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+			SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+
+	iwl4965_write_targ_mem(priv, priv->scd_base_addr +
+			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+			(SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+			& SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+	iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
+
+	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
+	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+	iwl4965_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id,
+					u16 ssn_idx, u8 tx_fifo)
+{
+	unsigned long flags;
+	int rc;
+
+	if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
+		IWL_WARNING("queue number too small: %d, must be > %d\n",
+				txq_id, IWL_BACK_QUEUE_FIRST_ID);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl4965_grab_nic_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+	iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id));
+
+	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+	/* supposes that ssn_idx is valid (!= 0xFFF) */
+	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+	iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
+	iwl4965_txq_ctx_deactivate(priv, txq_id);
+	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+	iwl4965_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	return 0;
 }
 
+#endif/* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 /**
  * iwl4965_add_station - Initialize a station's hardware rate table
  *
- * The uCode contains a table of fallback rates and retries per rate
+ * The uCode's station table contains a table of fallback rates
  * for automatic fallback during transmission.
  *
- * NOTE: This initializes the table for a single retry per data rate
- * which is not optimal.  Setting up an intelligent retry per rate
- * requires feedback from transmission, which isn't exposed through
- * rc80211_simple which is what this driver is currently using.
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
  *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
  */
-void iwl4965_add_station(struct iwl_priv *priv, const u8 * addr, int is_ap)
+void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
 {
 	int i, r;
-	struct iwl_link_quality_cmd link_cmd = {
+	struct iwl4965_link_quality_cmd link_cmd = {
 		.reserved1 = 0,
 	};
-	struct iwl_rate *table = link_cmd.rate_scale_table;
+	u16 rate_flags;
 
-	/* Set up the rate scaling to start at 54M and fallback
-	 * all the way to 1M in IEEE order and then spin on IEEE */
-	i = 0;
+	/* Set up the rate scaling to start at selected rate, fall back
+	 * all the way down to 1M in IEEE order, and then spin on 1M */
 	if (is_ap)
 		r = IWL_RATE_54M_INDEX;
-	else if ((priv->phymode == MODE_IEEE80211A) ||
-		 (priv->phymode == MODE_ATHEROS_TURBO))
+	else if (priv->phymode == MODE_IEEE80211A)
 		r = IWL_RATE_6M_INDEX;
 	else
 		r = IWL_RATE_1M_INDEX;
 
-	while (i < LINK_QUAL_MAX_RETRY_NUM) {
-		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) {
-			table[i].rate_n_flags |= RATE_MCS_CCK_MSK;
-		}
-		table[i].s.rate = iwl_rates[r].plcp;
-		table[i].rate_n_flags |= RATE_MCS_ANT_B_MSK;
-		table[i].rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
-		r = iwl_get_prev_ieee_rate(r);
-		i++;
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+		rate_flags = 0;
+		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+			rate_flags |= RATE_MCS_CCK_MSK;
+
+		/* Use Tx antenna B only */
+		rate_flags |= RATE_MCS_ANT_B_MSK;
+		rate_flags &= ~RATE_MCS_ANT_A_MSK;
+
+		link_cmd.rs_table[i].rate_n_flags =
+			iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags);
+		r = iwl4965_get_prev_ieee_rate(r);
 	}
 
 	link_cmd.general_params.single_stream_ant_msk = 2;
 	link_cmd.general_params.dual_stream_ant_msk = 3;
 	link_cmd.agg_params.agg_dis_start_th = 3;
-	link_cmd.agg_params.agg_time_limit = 4000;
+	link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
 
 	/* Update the rate scaling for control frame Tx to AP */
-	link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL_BROADCAST_ID;
+	link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
 
-	iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
+	iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
 			 &link_cmd);
 }
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 
-static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
-				   int channel, u8 extension_chan_offset)
+static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode,
+				   u16 channel, u8 extension_chan_offset)
 {
-	const struct iwl_channel_info *ch_info;
+	const struct iwl4965_channel_info *ch_info;
 
-	ch_info = iwl_get_channel_info(priv, phymode, channel);
+	ch_info = iwl4965_get_channel_info(priv, phymode, channel);
 	if (!is_channel_valid(ch_info))
 		return 0;
 
@@ -3728,165 +4550,310 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
 	return 0;
 }
 
-static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
-				const struct sta_ht_info *ht_info)
+static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv,
+				struct ieee80211_ht_info *sta_ht_inf)
 {
+	struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
 
-	if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-		return 0;
-
-	if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)
+	if ((!iwl_ht_conf->is_ht) ||
+	   (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
+	   (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO))
 		return 0;
 
-	if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
-		return 0;
+	if (sta_ht_inf) {
+		if ((!sta_ht_inf->ht_supported) ||
+		   (!sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))
+			return 0;
+	}
 
-	/* no fat tx allowed on 2.4GHZ */
-	if ((priv->phymode != MODE_IEEE80211A) &&
-	    (priv->phymode != MODE_ATHEROS_TURBO))
-		return 0;
-	return (iwl_is_channel_extension(priv, priv->phymode,
-					 ht_info->control_chan,
-					 ht_info->extension_chan_offset));
+	return (iwl4965_is_channel_extension(priv, priv->phymode,
+					 iwl_ht_conf->control_channel,
+					 iwl_ht_conf->extension_chan_offset));
 }
 
-void iwl4965_set_rxon_ht(struct iwl_priv *priv,
-			 struct sta_ht_info *ht_info)
+void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info)
 {
-	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+	struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
 	u32 val;
 
 	if (!ht_info->is_ht)
 		return;
 
-	if (iwl_is_fat_tx_allowed(priv, ht_info))
+	/* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
+	if (iwl4965_is_fat_tx_allowed(priv, NULL))
 		rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
 	else
-		rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY_MSK;
+		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+				 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
 
-	if (rxon->channel != ht_info->control_chan) {
+	if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
 		IWL_DEBUG_ASSOC("control diff than current %d %d\n",
-				rxon->channel, ht_info->control_chan);
-		rxon->channel = ht_info->control_chan;
+				le16_to_cpu(rxon->channel),
+				ht_info->control_channel);
+		rxon->channel = cpu_to_le16(ht_info->control_channel);
 		return;
 	}
 
-	rxon->flags &= ~RXON_FLG_CONTROL_CHANNEL_LOCATION_MSK;
-
+	/* Note: control channel is opposite of extension channel */
 	switch (ht_info->extension_chan_offset) {
 	case IWL_EXT_CHANNEL_OFFSET_ABOVE:
-		rxon->flags |= RXON_FLG_CONTROL_CHANNEL_LOC_LOW_MSK;
+		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
 		break;
 	case IWL_EXT_CHANNEL_OFFSET_BELOW:
-		rxon->flags |= RXON_FLG_CONTROL_CHANNEL_LOC_HIGH_MSK;
+		rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
 		break;
 	case IWL_EXT_CHANNEL_OFFSET_AUTO:
 		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
 		break;
 	default:
+		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
 		break;
 	}
 
-	val = ht_info->operating_mode;
+	val = ht_info->ht_protection;
 
-	rxon->flags |= val << RXON_FLG_HT_OPERATING_MODE_POS;
+	rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
 
-	priv->active_rate_ht[0] = ht_info->supp_rates[0];
-	priv->active_rate_ht[1] = ht_info->supp_rates[1];
 	iwl4965_set_rxon_chain(priv);
 
 	IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
-			"falgs 0x%X operation 0x%X\n",
-			priv->active_rate_ht[0], priv->active_rate_ht[1],
-			rxon->flags, ht_info->operating_mode);
+			"rxon flags 0x%X operation mode :0x%X "
+			"extension channel offset 0x%x "
+			"control chan %d\n",
+			ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1],
+			le32_to_cpu(rxon->flags), ht_info->ht_protection,
+			ht_info->extension_chan_offset,
+			ht_info->control_channel);
 	return;
 }
-void iwl4965_set_ht_add_station(struct iwl_priv *priv,
-				u8 index, u8 need_to_lock)
-{
-	u32 val;
-	u32 sta_rate;
-	u32 sta_flag;
-	unsigned long flags = 0;
-	u8 i = index;
-	struct sta_ht_info *ht_info = &priv->current_assoc_ht;
 
-	if (need_to_lock)
-		spin_lock_irqsave(&priv->sta_lock, flags);
+void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
+				struct ieee80211_ht_info *sta_ht_inf)
+{
+	__le32 sta_flags;
 
-	priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-	if (!ht_info->is_ht)
+	if (!sta_ht_inf || !sta_ht_inf->ht_supported)
 		goto done;
 
-	sta_rate = priv->stations[i].sta.tx_rate.rate_n_flags;
-	sta_flag = priv->stations[i].sta.station_flags;
+	sta_flags = priv->stations[index].sta.station_flags;
 
-	if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC)
-		sta_flag |= STA_FLG_RTS_MIMO_PROT_MSK;
+	if (((sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS >> 2))
+						== IWL_MIMO_PS_DYNAMIC)
+		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
 	else
-		sta_flag &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+		sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
 
-	val = (u32) ht_info->ampdu_factor;
-	sta_flag |= val << STA_FLG_MAX_AGG_SIZE_POS;
+	sta_flags |= cpu_to_le32(
+	      (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
 
-	val = (u32) ht_info->mpdu_density;
-	sta_flag |= val << STA_FLG_AGG_MPDU_DENSITY_POS;
+	sta_flags |= cpu_to_le32(
+	      (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
-	if ((ht_info->sgf & HT_SHORT_GI_20MHZ_ONLY) &&
-	    (ht_info->sgf & HT_SHORT_GI_40MHZ_ONLY)) {
-		val = 1;
-		sta_rate |= ((val << RATE_MCS_SGI_POS) & RATE_MCS_SGI_MSK);
-	}
+	if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
+		sta_flags |= STA_FLG_FAT_EN_MSK;
+	else
+		sta_flags &= (~STA_FLG_FAT_EN_MSK);
 
-	val = ht_info->is_green_field;
-	sta_rate |= ((val << RATE_MCS_GF_POS) & RATE_MCS_GF_MSK);
+	priv->stations[index].sta.station_flags = sta_flags;
+ done:
+	return;
+}
 
-	sta_rate &= (~RATE_MCS_FAT_MSK);
-	sta_flag &= (~STA_FLG_FAT_EN_MSK);
+#ifdef CONFIG_IWL4965_HT_AGG
 
-	ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
-	ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ;
+static void iwl4965_sta_modify_add_ba_tid(struct iwl4965_priv *priv,
+					  int sta_id, int tid, u16 ssn)
+{
+	unsigned long flags;
 
-	if (iwl_is_fat_tx_allowed(priv, ht_info)) {
-		sta_flag |= STA_FLG_FAT_EN_MSK;
-		ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ;
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-		if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) {
-			sta_rate |= RATE_MCS_FAT_MSK;
-			ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ;
-		}
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv,
+					  int sta_id, int tid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static const u16 default_tid_to_tx_fifo[] = {
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC0,
+	IWL_TX_FIFO_AC0,
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_AC3
+};
+
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
+ */
+static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv)
+{
+	int txq_id;
+
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+		if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+			return txq_id;
+	return -1;
+}
+
+int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
+			    u16 *start_seq_num)
+{
+
+	struct iwl4965_priv *priv = hw->priv;
+	int sta_id;
+	int tx_fifo;
+	int txq_id;
+	int ssn = -1;
+	unsigned long flags;
+	struct iwl4965_tid_data *tid_data;
+	DECLARE_MAC_BUF(mac);
+
+	/* Determine Tx DMA/FIFO channel for this Traffic ID */
+	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+		tx_fifo = default_tid_to_tx_fifo[tid];
+	else
+		return -EINVAL;
+
+	IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s"
+		    " tid=%d\n", print_mac(mac, da), tid);
+
+	/* Get index into station table */
+	sta_id = iwl4965_hw_find_station(priv, da);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	/* Find available Tx queue for aggregation */
+	txq_id = iwl4965_txq_ctx_activate_free(priv);
+	if (txq_id == -1)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	tid_data = &priv->stations[sta_id].tid[tid];
+
+	/* Get starting sequence number for 1st frame in block ack window.
+	 * We'll use least signif byte as 1st frame's index into Tx queue. */
+	ssn = SEQ_TO_SN(tid_data->seq_number);
+	tid_data->agg.txq_id = txq_id;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	*start_seq_num = ssn;
+
+	/* Update driver's link quality manager */
+	iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
+
+	/* Set up and enable aggregation for selected Tx queue and FIFO */
+	return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
+					   sta_id, tid, ssn);
+}
+
+
+int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
+			   int generator)
+{
+
+	struct iwl4965_priv *priv = hw->priv;
+	int tx_fifo_id, txq_id, sta_id, ssn = -1;
+	struct iwl4965_tid_data *tid_data;
+	int rc;
+	DECLARE_MAC_BUF(mac);
+
+	if (!da) {
+		IWL_ERROR("%s: da = NULL\n", __func__);
+		return -EINVAL;
 	}
 
-	priv->current_channel_width = ht_info->tx_chan_width;
+	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+		tx_fifo_id = default_tid_to_tx_fifo[tid];
+	else
+		return -EINVAL;
 
-	priv->stations[i].sta.tx_rate.rate_n_flags = sta_rate;
-	priv->stations[i].sta.station_flags = sta_flag;
+	sta_id = iwl4965_hw_find_station(priv, da);
 
- done:
-	if (need_to_lock)
-		spin_unlock_irqrestore(&priv->sta_lock, flags);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
 
-	return;
+	tid_data = &priv->stations[sta_id].tid[tid];
+	ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+	txq_id = tid_data->agg.txq_id;
+
+	rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
+	/* FIXME: need more safe way to handle error condition */
+	if (rc)
+		return rc;
+
+	iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
+	IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n",
+		       print_mac(mac, da), tid);
+
+	return 0;
 }
-#endif /* CONFIG_IWLWIFI_HT */
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
-static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id,
-					 int tid)
+int iwl4965_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+			    u16 tid, u16 start_seq_num)
 {
-	unsigned long lock_flags;
-	spin_lock_irqsave(&priv->sta_lock, lock_flags);
-	priv->stations[sta_id].sta.sta.modify_mask |= STA_MODIFY_TID_DISABLE_TX;
-	priv->stations[sta_id].sta.tid_disable_tx &= ~(1 << tid);
-	priv->stations[sta_id].sta.mode |= STA_CONTROL_MODIFY_MSK;
-	spin_unlock_irqrestore(&priv->sta_lock, lock_flags);
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	struct iwl4965_priv *priv = hw->priv;
+	int sta_id;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_WARNING("iwl-AGG iwl4965_mac_ht_rx_agg_start on da=%s"
+		    " tid=%d\n", print_mac(mac, da), tid);
+	sta_id = iwl4965_hw_find_station(priv, da);
+	iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num);
+	return 0;
 }
 
-#endif /* CONFIG_IWLWIFI_HT_AGG */
+int iwl4965_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+			   u16 tid, int generator)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	int sta_id;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_WARNING("iwl-AGG iwl4965_mac_ht_rx_agg_stop on da=%s tid=%d\n",
+		    print_mac(mac, da), tid);
+	sta_id = iwl4965_hw_find_station(priv, da);
+	iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+	return 0;
+}
+
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 /* Set up 4965-specific Rx frame reply handlers */
-void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv)
 {
 	/* Legacy Rx frames */
 	priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx;
@@ -3898,37 +4865,79 @@ void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
 	priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
 	    iwl4965_rx_missed_beacon_notif;
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
-#endif
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 }
 
-void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv)
 {
 	INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work, priv);
 	INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work, priv);
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work, priv);
 #endif
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work, priv);
-#endif
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 	init_timer(&priv->statistics_periodic);
 	priv->statistics_periodic.data = (unsigned long)priv;
 	priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
 }
 
-void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv)
 {
 	del_timer_sync(&priv->statistics_periodic);
 
 	cancel_delayed_work(&priv->init_alive_start);
 }
 
-struct pci_device_id iwl_hw_card_ids[] = {
-	{0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+struct pci_device_id iwl4965_hw_card_ids[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)},
 	{0}
 };
 
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
+{
+	u16 count;
+	int rc;
+
+	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+		/* Request semaphore */
+		iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+		/* See if we got it */
+		rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+					EEPROM_SEM_TIMEOUT);
+		if (rc >= 0) {
+			IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
+				count+1);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
+{
+	iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+
+MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index ec83f08..01fcc23 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -23,85 +23,802 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-4965.h) for driver implementation definitions.
+ * Please use iwl-4965-commands.h for uCode API definitions.
+ * Please use iwl-4965-hw.h for hardware-related definitions.
+ */
+
 #ifndef __iwl_4965_h__
 #define __iwl_4965_h__
 
-struct iwl_priv;
-struct sta_ht_info;
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl4965_hw_card_ids[];
+
+#define DRV_NAME        "iwl4965"
+#include "iwl-4965-hw.h"
+#include "iwl-prph.h"
+#include "iwl-4965-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl4965_param_hwcrypto;
+extern int iwl4965_param_queues_num;
+extern int iwl4965_param_amsdu_size_8K;
+
+enum iwl4965_antenna {
+	IWL_ANTENNA_DIVERSITY,
+	IWL_ANTENNA_MAIN,
+	IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl4965_rx_mem_buffer {
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+struct iwl4965_rt_rx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	__le64 rt_tsf;		/* TSF */
+	u8 rt_flags;		/* radiotap packet flags */
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channelMHz;	/* channel in MHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	s8 rt_dbmnoise;
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+struct iwl4965_rt_tx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channel;	/* channel in mHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl4965_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int write_ptr;       /* 1-st empty entry (index) host_w*/
+	int read_ptr;         /* last used entry (index) host_r*/
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	int low_mark;	       /* low watermark, resume queue if free
+				* space more than this */
+	int high_mark;         /* high watermark, stop queue if free
+				* space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+/* One for each TFD */
+struct iwl4965_tx_info {
+	struct ieee80211_tx_status status;
+	struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl4965_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @bd: base of circular buffer of TFDs
+ * @cmd: array of command/Tx buffers
+ * @dma_addr_cmd: physical address of cmd/tx buffer array
+ * @txb: array of per-TFD driver data
+ * @need_update: indicates need to update read/write index
+ * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl4965_tx_queue {
+	struct iwl4965_queue q;
+	struct iwl4965_tfd_frame *bd;
+	struct iwl4965_cmd *cmd;
+	dma_addr_t dma_addr_cmd;
+	struct iwl4965_tx_info *txb;
+	int need_update;
+	int sched_retry;
+	int active;
+};
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl4965_channel_tgd_info {
+	u8 type;
+	s8 max_power;
+};
+
+struct iwl4965_channel_tgh_info {
+	s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl4965_channel_power_info {
+	struct iwl4965_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 base_power_index;	/* gain index for power at factory temp. */
+	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl4965_scan_power_info {
+	struct iwl4965_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* For fat_extension_channel */
+enum {
+	HT_IE_EXT_CHANNEL_NONE = 0,
+	HT_IE_EXT_CHANNEL_ABOVE,
+	HT_IE_EXT_CHANNEL_INVALID,
+	HT_IE_EXT_CHANNEL_BELOW,
+	HT_IE_EXT_CHANNEL_MAX
+};
+
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl4965_channel_info {
+	struct iwl4965_channel_tgd_info tgd;
+	struct iwl4965_channel_tgh_info tgh;
+	struct iwl4965_eeprom_channel eeprom;	  /* EEPROM regulatory limit */
+	struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+						   * FAT channel */
+
+	u8 channel;	  /* channel number */
+	u8 flags;	  /* flags copied from EEPROM */
+	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) limit */
+	s8 min_power;	  /* always 0 */
+	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
+
+	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
+	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
+	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
+
+	/* Radio/DSP gain settings for each "normal" data Tx rate.
+	 * These include, in addition to RF and DSP gain, a few fields for
+	 *   remembering/modifying gain settings (indexes). */
+	struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE];
+
+	/* FAT channel info */
+	s8 fat_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 fat_curr_txpow;	/* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 fat_min_power;	/* always 0 */
+	s8 fat_scan_power;	/* (dBm) eeprom, direct scans, any rate */
+	u8 fat_flags;		/* flags copied from EEPROM */
+	u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
+
+	/* Radio/DSP gain settings for each scan rate, for directed scans. */
+	struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl4965_clip_group {
+	/* maximum power level to prevent clipping for each rate, derived by
+	 *   us from this band's saturation power in EEPROM */
+	const s8 clip_powers[IWL_MAX_RATES];
+};
+
+#include "iwl-4965-rs.h"
+
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
+
+/* Power management (not Tx power) structures */
+
+struct iwl4965_power_vec_entry {
+	struct iwl4965_powertable_cmd cmd;
+	u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0  (0)
+#define IWL_POWER_RANGE_1  (1)
+
+#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3	0x03
+#define IWL_POWER_INDEX_5	0x05
+#define IWL_POWER_AC		0x06
+#define IWL_POWER_BATTERY	0x07
+#define IWL_POWER_LIMIT		0x07
+#define IWL_POWER_MASK		0x0F
+#define IWL_POWER_ENABLED	0x10
+#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
+
+struct iwl4965_power_mgr {
+	spinlock_t lock;
+	struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC];
+	struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC];
+	u8 active_index;
+	u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl4965_frame {
+	union {
+		struct ieee80211_hdr frame;
+		struct iwl4965_tx_beacon_cmd beacon;
+		u8 raw[IEEE80211_FRAME_LEN];
+		u8 cmd[360];
+	} u;
+	struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+	/* CMD_SIZE_NORMAL = 0, */
+	CMD_SIZE_HUGE = (1 << 0),
+	/* CMD_SYNC = 0, */
+	CMD_ASYNC = (1 << 1),
+	/* CMD_NO_SKB = 0, */
+	CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl4965_cmd;
+struct iwl4965_priv;
+
+struct iwl4965_cmd_meta {
+	struct iwl4965_cmd_meta *source;
+	union {
+		struct sk_buff *skb;
+		int (*callback)(struct iwl4965_priv *priv,
+				struct iwl4965_cmd *cmd, struct sk_buff *skb);
+	} __attribute__ ((packed)) u;
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for a scan command
+ * (which is relatively huge; space is allocated separately).
+ */
+struct iwl4965_cmd {
+	struct iwl4965_cmd_meta meta;	/* driver data */
+	struct iwl4965_cmd_header hdr;	/* uCode API */
+	union {
+		struct iwl4965_addsta_cmd addsta;
+		struct iwl4965_led_cmd led;
+		u32 flags;
+		u8 val8;
+		u16 val16;
+		u32 val32;
+		struct iwl4965_bt_cmd bt;
+		struct iwl4965_rxon_time_cmd rxon_time;
+		struct iwl4965_powertable_cmd powertable;
+		struct iwl4965_qosparam_cmd qosparam;
+		struct iwl4965_tx_cmd tx;
+		struct iwl4965_tx_beacon_cmd tx_beacon;
+		struct iwl4965_rxon_assoc_cmd rxon_assoc;
+		u8 *indirect;
+		u8 payload[360];
+	} __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl4965_host_cmd {
+	u8 id;
+	u16 len;
+	struct iwl4965_cmd_meta meta;
+	const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \
+			      sizeof(struct iwl4965_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * struct iwl4965_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers
+ */
+struct iwl4965_rx_queue {
+	__le32 *bd;
+	dma_addr_t dma_addr;
+	struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+	struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+	u32 processed;
+	u32 read;
+	u32 write;
+	u32 free_count;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+/**
+ * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
+ * @txq_id: Tx queue used for Tx attempt
+ * @frame_count: # frames attempted by Tx command
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window
+ * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window
+ * @bitmap1: High order, one bit for each frame pending ACK in Tx window
+ * @rate_n_flags: Rate at which Tx was attempted
+ *
+ * If REPLY_TX indicates that aggregation was attempted, driver must wait
+ * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
+ * until block ack arrives.
+ */
+struct iwl4965_ht_agg {
+	u16 txq_id;
+	u16 frame_count;
+	u16 wait_for_ba;
+	u16 start_idx;
+	u32 bitmap0;
+	u32 bitmap1;
+	u32 rate_n_flags;
+};
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+struct iwl4965_tid_data {
+	u16 seq_number;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct iwl4965_ht_agg agg;
+#endif	/* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+};
+
+struct iwl4965_hw_key {
+	enum ieee80211_key_alg alg;
+	int keylen;
+	u8 key[32];
+};
+
+union iwl4965_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+#ifdef CONFIG_IWL4965_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
+#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct iwl_ht_info {
+	/* self configuration data */
+	u8 is_ht;
+	u8 supported_chan_width;
+	u16 tx_mimo_ps_mode;
+	u8 is_green_field;
+	u8 sgf;			/* HT_SHORT_GI_* short guard interval */
+	u8 max_amsdu_size;
+	u8 ampdu_factor;
+	u8 mpdu_density;
+	u8 supp_mcs_set[16];
+	/* BSS related data */
+	u8 control_channel;
+	u8 extension_chan_offset;
+	u8 tx_chan_width;
+	u8 ht_protection;
+	u8 non_GF_STA_present;
+};
+#endif				/*CONFIG_IWL4965_HT */
+
+#ifdef CONFIG_IWL4965_QOS
+
+union iwl4965_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS structures */
+struct iwl4965_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl4965_qos_capabity qos_cap;
+	struct iwl4965_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWL4965_QOS */
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl4965_station_entry {
+	struct iwl4965_addsta_cmd sta;
+	struct iwl4965_tid_data tid[MAX_TID_COUNT];
+	u8 used;
+	u8 ps_status;
+	struct iwl4965_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+	void *v_addr;		/* access by driver */
+	dma_addr_t p_addr;	/* access by card's busmaster DMA */
+	u32 len;		/* bytes */
+};
+
+/* uCode file layout */
+struct iwl4965_ucode {
+	__le32 ver;		/* major/minor/subminor */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
+	__le32 init_data_size;	/* bytes of initialization data */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
+	u8 data[0];		/* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl4965_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+/**
+ * struct iwl4965_driver_hw_info
+ * @max_txq_num: Max # Tx queues supported
+ * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
+ * @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
+ * @rx_buffer_size:
+ * @max_rxq_log: Log-base-2 of max_rxq_size
+ * @max_stations:
+ * @bcast_sta_id:
+ * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
+ * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
+ */
+struct iwl4965_driver_hw_info {
+	u16 max_txq_num;
+	u16 ac_queue_count;
+	u16 tx_cmd_len;
+	u16 max_rxq_size;
+	u32 rx_buf_size;
+	u32 max_pkt_size;
+	u16 max_rxq_log;
+	u8  max_stations;
+	u8  bcast_sta_id;
+	void *shared_virt;
+	dma_addr_t shared_phys;
+};
+
+#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
+
+
+#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
+		       x->u.rx_frame.stats.payload + \
+		       x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
+		       IWL_RX_HDR(x)->payload + \
+		       le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl4965_addsta_cmd;
+extern int iwl4965_send_add_station(struct iwl4965_priv *priv,
+				struct iwl4965_addsta_cmd *sta, u8 flags);
+extern u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+			  int is_ap, u8 flags, void *ht_data);
+extern int iwl4965_is_network_packet(struct iwl4965_priv *priv,
+				 struct ieee80211_hdr *header);
+extern int iwl4965_power_init_handle(struct iwl4965_priv *priv);
+extern int iwl4965_eeprom_init(struct iwl4965_priv *priv);
+#ifdef CONFIG_IWL4965_DEBUG
+extern void iwl4965_report_frame(struct iwl4965_priv *priv,
+			     struct iwl4965_rx_packet *pkt,
+			     struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl4965_report_frame(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_packet *pkt,
+				    struct ieee80211_hdr *header,
+				    int group100) {}
+#endif
+extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb,
+					   void *data, short len,
+					   struct ieee80211_rx_status *stats,
+					   u16 phy_flags);
+extern int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv,
+				       struct ieee80211_hdr *header);
+extern int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv);
+extern void iwl4965_rx_queue_reset(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_queue *rxq);
+extern int iwl4965_calc_db_from_ratio(int sig_ratio);
+extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
+			     struct iwl4965_tx_queue *txq, int count, u32 id);
+extern void iwl4965_rx_replenish(void *data);
+extern void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len,
+			    const void *data);
+extern int __must_check iwl4965_send_cmd(struct iwl4965_priv *priv,
+		struct iwl4965_host_cmd *cmd);
+extern unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
+extern int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv,
+					 struct iwl4965_rx_queue *q);
+extern int iwl4965_send_statistics_request(struct iwl4965_priv *priv);
+extern void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
+				   u32 decrypt_res,
+				   struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+
+extern const u8 iwl4965_broadcast_addr[ETH_ALEN];
 
-#if IWL != 4965
 /*
- * In non IWL == 4965 builds, these must build to nothing in order to allow
- * the common code to not have several #if IWL == XXXX / #endif blocks
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl4965_sync_station(struct iwl4965_priv *priv, int sta_id,
+			   u16 tx_rate, u8 flags);
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl4965_         <-- Its part of iwlwifi (should be changed to iwl4965_)
+ * iwl4965_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl4965_bg_      <-- Called from work queue context
+ * iwl4965_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv);
+extern void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv);
+extern void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv);
+extern int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv);
+extern int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_init(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv);
+extern void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv);
+extern void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_reset(struct iwl4965_priv *priv);
+extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl4965_hw_get_temperature(struct iwl4965_priv *priv);
+extern int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv,
+				struct iwl4965_tx_queue *txq);
+extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv,
+				 struct iwl4965_frame *frame, u8 rate);
+extern int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv);
+extern void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv,
+				     struct iwl4965_cmd *cmd,
+				     struct ieee80211_tx_control *ctrl,
+				     struct ieee80211_hdr *hdr,
+				     int sta_id, int tx_id);
+extern int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv);
+extern int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power);
+extern void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv,
+				 struct iwl4965_rx_mem_buffer *rxb);
+extern void iwl4965_disable_events(struct iwl4965_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl4965_priv *priv);
+
+/**
+ * iwl4965_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE:  This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
  */
-static inline void iwl4965_add_station(struct iwl_priv *priv, const u8 * addr,
-				       int is_ap) {}
-static inline void iwl4965_set_rxon_ht(struct iwl_priv *priv,
-				       struct sta_ht_info *ht_info) {}
-
-static inline void iwl4965_set_rxon_chain(struct iwl_priv *priv) {}
-static inline int iwl4965_tx_cmd(struct iwl_priv *priv,
-				 struct iwl_cmd *out_cmd,
-				 u8 sta_id, dma_addr_t txcmd_phys,
-				 struct ieee80211_hdr *hdr, u8 hdr_len,
-				 struct ieee80211_tx_control *ctrl,
-				 void *sta_in) { return 0; }
-static inline int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-						 struct iwl_tx_queue *txq,
-						 u16 len) { return 0; }
-static inline int iwl4965_init_hw_rates(struct iwl_priv *priv,
-					struct ieee80211_rate *rates)
-{ return 0; }
-static inline int iwl4965_alive_notify(struct iwl_priv *priv) { return 0; }
-static inline void iwl4965_update_rate_scaling(struct iwl_priv *priv,
-					       u8 mode) {}
-static inline void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
-					      u8 need_to_lock) {}
-static inline void iwl4965_chain_noise_reset(struct iwl_priv *priv) {}
-static inline void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
-					    u8 force) {}
-static inline int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
-				int channel,
-				const struct iwl_eeprom_channel *eeprom_ch,
-				u8 fat_extension_channel) { return 0; }
-static inline void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) {}
-#else				/* IWL == 4965 */
+extern u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *bssid);
+
+extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel);
+extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index);
+
+struct iwl4965_priv;
+
 /*
- * Forward declare iwl-4965.c functions for base.c
+ * Forward declare iwl-4965.c functions for iwl-base.c
  */
-extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-					  struct iwl_tx_queue *txq,
+extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
+extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv);
+
+extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
+					  struct iwl4965_tx_queue *txq,
 					  u16 byte_cnt);
-extern void iwl4965_add_station(struct iwl_priv *priv, const u8 * addr,
+extern void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr,
 				int is_ap);
-extern void iwl4965_set_rxon_ht(struct iwl_priv *priv,
-				struct sta_ht_info *ht_info);
-
-extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
-extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+extern void iwl4965_set_rxon_chain(struct iwl4965_priv *priv);
+extern int iwl4965_tx_cmd(struct iwl4965_priv *priv, struct iwl4965_cmd *out_cmd,
 			  u8 sta_id, dma_addr_t txcmd_phys,
 			  struct ieee80211_hdr *hdr, u8 hdr_len,
 			  struct ieee80211_tx_control *ctrl, void *sta_in);
-extern int iwl4965_init_hw_rates(struct iwl_priv *priv,
-				 struct ieee80211_rate *rates);
-extern int iwl4965_alive_notify(struct iwl_priv *priv);
-extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
-extern void iwl4965_set_ht_add_station(struct iwl_priv *priv,
-				       u8 index, u8 need_to_lock);
-
-extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
-extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
+extern int iwl4965_alive_notify(struct iwl4965_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl4965_priv *priv, u8 mode);
+extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv);
+extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags,
 				     u8 force);
-extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
-				int channel,
-				const struct iwl_eeprom_channel *eeprom_ch,
+extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode,
+				u16 channel,
+				const struct iwl4965_eeprom_channel *eeprom_ch,
 				u8 fat_extension_channel);
-extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
+extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv);
+
+#ifdef CONFIG_IWL4965_HT
+extern void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
+					int mode);
+extern void iwl4965_set_rxon_ht(struct iwl4965_priv *priv,
+				struct iwl_ht_info *ht_info);
+extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
+				struct ieee80211_ht_info *sta_ht_inf);
+#ifdef CONFIG_IWL4965_HT_AGG
+extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
+				   u16 tid, u16 *start_seq_num);
+extern int iwl4965_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+				   u16 tid, u16 start_seq_num);
+extern int iwl4965_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+				  u16 tid, int generator);
+extern int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+				  u16 tid, int generator);
+extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
 /* Structures, enum, and defines specific to the 4965 */
 
 #define IWL4965_KW_SIZE 0x1000	/*4k */
 
-struct iwl_kw {
+struct iwl4965_kw {
 	dma_addr_t dma_addr;
 	void *v_addr;
 	size_t size;
@@ -141,7 +858,9 @@ struct iwl_kw {
 #define NRG_NUM_PREV_STAT_L     20
 #define NUM_RX_CHAINS           (3)
 
-struct iwl_traffic_load {
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+
+struct iwl4965_traffic_load {
 	unsigned long time_stamp;
 	u32 packet_count[TID_QUEUE_MAX_SIZE];
 	u8 queue_count;
@@ -149,8 +868,13 @@ struct iwl_traffic_load {
 	u32 total;
 };
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
-struct iwl_agg_control {
+#ifdef CONFIG_IWL4965_HT_AGG
+/**
+ * struct iwl4965_agg_control
+ * @requested_ba: bit map of tids requesting aggregation/block-ack
+ * @granted_ba: bit map of tids granted aggregation/block-ack
+ */
+struct iwl4965_agg_control {
 	unsigned long next_retry;
 	u32 wait_for_agg_status;
 	u32 tid_retry;
@@ -159,17 +883,16 @@ struct iwl_agg_control {
 	u8 auto_agg;
 	u32 tid_traffic_load_threshold;
 	u32 ba_timeout;
-	struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
+	struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
 };
-#endif				/*CONFIG_IWLWIFI_HT_AGG */
+#endif				/*CONFIG_IWL4965_HT_AGG */
 
-struct iwl_lq_mngr {
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	struct iwl_agg_control agg_ctrl;
+struct iwl4965_lq_mngr {
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct iwl4965_agg_control agg_ctrl;
 #endif
 	spinlock_t lock;
 	s32 max_window_size;
-	struct iwl_rate_scaling_cmd scale_rate_cmd;
 	s32 *expected_tpt;
 	u8 *next_higher_rate;
 	u8 *next_lower_rate;
@@ -177,31 +900,16 @@ struct iwl_lq_mngr {
 	unsigned long stamp_last;
 	u32 flush_time;
 	u32 tx_packets;
+	u8 lq_ready;
 };
 
 
 /* Sensitivity and chain noise calibration */
+#define INTERFERENCE_DATA_AVAILABLE	__constant_cpu_to_le32(1)
 #define INITIALIZATION_VALUE		0xFFFF
 #define CAL_NUM_OF_BEACONS		20
-#define IN_BAND_FILTER			0xFF
 #define MAXIMUM_ALLOWED_PATHLOSS	15
 
-/* Param table within SENSITIVITY_CMD */
-#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)
-#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
-#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
-#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
-#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
-
-#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE       (0)
-#define SENSITIVITY_CMD_CONTROL_WORK_TABLE          (1)
-
 #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
 
 #define MAX_FA_OFDM  50
@@ -229,8 +937,6 @@ struct iwl_lq_mngr {
 #define AUTO_CORR_STEP_CCK     3
 #define AUTO_CORR_MAX_TH_CCK   160
 
-#define NRG_ALG                0
-#define AUTO_CORR_ALG          1
 #define NRG_DIFF               2
 #define NRG_STEP_CCK           2
 #define NRG_MARGIN             8
@@ -243,26 +949,27 @@ struct iwl_lq_mngr {
 #define CHAIN_C             2
 #define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
 #define ALL_BAND_FILTER			0xFF00
+#define IN_BAND_FILTER			0xFF
 #define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
 
-enum iwl_false_alarm_state {
+enum iwl4965_false_alarm_state {
 	IWL_FA_TOO_MANY = 0,
 	IWL_FA_TOO_FEW = 1,
 	IWL_FA_GOOD_RANGE = 2,
 };
 
-enum iwl_chain_noise_state {
+enum iwl4965_chain_noise_state {
 	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
 	IWL_CHAIN_NOISE_ACCUMULATE = 1,
 	IWL_CHAIN_NOISE_CALIBRATED = 2,
 };
 
-enum iwl_sensitivity_state {
+enum iwl4965_sensitivity_state {
 	IWL_SENS_CALIB_ALLOWED = 0,
 	IWL_SENS_CALIB_NEED_REINIT = 1,
 };
 
-enum iwl_calib_enabled_state {
+enum iwl4965_calib_enabled_state {
 	IWL_CALIB_DISABLED = 0,  /* must be 0 */
 	IWL_CALIB_ENABLED = 1,
 };
@@ -277,7 +984,7 @@ struct statistics_general_data {
 };
 
 /* Sensitivity calib data */
-struct iwl_sensitivity_data {
+struct iwl4965_sensitivity_data {
 	u32 auto_corr_ofdm;
 	u32 auto_corr_ofdm_mrc;
 	u32 auto_corr_ofdm_x1;
@@ -306,7 +1013,7 @@ struct iwl_sensitivity_data {
 };
 
 /* Chain noise (differential Rx gain) calib data */
-struct iwl_chain_noise_data {
+struct iwl4965_chain_noise_data {
 	u8 state;
 	u16 beacon_count;
 	u32 chain_noise_a;
@@ -320,26 +1027,323 @@ struct iwl_chain_noise_data {
 	u8 radio_write;
 };
 
-/* IWL4965 */
-#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_MIMO_POS 3
-#define RATE_MCS_MIMO_MSK 0x8
-#define RATE_MCS_HT_DUP_POS 5
-#define RATE_MCS_HT_DUP_MSK 0x20
-#define RATE_MCS_FLAGS_POS 8
-#define RATE_MCS_HT_POS 8
-#define RATE_MCS_HT_MSK 0x100
-#define RATE_MCS_CCK_POS 9
-#define RATE_MCS_CCK_MSK 0x200
-#define RATE_MCS_GF_POS 10
-#define RATE_MCS_GF_MSK 0x400
-
-#define RATE_MCS_FAT_POS 11
-#define RATE_MCS_FAT_MSK 0x800
-#define RATE_MCS_DUP_POS 12
-#define RATE_MCS_DUP_MSK 0x1000
-#define RATE_MCS_SGI_POS 13
-#define RATE_MCS_SGI_MSK 0x2000
-
-#endif				/* IWL == 4965 */
-#endif				/* __iwl_4965_h__ */
+#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
+
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl4965_priv {
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+	struct ieee80211_channel *ieee_channels;
+	struct ieee80211_rate *ieee_rates;
+	struct ieee80211_conf *cache_conf;
+
+	/* temporary frame storage list */
+	struct list_head free_frames;
+	int frames_count;
+
+	u8 phymode;
+	int alloc_rxb_skb;
+
+	void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv,
+				       struct iwl4965_rx_mem_buffer *rxb);
+
+	const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+	/* spectrum measurement report caching */
+	struct iwl4965_spectrum_notification measure_report;
+	u8 measurement_status;
+#endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+
+	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
+	 *    Access via channel # using indirect index array */
+	struct iwl4965_channel_info *channel_info;	/* channel info array */
+	u8 channel_count;	/* # of channels */
+
+	/* each calibration channel group in the EEPROM has a derived
+	 * clip setting for each rate. */
+	const struct iwl4965_clip_group clip_groups[5];
+
+	/* thermal calibration */
+	s32 temperature;	/* degrees Kelvin */
+	s32 last_temperature;
+
+	/* Scan related variables */
+	unsigned long last_scan_jiffies;
+	unsigned long next_scan_jiffies;
+	unsigned long scan_start;
+	unsigned long scan_pass_start;
+	unsigned long scan_start_tsf;
+	int scan_bands;
+	int one_direct_scan;
+	u8 direct_ssid_len;
+	u8 direct_ssid[IW_ESSID_MAX_SIZE];
+	struct iwl4965_scan_cmd *scan;
+	u8 only_active_channel;
+
+	/* spinlock */
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
+	struct mutex mutex;
+
+	/* basic pci-network driver stuff */
+	struct pci_dev *pci_dev;
+
+	/* pci hardware address support */
+	void __iomem *hw_base;
+
+	/* uCode images, save to reload in case of failure */
+	struct fw_desc ucode_code;	/* runtime inst */
+	struct fw_desc ucode_data;	/* runtime data original */
+	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
+	struct fw_desc ucode_init;	/* initialization inst */
+	struct fw_desc ucode_init_data;	/* initialization data */
+	struct fw_desc ucode_boot;	/* bootstrap inst */
+
+
+	struct iwl4965_rxon_time_cmd rxon_timing;
+
+	/* We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware */
+	const struct iwl4965_rxon_cmd active_rxon;
+	struct iwl4965_rxon_cmd staging_rxon;
+
+	int error_recovering;
+	struct iwl4965_rxon_cmd recovery_rxon;
+
+	/* 1st responses from initialize and runtime uCode images.
+	 * 4965's initialize alive response contains some calibration data. */
+	struct iwl4965_init_alive_resp card_alive_init;
+	struct iwl4965_alive_resp card_alive;
+
+#ifdef LED
+	/* LED related variables */
+	struct iwl4965_activity_blink activity;
+	unsigned long led_packets;
+	int led_state;
+#endif
+
+	u16 active_rate;
+	u16 active_rate_basic;
+
+	u8 call_post_assoc_from_beacon;
+	u8 assoc_station_added;
+	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
+	u8 valid_antenna;	/* Bit mask of antennas actually connected */
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct iwl4965_sensitivity_data sensitivity_data;
+	struct iwl4965_chain_noise_data chain_noise_data;
+	u8 start_calib;
+	__le16 sensitivity_tbl[HD_TABLE_SIZE];
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
+
+#ifdef CONFIG_IWL4965_HT
+	struct iwl_ht_info current_ht_config;
+#endif
+	u8 last_phy_res[100];
+
+	/* Rate scaling data */
+	struct iwl4965_lq_mngr lq_mngr;
+
+	/* Rate scaling data */
+	s8 data_retry_limit;
+	u8 retry_rate;
+
+	wait_queue_head_t wait_command_queue;
+
+	int activity_timer_active;
+
+	/* Rx and Tx DMA processing queues */
+	struct iwl4965_rx_queue rxq;
+	struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
+	unsigned long txq_ctx_active_msk;
+	struct iwl4965_kw kw;	/* keep warm address */
+	u32 scd_base_addr;	/* scheduler sram base address */
+
+	unsigned long status;
+	u32 config;
+
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
+
+	struct iwl4965_power_mgr power_data;
+
+	struct iwl4965_notif_statistics statistics;
+	unsigned long last_statistics_time;
+
+	/* context information */
+	u8 essid[IW_ESSID_MAX_SIZE];
+	u8 essid_len;
+	u16 rates_mask;
+
+	u32 power_mode;
+	u32 antenna;
+	u8 bssid[ETH_ALEN];
+	u16 rts_threshold;
+	u8 mac_addr[ETH_ALEN];
+
+	/*station table variables */
+	spinlock_t sta_lock;
+	int num_stations;
+	struct iwl4965_station_entry stations[IWL_STATION_COUNT];
+
+	/* Indication if ieee80211_ops->open has been called */
+	int is_open;
+
+	u8 mac80211_registered;
+	int is_abg;
+
+	u32 notif_missed_beacons;
+
+	/* Rx'd packet timing information */
+	u32 last_beacon_time;
+	u64 last_tsf;
+
+	/* Duplicate packet detection */
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+
+	/* Hash table for finding stations in IBSS network */
+	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+	/* eeprom */
+	struct iwl4965_eeprom eeprom;
+
+	int iw_mode;
+
+	struct sk_buff *ibss_beacon;
+
+	/* Last Rx'd beacon timestamp */
+	u32 timestamp0;
+	u32 timestamp1;
+	u16 beacon_int;
+	struct iwl4965_driver_hw_info hw_setting;
+	int interface_id;
+
+	/* Current association information needed to configure the
+	 * hardware */
+	u16 assoc_id;
+	u16 assoc_capability;
+	u8 ps_mode;
+
+#ifdef CONFIG_IWL4965_QOS
+	struct iwl4965_qos_info qos_data;
+#endif /*CONFIG_IWL4965_QOS */
+
+	struct workqueue_struct *workqueue;
+
+	struct work_struct up;
+	struct work_struct restart;
+	struct work_struct calibrated_work;
+	struct work_struct scan_completed;
+	struct work_struct rx_replenish;
+	struct work_struct rf_kill;
+	struct work_struct abort_scan;
+	struct work_struct update_link_led;
+	struct work_struct auth_work;
+	struct work_struct report_work;
+	struct work_struct request_scan;
+	struct work_struct beacon_update;
+
+	struct tasklet_struct irq_tasklet;
+
+	struct work_struct init_alive_start;
+	struct work_struct alive_start;
+	struct work_struct activity_timer;
+	struct work_struct thermal_periodic;
+	struct work_struct gather_stats;
+	struct work_struct scan_check;
+	struct work_struct post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+	s8 user_txpower_limit;
+	s8 max_channel_txpower_limit;
+
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWL4965_DEBUG
+	/* debugging info */
+	u32 framecnt_to_us;
+	atomic_t restrict_refcnt;
+#endif
+
+	struct work_struct txpower_work;
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct work_struct sensitivity_work;
+#endif
+	struct work_struct statistics_work;
+	struct timer_list statistics_periodic;
+
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct work_struct agg_work;
+#endif
+};				/*iwl4965_priv */
+
+static inline int iwl4965_is_associated(struct iwl4965_priv *priv)
+{
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int is_channel_valid(const struct iwl4965_channel_info *ch_info)
+{
+	if (ch_info == NULL)
+		return 0;
+	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl4965_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl4965_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info)
+{
+	return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info)
+{
+	return ((ch_info->phymode == MODE_IEEE80211B) ||
+		(ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl4965_channel_info *ch)
+{
+	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl4965_channel_info *ch)
+{
+	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl4965_channel_info *iwl4965_get_channel_info(
+	const struct iwl4965_priv *priv, int phymode, u16 channel);
+
+/* Requires full declaration of iwl4965_priv before including */
+#include "iwl-4965-io.h"
+
+#endif				/* __iwl4965_4965_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h
index d320c2b..023c3f2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-channel.h
+++ b/drivers/net/wireless/iwlwifi/iwl-channel.h
@@ -136,15 +136,13 @@ static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
 
 static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
 {
-	return ((ch_info->phymode == MODE_IEEE80211A) ||
-		(ch_info->phymode == MODE_ATHEROS_TURBO)) ? 1 : 0;
+	return ch_info->phymode == MODE_IEEE80211A;
 }
 
 static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
 {
 	return ((ch_info->phymode == MODE_IEEE80211B) ||
-		(ch_info->phymode == MODE_IEEE80211G) ||
-		(ch_info->phymode == MODE_ATHEROS_TURBOG)) ? 1 : 0;
+		(ch_info->phymode == MODE_IEEE80211G));
 }
 
 static inline int is_channel_passive(const struct iwl_channel_info *ch)
@@ -158,6 +156,6 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
 }
 
 extern const struct iwl_channel_info *iwl_get_channel_info(
-	const struct iwl_priv *priv, int phymode, int channel);
+	const struct iwl_priv *priv, int phymode, u16 channel);
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index f0c0107..9de8d7f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -68,7 +68,7 @@ enum {
 	REPLY_ALIVE = 0x1,
 	REPLY_ERROR = 0x2,
 
-	/* RXON state commands */
+	/* RXON and QOS commands */
 	REPLY_RXON = 0x10,
 	REPLY_RXON_ASSOC = 0x11,
 	REPLY_QOS_PARAM = 0x13,
@@ -76,39 +76,27 @@ enum {
 
 	/* Multi-Station support */
 	REPLY_ADD_STA = 0x18,
-#if IWL == 3945
-	REPLY_REMOVE_STA = 0x19,
-	REPLY_REMOVE_ALL_STA = 0x1a,
-#endif
+	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
 
-	/* RX, TX */
+	/* RX, TX, LEDs */
 #if IWL == 3945
-	REPLY_3945_RX = 0x1b,
+	REPLY_3945_RX = 0x1b,		/* 3945 only */
 #endif
-
 	REPLY_TX = 0x1c,
-
-	/* timers commands */
-	REPLY_BCON = 0x27,
-
-#if IWL == 4965
-	REPLY_SHUTDOWN = 0x40,
-#endif
-
-	/* MISC commands */
-	REPLY_RATE_SCALE = 0x47,
+	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
 	REPLY_LEDS_CMD = 0x48,
-	REPLY_TX_LINK_QUALITY_CMD = 0x4e,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
 
 	/* 802.11h related */
-	RADAR_NOTIFICATION = 0x70,
-	REPLY_QUIET_CMD = 0x71,
+	RADAR_NOTIFICATION = 0x70,	/* not used */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
 	REPLY_CHANNEL_SWITCH = 0x72,
 	CHANNEL_SWITCH_NOTIFICATION = 0x73,
 	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
 	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
 
-	/* Power Management *** */
+	/* Power Management */
 	POWER_TABLE_CMD = 0x77,
 	PM_SLEEP_NOTIFICATION = 0x7A,
 	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
@@ -116,7 +104,6 @@ enum {
 	/* Scan commands and notifications */
 	REPLY_SCAN_CMD = 0x80,
 	REPLY_SCAN_ABORT_CMD = 0x81,
-
 	SCAN_START_NOTIFICATION = 0x82,
 	SCAN_RESULTS_NOTIFICATION = 0x83,
 	SCAN_COMPLETE_NOTIFICATION = 0x84,
@@ -124,110 +111,602 @@ enum {
 	/* IBSS/AP commands */
 	BEACON_NOTIFICATION = 0x90,
 	REPLY_TX_BEACON = 0x91,
-	WHO_IS_AWAKE_NOTIFICATION = 0x94,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
 
-	QUIET_NOTIFICATION = 0x96,
+	/* Miscellaneous commands */
+	QUIET_NOTIFICATION = 0x96,		/* not used */
 	REPLY_TX_PWR_TABLE_CMD = 0x97,
-	MEASURE_ABORT_NOTIFICATION = 0x99,
-
-	REPLY_CALIBRATION_TUNE = 0x9a,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
 
 	/* BT config command */
 	REPLY_BT_CONFIG = 0x9b,
+
+	/* 4965 Statistics */
 	REPLY_STATISTICS_CMD = 0x9c,
 	STATISTICS_NOTIFICATION = 0x9d,
 
-	/* RF-KILL commands and notifications *** */
+	/* RF-KILL commands and notifications */
 	REPLY_CARD_STATE_CMD = 0xa0,
 	CARD_STATE_NOTIFICATION = 0xa1,
 
 	/* Missed beacons notification */
 	MISSED_BEACONS_NOTIFICATION = 0xa2,
-	MISSED_BEACONS_NOTIFICATION_TH_CMD = 0xa3,
 
 #if IWL == 4965
 	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
 	SENSITIVITY_CMD = 0xa8,
 	REPLY_PHY_CALIBRATION_CMD = 0xb0,
-	REPLY_4965_RX = 0xc3,
 	REPLY_RX_PHY_CMD = 0xc0,
 	REPLY_RX_MPDU_CMD = 0xc1,
+	REPLY_4965_RX = 0xc3,
 	REPLY_COMPRESSED_BA = 0xc5,
 #endif
 	REPLY_MAX = 0xff
 };
 
+/******************************************************************************
+ * (0)
+ * Header
+ *
+ *****************************************************************************/
+
+#define IWL_CMD_FAILED_MSK 0x40
+
+struct iwl_cmd_header {
+	u8 cmd;
+	u8 flags;
+	/* We have 15 LSB to use as we please (MSB indicates
+	 * a frame Rx'd from the HW).  We encode the following
+	 * information into the sequence field:
+	 *
+	 *  0:7    index in fifo
+	 *  8:13   fifo selection
+	 * 14:14   bit indicating if this packet references the 'extra'
+	 *         storage at the end of the memory queue
+	 * 15:15   (Rx indication)
+	 *
+	 */
+	__le16 sequence;
+
+	/* command data follows immediately */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
 /*
- * Tx Command & Response:
+ * REPLY_ALIVE = 0x1 (response only, not a command)
  */
+struct iwl_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
 
-/* Tx flags */
-enum {
-	TX_CMD_FLG_RTS_MSK = (1 << 1),
-	TX_CMD_FLG_CTS_MSK = (1 << 2),
-	TX_CMD_FLG_ACK_MSK = (1 << 3),
-	TX_CMD_FLG_STA_RATE_MSK = (1 << 4),
-	TX_CMD_FLG_IMM_BA_RSP_MASK = (1 << 6),
-	TX_CMD_FLG_FULL_TXOP_PROT_MSK = (1 << 7),
-	TX_CMD_FLG_ANT_SEL_MSK = 0xf00,
-	TX_CMD_FLG_ANT_A_MSK = (1 << 8),
-	TX_CMD_FLG_ANT_B_MSK = (1 << 9),
+struct iwl_init_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
 
-	/* ucode ignores BT priority for this frame */
-	TX_CMD_FLG_BT_DIS_MSK = (1 << 12),
+#if IWL == 4965
+	/* calibration values from "initialize" uCode */
+	__le32 voltage;		/* signed */
+	__le32 therm_r1[2];	/* signed 1st for normal, 2nd for FAT channel */
+	__le32 therm_r2[2];	/* signed */
+	__le32 therm_r3[2];	/* signed */
+	__le32 therm_r4[2];	/* signed */
+	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
+				 * 2 Tx chains */
+#endif
+} __attribute__ ((packed));
 
-	/* ucode overrides sequence control */
-	TX_CMD_FLG_SEQ_CTL_MSK = (1 << 13),
+union tsf {
+	u8 byte[8];
+	__le16 word[4];
+	__le32 dw[2];
+};
 
-	/* signal that this frame is non-last MPDU */
-	TX_CMD_FLG_MORE_FRAG_MSK = (1 << 14),
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+#if IWL == 3945
+	__le16 reserved2;
+#endif
+	__le32 error_info;
+	union tsf timestamp;
+} __attribute__ ((packed));
 
-	/* calculate TSF in outgoing frame */
-	TX_CMD_FLG_TSF_MSK = (1 << 16),
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
 
-	/* activate TX calibration. */
-	TX_CMD_FLG_CALIB_MSK = (1 << 17),
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+};
 
-	/* signals that 2 bytes pad was inserted
-	 * after the MAC header */
-	TX_CMD_FLG_MH_PAD_MSK = (1 << 20),
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
 
-	/* HCCA-AP - disable duration overwriting. */
-	TX_CMD_FLG_DUR_MSK = (1 << 25),
-};
+/*
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ */
+struct iwl_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+#if IWL == 3945
+	__le16 reserved4;
+#elif IWL == 4965
+	__le16 rx_chain;
+#endif
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+#if IWL == 3945
+	__le16 reserved5;
+#elif IWL == 4965
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+#endif
+} __attribute__ ((packed));
 
 /*
- * TX command security control
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
  */
-#define TX_CMD_SEC_CCM               0x2
-#define TX_CMD_SEC_TKIP              0x3
+struct iwl_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+#if IWL == 4965
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	__le16 rx_chain_select_flags;
+#endif
+	__le16 reserved;
+} __attribute__ ((packed));
 
 /*
- * TX command Frame life time
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
  */
+struct iwl_rxon_time_cmd {
+	union tsf timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
 
 #if IWL == 3945
-struct iwl_rate {
-	union {
-		struct {
-			u8 rate;
-			u8 flags;
-		} s;
-		__le16 rate_n_flags;
-	};
+struct iwl_power_per_rate {
+	u8 rate;		/* plcp */
+	struct iwl_tx_power tpc;
+	u8 reserved;
 } __attribute__ ((packed));
+
 #elif IWL == 4965
-struct iwl_rate {
-	union {
-		struct {
-			u8 rate;
-			u8 flags;
-			__le16 ext_flags;
-		} s;
-		__le32 rate_n_flags;
-	};
+#define POWER_TABLE_NUM_ENTRIES			33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
+#define POWER_TABLE_CCK_ENTRY			32
+struct tx_power_dual_stream {
+	__le32 dw;
+} __attribute__ ((packed));
+
+struct iwl_tx_power_db {
+	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+#if IWL == 3945
+	struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+	struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+struct iwl_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+
+/*
+ *  TXFIFO Queue number defines
+ */
+/* number of Access categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ */
+struct iwl_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl_ac_qos ac[AC_NUM];
 } __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+#define	IWL_AP_ID		0
+#define IWL_MULTICAST_ID	1
+#define	IWL_STA_ID		2
+
+#define	IWL3945_BROADCAST_ID	24
+#define IWL3945_STATION_COUNT	25
+
+#define IWL4965_BROADCAST_ID	31
+#define	IWL4965_STATION_COUNT	32
+
+#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
+#define	IWL_INVALID_STATION 	255
+
+#if IWL == 3945
+#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1<<2);
 #endif
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1<<8);
+
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+
+/* modify flags  */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+#define STA_MODIFY_ADDBA_TID_MSK	0x08
+#define STA_MODIFY_DELBA_TID_MSK	0x10
+#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
+
+/*
+ * Antenna masks:
+ * bit14:15 01 B inactive, A active
+ *          10 B active, A inactive
+ *          11 Both active
+ */
+#define RATE_MCS_ANT_A_POS	14
+#define RATE_MCS_ANT_B_POS	15
+#define RATE_MCS_ANT_A_MSK	0x4000
+#define RATE_MCS_ANT_B_MSK	0x8000
+#define RATE_MCS_ANT_AB_MSK	0xc000
+
+struct iwl_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	__le16 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ */
+struct iwl_addsta_cmd {
+	u8 mode;
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl_keyinfo key;
+	__le32 station_flags;
+	__le32 station_flags_msk;
+	__le16 tid_disable_tx;
+#if IWL == 3945
+	__le16 rate_n_flags;
+#else
+	__le16	reserved1;
+#endif
+	u8 add_immediate_ba_tid;
+	u8 remove_immediate_ba_tid;
+	__le16 add_immediate_ba_ssn;
+#if IWL == 4965
+	__le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+	u8 status;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK              0x1
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_frame_stats {
+	u8 phy_count;
+	u8 id;
+	u8 rssi;
+	u8 agc;
+	__le16 sig_avg;
+	__le16 noise_diff;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl_rx_frame_hdr {
+	__le16 channel;
+	__le16 phy_flags;
+	u8 reserved1;
+	u8 rate;
+	__le16 len;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+#define	RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
+#define	RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+
+#define	RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
+#define	RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
+#define	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
+#define	RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
+#define	RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+
+#define	RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+
+#define	RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define	RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define	RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+struct iwl_rx_frame_end {
+	__le32 status;
+	__le64 timestamp;
+	__le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl_rx_frame {
+	struct iwl_rx_frame_stats stats;
+	struct iwl_rx_frame_hdr hdr;
+	struct iwl_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
+#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
+#define IWL_AGC_DB_POS		(7)
+struct iwl4965_rx_non_cfg_phy {
+	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
+	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
+	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
+	u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
+	__le32 reserved2;
+	__le32 rate_n_flags;
+	__le16 byte_count;		/* frame's byte-count */
+	__le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ *****************************************************************************/
+
+/* Tx flags */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* ucode ignores BT priority for this frame */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* ucode overrides sequence control */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* signal that this frame is non-last MPDU */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* calculate TSF in outgoing frame */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* activate TX calibration. */
+#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17)
+
+/* signals that 2 bytes pad was inserted
+   after the MAC header */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * TX command Frame life time
+ */
 
 struct iwl_dram_scratch {
 	u8 try_cnt;
@@ -235,6 +714,9 @@ struct iwl_dram_scratch {
 	__le16 reserved;
 } __attribute__ ((packed));
 
+/*
+ * REPLY_TX = 0x1c (command)
+ */
 struct iwl_tx_cmd {
 	__le16 len;
 	__le16 next_frame_len;
@@ -245,7 +727,7 @@ struct iwl_tx_cmd {
 	u8 tid_tspec;
 #elif IWL == 4965
 	struct iwl_dram_scratch scratch;
-	struct iwl_rate rate;
+	__le32 rate_n_flags;
 	u8 sta_id;
 #endif
 	u8 sec_ctl;
@@ -289,8 +771,32 @@ struct iwl_tx_cmd {
 	struct ieee80211_hdr hdr[0];
 } __attribute__ ((packed));
 
-/*
- * TX command response status
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
  */
 enum {
 	TX_STATUS_SUCCESS = 0x01,
@@ -313,11 +819,9 @@ enum {
 	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
 };
 
-enum {
-	TX_PACKET_MODE_REGULAR = 0x0000,
-	TX_PACKET_MODE_BURST_PART = 0x00100,
-	TX_PACKET_MODE_BURST_FIRST = 0x0200,
-};
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
 
 enum {
 	TX_POWER_PA_NOT_ACTIVE = 0x0,
@@ -365,69 +869,403 @@ enum {
 #define AGG_TX_STATE_SEQ_NUM_POS 16
 #define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
 
-struct iwl_tx_resp {
+/*
+ * REPLY_TX = 0x1c (response)
+ */
 #if IWL == 4965
+struct iwl_tx_resp {
 	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
 	u8 bt_kill_count;
-#endif
 	u8 failure_rts;
 	u8 failure_frame;
-#if IWL == 3945
-	u8 bt_kill_count;
-	u8 rate;
-	__le32 wireless_media_time;
-#elif IWL == 4965
-	struct iwl_rate rate;
+	__le32 rate_n_flags;
 	__le16 wireless_media_time;
 	__le16 reserved;
 	__le32 pa_power1;
 	__le32 pa_power2;
-#endif
 	__le32 status;	/* TX status (for aggregation status of 1st frame) */
 } __attribute__ ((packed));
 
-/* TX command response is sent after *all* transmission attempts.
+#elif IWL == 3945
+struct iwl_tx_resp {
+	u8 failure_rts;
+	u8 failure_frame;
+	u8 bt_kill_count;
+	u8 rate;
+	__le32 wireless_media_time;
+	__le32 status;	/* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ */
+struct iwl_compressed_ba_resp {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+	u8 sta_id;
+	u8 tid;
+	__le16 ba_seq_ctl;
+	__le32 ba_bitmap0;
+	__le32 ba_bitmap1;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ */
+struct iwl_txpowertable_cmd {
+	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
+	u8 reserved;
+	__le16 channel;
+#if IWL == 3945
+	struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+	struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_rate_scaling_info {
+	__le16 rate_n_flags;
+	u8 try_cnt;
+	u8 next_rate_index;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
  *
- * NOTES:
+ * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
  *
- * TX_STATUS_FAIL_NEXT_FRAG
+ * NOTE: The table of rates passed to the uCode via the
+ * RATE_SCALE command sets up the corresponding order of
+ * rates used for all related commands, including rate
+ * masks, etc.
  *
- * If the fragment flag in the MAC header for the frame being transmitted
- * is set and there is insufficient time to transmit the next frame, the
- * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ * For example, if you set 9MB (PLCP 0x0f) as the first
+ * rate in the rate table, the bit mask for that rate
+ * when passed through ofdm_basic_rates on the REPLY_RXON
+ * command would be bit 0 (1<<0)
+ */
+struct iwl_rate_scaling_cmd {
+	u8 table_id;
+	u8 reserved[3];
+	struct iwl_rate_scaling_info table[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1<<0)
+
+#define  LINK_QUAL_AC_NUM AC_NUM
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+#define  LINK_QUAL_ANT_A_MSK (1<<0)
+#define  LINK_QUAL_ANT_B_MSK (1<<1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+struct iwl_link_qual_general_params {
+	u8 flags;
+	u8 mimo_delimiter;
+	u8 single_stream_ant_msk;
+	u8 dual_stream_ant_msk;
+	u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+struct iwl_link_qual_agg_params {
+	__le16 agg_time_limit;
+	u8 agg_dis_start_th;
+	u8 agg_frame_cnt_limit;
+	__le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ */
+struct iwl_link_quality_cmd {
+	u8 sta_id;
+	u8 reserved1;
+	__le16 control;
+	struct iwl_link_qual_general_params general_params;
+	struct iwl_link_qual_agg_params agg_params;
+	struct {
+		__le32 rate_n_flags;
+	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
+	__le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
  *
- * TX_STATUS_FIFO_UNDERRUN
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl_measure_type */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __attribute__ ((packed));
+
+enum iwl_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
  *
- * Indicates the host did not provide bytes to the FIFO fast enough while
- * a TX was in progress.
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
  *
- * TX_STATUS_FAIL_MGMNT_ABORT
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
  *
- * This status is only possible if the ABORT ON MGMT RX parameter was
- * set to true with the TX command.
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
  *
- * If the MSB of the status parameter is set then an abort sequence is
- * required.  This sequence consists of the host activating the TX Abort
- * control line, and then waiting for the TX Abort command response.  This
- * indicates that a the device is no longer in a transmit state, and that the
- * command FIFO has been cleared.  The host must then deactivate the TX Abort
- * control line.  Receiving is still allowed in this case.
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
  */
+#define IWL_POWER_VEC_SIZE 5
 
-struct iwl_tx_power {
-	u8 tx_gain;		/* gain for analog radio */
-	u8 dsp_atten;		/* gain for DSP */
+
+#if IWL == 3945
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1<<3)
+struct iwl_powertable_cmd {
+	__le32 flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+} __attribute__((packed));
+
+#elif IWL == 4965
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1<<3)
+
+struct iwl_powertable_cmd {
+	__le16 flags;
+	u8 keep_alive_seconds;
+	u8 debug_flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+	__le32 keep_alive_beacons;
 } __attribute__ ((packed));
+#endif
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
 
 struct iwl_scan_channel {
-	u8 type;
 	/* type is defined as:
 	 * 0:0 active (0 - passive)
 	 * 1:4 SSID direct
 	 *     If 1 is set then corresponding SSID IE is transmitted in probe
-	 * 5:6 reserved
-	 * 7:7 Narrow
+	 * 5:7 reserved
 	 */
+	u8 type;
 	u8 channel;
 	struct iwl_tx_power tpc;
 	__le16 active_dwell;
@@ -441,11 +1279,13 @@ struct iwl_ssid_ie {
 } __attribute__ ((packed));
 
 #define PROBE_OPTION_MAX        0x4
-#define TX_CMD_FLG_SEQ_CTL_MSK  0x2000
-#define TX_CMD_LIFE_TIME_INFINITE       0xFFFFFFFF
-#define IWL_GOOD_CRC_TH             (1)
-
+#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
 #define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
 struct iwl_scan_cmd {
 	__le16 len;
 	u8 reserved0;
@@ -485,225 +1325,410 @@ struct iwl_scan_cmd {
 	 */
 } __attribute__ ((packed));
 
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
 /*
- * RXON-ASSOCIATED Command & Response
+ * REPLY_SCAN_CMD = 0x80 (response)
  */
-struct iwl_rxon_assoc_cmd {
-	__le32 flags;
-	__le32 filter_flags;
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-#if IWL == 4965
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-	__le16 rx_chain_select_flags;
-#endif
-	__le16 reserved;
+struct iwl_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
 } __attribute__ ((packed));
 
 /*
- * RXON Command & Response
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
  */
-struct iwl_rxon_cmd {
-	u8 node_addr[6];
-	__le16 reserved1;
-	u8 bssid_addr[6];
-	__le16 reserved2;
-	u8 wlap_bssid_addr[6];
-	__le16 reserved3;
-	u8 dev_type;
-	u8 air_propagation;
-#if IWL == 3945
-	__le16 reserved4;
-#elif IWL == 4965
-	__le16 rx_chain;
-#endif
-	u8 ofdm_basic_rates;
-	u8 cck_basic_rates;
-	__le16 assoc_id;
-	__le32 flags;
-	__le32 filter_flags;
-	__le16 channel;
-#if IWL == 3945
-	__le16 reserved5;
-#elif IWL == 4965
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-#endif
-} __attribute__ ((packed));
-
-struct iwl_compressed_ba_resp {
-	__le32 sta_addr_lo32;
-	__le16 sta_addr_hi16;
-	__le16 reserved;
-	u8 sta_id;
-	u8 tid;
-	__le16 ba_seq_ctl;
-	__le32 ba_bitmap0;
-	__le32 ba_bitmap1;
-	__le16 scd_flow;
-	__le16 scd_ssn;
+struct iwl_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
 } __attribute__ ((packed));
 
-#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
-#define HD_TABLE_SIZE  (11)
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
 
-struct iwl_sensitivity_cmd {
-	__le16 control;
-	__le16 table[HD_TABLE_SIZE];
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
 } __attribute__ ((packed));
 
-struct iwl_calibration_cmd {
-	u8 opCode;
-	u8 flags;
-	__le16 reserved;
-	s8 diff_gain_a;
-	s8 diff_gain_b;
-	s8 diff_gain_c;
-	u8 reserved1;
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 reserved;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
 } __attribute__ ((packed));
 
-struct iwl_missed_beacon_notif {
-	__le32 consequtive_missed_beacons;
-	__le32 total_missed_becons;
-	__le32 num_expected_beacons;
-	__le32 num_recvd_beacons;
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl_beacon_notif {
+	struct iwl_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
 } __attribute__ ((packed));
 
-struct iwl_ct_kill_config {
-	u32   reserved;
-	u32   critical_temperature_M;
-	u32   critical_temperature_R;
-}  __attribute__ ((packed));
 /*
- * Add/Modify Station Command & Response
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
  */
-struct iwl_keyinfo {
-	__le16 key_flags;
-	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+struct iwl_tx_beacon_cmd {
+	struct iwl_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
 	u8 reserved1;
-	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
-	__le16 reserved2;
-	u8 key[16];		/* 16-byte unicast decryption key */
+	struct ieee80211_hdr frame[0];	/* beacon frame */
 } __attribute__ ((packed));
 
-struct sta_id_modify {
-	u8 addr[ETH_ALEN];
-	__le16 reserved1;
-	u8 sta_id;
-	u8 modify_mask;
-	__le16 reserved2;
-} __attribute__ ((packed));
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
 
-struct iwl_addsta_cmd {
-	u8 mode;
-	u8 reserved[3];
-	struct sta_id_modify sta;
-	struct iwl_keyinfo key;
-	__le32 station_flags;
-	__le32 station_flags_msk;
-	__le16 tid_disable_tx;
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
 	union {
-		struct {
-			u8 rate;
-			u8 flags;
-		} s;
-		__le16 rate_n_flags;
-	} tx_rate;
-	u8 add_immediate_ba_tid;
-	u8 remove_immediate_ba_tid;
-	__le16 add_immediate_ba_start_seq;
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+#if IWL == 4965
+	__le32 sent_ba_rsp_cnt;
+	__le32 dsp_self_kill;
+	__le32 mh_format_err;
+	__le32 re_acq_main_rssi_sum;
+	__le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_rx_ht_phy {
+	__le32 plcp_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 crc32_err;
+	__le32 mh_format_err;
+	__le32 agg_crc32_good;
+	__le32 agg_mpdu_cnt;
+	__le32 agg_cnt;
+	__le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+#if IWL == 4965
+	__le32 channel_beacons;	/* beacons with our bss id and in our
+				 * serving channel */
+	__le32 num_missed_bcon;	/* number of missed beacons */
+	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
+					 * ADC was in saturation */
+	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
+					  * for INA */
+	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
+	__le32 interference_data_flag;	/* flag for interference data
+					 * availability. 1 when data is
+					 * available. */
+	__le32 channel_load;	/* counts RX Enable time */
+	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
+					 * and CCK) counter */
+	__le32 beacon_rssi_a;
+	__le32 beacon_rssi_b;
+	__le32 beacon_rssi_c;
+	__le32 beacon_energy_a;
+	__le32 beacon_energy_b;
+	__le32 beacon_energy_c;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_rx {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy general;
+#if IWL == 4965
+	struct statistics_rx_ht_phy ofdm_ht;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_tx_non_phy_agg {
+	__le32 ba_timeout;
+	__le32 ba_reschedule_frames;
+	__le32 scd_query_agg_frame_cnt;
+	__le32 scd_query_no_agg;
+	__le32 scd_query_agg;
+	__le32 scd_query_mismatch;
+	__le32 frame_not_ready;
+	__le32 underrun;
+	__le32 bt_prio_kill;
+	__le32 rx_ba_rsp_cnt;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+#if IWL == 4965
+	__le32 dump_msdu_cnt;
+	__le32 burst_abort_next_frame_mismatch_cnt;
+	__le32 burst_abort_missing_next_frame_cnt;
+	__le32 cts_timeout_collision;
+	__le32 ack_or_ba_timeout_collision;
+	struct statistics_tx_non_phy_agg agg;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
 #if IWL == 4965
 	__le32 reserved1;
+	__le32 reserved2;
 #endif
 } __attribute__ ((packed));
 
-struct iwl_add_sta_resp {
-	u8 status;
+struct statistics_general {
+	__le32 temperature;
+#if IWL == 4965
+	__le32 temperature_m;
+#endif
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+#if IWL == 4965
+	__le32 rx_enable_counter;
+	__le32 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+#endif
 } __attribute__ ((packed));
 
-#define ADD_STA_SUCCESS_MSK              0x1
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
 
-/**
- * struct iwl_powertable_cmd - Power Table Command & Response
- * @flags: See below:
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
  *
- * PM allow:
- *   bit 0 - '0' Driver not allow power management
- *           '1' Driver allow PM (use rest of parameters)
- * uCode send sleep notifications:
- *   bit 1 - '0' Don't send sleep notification
- *           '1' send sleep notification (SEND_PM_NOTIFICATION)
- * Sleep over DTIM
- *   bit 2 - '0' PM have to walk up every DTIM
- *           '1' PM could sleep over DTIM till listen Interval.
- * PCI power managed
- *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
- *           '1' !(PCI_LINK_CTRL & 0x1)
- * Force sleep Modes
- *   bit 31/30- '00' use both mac/xtal sleeps
- *              '01' force Mac sleep
- *              '10' force xtal sleep
- *              '11' Illegal set
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
  *
- * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
- * ucode assume sleep over DTIM is allowed and we don't need to wakeup
- * for every DTIM.
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
  */
-#define IWL_POWER_TABLE_SIZE 5
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __attribute__ ((packed));
 
-enum {
-	IWL_POWER_DRIVER_ALLOW_SLEEP_MSK = (1<<0),
-	IWL_POWER_SLEEP_OVER_DTIM_MSK = (1<<2),
-	IWL_POWER_PCI_PM_MSK = (1<<3),
-};
 
-struct iwl_powertable_cmd {
-#if IWL == 3945
-	__le32 flags;
-#elif IWL == 4965
-	__le16 flags;
-	u8 keep_alive_seconds;
-	u8 debug_flags;
-#endif
-	__le32 rx_data_timeout;
-	__le32 tx_data_timeout;
-	__le32 sleep_interval[IWL_POWER_TABLE_SIZE];
-#if IWL == 4965
-	__le32 keep_alive_beacons;
-#endif
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl_missed_beacon_notif {
+	__le32 consequtive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
 } __attribute__ ((packed));
 
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ *****************************************************************************/
 
-struct iwl_rate_scaling_info {
-	union {
-		struct {
-			u8 tx_rate;
-			u8 flags;
-		} s;
-		__le16 rate_n_flags;
-	};
-	u8 try_cnt;
-	u8 next_rate_index;
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+#define HD_TABLE_SIZE  (11)
+
+struct iwl_sensitivity_cmd {
+	__le16 control;
+	__le16 table[HD_TABLE_SIZE];
 } __attribute__ ((packed));
 
-/**
- * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
+struct iwl_calibration_cmd {
+	u8 opCode;
+	u8 flags;
+	__le16 reserved;
+	s8 diff_gain_a;
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
  *
- * NOTE: The table of rates passed to the uCode via the
- * RATE_SCALE command sets up the corresponding order of
- * rates used for all related commands, including rate
- * masks, etc.
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
  *
- * For example, if you set 9MB (PLCP 0x0f) as the first
- * rate in the rate table, the bit mask for that rate
- * when passed through ofdm_basic_rates on the REPLY_RXON
- * command would be bit 0 (1<<0)
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
  */
-struct iwl_rate_scaling_cmd {
-	u8 table_id;
-	u8 reserved[3];
-	struct iwl_rate_scaling_info table[IWL_MAX_RATES];
+struct iwl_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_packet {
+	__le32 len;
+	struct iwl_cmd_header hdr;
+	union {
+		struct iwl_alive_resp alive_frame;
+		struct iwl_rx_frame rx_frame;
+		struct iwl_tx_resp tx_resp;
+		struct iwl_spectrum_notification spectrum_notif;
+		struct iwl_csa_notification csa_notif;
+		struct iwl_error_resp err_resp;
+		struct iwl_card_state_notif card_state_notif;
+		struct iwl_beacon_notif beacon_status;
+		struct iwl_add_sta_resp add_sta;
+		struct iwl_sleep_notification sleep_notif;
+		struct iwl_spectrum_resp spectrum;
+		struct iwl_notif_statistics stats;
+#if IWL == 4965
+		struct iwl_compressed_ba_resp compressed_ba;
+		struct iwl_missed_beacon_notif missed_beacon;
+#endif
+		__le32 status;
+		u8 raw[0];
+	} u;
 } __attribute__ ((packed));
 
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl_rx_frame))
+
 #endif				/* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 19ea474..abd344c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -35,10 +35,18 @@ extern u32 iwl_debug_level;
 do { if (iwl_debug_level & (level)) \
   printk(KERN_ERR DRV_NAME": %c %s " fmt, \
 	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 #else
 static inline void IWL_DEBUG(int level, const char *fmt, ...)
 {
 }
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
 #endif				/* CONFIG_IWLWIFI_DEBUG */
 
 /*
@@ -58,11 +66,11 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...)
  *
  * To add your debug level to the list of levels seen when you perform
  *
- * % cat /proc/net/ipw/debug_level
+ * % cat /proc/net/iwl/debug_level
  *
  * you simply need to add your entry to the iwl_debug_levels array.
  *
- * If you do not see debug_level in /proc/net/ipw then you do not have
+ * If you do not see debug_level in /proc/net/iwl then you do not have
  * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
  *
  */
@@ -123,6 +131,7 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...)
 #define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
 #define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
 #define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
 #define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
 #define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
 #define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 19d7028..e473c97 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -69,6 +69,8 @@
  *
  */
 
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
 /* EEPROM field values */
 #define ANTENNA_SWITCH_NORMAL     0
 #define ANTENNA_SWITCH_INVERSE    1
@@ -142,7 +144,7 @@ struct iwl_eeprom_channel {
 struct iwl_eeprom_txpower_sample {
 	u8 gain_index;		/* index into power (gain) setup table ... */
 	s8 power;		/* ... for this pwr level for this chnl group */
-	__le16 v_det;		/* PA output voltage */
+	u16 v_det;		/* PA output voltage */
 } __attribute__ ((packed));
 
 /*
@@ -155,14 +157,14 @@ struct iwl_eeprom_txpower_sample {
  */
 struct iwl_eeprom_txpower_group {
 	struct iwl_eeprom_txpower_sample samples[5];	/* 5 power levels */
-	__le32 a, b, c, d, e;	/* coefficients for voltage->power
+	s32 a, b, c, d, e;	/* coefficients for voltage->power
 				 * formula (signed) */
-	__le32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
+	s32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
 					 * frequency (signed) */
 	s8 saturation_power;	/* highest power possible by h/w in this
 				 * band */
 	u8 group_channel;	/* "representative" channel # in this band */
-	__le16 temperature;	/* h/w temperature at factory calib this band
+	s16 temperature;	/* h/w temperature at factory calib this band
 				 * (signed) */
 } __attribute__ ((packed));
 
@@ -173,11 +175,11 @@ struct iwl_eeprom_txpower_group {
  * Data copied from EEPROM.
  */
 struct iwl_eeprom_temperature_corr {
-	__le32 Ta;
-	__le32 Tb;
-	__le32 Tc;
-	__le32 Td;
-	__le32 Te;
+	u32 Ta;
+	u32 Tb;
+	u32 Tc;
+	u32 Td;
+	u32 Te;
 } __attribute__ ((packed));
 
 #if IWL == 4965
@@ -187,32 +189,31 @@ struct iwl_eeprom_temperature_corr {
 #define EEPROM_TX_POWER_VERSION        (2)
 #define EEPROM_TX_POWER_VERSION_NEW    (5)
 
-struct iwl_eeprom_calib_measurement {
+struct iwl_eeprom_calib_measure {
 	u8 temperature;
 	u8 gain_idx;
 	u8 actual_pow;
 	s8 pa_det;
 } __attribute__ ((packed));
 
-struct iwl_eeprom_calib_channel_info {
+struct iwl_eeprom_calib_ch_info {
 	u8 ch_num;
-	struct iwl_eeprom_calib_measurement
-	 measurements[EEPROM_TX_POWER_TX_CHAINS][EEPROM_TX_POWER_MEASUREMENTS];
+	struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+		[EEPROM_TX_POWER_MEASUREMENTS];
 } __attribute__ ((packed));
 
 struct iwl_eeprom_calib_subband_info {
 	u8 ch_from;
 	u8 ch_to;
-	struct iwl_eeprom_calib_channel_info ch1;
-	struct iwl_eeprom_calib_channel_info ch2;
+	struct iwl_eeprom_calib_ch_info ch1;
+	struct iwl_eeprom_calib_ch_info ch2;
 } __attribute__ ((packed));
 
 struct iwl_eeprom_calib_info {
 	u8 saturation_power24;
 	u8 saturation_power52;
-	__le16 voltage;		/* signed */
-	struct iwl_eeprom_calib_subband_info
-	 band_info_tbl[EEPROM_TX_POWER_BANDS];
+	s16 voltage;		/* signed */
+	struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
 } __attribute__ ((packed));
 
 #endif
@@ -220,32 +221,32 @@ struct iwl_eeprom_calib_info {
 struct iwl_eeprom {
 	u8 reserved0[16];
 #define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
-	__le16 device_id;	/* abs.ofs: 16 */
+	u16 device_id;	/* abs.ofs: 16 */
 	u8 reserved1[2];
 #define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
-	__le16 pmc;		/* abs.ofs: 20 */
+	u16 pmc;		/* abs.ofs: 20 */
 	u8 reserved2[20];
 #define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
 	u8 mac_address[6];	/* abs.ofs: 42 */
 	u8 reserved3[58];
 #define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
-	__le16 board_revision;	/* abs.ofs: 106 */
+	u16 board_revision;	/* abs.ofs: 106 */
 	u8 reserved4[11];
 #define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
 	u8 board_pba_number[9];	/* abs.ofs: 119 */
 	u8 reserved5[8];
 #define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
-	__le16 version;		/* abs.ofs: 136 */
+	u16 version;		/* abs.ofs: 136 */
 #define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
 	u8 sku_cap;		/* abs.ofs: 138 */
 #define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
 	u8 leds_mode;		/* abs.ofs: 139 */
 #define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
-	__le16 oem_mode;
+	u16 oem_mode;
 #define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
-	__le16 wowlan_mode;	/* abs.ofs: 142 */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
 #define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
-	__le16 leds_time_interval;	/* abs.ofs: 144 */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
 #define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
 	u8 leds_off_time;	/* abs.ofs: 146 */
 #define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
@@ -259,7 +260,7 @@ struct iwl_eeprom {
 #else
 	u8 reserved6[8];
 #define EEPROM_4965_BOARD_REVISION          (2*0x4F)	/* 2 bytes */
-	__le16 board_revision_4965;	/* abs.ofs: 158 */
+	u16 board_revision_4965;	/* abs.ofs: 158 */
 	u8 reserved7[13];
 #define EEPROM_4965_BOARD_PBA               (2*0x56+1)	/* 9 bytes */
 	u8 board_pba_number_4965[9];	/* abs.ofs: 173 */
@@ -268,23 +269,23 @@ struct iwl_eeprom {
 #define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
 	u8 sku_id[4];		/* abs.ofs: 192 */
 #define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
-	__le16 band_1_count;	/* abs.ofs: 196 */
+	u16 band_1_count;	/* abs.ofs: 196 */
 #define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
 	struct iwl_eeprom_channel band_1_channels[14];	/* abs.ofs: 196 */
 #define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
-	__le16 band_2_count;	/* abs.ofs: 226 */
+	u16 band_2_count;	/* abs.ofs: 226 */
 #define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
 	struct iwl_eeprom_channel band_2_channels[13];	/* abs.ofs: 228 */
 #define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
-	__le16 band_3_count;	/* abs.ofs: 254 */
+	u16 band_3_count;	/* abs.ofs: 254 */
 #define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
 	struct iwl_eeprom_channel band_3_channels[12];	/* abs.ofs: 256 */
 #define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
-	__le16 band_4_count;	/* abs.ofs: 280 */
+	u16 band_4_count;	/* abs.ofs: 280 */
 #define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
 	struct iwl_eeprom_channel band_4_channels[11];	/* abs.ofs: 282 */
 #define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
-	__le16 band_5_count;	/* abs.ofs: 304 */
+	u16 band_5_count;	/* abs.ofs: 304 */
 #define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
 	struct iwl_eeprom_channel band_5_channels[6];	/* abs.ofs: 306 */
 
@@ -316,10 +317,10 @@ struct iwl_eeprom {
 	struct iwl_eeprom_channel band_52_channels[11];	/* abs.ofs: 336 */
 	u8 reserved12[6];
 #define EEPROM_CALIB_VERSION_OFFSET            (2*0xB6)	/* 2 bytes */
-	__le16 calib_version;	/* abs.ofs: 364 */
+	u16 calib_version;	/* abs.ofs: 364 */
 	u8 reserved13[2];
 #define EEPROM_SATURATION_POWER_OFFSET         (2*0xB8)	/* 2 bytes */
-	__le16 satruation_power;	/* abs.ofs: 368 */
+	u16 satruation_power;	/* abs.ofs: 368 */
 	u8 reserved14[94];
 #define EEPROM_IWL_CALIB_TXPOWER_OFFSET        (2*0xE8)	/* 48  bytes */
 	struct iwl_eeprom_calib_info calib_info;	/* abs.ofs: 464 */
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index c29a568..e2a8d95 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -30,6 +30,8 @@
 #ifndef __iwl_helpers_h__
 #define __iwl_helpers_h__
 
+#include <linux/ctype.h>
+
 /*
  * The structures defined by the hardware/uCode interface
  * have bit-wise operations.  For each bit-field there is
@@ -57,13 +59,14 @@
  * NOTE:  If used from IWL_GET_BITS then pos and len are compile-constants and
  *        will collapse to minimal code by the compiler.
  */
-#define iwl_get_bits(src, pos, len)   \
-({                                    \
-	u32 __tmp = le32_to_cpu(src); \
-	__tmp >>= pos;                \
-	__tmp &= (1UL << len) - 1;    \
-	__tmp;                        \
-})
+static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
+{
+	u32 tmp = le32_to_cpu(src);
+
+	tmp >>= pos;
+	tmp &= (1UL << len) - 1;
+	return tmp;
+}
 
 /**
  * iwl_set_bits - Set a hardware bit-field value
@@ -78,13 +81,23 @@
  * NOTE:  If used IWL_SET_BITS pos and len will be compile-constants and
  *        will collapse to minimal code by the compiler.
  */
-#define iwl_set_bits(dst, pos, len, val)                 \
-({                                                       \
-	u32 __tmp = le32_to_cpu(*dst);                   \
-	__tmp &= ~((1ULL << (pos+len)) - (1 << pos));    \
-	__tmp |= (val & ((1UL << len) - 1)) << pos;      \
-	*dst = cpu_to_le32(__tmp);                       \
-})
+static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
+{
+	u32 tmp = le32_to_cpu(*dst);
+
+	tmp &= ~(((1UL << len) - 1) << pos);
+	tmp |= (val & ((1UL << len) - 1)) << pos;
+	*dst = cpu_to_le32(tmp);
+}
+
+static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
+{
+	u16 tmp = le16_to_cpu(*dst);
+
+	tmp &= ~((1UL << (pos + len)) - (1UL << pos));
+	tmp |= (val & ((1UL << len) - 1)) << pos;
+	*dst = cpu_to_le16(tmp);
+}
 
 /*
  * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
@@ -108,46 +121,18 @@
  * and iwl_{get,set}_bits.
  *
  */
-#define _IWL_SET_BITS(s, d, o, l, v) \
-	iwl_set_bits(&s.d, o, l, v)
-
 #define IWL_SET_BITS(s, sym, v) \
-	_IWL_SET_BITS((s), IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
-		      IWL_ ## sym ## _LEN, (v))
+	iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+		     IWL_ ## sym ## _LEN, (v))
 
-#define _IWL_GET_BITS(s, v, o, l) \
-	iwl_get_bits(s.v, o, l)
+#define IWL_SET_BITS16(s, sym, v) \
+	iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+		       IWL_ ## sym ## _LEN, (v))
 
 #define IWL_GET_BITS(s, sym) \
-	_IWL_GET_BITS((s), IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+	iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
 		      IWL_ ## sym ## _LEN)
 
-/*
- * make C=2 CF=-Wall will complain if you use ARRAY_SIZE on global data
- */
-#define GLOBAL_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-/* Debug and printf string expansion helpers for printing bitfields */
-#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
-#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
-#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
-
-#define BITC(x, y) (((x>>y) & 1) ? '1' : '0')
-#define BIT_ARG8(x) \
-BITC(x, 7), BITC(x, 6), BITC(x, 5), BITC(x, 4), \
-BITC(x, 3), BITC(x, 2), BITC(x, 1), BITC(x, 0)
-
-#define BIT_ARG16(x) \
-BITC(x, 15), BITC(x, 14), BITC(x, 13), BITC(x, 12), \
-BITC(x, 11), BITC(x, 10), BITC(x, 9), BITC(x, 8), \
-BIT_ARG8(x)
-
-#define BIT_ARG32(x) \
-BITC(x, 31), BITC(x, 30), BITC(x, 29), BITC(x, 28), \
-BITC(x, 27), BITC(x, 26), BITC(x, 25), BITC(x, 24), \
-BITC(x, 23), BITC(x, 22), BITC(x, 21), BITC(x, 20), \
-BITC(x, 19), BITC(x, 18), BITC(x, 17), BITC(x, 16), \
-BIT_ARG16(x)
 
 #define KELVIN_TO_CELSIUS(x) ((x)-273)
 #define CELSIUS_TO_KELVIN(x) ((x)+273)
@@ -160,138 +145,102 @@ static inline struct ieee80211_conf *ieee80211_get_hw_conf(
 	return &hw->conf;
 }
 
-static inline const struct ieee80211_hw_mode *iwl_get_hw_mode(
-	struct iwl_priv *priv, int mode)
-{
-	int i;
-
-	for (i = 0; i < 3; i++)
-		if (priv->modes[i].mode == mode)
-			return &priv->modes[i];
-
-	return NULL;
-}
-
-#define WLAN_FC_GET_TYPE(fc)    (((fc) & IEEE80211_FCTL_FTYPE))
-#define WLAN_FC_GET_STYPE(fc)   (((fc) & IEEE80211_FCTL_STYPE))
-#define WLAN_GET_SEQ_FRAG(seq)  ((seq) & 0x000f)
-#define WLAN_GET_SEQ_SEQ(seq)   ((seq) >> 4)
-
 #define QOS_CONTROL_LEN 2
 
-static inline __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
-	u16 fc = le16_to_cpu(hdr->frame_control);
-	int hdr_len = ieee80211_get_hdrlen(fc);
-	if ( (fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA|IEEE80211_FTYPE_DATA))
-		return (u16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
-	return NULL;
-}
-
 #define IEEE80211_STYPE_BACK_REQ	0x0080
 #define IEEE80211_STYPE_BACK		0x0090
 
-#define ieee80211_is_back_request(fc) \
-	((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) && \
-	(WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BACK_REQ))
 
-#define ieee80211_is_probe_response(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-    ( WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_PROBE_RESP ))
-
-#define ieee80211_is_probe_request(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-    ( WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_PROBE_REQ ))
+static inline int ieee80211_is_management(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT;
+}
 
-#define ieee80211_is_beacon(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-    ( WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON ))
+static inline int ieee80211_is_control(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL;
+}
 
-#define ieee80211_is_atim(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-    ( WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ATIM ))
+static inline int ieee80211_is_data(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA;
+}
 
-#define ieee80211_is_management(fc) \
-   (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT)
+static inline int ieee80211_is_back_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ);
+}
 
-#define ieee80211_is_control(fc) \
-   (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL)
+static inline int ieee80211_is_probe_response(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP);
+}
 
-#define ieee80211_is_data(fc) \
-   (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA)
+static inline int ieee80211_is_probe_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ);
+}
 
-#define ieee80211_is_assoc_request(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ASSOC_REQ))
+static inline int ieee80211_is_beacon(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON);
+}
 
-#define ieee80211_is_assoc_response(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ASSOC_RESP))
+static inline int ieee80211_is_atim(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM);
+}
 
-#define ieee80211_is_auth(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ASSOC_REQ))
+static inline int ieee80211_is_assoc_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
 
-#define ieee80211_is_deauth(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ASSOC_REQ))
+static inline int ieee80211_is_assoc_response(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP);
+}
 
-#define ieee80211_is_disassoc(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_ASSOC_REQ))
+static inline int ieee80211_is_auth(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
 
-#define ieee80211_is_reassoc_request(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_REASSOC_REQ))
+static inline int ieee80211_is_deauth(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
 
-#define ieee80211_is_reassoc_response(fc) \
-   ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT) && \
-   (WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_REASSOC_RESP))
+static inline int ieee80211_is_disassoc(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
 
-static inline int iwl_is_empty_essid(const char *essid, int essid_len)
+static inline int ieee80211_is_reassoc_request(u16 fc)
 {
-	/* Single white space is for Linksys APs */
-	if (essid_len == 1 && essid[0] == ' ')
-		return 1;
-
-	/* Otherwise, if the entire essid is 0, we assume it is hidden */
-	while (essid_len) {
-		essid_len--;
-		if (essid[essid_len] != '\0')
-			return 0;
-	}
-
-	return 1;
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ);
 }
 
-static inline int iwl_check_bits(unsigned long field, unsigned long mask)
+static inline int ieee80211_is_reassoc_response(u16 fc)
 {
-	return ((field & mask) == mask) ? 1 : 0;
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
 }
 
-static inline const char *iwl_escape_essid(const char *essid, u8 essid_len)
+static inline int iwl_check_bits(unsigned long field, unsigned long mask)
 {
-	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-	const char *s = essid;
-	char *d = escaped;
-
-	if (iwl_is_empty_essid(essid, essid_len)) {
-		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
-		return escaped;
-	}
-
-	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
-	while (essid_len--) {
-		if (*s == '\0') {
-			*d++ = '\\';
-			*d++ = '0';
-			s++;
-		} else {
-			*d++ = *s++;
-		}
-	}
-	*d = '\0';
-	return escaped;
+	return ((field & mask) == mask) ? 1 : 0;
 }
 
 static inline unsigned long elapsed_jiffies(unsigned long start,
@@ -303,62 +252,4 @@ static inline unsigned long elapsed_jiffies(unsigned long start,
 	return end + (MAX_JIFFY_OFFSET - start);
 }
 
-#include <linux/ctype.h>
-
-static inline int snprint_line(char *buf, size_t count,
-			       const u8 * data, u32 len, u32 ofs)
-{
-	int out, i, j, l;
-	char c;
-
-	out = snprintf(buf, count, "%08X", ofs);
-
-	for (l = 0, i = 0; i < 2; i++) {
-		out += snprintf(buf + out, count - out, " ");
-		for (j = 0; j < 8 && l < len; j++, l++)
-			out +=
-			    snprintf(buf + out, count - out, "%02X ",
-				     data[(i * 8 + j)]);
-		for (; j < 8; j++)
-			out += snprintf(buf + out, count - out, "   ");
-	}
-	out += snprintf(buf + out, count - out, " ");
-	for (l = 0, i = 0; i < 2; i++) {
-		out += snprintf(buf + out, count - out, " ");
-		for (j = 0; j < 8 && l < len; j++, l++) {
-			c = data[(i * 8 + j)];
-			if (!isascii(c) || !isprint(c))
-				c = '.';
-
-			out += snprintf(buf + out, count - out, "%c", c);
-		}
-
-		for (; j < 8; j++)
-			out += snprintf(buf + out, count - out, " ");
-	}
-
-	return out;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void printk_buf(int level, const void *p, u32 len)
-{
-	const u8 *data = p;
-	char line[81];
-	u32 ofs = 0;
-	if (!(iwl_debug_level & level))
-		return;
-
-	while (len) {
-		snprint_line(line, sizeof(line), &data[ofs],
-			     min(len, 16U), ofs);
-		printk(KERN_DEBUG "%s\n", line);
-		ofs += 16;
-		len -= min(len, 16U);
-	}
-}
-#else
-#define printk_buf(level, p, len) do {} while (0)
-#endif
-
 #endif				/* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
index e0facac..1aa6fcd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-hw.h
@@ -64,18 +64,19 @@
 #define __iwlwifi_hw_h__
 
 /*
- * This file defines hardware / uCode API constants, enums,
- * and inline functions.
+ * This file defines hardware constants common to 3945 and 4965.
  *
- * For common usage code where the implementation can be the same
- * with the exception of a different value going into a constant
- * those constants are defined in this file.
+ * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h,
+ * although this file contains a few definitions for which the .c
+ * implementation is the same for 3945 and 4965, except for the value of
+ * a constant.
  *
- * NOTE:  DO NOT PUT IMPLEMENTATION SPECIFIC DECLRATIONS HERE
+ * uCode API constants are defined in iwl-commands.h.
  *
- * The iwl-*hw.h (and files they include) files should remain OS driver
- * implementation independent, declaring only the hardware/uCode API
+ * NOTE:  DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE
  *
+ * The iwl-*hw.h (and files they include) files should remain OS/driver
+ * implementation independent, declaring only the hardware interface.
  */
 
 /* uCode queue management definitions */
@@ -83,6 +84,7 @@
 #define IWL_CMD_FIFO_NUM        4
 #define IWL_BACK_QUEUE_FIRST_ID 7
 
+/* Tx rates */
 #define IWL_CCK_RATES 4
 #define IWL_OFDM_RATES 8
 
@@ -94,12 +96,9 @@
 
 #define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
 
-/*
- *  Time constants
- */
+/* Time constants */
 #define SHORT_SLOT_TIME 9
 #define LONG_SLOT_TIME 20
-#define OFDM_SYMBOL_TIME 4
 
 /* RSSI to dBm */
 #if IWL == 3945
@@ -111,658 +110,13 @@
 #include "iwl-eeprom.h"
 #include "iwl-commands.h"
 
-union tsf {
-	u8 byte[8];
-	__le16 word[4];
-	__le32 dw[2];
-};
-
-/*
- * Alive Command & Response
- */
-
-#define UCODE_VALID_OK      (0x1)
-#define INITIALIZE_SUBTYPE    (9)
-
-struct iwl_alive_resp {
-	u8 ucode_minor;
-	u8 ucode_major;
-	__le16 reserved1;
-	u8 sw_rev[8];
-	u8 ver_type;
-	u8 ver_subtype;
-	__le16 reserved2;
-	__le32 log_event_table_ptr;
-	__le32 error_event_table_ptr;
-	__le32 timestamp;
-	__le32 is_valid;
-} __attribute__ ((packed));
-
-struct iwl_init_alive_resp {
-	u8 ucode_minor;
-	u8 ucode_major;
-	__le16 reserved1;
-	u8 sw_rev[8];
-	u8 ver_type;
-	u8 ver_subtype;
-	__le16 reserved2;
-	__le32 log_event_table_ptr;
-	__le32 error_event_table_ptr;
-	__le32 timestamp;
-	__le32 is_valid;
-
-#if IWL == 4965
-	/* calibration values from "initialize" uCode */
-	__le32 voltage;		/* signed */
-	__le32 therm_r1[2];	/* signed 1st for normal, 2nd for FAT channel */
-	__le32 therm_r2[2];	/* signed */
-	__le32 therm_r3[2];	/* signed */
-	__le32 therm_r4[2];	/* signed */
-	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
-				 * 2 Tx chains */
-#endif
-} __attribute__ ((packed));
-
-/*
- * Error Command & Response
- */
-
-struct iwl_error_resp {
-	__le32 error_type;
-	u8 cmd_id;
-	u8 reserved1;
-	__le16 bad_cmd_seq_num;
-#if IWL == 3945
-	__le16 reserved2;
-#endif
-	__le32 error_info;
-	union tsf timestamp;
-} __attribute__ ((packed));
-
 #define PCI_LINK_CTRL      0x0F0
-
-/*
- * Rx config defines & structure
- */
-/* rx_config device types  */
-enum {
-	RXON_DEV_TYPE_AP = 1,
-	RXON_DEV_TYPE_ESS = 3,
-	RXON_DEV_TYPE_IBSS = 4,
-	RXON_DEV_TYPE_SNIFFER = 6,
-};
-
-/* rx_config flags */
-enum {
-	/* band & modulation selection */
-	RXON_FLG_BAND_24G_MSK = (1 << 0),
-	RXON_FLG_CCK_MSK = (1 << 1),
-	/* auto detection enable */
-	RXON_FLG_AUTO_DETECT_MSK = (1 << 2),
-	/* TGg protection when tx */
-	RXON_FLG_TGG_PROTECT_MSK = (1 << 3),
-	/* cck short slot & preamble */
-	RXON_FLG_SHORT_SLOT_MSK = (1 << 4),
-	RXON_FLG_SHORT_PREAMBLE_MSK = (1 << 5),
-	/* antenna selection */
-	RXON_FLG_DIS_DIV_MSK = (1 << 7),
-	RXON_FLG_ANT_SEL_MSK = 0x0f00,
-	RXON_FLG_ANT_A_MSK = (1 << 8),
-	RXON_FLG_ANT_B_MSK = (1 << 9),
-	/* radar detection enable */
-	RXON_FLG_RADAR_DETECT_MSK = (1 << 12),
-	RXON_FLG_TGJ_NARROW_BAND_MSK = (1 << 13),
-	/* rx response to host with 8-byte TSF
-	 * (according to ON_AIR deassertion) */
-	RXON_FLG_TSF2HOST_MSK = (1 << 15)
-};
-
-/* rx_config filter flags */
-enum {
-	/* accept all data frames */
-	RXON_FILTER_PROMISC_MSK = (1 << 0),
-	/* pass control & management to host */
-	RXON_FILTER_CTL2HOST_MSK = (1 << 1),
-	/* accept multi-cast */
-	RXON_FILTER_ACCEPT_GRP_MSK = (1 << 2),
-	/* don't decrypt uni-cast frames */
-	RXON_FILTER_DIS_DECRYPT_MSK = (1 << 3),
-	/* don't decrypt multi-cast frames */
-	RXON_FILTER_DIS_GRP_DECRYPT_MSK = (1 << 4),
-	/* STA is associated */
-	RXON_FILTER_ASSOC_MSK = (1 << 5),
-	/* transfer to host non bssid beacons in associated state */
-	RXON_FILTER_BCON_AWARE_MSK = (1 << 6)
-};
-
-/*
- * RXON-Timings Command & Response
- */
-struct iwl_rxon_time_cmd {
-	union tsf timestamp;
-	__le16 beacon_interval;
-	__le16 atim_window;
-	__le32 beacon_init_val;
-	__le16 listen_interval;
-	__le16 reserved;
-} __attribute__ ((packed));
-
-/*
- * beacon QOS parameters Command & Response
- */
-struct iwl_ac_qos {
-	__le16 cw_min;
-	__le16 cw_max;
-	u8 aifsn;
-	u8 reserved1;
-	__le16 edca_txop;
-} __attribute__ ((packed));
-
-/* QoS flags defines */
-#define MH_QOS_TXOP_TYPE_MSK 0x10
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK 0x1
-#define QOS_PARAM_FLG_TGN_MSK 0x2
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK MH_QOS_TXOP_TYPE_MSK
-
-/*
- *  TXFIFO Queue number defines
- */
-/* number of Access categories (AC) (EDCA), queues 0..3 */
-#define AC_NUM                4
-/* total number of queues */
-#define QUEUE_NUM             7
-/* command queue number */
-
-struct iwl_qosparam_cmd {
-	__le32 qos_flags;
-	struct iwl_ac_qos ac[AC_NUM];
-} __attribute__ ((packed));
-
-/*
- * Multi station support
- */
-#if IWL == 3945
-enum {
-	IWL_AP_ID = 0,
-	IWL_MULTICAST_ID,
-	IWL_STA_ID,
-	IWL_BROADCAST_ID = 24,
-	IWL_STATION_COUNT = 25,
-	IWL_INVALID_STATION
-};
-#elif IWL == 4965
-enum {
-	IWL_AP_ID = 0,
-	IWL_MULTICAST_ID,
-	IWL_STA_ID,
-	IWL_BROADCAST_ID = 31,
-	IWL_STATION_COUNT = 32,
-	IWL_INVALID_STATION
-};
-#endif
-
-#define STA_CONTROL_MODIFY_MSK             0x01
-
-/* key flags */
-enum {
-	STA_KEY_FLG_ENCRYPT_MSK = 0x7,
-	STA_KEY_FLG_NO_ENC = 0x0,
-	STA_KEY_FLG_WEP = 0x1,
-	STA_KEY_FLG_CCMP = 0x2,
-	STA_KEY_FLG_TKIP = 0x3,
-
-	STA_KEY_FLG_KEYID_POS = 8,
-	STA_KEY_FLG_INVALID = 0x0800,
-};
-
-/* modify flags  */
-enum {
-	STA_MODIFY_KEY_MASK = 0x01,
-	STA_MODIFY_TID_DISABLE_TX = 0x02,
-	STA_MODIFY_TX_RATE_MSK = 0x04
-};
-
-/*
- * Antenna masks:
- * bit14:15 01 B inactive, A active
- *          10 B active, A inactive
- *          11 Both active
- */
-#define RATE_MCS_ANT_A_POS 14
-#define RATE_MCS_ANT_B_POS 15
-#define RATE_MCS_ANT_A_MSK 0x4000
-#define RATE_MCS_ANT_B_MSK 0x8000
-#define RATE_MCS_ANT_AB_MSK 0xc000
-
-/*
- * WEP/CKIP group key command
- */
-struct iwl_key {
-	u8 index;
-	u8 reserved[3];
-	__le32 size;
-	u8 key[16];
-} __attribute__ ((packed));
-
-struct iwl_key_cmd {
-	u8 count;
-	u8 decrypt_type;
-	u8 reserved[2];
-	struct iwl_key key[4];
-} __attribute__ ((packed));
-
-struct iwl_rx_frame_stats {
-	u8 phy_count;
-	u8 id;
-	u8 rssi;
-	u8 agc;
-	__le16 sig_avg;
-	__le16 noise_diff;
-	u8 payload[0];
-} __attribute__ ((packed));
-
-struct iwl_rx_frame_hdr {
-	__le16 channel;
-	__le16 phy_flags;
-	u8 reserved1;
-	u8 rate;
-	__le16 len;
-	u8 payload[0];
-} __attribute__ ((packed));
-
-enum {
-	RX_RES_STATUS_NO_CRC32_ERROR = (1 << 0),
-	RX_RES_STATUS_NO_RXE_OVERFLOW = (1 << 1),
-};
-
-enum {
-	RX_RES_PHY_FLAGS_BAND_24_MSK = (1 << 0),
-	RX_RES_PHY_FLAGS_MOD_CCK_MSK = (1 << 1),
-	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK = (1 << 2),
-	RX_RES_PHY_FLAGS_NARROW_BAND_MSK = (1 << 3),
-	RX_RES_PHY_FLAGS_ANTENNA_MSK = 0xf0,
-
-	RX_RES_STATUS_SEC_TYPE_MSK = (0x7 << 8),
-	RX_RES_STATUS_SEC_TYPE_NONE = (STA_KEY_FLG_NO_ENC << 8),
-	RX_RES_STATUS_SEC_TYPE_WEP = (STA_KEY_FLG_WEP << 8),
-	RX_RES_STATUS_SEC_TYPE_TKIP = (STA_KEY_FLG_TKIP << 8),
-	RX_RES_STATUS_SEC_TYPE_CCMP = (STA_KEY_FLG_CCMP << 8),
-
-	RX_RES_STATUS_DECRYPT_TYPE_MSK = (0x3 << 11),
-	RX_RES_STATUS_NOT_DECRYPT = (0x0 << 11),
-	RX_RES_STATUS_DECRYPT_OK = (0x3 << 11),
-	RX_RES_STATUS_BAD_ICV_MIC = (0x1 << 11),
-	RX_RES_STATUS_BAD_KEY_TTAK = (0x2 << 11),
-};
-
-struct iwl_rx_frame_end {
-	__le32 status;
-	__le64 timestamp;
-	__le32 beacon_timestamp;
-} __attribute__ ((packed));
-
-/* NOTE:  DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count */
-struct iwl_rx_frame {
-	struct iwl_rx_frame_stats stats;
-	struct iwl_rx_frame_hdr hdr;
-	struct iwl_rx_frame_end end;
-} __attribute__ ((packed));
-
-/*
- * Tx Power Table Command
- */
-struct iwl_power_per_rate {
-	u8 rate;		/* plcp */
-	struct iwl_tx_power tpc;
-	u8 reserved;
-} __attribute__ ((packed));
-
-struct iwl_txpowertable_cmd {
-	u8 band;
-	u8 reserved;
-	__le16 channel;
-	struct iwl_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
-
-/*
- * Scan Request Commands , Responses  & Notifications
- */
-
-/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS        0x1
-
-struct iwl_scanreq_notification {
-	__le32 status;
-} __attribute__ ((packed));
-
-struct iwl_scanstart_notification {
-	__le32 tsf_low;
-	__le32 tsf_high;
-	__le32 beacon_timer;
-	u8 channel;
-	u8 band;
-	u8 reserved[2];
-	__le32 status;
-} __attribute__ ((packed));
-
-#define  SCAN_OWNER_STATUS 0x1;
-#define  MEASURE_OWNER_STATUS 0x2;
-
-#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
-struct iwl_scanresults_notification {
-	u8 channel;
-	u8 band;
-	u8 reserved[2];
-	__le32 tsf_low;
-	__le32 tsf_high;
-	__le32 statistics[NUMBER_OF_STATISTICS];
-} __attribute__ ((packed));
-
-struct iwl_scancomplete_notification {
-	u8 scanned_channels;
-	u8 status;
-	u8 reserved;
-	u8 last_channel;
-	__le32 tsf_low;
-	__le32 tsf_high;
-} __attribute__ ((packed));
-
-/* complete notification statuses */
-#define ABORT_STATUS            0x2
-
-/*
- * LEDs Command & Response
- */
-struct iwl_led_cmd {
-	__le32 interval;
-	u8 id;
-	u8 off;
-	u8 on;
-	u8 reserved;
-} __attribute__ ((packed));
-
-/*
- * card_state Command and Notification
- */
-
-#define CARD_STATE_CMD_DISABLE 0x00
-#define CARD_STATE_CMD_ENABLE 0x01
-
-struct iwl_card_state_notif {
-	__le32 flags;
-} __attribute__ ((packed));
-
-#define HW_CARD_DISABLED   0x01
-#define SW_CARD_DISABLED   0x02
-#define RF_CARD_DISABLED   0x04
-#define RXON_CARD_DISABLED 0x10
-
-/*
- * Tx Beacon Command & Response
- */
-struct iwl_beacon_notif {
-	struct iwl_tx_resp beacon_notify_hdr;
-	__le32 low_tsf;
-	__le32 high_tsf;
-	__le32 ibss_mgr_status;
-} __attribute__ ((packed));
-
-struct iwl_tx_beacon_cmd {
-	struct iwl_tx_cmd tx;
-	__le16 tim_idx;
-	u8 tim_size;
-	u8 reserved1;
-	struct ieee80211_hdr frame[0];	/* beacon frame */
-} __attribute__ ((packed));
-
-/*
- * Spectrum Management
- */
-#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
-				 RXON_FILTER_CTL2HOST_MSK        | \
-				 RXON_FILTER_ACCEPT_GRP_MSK      | \
-				 RXON_FILTER_DIS_DECRYPT_MSK     | \
-				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
-				 RXON_FILTER_ASSOC_MSK           | \
-				 RXON_FILTER_BCON_AWARE_MSK)
-
-struct iwl_measure_channel {
-	__le32 duration;	/* measurement duration in extended beacon
-				 * format */
-	u8 channel;		/* channel to measure */
-	u8 type;		/* see enum iwl_measure_type */
-	__le16 reserved;
-} __attribute__ ((packed));
-
-struct iwl_spectrum_cmd {
-	__le16 len;		/* number of bytes starting from token */
-	u8 token;		/* token id */
-	u8 id;			/* measurement id -- 0 or 1 */
-	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
-	u8 periodic;		/* 1 = periodic */
-	__le16 path_loss_timeout;
-	__le32 start_time;	/* start time in extended beacon format */
-	__le32 reserved2;
-	__le32 flags;		/* rxon flags */
-	__le32 filter_flags;	/* rxon filter flags */
-	__le16 channel_count;	/* minimum 1, maximum 10 */
-	__le16 reserved3;
-	struct iwl_measure_channel channels[10];
-} __attribute__ ((packed));
-
-struct iwl_spectrum_resp {
-	u8 token;
-	u8 id;			/* id of the prior command replaced, or 0xff */
-	__le16 status;		/* 0 - command will be handled
-				 * 1 - cannot handle (conflicts with another
-				 *     measurement) */
-} __attribute__ ((packed));
-
-enum iwl_measurement_state {
-	IWL_MEASUREMENT_START = 0,
-	IWL_MEASUREMENT_STOP = 1,
-};
-
-enum iwl_measurement_status {
-	IWL_MEASUREMENT_OK = 0,
-	IWL_MEASUREMENT_CONCURRENT = 1,
-	IWL_MEASUREMENT_CSA_CONFLICT = 2,
-	IWL_MEASUREMENT_TGH_CONFLICT = 3,
-	/* 4-5 reserved */
-	IWL_MEASUREMENT_STOPPED = 6,
-	IWL_MEASUREMENT_TIMEOUT = 7,
-	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
-};
-
-#define NUM_ELEMENTS_IN_HISTOGRAM 8
-
-struct iwl_measurement_histogram {
-	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
-	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
-} __attribute__ ((packed));
-
-/* clear channel availability counters */
-struct iwl_measurement_cca_counters {
-	__le32 ofdm;
-	__le32 cck;
-} __attribute__ ((packed));
-
-enum iwl_measure_type {
-	IWL_MEASURE_BASIC = (1 << 0),
-	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
-	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
-	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
-	IWL_MEASURE_FRAME = (1 << 4),
-	/* bits 5:6 are reserved */
-	IWL_MEASURE_IDLE = (1 << 7),
-};
-
-struct iwl_spectrum_notification {
-	u8 id;			/* measurement id -- 0 or 1 */
-	u8 token;
-	u8 channel_index;	/* index in measurement channel list */
-	u8 state;		/* 0 - start, 1 - stop */
-	__le32 start_time;	/* lower 32-bits of TSF */
-	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
-	u8 channel;
-	u8 type;		/* see enum iwl_measurement_type */
-	u8 reserved1;
-	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
-	 * valid if applicable for measurement type requested. */
-	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
-	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
-	__le32 cca_time;	/* channel load time in usecs */
-	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
-				 * unidentified */
-	u8 reserved2[3];
-	struct iwl_measurement_histogram histogram;
-	__le32 stop_time;	/* lower 32-bits of TSF */
-	__le32 status;		/* see iwl_measurement_status */
-} __attribute__ ((packed));
-
-struct iwl_csa_notification {
-	__le16 band;
-	__le16 channel;
-	__le32 status;		/* 0 - OK, 1 - fail */
-} __attribute__ ((packed));
-
-struct iwl_sleep_notification {
-	u8 pm_sleep_mode;
-	u8 pm_wakeup_src;
-	__le16 reserved;
-	__le32 sleep_time;
-	__le32 tsf_low;
-	__le32 bcon_timer;
-} __attribute__ ((packed));
-
-enum {
-	IWL_PM_NO_SLEEP = 0,
-	IWL_PM_SLP_MAC = 1,
-	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
-	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
-	IWL_PM_SLP_PHY = 4,
-	IWL_PM_SLP_REPENT = 5,
-	IWL_PM_WAKEUP_BY_TIMER = 6,
-	IWL_PM_WAKEUP_BY_DRIVER = 7,
-	IWL_PM_WAKEUP_BY_RFKILL = 8,
-	/* 3 reserved */
-	IWL_PM_NUM_OF_MODES = 12,
-};
-
-struct iwl_bt_cmd {
-	u8 flags;
-	u8 lead_time;
-	u8 max_kill;
-	u8 reserved;
-	__le32 kill_ack_mask;
-	__le32 kill_cts_mask;
-} __attribute__ ((packed));
-
-struct rx_phy_statistics {
-	__le32 ina_cnt;		/* number of INA signal assertions (enter RX) */
-	__le32 fina_cnt;	/* number of FINA signal assertions
-				 * (false_alarm = INA - FINA) */
-	__le32 plcp_err;	/* number of bad PLCP header detections
-				 * (PLCP_good = FINA - PLCP_bad) */
-	__le32 crc32_err;	/* number of CRC32 error detections */
-	__le32 overrun_err;	/* number of Overrun detections (this is due
-				 * to RXE sync overrun) */
-	__le32 early_overrun_err;	/* number of times RX is aborted at the
-					 * start because rxfifo is full behind
-					 * threshold */
-	__le32 crc32_good;	/* number of frames with good CRC */
-	__le32 false_alarm_cnt;	/* number of times false alarm was
-				 * detected (i.e. INA w/o FINA) */
-	__le32 fina_sync_err_cnt;	/* number of times sync problem between
-					 * HW & SW FINA counter was found */
-	__le32 sfd_timeout;	/* number of times got SFD timeout
-				 * (i.e. got FINA w/o rx_frame) */
-	__le32 fina_timeout;	/* number of times got FINA timeout (i.e. got
-				 * INA w/o FINA, w/o false alarm) */
-	__le32 unresponded_rts;	/* un-responded RTS, due to NAV not zero */
-	__le32 rxe_frame_limit_overrun;	/* RXE got frame limit overrun */
-	__le32 sent_ack_cnt;	/* ACK TX count */
-	__le32 sent_cts_cnt;	/* CTS TX count */
-} __attribute__ ((packed));
-
-struct rx_non_phy_statistics {
-	__le32 bogus_cts;	/* CTS received when not expecting CTS */
-	__le32 bogus_ack;	/* ACK received when not expecting ACK */
-	__le32 non_bssid_frames;/* number of frames with BSSID that doesn't
-				 * belong to the STA BSSID */
-	__le32 filtered_frames;	/* count frames that were dumped in the
-				 * filtering process */
-} __attribute__ ((packed));
-
-struct rx_statistics {
-	struct rx_phy_statistics ofdm;
-	struct rx_phy_statistics cck;
-	struct rx_non_phy_statistics general;
-} __attribute__ ((packed));
-
-struct tx_non_phy_statistics {
-	__le32 preamble_cnt;	/* number of times preamble was asserted */
-	__le32 rx_detected_cnt;	/* number of times TX was delayed to RX
-				 * detected */
-	__le32 bt_prio_defer_cnt;/* number of times TX was deferred due to
-				  * BT priority */
-	__le32 bt_prio_kill_cnt;/* number of times TX was killed due to BT
-				 * priority */
-	__le32 few_bytes_cnt;	/* number of times TX was delayed due to not
-				 * enough bytes in TXFIFO */
-	__le32 cts_timeout;	/* timeout when waiting for CTS */
-	__le32 ack_timeout;	/* timeout when waiting for ACK */
-	__le32 expected_ack_cnt;/* number of data frames that need ack or
-				 * rts that need cts */
-	__le32 actual_ack_cnt;	/* number of expected ack or cts that were
-				 * actually received */
-} __attribute__ ((packed));
-
-struct tx_statistics {
-	struct tx_non_phy_statistics general;
-} __attribute__ ((packed));
-
-struct debug_statistics {
-	__le32 cont_burst_chk_cnt;/* number of times continuation or
-				   * fragmentation or bursting was checked */
-	__le32 cont_burst_cnt;	/* number of times continuation,
-				 * fragmentation, or bursting was successful */
-	__le32 reserved[4];
-} __attribute__ ((packed));
-
-#define IWL_TEMP_CONVERT 260
-
-struct general_statistics {
-	__le32 temperature;
-	struct debug_statistics debug;
-	__le32 usec_sleep;   /* < usecs NIC was asleep. Running counter. */
-	__le32 slots_out;    /* < slots NIC was out of serving channel */
-	__le32 slots_idle;   /* < slots NIC was idle */
-} __attribute__ ((packed));
-
-struct statistics {
-	__le32 flags;
-	struct rx_statistics rx_statistics;
-	struct tx_statistics tx_statistics;
-	struct general_statistics general_statistics;
-} __attribute__ ((packed));
-
-/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
- * then this notification will be sent. */
-#define CONSECUTIVE_MISSED_BCONS_TH 20
-
-/* register and values */
-/* base */
-#define CSR_BASE    (0x0)
-#define HBUS_BASE   (0x400)
-#define FH_BASE     (0x800)
-
-#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
 
 /*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
 
 #define CSR_SW_VER              (CSR_BASE+0x000)
 #define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
@@ -773,55 +127,129 @@ struct statistics {
 #define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
 #define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
 #define CSR_GP_CNTRL            (CSR_BASE+0x024)
-/* 0x028 - reserved */
+#define CSR_HW_REV              (CSR_BASE+0x028)
 #define CSR_EEPROM_REG          (CSR_BASE+0x02c)
 #define CSR_EEPROM_GP           (CSR_BASE+0x030)
-#define   CSR_EEPROM_GP_VALID_MSK	0x00000007
-#define   CSR_EEPROM_GP_BAD_SIGNATURE	0x00000000
-#if IWL == 3945
-#define   CSR_EEPROM_GP_OWNER		0x00000180
-#endif
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
 #define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
 #define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
 #define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
 #define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_LED_REG		(CSR_BASE+0x094)
+#define CSR_DRAM_INT_TBL_CTL	(CSR_BASE+0x0A0)
 #define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 #define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
 #define CSR_HW_REV_WA_REG	(CSR_BASE+0x22C)
 
-/* BSM (Bootstrap State Machine) */
-#define BSM_BASE                     (CSR_BASE + 0x3400)
+/* HW I/F configuration */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM     (0x00200000)
 
-#define BSM_WR_CTRL_REG              (BSM_BASE + 0x000) /* ctl and status */
-#define BSM_WR_MEM_SRC_REG           (BSM_BASE + 0x004) /* source in BSM mem */
-#define BSM_WR_MEM_DST_REG           (BSM_BASE + 0x008) /* dest in SRAM mem */
-#define BSM_WR_DWCOUNT_REG           (BSM_BASE + 0x00C) /* bytes */
-#define BSM_WR_STATUS_REG            (BSM_BASE + 0x010) /* bit 0:  1 == done */
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
 
-/* pointers and size regs for bootstrap load and data SRAM save */
-#define BSM_DRAM_INST_PTR_REG        (BSM_BASE + 0x090)
-#define BSM_DRAM_INST_BYTECOUNT_REG  (BSM_BASE + 0x094)
-#define BSM_DRAM_DATA_PTR_REG        (BSM_BASE + 0x098)
-#define BSM_DRAM_DATA_BYTECOUNT_REG  (BSM_BASE + 0x09C)
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2  (1<<18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6  (1<<6)  /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
 
-/* BSM special memory, stays powered during power-save sleeps */
-#define BSM_SRAM_LOWER_BOUND         (CSR_BASE + 0x3800)
-#define BSM_SRAM_SIZE			(1024)
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL2 | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
 
-/* DBG MON */
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL6 | \
+				 CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0 )
 
-/* SCD */
-#define SCD_BASE                        (CSR_BASE + 0x2E00)
 
-#define SCD_MODE_REG                    (SCD_BASE + 0x000)
-#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
-#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
-#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
-#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
-#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
-#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH		(0x00880300)
+
+#define CSR_LED_REG_TRUN_ON		(0x00000078)
+#define CSR_LED_REG_TRUN_OFF		(0x00000038)
+#define CSR_LED_BSM_CTRL_MSK		(0xFFFFFFDF)
+
+/* DRAM_INT_TBL_CTRL */
+#define CSR_DRAM_INT_TBL_CTRL_EN	(1<<31)
+#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK	(1<<27)
 
-/*=== HBUS (Host-side bus) ===*/
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
 
 #define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
 #define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
@@ -832,7 +260,23 @@ struct statistics {
 #define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
 #define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
 #define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
-/*=== FH (data Flow handler) ===*/
+
+#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+
+
+/* SCD (Scheduler) */
+#define SCD_BASE                        (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG                    (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE     (0x800)
 
 #define FH_CBCC_TABLE           (FH_BASE+0x140)
 #define FH_TFDB_TABLE           (FH_BASE+0x180)
@@ -879,125 +323,9 @@ struct statistics {
 /* 18 - reserved */
 
 /* card static random access memory (SRAM) for processor data and instructs */
-#define RTC_INST_LOWER_BOUND                        (0x00000)
-#define ALM_RTC_INST_UPPER_BOUND                    (0x14000)
-
-#define RTC_DATA_LOWER_BOUND                                (0x800000)
-#define ALM_RTC_DATA_UPPER_BOUND                            (0x808000)
-
-#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
-#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+#define RTC_INST_LOWER_BOUND			(0x000000)
+#define RTC_DATA_LOWER_BOUND			(0x800000)
 
-#define VALID_RTC_DATA_ADDR(addr)               \
-    ( ((addr) >= RTC_DATA_LOWER_BOUND) && ((addr) < ALM_RTC_DATA_UPPER_BOUND) )
-
-
-/* HW I/F configuration */
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
-#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
-#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
-
-#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
-#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
-#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
-#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
-
-#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC               CSR_GPIO_IN_BIT_AUX_POWER
-
-#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
-
-
-/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
- * acknowledged (reset) by host writing "1" to flagged bits. */
-#define BIT_INT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
-#define BIT_INT_ERR          (1<<29) /* DMA hardware error FH_INT[31] */
-#define BIT_INT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
-#define BIT_INT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
-#define BIT_INT_SWERROR      (1<<25) /* uCode error */
-#define BIT_INT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
-#define BIT_INT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
-#define BIT_INT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
-#define BIT_INT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
-#define BIT_INT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
-
-#define CSR_INI_SET_MASK      ( BIT_INT_FH_RX   |  \
-				BIT_INT_ERR     |  \
-				BIT_INT_FH_TX   |  \
-				BIT_INT_SWERROR |  \
-				BIT_INT_RF_KILL |  \
-				BIT_INT_SW_RX   |  \
-				BIT_INT_WAKEUP  |  \
-				BIT_INT_ALIVE )
-
-/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
-#define BIT_FH_INT_ERR       (1<<31) /* Error */
-#define BIT_FH_INT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
-#define BIT_FH_INT_RX_CHNL2  (1<<18) /* Rx channel 2 (3945 only) */
-#define BIT_FH_INT_RX_CHNL1  (1<<17) /* Rx channel 1 */
-#define BIT_FH_INT_RX_CHNL0  (1<<16) /* Rx channel 0 */
-#define BIT_FH_INT_TX_CHNL6  (1<<6)  /* Tx channel 6 (3945 only) */
-#define BIT_FH_INT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
-#define BIT_FH_INT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
-
-#define FH_INT_RX_MASK        ( BIT_FH_INT_HI_PRIOR |  \
-				BIT_FH_INT_RX_CHNL2 |  \
-				BIT_FH_INT_RX_CHNL1 |  \
-				BIT_FH_INT_RX_CHNL0 )
-
-#define FH_INT_TX_MASK        ( BIT_FH_INT_TX_CHNL6 |  \
-				BIT_FH_INT_TX_CHNL1 |  \
-				BIT_FH_INT_TX_CHNL0 )
-
-/* RESET */
-#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
-#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
-#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
-#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
-#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
-
-/* GP (general purpose) CONTROL */
-#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
-#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
-#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
-
-#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN          (0x00000001)
-
-#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE        (0x07000000)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
-#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
-
-/* APMG (power management) constants */
-#define APMG_CLK_CTRL_REG                        (0x003000)
-#define ALM_APMG_CLK_EN                          (0x003004)
-#define ALM_APMG_CLK_DIS                         (0x003008)
-#define ALM_APMG_PS_CTL                          (0x00300c)
-#define ALM_APMG_PCIDEV_STT                      (0x003010)
-#define ALM_APMG_RFKILL				 (0x003014)
-#define ALM_APMG_LARC_INT                        (0x00301c)
-#define ALM_APMG_LARC_INT_MSK                    (0x003020)
-
-#define APMG_CLK_REG_VAL_DMA_CLK_RQT                (0x00000200)
-#define APMG_CLK_REG_VAL_BSM_CLK_RQT                (0x00000800)
-
-#define APMG_PS_CTRL_REG_VAL_ALM_R_RESET_REQ        (0x04000000)
-
-#define APMG_DEV_STATE_REG_VAL_L1_ACTIVE_DISABLE    (0x00000800)
-
-#define APMG_PS_CTRL_REG_MSK_POWER_SRC              (0x03000000)
-#define APMG_PS_CTRL_REG_VAL_POWER_SRC_VMAIN        (0x00000000)
-#define APMG_PS_CTRL_REG_VAL_POWER_SRC_VAUX         (0x01000000)
-
-/* BSM (bootstrap state machine) */
-#define BSM_WR_CTRL_REG_BIT_START     (0x80000000) /* start boot load now */
-#define BSM_WR_CTRL_REG_BIT_START_EN  (0x40000000) /* enable boot after pwrup*/
 
 /* DBM */
 
@@ -1075,8 +403,6 @@ struct statistics {
 
 #define IWL_MAX_CMD_SIZE 1024
 
-/* LEDs mode */
-
 #define IWL_DEFAULT_TX_RETRY  15
 #define IWL_MAX_TX_RETRY      16
 
@@ -1086,35 +412,9 @@ struct statistics {
 #define NUM_TFD_CHUNKS                        4
 
 #define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
 #define RX_QUEUE_SIZE_LOG                     8
 
-/*
- * TX Queue Flag Definitions
- */
-
-/* abort attempt if mgmt frame is rx'd */
-
-/* require CTS */
-
-/* use short preamble */
-#define DCT_FLAG_LONG_PREAMBLE             0x00
-#define DCT_FLAG_SHORT_PREAMBLE            0x04
-
-/* RTS/CTS first */
-
-/* don't calculate duration field */
-
-/* even if MAC WEP set (allows pre-encrypt) */
-#define IWL_
-/* overwrite TSF field */
-
-/* ACK rx is expected to follow */
-#define DCT_FLAG_ACK_REQD                  0x80
-
-#define IWL_MB_DISASSOCIATE_THRESHOLD_DEFAULT           24
-#define IWL_MB_ROAMING_THRESHOLD_DEFAULT                8
-#define IWL_REAL_RATE_RX_PACKET_THRESHOLD               300
-
 /* QoS  definitions */
 
 #define CW_MIN_OFDM          15
@@ -1124,28 +424,28 @@ struct statistics {
 
 #define QOS_TX0_CW_MIN_OFDM      CW_MIN_OFDM
 #define QOS_TX1_CW_MIN_OFDM      CW_MIN_OFDM
-#define QOS_TX2_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
-#define QOS_TX3_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 4 - 1 )
+#define QOS_TX2_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 4 - 1)
 
 #define QOS_TX0_CW_MIN_CCK       CW_MIN_CCK
 #define QOS_TX1_CW_MIN_CCK       CW_MIN_CCK
-#define QOS_TX2_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
-#define QOS_TX3_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 4 - 1 )
+#define QOS_TX2_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 4 - 1)
 
 #define QOS_TX0_CW_MAX_OFDM      CW_MAX_OFDM
 #define QOS_TX1_CW_MAX_OFDM      CW_MAX_OFDM
 #define QOS_TX2_CW_MAX_OFDM      CW_MIN_OFDM
-#define QOS_TX3_CW_MAX_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
+#define QOS_TX3_CW_MAX_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
 
 #define QOS_TX0_CW_MAX_CCK       CW_MAX_CCK
 #define QOS_TX1_CW_MAX_CCK       CW_MAX_CCK
 #define QOS_TX2_CW_MAX_CCK       CW_MIN_CCK
-#define QOS_TX3_CW_MAX_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
+#define QOS_TX3_CW_MAX_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
 
-#define QOS_TX0_AIFS            (3)
-#define QOS_TX1_AIFS            (7)
-#define QOS_TX2_AIFS            (2)
-#define QOS_TX3_AIFS            (2)
+#define QOS_TX0_AIFS            3
+#define QOS_TX1_AIFS            7
+#define QOS_TX2_AIFS            2
+#define QOS_TX3_AIFS            2
 
 #define QOS_TX0_ACM             0
 #define QOS_TX1_ACM             0
@@ -1210,17 +510,7 @@ struct statistics {
 #define CTRL_QOS_NO_ACK               (0x0020)
 #define DCT_FLAG_EXT_QOS_ENABLED      (0x10)
 
-#define IWL_TX_QUEUE_AC0        0
-#define IWL_TX_QUEUE_AC1        1
-#define IWL_TX_QUEUE_AC2        2
-#define IWL_TX_QUEUE_AC3        3
-#define IWL_TX_QUEUE_HCCA_1     5
-#define IWL_TX_QUEUE_HCCA_2     6
-
-#define U32_PAD(n)                     ((4-(n%4))%4)
-
-#define AC_BE_TID_MASK 0x9	/* TID 0 and 3 */
-#define AC_BK_TID_MASK 0x6	/* TID 1 and 2 */
+#define U32_PAD(n)		((4-(n))&0x3)
 
 /*
  * Generic queue structure
@@ -1232,7 +522,7 @@ struct statistics {
 #define TFD_CTL_PAD_SET(n)         (n<<28)
 #define TFD_CTL_PAD_GET(ctl)       (ctl>>28)
 
-#define TFD_TX_CMD_SLOTS 64
+#define TFD_TX_CMD_SLOTS 256
 #define TFD_CMD_SLOTS 32
 
 #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
@@ -1242,305 +532,6 @@ struct statistics {
  * RX related structures and functions
  */
 #define RX_FREE_BUFFERS 64
-#if IWL == 4965
-#define RX_LOW_WATERMARK 25
-#else
 #define RX_LOW_WATERMARK 8
-#endif
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-#define IWL_CMD_FAILED_MSK 0x40
-
-struct iwl_cmd_header {
-	u8 cmd;
-	u8 flags;
-	/* We have 15 LSB to use as we please (MSB indicates
-	 * a frame Rx'd from the HW).  We encode the following
-	 * information into the sequence field:
-	 *
-	 *  0:7    index in fifo
-	 *  8:13   fifo selection
-	 * 14:14   bit indicating if this packet references the 'extra'
-	 *         storage at the end of the memory queue
-	 * 15:15   (Rx indication)
-	 *
-	 */
-	__le16 sequence;
-
-	/* command data follows immediately */
-	u8 data[0];
-} __attribute__ ((packed));
-
-/* Used for passing to driver number of successes and failures per rate */
-struct rate_histogram {
-	union {
-		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-	} success;
-	union {
-		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-	} failed;
-} __attribute__ ((packed));
-
-/* statistics command response */
-
-struct statistics_rx_phy {
-	__le32 ina_cnt;
-	__le32 fina_cnt;
-	__le32 plcp_err;
-	__le32 crc32_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 false_alarm_cnt;
-	__le32 fina_sync_err_cnt;
-	__le32 sfd_timeout;
-	__le32 fina_timeout;
-	__le32 unresponded_rts;
-	__le32 rxe_frame_limit_overrun;
-	__le32 sent_ack_cnt;
-	__le32 sent_cts_cnt;
-#if IWL == 4965
-	__le32 sent_ba_rsp_cnt;
-	__le32 dsp_self_kill;
-	__le32 mh_format_err;
-	__le32 re_acq_main_rssi_sum;
-	__le32 reserved3;
-#endif
-} __attribute__ ((packed));
-
-#if IWL == 4965
-struct statistics_rx_ht_phy {
-	__le32 plcp_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 crc32_err;
-	__le32 mh_format_err;
-	__le32 agg_crc32_good;
-	__le32 agg_mpdu_cnt;
-	__le32 agg_cnt;
-	__le32 reserved2;
-} __attribute__ ((packed));
-#endif
-
-struct statistics_rx_non_phy {
-	__le32 bogus_cts;	/* CTS received when not expecting CTS */
-	__le32 bogus_ack;	/* ACK received when not expecting ACK */
-	__le32 non_bssid_frames;	/* number of frames with BSSID that
-					 * doesn't belong to the STA BSSID */
-	__le32 filtered_frames;	/* count frames that were dumped in the
-				 * filtering process */
-	__le32 non_channel_beacons;	/* beacons with our bss id but not on
-					 * our serving channel */
-#if IWL == 4965
-	__le32 channel_beacons;	/* beacons with our bss id and in our
-				 * serving channel */
-	__le32 num_missed_bcon;	/* number of missed beacons */
-	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
-					 * ADC was in saturation */
-	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
-					  * for INA */
-	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
-	__le32 interference_data_flag;	/* flag for interference data
-					 * availability. 1 when data is
-					 * available. */
-	__le32 channel_load;	/* counts RX Enable time */
-	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
-					 * and CCK) counter */
-	__le32 beacon_rssi_a;
-	__le32 beacon_rssi_b;
-	__le32 beacon_rssi_c;
-	__le32 beacon_energy_a;
-	__le32 beacon_energy_b;
-	__le32 beacon_energy_c;
-#endif
-} __attribute__ ((packed));
-
-struct statistics_rx {
-	struct statistics_rx_phy ofdm;
-	struct statistics_rx_phy cck;
-	struct statistics_rx_non_phy general;
-#if IWL == 4965
-	struct statistics_rx_ht_phy ofdm_ht;
-#endif
-} __attribute__ ((packed));
-
-#if IWL == 4965
-struct statistics_tx_non_phy_agg {
-	__le32 ba_timeout;
-	__le32 ba_reschedule_frames;
-	__le32 scd_query_agg_frame_cnt;
-	__le32 scd_query_no_agg;
-	__le32 scd_query_agg;
-	__le32 scd_query_mismatch;
-	__le32 frame_not_ready;
-	__le32 underrun;
-	__le32 bt_prio_kill;
-	__le32 rx_ba_rsp_cnt;
-	__le32 reserved2;
-	__le32 reserved3;
-} __attribute__ ((packed));
-#endif
-
-struct statistics_tx {
-	__le32 preamble_cnt;
-	__le32 rx_detected_cnt;
-	__le32 bt_prio_defer_cnt;
-	__le32 bt_prio_kill_cnt;
-	__le32 few_bytes_cnt;
-	__le32 cts_timeout;
-	__le32 ack_timeout;
-	__le32 expected_ack_cnt;
-	__le32 actual_ack_cnt;
-#if IWL == 4965
-	__le32 dump_msdu_cnt;
-	__le32 burst_abort_next_frame_mismatch_cnt;
-	__le32 burst_abort_missing_next_frame_cnt;
-	__le32 cts_timeout_collision;
-	__le32 ack_or_ba_timeout_collision;
-	struct statistics_tx_non_phy_agg agg;
-#endif
-} __attribute__ ((packed));
-
-struct statistics_dbg {
-	__le32 burst_check;
-	__le32 burst_count;
-	__le32 reserved[4];
-} __attribute__ ((packed));
-
-struct statistics_div {
-	__le32 tx_on_a;
-	__le32 tx_on_b;
-	__le32 exec_time;
-	__le32 probe_time;
-#if IWL == 4965
-	__le32 reserved1;
-	__le32 reserved2;
-#endif
-} __attribute__ ((packed));
-
-struct statistics_general {
-	__le32 temperature;
-#if IWL == 4965
-	__le32 temperature_m;
-#endif
-	struct statistics_dbg dbg;
-	__le32 sleep_time;
-	__le32 slots_out;
-	__le32 slots_idle;
-	__le32 ttl_timestamp;
-	struct statistics_div div;
-#if IWL == 4965
-	__le32 rx_enable_counter;
-	__le32 reserved1;
-	__le32 reserved2;
-	__le32 reserved3;
-#endif
-} __attribute__ ((packed));
-
-struct iwl_notif_statistics {
-	__le32 flag;
-	struct statistics_rx rx;
-	struct statistics_tx tx;
-	struct statistics_general general;
-} __attribute__ ((packed));
-
-struct iwl_rx_packet {
-	__le32 len;
-	struct iwl_cmd_header hdr;
-	union {
-		struct iwl_alive_resp alive_frame;
-		struct iwl_rx_frame rx_frame;
-		struct iwl_tx_resp tx_resp;
-		struct iwl_spectrum_notification spectrum_notif;
-		struct iwl_csa_notification csa_notif;
-		struct iwl_error_resp err_resp;
-		struct iwl_card_state_notif card_state_notif;
-		struct iwl_beacon_notif beacon_status;
-		struct iwl_add_sta_resp add_sta;
-		struct iwl_sleep_notification sleep_notif;
-		struct iwl_spectrum_resp spectrum;
-		struct iwl_notif_statistics stats;
-#if IWL == 4965
-		struct iwl_compressed_ba_resp compressed_ba;
-		struct iwl_missed_beacon_notif missed_beacon;
-#endif
-		__le32 status;
-		u8 raw[0];
-	} u;
-} __attribute__ ((packed));
-
-#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl_rx_frame))
-
-struct iwl_multicast_addr {
-	u8 num_of_multicast_addresses;
-	u8 reserved[3];
-	u8 mac1[6];
-	u8 mac2[6];
-	u8 mac3[6];
-	u8 mac4[6];
-} __attribute__ ((packed));
-
-struct iwl_tgi_tx_key {
-	u8 key_id;
-	u8 security_type;
-	u8 station_index;
-	u8 flags;
-	u8 key[16];
-	__le32 tx_counter[2];
-} __attribute__ ((packed));
-
-struct iwl_associate {
-	u8 channel;
-	u8 auth; /* & 0xf0 = auth_type, & 0xf0 = auth_key*/
-	u8 assoc_type;
-	u8 reserved;
-	__le16 policy_support;
-	u8 preamble_length;
-	u8 ieee_mode;
-	u8 bssid[ETH_ALEN];
-	__le32 assoc_tsf_msw;
-	__le32 assoc_tsf_lsw;
-	__le16 capability;
-	__le16 listen_interval;
-	__le16 beacon_interval;
-	u8 dest[ETH_ALEN];
-	__le16 atim_window;
-	u8 smr;
-	u8 reserved1;
-	__le16 reserved2;
-	__le16 assoc_id;
-	u8 erp_value;
-} __attribute__ ((packed));
-
-#define IWL_SUPPORTED_RATES_IE_LEN         8
-
-struct iwl_supported_rates {
-	u8 ieee_mode;
-	u8 num_rates;
-	u8 purpose;
-	u8 reserved;
-	u8 supported_rates[IWL_MAX_RATES];
-} __attribute__ ((packed));
-
-struct iwl_channel_tx_power {
-	u8 channel_number;
-	s8 tx_power;
-} __attribute__ ((packed));
-
-#if IWL == 3945
-#include "iwl-3945-hw.h"
-#elif IWL == 4965
-#include "iwl-4965-hw.h"
-#endif
 
 #endif				/* __iwlwifi_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 984060d..8a8b96f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -60,32 +60,29 @@
  *
  */
 
-#define _iwl_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))
-static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *ipw,
+#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl,
 				 u32 ofs, u32 val)
 {
 	IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n",
 		     (u32) (ofs), (u32) (val), f, l);
-	_iwl_write32(ipw, ofs, val);
+	_iwl_write32(iwl, ofs, val);
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define iwl_write32(ipw, ofs, val) \
-	__iwl_write32(__FILE__, __LINE__, ipw, ofs, val)
+#define iwl_write32(iwl, ofs, val) \
+	__iwl_write32(__FILE__, __LINE__, iwl, ofs, val)
 #else
-#define iwl_write32(ipw, ofs, val) _iwl_write32(ipw, ofs, val)
+#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val)
 #endif
 
-#define _iwl_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))
-static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *ipw, u32 ofs)
+#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs)
 {
 	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
-	return _iwl_read32(ipw, ofs);
+	return _iwl_read32(iwl, ofs);
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define iwl_read32(ipw, ofs) \
-	__iwl_read32(__FILE__, __LINE__, ipw, ofs)
+#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs)
 #else
 #define iwl_read32(p, o) _iwl_read32(p, o)
 #endif
@@ -104,6 +101,7 @@ static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
 
 	return -ETIMEDOUT;
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline int __iwl_poll_bit(const char *f, u32 l,
 				 struct iwl_priv *priv, u32 addr,
 				 u32 bits, u32 mask, int timeout)
@@ -119,10 +117,8 @@ static inline int __iwl_poll_bit(const char *f, u32 l,
 		     addr, bits, mask, rc, f, l);
 	return rc;
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define iwl_poll_bit(ipw, addr, bits, mask, timeout) \
-	__iwl_poll_bit(__FILE__, __LINE__, ipw, addr, bits, mask, timeout)
+#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
 #else
 #define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
 #endif
@@ -131,6 +127,7 @@ static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
 {
 	_iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_set_bit(const char *f, u32 l,
 				 struct iwl_priv *priv, u32 reg, u32 mask)
 {
@@ -138,8 +135,6 @@ static inline void __iwl_set_bit(const char *f, u32 l,
 	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
 	_iwl_write32(priv, reg, val);
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
 #else
 #define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
@@ -149,6 +144,7 @@ static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
 {
 	_iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_clear_bit(const char *f, u32 l,
 				   struct iwl_priv *priv, u32 reg, u32 mask)
 {
@@ -156,8 +152,6 @@ static inline void __iwl_clear_bit(const char *f, u32 l,
 	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
 	_iwl_write32(priv, reg, val);
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
 #else
 #define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
@@ -168,7 +162,12 @@ static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
 	int rc;
 	u32 gp_ctl;
 
-	if (priv->status & STATUS_RF_KILL_MASK) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
 		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
 			"wakes up NIC\n");
 
@@ -178,10 +177,9 @@ static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
 			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
 				"gpctl = 0x%08x\n", gp_ctl);
 			mdelay(10);
-		} else {
+		} else
 			IWL_DEBUG_RF_KILL("power-down complete, "
-				"gpctl = 0x%08x\n", gp_ctl);
-		}
+					  "gpctl = 0x%08x\n", gp_ctl);
 	}
 
 	/* this bit wakes up the NIC */
@@ -195,23 +193,24 @@ static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
 		return -EIO;
 	}
 
-	priv->status |= STATUS_RESTRICTED;
-
+#ifdef CONFIG_IWLWIFI_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
 	return 0;
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline int __iwl_grab_restricted_access(const char *f, u32 l,
 					       struct iwl_priv *priv)
 {
-	if (priv->status & STATUS_RESTRICTED)
-		IWL_ERROR
-		    ("Grabbing access while already held at line %d.\n", l);
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
 
 	IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l);
 
 	return _iwl_grab_restricted_access(priv);
 }
-#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_grab_restricted_access(priv) \
 	__iwl_grab_restricted_access(__FILE__, __LINE__, priv)
 #else
@@ -219,75 +218,76 @@ static inline int __iwl_grab_restricted_access(const char *f, u32 l,
 	_iwl_grab_restricted_access(priv)
 #endif
 
-static inline void _iwl_release_restricted_access(struct iwl_priv
-						  *priv)
+static inline void _iwl_release_restricted_access(struct iwl_priv *priv)
 {
-	_iwl_clear_bit(priv, CSR_GP_CNTRL,
-		       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	priv->status &= ~STATUS_RESTRICTED;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 }
-
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_release_restricted_access(const char *f, u32 l,
 						   struct iwl_priv *priv)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
-		IWL_ERROR
-		    ("Release unheld restricted access at line %d.\n", l);
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld restricted access at line %d.\n", l);
 
 	IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l);
 	_iwl_release_restricted_access(priv);
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_release_restricted_access(priv) \
 	__iwl_release_restricted_access(__FILE__, __LINE__, priv)
 #else
 #define iwl_release_restricted_access(priv) \
 	_iwl_release_restricted_access(priv)
 #endif
+
 static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg)
 {
 	return _iwl_read32(priv, reg);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline u32 __iwl_read_restricted(const char *f, u32 l,
 					struct iwl_priv *priv, u32 reg)
 {
 	u32 value = _iwl_read_restricted(priv, reg);
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from %s %d\n", f, l);
 	IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value,
 		     f, l);
 	return value;
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
 #define iwl_read_restricted(priv, reg) \
 	__iwl_read_restricted(__FILE__, __LINE__, priv, reg)
 #else
-#define iwl_read_restricted(p, r) _iwl_read_restricted(p, r)
+#define iwl_read_restricted _iwl_read_restricted
 #endif
 
-static void inline _iwl_write_restricted(struct iwl_priv *priv,
+static inline void _iwl_write_restricted(struct iwl_priv *priv,
 					 u32 reg, u32 value)
 {
 	_iwl_write32(priv, reg, value);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static void __iwl_write_restricted(u32 line,
 				   struct iwl_priv *priv, u32 reg, u32 value)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from line %d\n", line);
 	_iwl_write_restricted(priv, reg, value);
 }
-
 #define iwl_write_restricted(priv, reg, value) \
 	__iwl_write_restricted(__LINE__, priv, reg, value)
+#else
+#define iwl_write_restricted _iwl_write_restricted
+#endif
 
 static inline void iwl_write_buffer_restricted(struct iwl_priv *priv,
-					       u32 reg, u32 len, u32 * values)
+					       u32 reg, u32 len, u32 *values)
 {
 	u32 count = sizeof(u32);
+
 	if ((priv != NULL) && (values != NULL)) {
 		for (; 0 < len; len -= count, reg += count, values++)
 			_iwl_write_restricted(priv, reg, *values);
@@ -308,27 +308,26 @@ static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv,
 
 	return -ETIMEDOUT;
 }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline int __iwl_poll_restricted_bit(const char *f, u32 l,
 					    struct iwl_priv *priv,
 					    u32 addr, u32 mask, int timeout)
 {
 	int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout);
+
 	if (unlikely(rc == -ETIMEDOUT))
-		IWL_DEBUG_IO
-		    ("poll_restricted_bit(0x%08X, 0x%08X) - timedout - %s %d\n",
-		     addr, mask, f, l);
+		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
 	else
-		IWL_DEBUG_IO
-		    ("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X - %s %d\n",
-		     addr, mask, rc, f, l);
+		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, rc, f, l);
 	return rc;
 }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define iwl_poll_restricted_bit(ipw, addr, mask, timeout) \
-	__iwl_poll_restricted_bit(__FILE__, __LINE__, ipw, addr, mask, timeout)
+#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \
+	__iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
 #else
-#define iwl_poll_restricted_bit(p, a, m, t) _iwl_poll_restricted_bit(p, a, m, t)
+#define iwl_poll_restricted_bit _iwl_poll_restricted_bit
 #endif
 
 static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
@@ -336,16 +335,20 @@ static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
 	_iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
 	return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline u32 __iwl_read_restricted_reg(u32 line,
 					    struct iwl_priv *priv, u32 reg)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from line %d\n", line);
 	return _iwl_read_restricted_reg(priv, reg);
 }
 
 #define iwl_read_restricted_reg(priv, reg) \
 	__iwl_read_restricted_reg(__LINE__, priv, reg)
+#else
+#define iwl_read_restricted_reg _iwl_read_restricted_reg
+#endif
 
 static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
 					     u32 addr, u32 val)
@@ -354,46 +357,56 @@ static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
 			      ((addr & 0x0000FFFF) | (3 << 24)));
 	_iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val);
 }
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_write_restricted_reg(u32 line,
 					      struct iwl_priv *priv,
 					      u32 addr, u32 val)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from line %d\n", line);
 	_iwl_write_restricted_reg(priv, addr, val);
 }
 
 #define iwl_write_restricted_reg(priv, addr, val) \
 	__iwl_write_restricted_reg(__LINE__, priv, addr, val);
+#else
+#define iwl_write_restricted_reg _iwl_write_restricted_reg
+#endif
 
 #define _iwl_set_bits_restricted_reg(priv, reg, mask) \
 	_iwl_write_restricted_reg(priv, reg, \
 				  (_iwl_read_restricted_reg(priv, reg) | mask))
+#ifdef CONFIG_IWLWIFI_DEBUG
 static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv
 						 *priv, u32 reg, u32 mask)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from line %d\n", line);
 	_iwl_set_bits_restricted_reg(priv, reg, mask);
 }
-
 #define iwl_set_bits_restricted_reg(priv, reg, mask) \
 	__iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask)
+#else
+#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg
+#endif
 
 #define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
 	_iwl_write_restricted_reg( \
 	    priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits))
-static void inline __iwl_set_bits_mask_restricted_reg(u32 line, struct iwl_priv
-						      *priv, u32 reg,
-						      u32 bits, u32 mask)
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_mask_restricted_reg(u32 line,
+		struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
 {
-	if (!(priv->status & STATUS_RESTRICTED))
+	if (!atomic_read(&priv->restrict_refcnt))
 		IWL_ERROR("Unrestricted access from line %d\n", line);
 	_iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask);
 }
 
 #define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
 	__iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg
+#endif
 
 static inline void iwl_clear_bits_restricted_reg(struct iwl_priv
 						 *priv, u32 reg, u32 mask)
@@ -415,18 +428,16 @@ static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr,
 	iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val);
 }
 
-static inline void iwl_write_restricted_mem_buffer(struct iwl_priv *priv,
-						   u32 addr, u32 len,
-						   u32 * values)
+static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr,
+					     u32 len, u32 *values)
 {
 	iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
 	for (; 0 < len; len -= sizeof(u32), values++)
 		iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values);
 }
 
-static inline void iwl_write_restricted_reg_buffer(struct iwl_priv *priv,
-						   u32 reg, u32 len,
-						   u8 * values)
+static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg,
+					     u32 len, u8 *values)
 {
 	u32 reg_offset = reg;
 	u32 aligment = reg & 0x3;
@@ -456,19 +467,4 @@ static inline void iwl_write_restricted_reg_buffer(struct iwl_priv *priv,
 		_iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values));
 }
 
-/**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
- *
- * NOTE: This function has 3945 and 4965 specific code paths in it.
- */
-static inline u32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
-				       dma_addr_t dma_addr)
-{
-#if IWL == 3945
-	return cpu_to_le32((u32)dma_addr);
-#elif IWL == 4965
-	return cpu_to_le32((u32)(dma_addr >> 8));
-#endif
-}
-
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h
index 847ef5a..7da1d4d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-priv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-priv.h
@@ -52,8 +52,8 @@ struct iwl_priv {
 	u8 phymode;
 	int alloc_rxb_skb;
 
-	void (*rx_handlers[REPLY_MAX])(struct iwl_priv * priv,
-				       struct iwl_rx_mem_buffer * rxb);
+	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+				       struct iwl_rx_mem_buffer *rxb);
 
 	const struct ieee80211_hw_mode *modes;
 
@@ -62,6 +62,8 @@ struct iwl_priv {
 	struct iwl_spectrum_notification measure_report;
 	u8 measurement_status;
 #endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
 
 	/* we allocate array of iwl_channel_info for NIC's valid channels.
 	 *    Access via channel # using indirect index array */
@@ -89,7 +91,8 @@ struct iwl_priv {
 	u8 only_active_channel;
 
 	/* spinlock */
-	spinlock_t lock;
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
 	struct mutex mutex;
 
 	/* basic pci-network driver stuff */
@@ -97,7 +100,6 @@ struct iwl_priv {
 
 	/* pci hardware address support */
 	void __iomem *hw_base;
-	unsigned long hw_len;
 
 	/* uCode images, save to reload in case of failure */
 	struct fw_image_desc ucode_code;	/* runtime inst */
@@ -174,17 +176,16 @@ struct iwl_priv {
 	struct iwl_rx_queue rxq;
 	struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
 #if IWL == 4965
+	unsigned long txq_ctx_active_msk;
 	struct iwl_kw kw;	/* keep warm address */
 	u32 scd_base_addr;	/* scheduler sram base address */
 #endif
 
-	u32 status;
+	unsigned long status;
 	u32 config;
 
-	int quality;
-	int last_rx_rssi;
-	int last_rx_noise;
-	int last_rx_snr;
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
 
 	struct iwl_power_mgr power_data;
 
@@ -204,7 +205,7 @@ struct iwl_priv {
 
 	/*station table variables */
 	spinlock_t sta_lock;
-	u8 num_stations;
+	int num_stations;
 	struct iwl_station_entry stations[IWL_STATION_COUNT];
 
 	/* Indication if ieee80211_ops->open has been called */
@@ -245,6 +246,10 @@ struct iwl_priv {
 	u16 assoc_capability;
 	u8 ps_mode;
 
+#ifdef CONFIG_IWLWIFI_QOS
+	struct iwl_qos_info qos_data;
+#endif /*CONFIG_IWLWIFI_QOS */
+
 	struct workqueue_struct *workqueue;
 
 	struct work_struct up;
@@ -258,6 +263,7 @@ struct iwl_priv {
 	struct work_struct auth_work;
 	struct work_struct report_work;
 	struct work_struct request_scan;
+	struct work_struct beacon_update;
 
 	struct tasklet_struct irq_tasklet;
 
@@ -278,10 +284,11 @@ struct iwl_priv {
 	u32 pm_state[16];
 #endif
 
+#ifdef CONFIG_IWLWIFI_DEBUG
 	/* debugging info */
 	u32 framecnt_to_us;
-
-
+	atomic_t restrict_refcnt;
+#endif
 
 #if IWL == 4965
 	struct work_struct txpower_work;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
new file mode 100644
index 0000000..4ba1216
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef	__iwl_prph_h__
+#define __iwl_prph_h__
+
+/*
+ * Registers in this file are internal, not PCI bus memory mapped.
+ * Driver accesses these via HBUS_TARG_PRPH_* registers.
+ */
+#define PRPH_BASE	(0x00000)
+#define PRPH_END	(0xFFFFF)
+
+/* APMG (power management) constants */
+#define APMG_BASE			(PRPH_BASE + 0x3000)
+#define APMG_CLK_CTRL_REG		(APMG_BASE + 0x0000)
+#define APMG_CLK_EN_REG			(APMG_BASE + 0x0004)
+#define APMG_CLK_DIS_REG		(APMG_BASE + 0x0008)
+#define APMG_PS_CTRL_REG		(APMG_BASE + 0x000c)
+#define APMG_PCIDEV_STT_REG		(APMG_BASE + 0x0010)
+#define APMG_RFKILL_REG			(APMG_BASE + 0x0014)
+#define APMG_RTC_INT_STT_REG		(APMG_BASE + 0x001c)
+#define APMG_RTC_INT_MSK_REG		(APMG_BASE + 0x0020)
+
+#define APMG_CLK_VAL_DMA_CLK_RQT	(0x00000200)
+#define APMG_CLK_VAL_BSM_CLK_RQT	(0x00000800)
+
+#define APMG_PS_CTRL_VAL_RESET_REQ	(0x04000000)
+
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS	(0x00000800)
+
+#define APMG_PS_CTRL_MSK_PWR_SRC              (0x03000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN        (0x00000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX         (0x01000000)
+
+
+/**
+ * BSM (Bootstrap State Machine)
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down when the embedded control
+ * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
+ *
+ * When powering back up after sleeps (or during initial uCode load), the BSM
+ * internally loads the short bootstrap program from the special SRAM into the
+ * embedded processor's instruction SRAM, and starts the processor so it runs
+ * the bootstrap program.
+ *
+ * This bootstrap program loads (via PCI busmaster DMA) instructions and data
+ * images for a uCode program from host DRAM locations.  The host driver
+ * indicates DRAM locations and sizes for instruction and data images via the
+ * four BSM_DRAM_* registers.  Once the bootstrap program loads the new program,
+ * the new program starts automatically.
+ *
+ * The uCode used for open-source drivers includes two programs:
+ *
+ * 1)  Initialization -- performs hardware calibration and sets up some
+ *     internal data, then notifies host via "initialize alive" notification
+ *     (struct iwl_init_alive_resp) that it has completed all of its work.
+ *     After signal from host, it then loads and starts the runtime program.
+ *     The initialization program must be used when initially setting up the
+ *     NIC after loading the driver.
+ *
+ * 2)  Runtime/Protocol -- performs all normal runtime operations.  This
+ *     notifies host via "alive" notification (struct iwl_alive_resp) that it
+ *     is ready to be used.
+ *
+ * When initializing the NIC, the host driver does the following procedure:
+ *
+ * 1)  Load bootstrap program (instructions only, no data image for bootstrap)
+ *     into bootstrap memory.  Use dword writes starting at BSM_SRAM_LOWER_BOUND
+ *
+ * 2)  Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
+ *     images in host DRAM.
+ *
+ * 3)  Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
+ *     BSM_WR_MEM_SRC_REG = 0
+ *     BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
+ *     BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
+ *
+ * 4)  Load bootstrap into instruction SRAM:
+ *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
+ *
+ * 5)  Wait for load completion:
+ *     Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
+ *
+ * 6)  Enable future boot loads whenever NIC's power management triggers it:
+ *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
+ *
+ * 7)  Start the NIC by removing all reset bits:
+ *     CSR_RESET = 0
+ *
+ *     The bootstrap uCode (already in instruction SRAM) loads initialization
+ *     uCode.  Initialization uCode performs data initialization, sends
+ *     "initialize alive" notification to host, and waits for a signal from
+ *     host to load runtime code.
+ *
+ * 4)  Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
+ *     images in host DRAM.  The last register loaded must be the instruction
+ *     bytecount register ("1" in MSbit tells initialization uCode to load
+ *     the runtime uCode):
+ *     BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ *
+ * 5)  Wait for "alive" notification, then issue normal runtime commands.
+ *
+ * Data caching during power-downs:
+ *
+ * Just before the embedded controller powers down (e.g for automatic
+ * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
+ * a current snapshot of the embedded processor's data SRAM into host DRAM.
+ * This caches the data while the embedded processor's memory is powered down.
+ * Location and size are controlled by BSM_DRAM_DATA_* registers.
+ *
+ * NOTE:  Instruction SRAM does not need to be saved, since that doesn't
+ *        change during operation; the original image (from uCode distribution
+ *        file) can be used for reload.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  Bootstrap looks
+ * at the BSM_DRAM_* registers, which now point to the runtime instruction
+ * image and the cached (modified) runtime data (*not* the initialization
+ * uCode).  Bootstrap reloads these runtime images into SRAM, and restarts the
+ * uCode from where it left off before the power-down.
+ *
+ * NOTE:  Initialization uCode does *not* run as part of the save/restore
+ *        procedure.
+ *
+ * This save/restore method is mostly for autonomous power management during
+ * normal operation (result of POWER_TABLE_CMD).  Platform suspend/resume and
+ * RFKILL should use complete restarts (with total re-initialization) of uCode,
+ * allowing total shutdown (including BSM memory).
+ *
+ * Note that, during normal operation, the host DRAM that held the initial
+ * startup data for the runtime code is now being used as a backup data cache
+ * for modified data!  If you need to completely re-initialize the NIC, make
+ * sure that you use the runtime data image from the uCode distribution file,
+ * not the modified/saved runtime data.  You may want to store a separate
+ * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
+ */
+
+/* BSM bit fields */
+#define BSM_WR_CTRL_REG_BIT_START     (0x80000000) /* start boot load now */
+#define BSM_WR_CTRL_REG_BIT_START_EN  (0x40000000) /* enable boot after pwrup*/
+#define BSM_DRAM_INST_LOAD            (0x80000000) /* start program load now */
+
+/* BSM addresses */
+#define BSM_BASE                     (PRPH_BASE + 0x3400)
+#define BSM_END                      (PRPH_BASE + 0x3800)
+
+#define BSM_WR_CTRL_REG              (BSM_BASE + 0x000) /* ctl and status */
+#define BSM_WR_MEM_SRC_REG           (BSM_BASE + 0x004) /* source in BSM mem */
+#define BSM_WR_MEM_DST_REG           (BSM_BASE + 0x008) /* dest in SRAM mem */
+#define BSM_WR_DWCOUNT_REG           (BSM_BASE + 0x00C) /* bytes */
+#define BSM_WR_STATUS_REG            (BSM_BASE + 0x010) /* bit 0:  1 == done */
+
+/*
+ * Pointers and size regs for bootstrap load and data SRAM save/restore.
+ * NOTE:  3945 pointers use bits 31:0 of DRAM address.
+ *        4965 pointers use bits 35:4 of DRAM address.
+ */
+#define BSM_DRAM_INST_PTR_REG        (BSM_BASE + 0x090)
+#define BSM_DRAM_INST_BYTECOUNT_REG  (BSM_BASE + 0x094)
+#define BSM_DRAM_DATA_PTR_REG        (BSM_BASE + 0x098)
+#define BSM_DRAM_DATA_BYTECOUNT_REG  (BSM_BASE + 0x09C)
+
+/*
+ * BSM special memory, stays powered on during power-save sleeps.
+ * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
+ */
+#define BSM_SRAM_LOWER_BOUND         (PRPH_BASE + 0x3800)
+#define BSM_SRAM_SIZE			(1024) /* bytes */
+
+
+/* 3945 Tx scheduler registers */
+#define ALM_SCD_BASE                        (PRPH_BASE + 0x2E00)
+#define ALM_SCD_MODE_REG                    (ALM_SCD_BASE + 0x000)
+#define ALM_SCD_ARASTAT_REG                 (ALM_SCD_BASE + 0x004)
+#define ALM_SCD_TXFACT_REG                  (ALM_SCD_BASE + 0x010)
+#define ALM_SCD_TXF4MF_REG                  (ALM_SCD_BASE + 0x014)
+#define ALM_SCD_TXF5MF_REG                  (ALM_SCD_BASE + 0x020)
+#define ALM_SCD_SBYP_MODE_1_REG             (ALM_SCD_BASE + 0x02C)
+#define ALM_SCD_SBYP_MODE_2_REG             (ALM_SCD_BASE + 0x030)
+
+/*
+ * 4965 Tx Scheduler registers.
+ * Details are documented in iwl-4965-hw.h
+ */
+#define KDR_SCD_BASE		(PRPH_BASE + 0xa02c00)
+
+#define KDR_SCD_SRAM_BASE_ADDR         (KDR_SCD_BASE + 0x0)
+#define KDR_SCD_EMPTY_BITS             (KDR_SCD_BASE + 0x4)
+#define KDR_SCD_DRAM_BASE_ADDR         (KDR_SCD_BASE + 0x10)
+#define KDR_SCD_AIT                    (KDR_SCD_BASE + 0x18)
+#define KDR_SCD_TXFACT                 (KDR_SCD_BASE + 0x1c)
+#define KDR_SCD_QUEUE_WRPTR(x)         (KDR_SCD_BASE + 0x24 + (x) * 4)
+#define KDR_SCD_QUEUE_RDPTR(x)         (KDR_SCD_BASE + 0x64 + (x) * 4)
+#define KDR_SCD_SETQUEUENUM            (KDR_SCD_BASE + 0xa4)
+#define KDR_SCD_SET_TXSTAT_TXED        (KDR_SCD_BASE + 0xa8)
+#define KDR_SCD_SET_TXSTAT_DONE        (KDR_SCD_BASE + 0xac)
+#define KDR_SCD_SET_TXSTAT_NOT_SCHD    (KDR_SCD_BASE + 0xb0)
+#define KDR_SCD_DECREASE_CREDIT        (KDR_SCD_BASE + 0xb4)
+#define KDR_SCD_DECREASE_SCREDIT       (KDR_SCD_BASE + 0xb8)
+#define KDR_SCD_LOAD_CREDIT            (KDR_SCD_BASE + 0xbc)
+#define KDR_SCD_LOAD_SCREDIT           (KDR_SCD_BASE + 0xc0)
+#define KDR_SCD_BAR                    (KDR_SCD_BASE + 0xc4)
+#define KDR_SCD_BAR_DW0                (KDR_SCD_BASE + 0xc8)
+#define KDR_SCD_BAR_DW1                (KDR_SCD_BASE + 0xcc)
+#define KDR_SCD_QUEUECHAIN_SEL         (KDR_SCD_BASE + 0xd0)
+#define KDR_SCD_QUERY_REQ              (KDR_SCD_BASE + 0xd8)
+#define KDR_SCD_QUERY_RES              (KDR_SCD_BASE + 0xdc)
+#define KDR_SCD_PENDING_FRAMES         (KDR_SCD_BASE + 0xe0)
+#define KDR_SCD_INTERRUPT_MASK         (KDR_SCD_BASE + 0xe4)
+#define KDR_SCD_INTERRUPT_THRESHOLD    (KDR_SCD_BASE + 0xe8)
+#define KDR_SCD_QUERY_MIN_FRAME_SIZE   (KDR_SCD_BASE + 0x100)
+#define KDR_SCD_QUEUE_STATUS_BITS(x)   (KDR_SCD_BASE + 0x104 + (x) * 4)
+
+/* SP SCD */
+#define SHL_SCD_BASE			(PRPH_BASE + 0xa02c00)
+
+#define SHL_SCD_AIT                    (SHL_SCD_BASE + 0x0c)
+#define SHL_SCD_TXFACT                 (SHL_SCD_BASE + 0x10)
+#define SHL_SCD_QUEUE_WRPTR(x)         (SHL_SCD_BASE + 0x18 + (x) * 4)
+#define SHL_SCD_QUEUE_RDPTR(x)         (SHL_SCD_BASE + 0x68 + (x) * 4)
+#define SHL_SCD_QUEUECHAIN_SEL         (SHL_SCD_BASE + 0xe8)
+#define SHL_SCD_AGGR_SEL	       (SHL_SCD_BASE + 0x248)
+#define SHL_SCD_INTERRUPT_MASK         (SHL_SCD_BASE + 0x108)
+
+#endif				/* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
new file mode 100644
index 0000000..9b62b7e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -0,0 +1,8969 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-3945.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWL3945_DEBUG
+u32 iwl3945_debug_level;
+#endif
+
+static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
+				  struct iwl3945_tx_queue *txq);
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
+static int iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
+static int iwl3945_param_disable;  /* def: 0 = enable radio */
+static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
+int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
+static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION	\
+"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
+
+#ifdef CONFIG_IWL3945_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.2.22k" VD VS
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION     IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ *   *only* when uCode interface or architecture changes so that it
+ *   is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL3945_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	int hdr_len = ieee80211_get_hdrlen(fc);
+
+	if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+		return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+	return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl3945_get_hw_mode(
+		struct iwl3945_priv *priv, int mode)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		if (priv->modes[i].mode == mode)
+			return &priv->modes[i];
+
+	return NULL;
+}
+
+static int iwl3945_is_empty_essid(const char *essid, int essid_len)
+{
+	/* Single white space is for Linksys APs */
+	if (essid_len == 1 && essid[0] == ' ')
+		return 1;
+
+	/* Otherwise, if the entire essid is 0, we assume it is hidden */
+	while (essid_len) {
+		essid_len--;
+		if (essid[essid_len] != '\0')
+			return 0;
+	}
+
+	return 1;
+}
+
+static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
+{
+	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+	const char *s = essid;
+	char *d = escaped;
+
+	if (iwl3945_is_empty_essid(essid, essid_len)) {
+		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+		return escaped;
+	}
+
+	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+	while (essid_len--) {
+		if (*s == '\0') {
+			*d++ = '\\';
+			*d++ = '0';
+			s++;
+		} else
+			*d++ = *s++;
+	}
+	*d = '\0';
+	return escaped;
+}
+
+static void iwl3945_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	if (!(iwl3945_debug_level & level))
+		return;
+
+	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The 3945 operates with six queues:  One receive queue, one transmit queue
+ * (#4) for sending commands to the device firmware, and four transmit queues
+ * (#0-3) for data tx via EDCA.  An additional 2 HCCA queues are unused.
+ ***************************************************/
+
+static int iwl3945_queue_space(const struct iwl3945_queue *q)
+{
+	int s = q->read_ptr - q->write_ptr;
+
+	if (q->read_ptr > q->write_ptr)
+		s -= q->n_bd;
+
+	if (s <= 0)
+		s += q->n_window;
+	/* keep some reserve to not confuse empty and full situations */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl3945_queue_inc_wrap(int index, int n_bd)
+{
+	return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl3945_queue_dec_wrap - increment queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl3945_queue_dec_wrap(int index, int n_bd)
+{
+	return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl3945_queue *q, int i)
+{
+	return q->write_ptr > q->read_ptr ?
+		(i >= q->read_ptr && i < q->write_ptr) :
+		!(i < q->read_ptr && i >= q->write_ptr);
+}
+
+static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge)
+{
+	/* This is for scan command, the big buffer at end of command array */
+	if (is_huge)
+		return q->n_window;	/* must be power of 2 */
+
+	/* Otherwise, use normal size buffers */
+	return index & (q->n_window - 1);
+}
+
+/**
+ * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q,
+			  int count, int slots_num, u32 id)
+{
+	q->n_bd = count;
+	q->n_window = slots_num;
+	q->id = id;
+
+	/* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap
+	 * and iwl3945_queue_dec_wrap are broken. */
+	BUG_ON(!is_power_of_2(count));
+
+	/* slots_num must be power-of-two size, otherwise
+	 * get_cmd_index is broken. */
+	BUG_ON(!is_power_of_2(slots_num));
+
+	q->low_mark = q->n_window / 4;
+	if (q->low_mark < 4)
+		q->low_mark = 4;
+
+	q->high_mark = q->n_window / 8;
+	if (q->high_mark < 2)
+		q->high_mark = 2;
+
+	q->write_ptr = q->read_ptr = 0;
+
+	return 0;
+}
+
+/**
+ * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv,
+			      struct iwl3945_tx_queue *txq, u32 id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+
+	/* Driver private data, only for Tx (not command) queues,
+	 * not shared with device. */
+	if (id != IWL_CMD_QUEUE_NUM) {
+		txq->txb = kmalloc(sizeof(txq->txb[0]) *
+				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+		if (!txq->txb) {
+			IWL_ERROR("kmalloc for auxiliary BD "
+				  "structures failed\n");
+			goto error;
+		}
+	} else
+		txq->txb = NULL;
+
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
+	txq->bd = pci_alloc_consistent(dev,
+			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+			&txq->q.dma_addr);
+
+	if (!txq->bd) {
+		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+		goto error;
+	}
+	txq->q.id = id;
+
+	return 0;
+
+ error:
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+/**
+ * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
+		      struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+	int rc = 0;
+
+	/*
+	 * Alloc buffer array for commands (Tx or other types of commands).
+	 * For the command queue (#4), allocate command space + one big
+	 * command for scan, since scan command is very huge; the system will
+	 * not have two scans at the same time, so only one is needed.
+	 * For data Tx queues (all other queues), no super-size command
+	 * space is needed.
+	 */
+	len = sizeof(struct iwl3945_cmd) * slots_num;
+	if (txq_id == IWL_CMD_QUEUE_NUM)
+		len +=  IWL_MAX_SCAN_SIZE;
+	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+	if (!txq->cmd)
+		return -ENOMEM;
+
+	/* Alloc driver data array and TFD circular buffer */
+	rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
+	if (rc) {
+		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+		return -ENOMEM;
+	}
+	txq->need_update = 0;
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+	/* Initialize queue high/low-water, head/tail indexes */
+	iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	/* Tell device where to find queue, enable DMA channel. */
+	iwl3945_hw_tx_queue_init(priv, txq);
+
+	return 0;
+}
+
+/**
+ * iwl3945_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
+{
+	struct iwl3945_queue *q = &txq->q;
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+
+	if (q->n_bd == 0)
+		return;
+
+	/* first, empty all BD's */
+	for (; q->write_ptr != q->read_ptr;
+	     q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd))
+		iwl3945_hw_txq_free_tfd(priv, txq);
+
+	len = sizeof(struct iwl3945_cmd) * q->n_window;
+	if (q->id == IWL_CMD_QUEUE_NUM)
+		len += IWL_MAX_SCAN_SIZE;
+
+	/* De-alloc array of command/tx buffers */
+	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+	/* De-alloc circular buffer of TFDs */
+	if (txq->q.n_bd)
+		pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) *
+				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+	/* De-alloc array of per-TFD driver data */
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	/* 0-fill queue descriptor structure */
+	memset(txq, 0, sizeof(*txq));
+}
+
+const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ * mac80211 should be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+#if 0 /* temporary disable till we add real remove station */
+/**
+ * iwl3945_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE:  This does not remove station from device's station table.
+ */
+static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap)
+{
+	int index = IWL_INVALID_STATION;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+			if (priv->stations[i].used &&
+			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+	if (unlikely(index == IWL_INVALID_STATION))
+		goto out;
+
+	if (priv->stations[index].used) {
+		priv->stations[index].used = 0;
+		priv->num_stations--;
+	}
+
+	BUG_ON(priv->num_stations < 0);
+
+out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return 0;
+}
+#endif
+
+/**
+ * iwl3945_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+static void iwl3945_clear_stations_table(struct iwl3945_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+/**
+ * iwl3945_add_station - Add station to station tables in driver and device
+ */
+u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+	int i;
+	int index = IWL_INVALID_STATION;
+	struct iwl3945_station_entry *station;
+	unsigned long flags_spin;
+	DECLARE_MAC_BUF(mac);
+	u8 rate;
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+			if (!priv->stations[i].used &&
+			    index == IWL_INVALID_STATION)
+				index = i;
+		}
+
+	/* These two conditions has the same outcome but keep them separate
+	  since they have different meaning */
+	if (unlikely(index == IWL_INVALID_STATION)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	if (priv->stations[index].used &&
+	   !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+	station = &priv->stations[index];
+	station->used = 1;
+	priv->num_stations++;
+
+	/* Set up the REPLY_ADD_STA command to send to device */
+	memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
+	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+	station->sta.mode = 0;
+	station->sta.sta.sta_id = index;
+	station->sta.station_flags = 0;
+
+	if (priv->phymode == MODE_IEEE80211A)
+		rate = IWL_RATE_6M_PLCP;
+	else
+		rate =	IWL_RATE_1M_PLCP;
+
+	/* Turn on both antennas for the station... */
+	station->sta.rate_n_flags =
+			iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
+	station->current_rate.rate_n_flags =
+			le16_to_cpu(station->sta.rate_n_flags);
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+	/* Add station to device's station table */
+	iwl3945_send_add_station(priv, &station->sta, flags);
+	return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS   *****/
+
+static inline int iwl3945_is_ready(struct iwl3945_priv *priv)
+{
+	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+	 * set but EXIT_PENDING is not */
+	return test_bit(STATUS_READY, &priv->status) &&
+	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl3945_is_alive(struct iwl3945_priv *priv)
+{
+	return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl3945_is_init(struct iwl3945_priv *priv)
+{
+	return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
+{
+	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	       test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
+{
+
+	if (iwl3945_is_rfkill(priv))
+		return 0;
+
+	return iwl3945_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+		IWL_CMD(REPLY_ALIVE);
+		IWL_CMD(REPLY_ERROR);
+		IWL_CMD(REPLY_RXON);
+		IWL_CMD(REPLY_RXON_ASSOC);
+		IWL_CMD(REPLY_QOS_PARAM);
+		IWL_CMD(REPLY_RXON_TIMING);
+		IWL_CMD(REPLY_ADD_STA);
+		IWL_CMD(REPLY_REMOVE_STA);
+		IWL_CMD(REPLY_REMOVE_ALL_STA);
+		IWL_CMD(REPLY_3945_RX);
+		IWL_CMD(REPLY_TX);
+		IWL_CMD(REPLY_RATE_SCALE);
+		IWL_CMD(REPLY_LEDS_CMD);
+		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+		IWL_CMD(RADAR_NOTIFICATION);
+		IWL_CMD(REPLY_QUIET_CMD);
+		IWL_CMD(REPLY_CHANNEL_SWITCH);
+		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+		IWL_CMD(POWER_TABLE_CMD);
+		IWL_CMD(PM_SLEEP_NOTIFICATION);
+		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+		IWL_CMD(REPLY_SCAN_CMD);
+		IWL_CMD(REPLY_SCAN_ABORT_CMD);
+		IWL_CMD(SCAN_START_NOTIFICATION);
+		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+		IWL_CMD(BEACON_NOTIFICATION);
+		IWL_CMD(REPLY_TX_BEACON);
+		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+		IWL_CMD(QUIET_NOTIFICATION);
+		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+		IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+		IWL_CMD(REPLY_BT_CONFIG);
+		IWL_CMD(REPLY_STATISTICS_CMD);
+		IWL_CMD(STATISTICS_NOTIFICATION);
+		IWL_CMD(REPLY_CARD_STATE_CMD);
+		IWL_CMD(CARD_STATE_NOTIFICATION);
+		IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl3945_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
+{
+	struct iwl3945_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl3945_queue *q = &txq->q;
+	struct iwl3945_tfd_frame *tfd;
+	u32 *control_flags;
+	struct iwl3945_cmd *out_cmd;
+	u32 idx;
+	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+	dma_addr_t phys_addr;
+	int pad;
+	u16 count;
+	int ret;
+	unsigned long flags;
+
+	/* If any of the command structures end up being larger than
+	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+	 * we will need to increase the size of the TFD entries */
+	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+	       !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+	if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+		IWL_ERROR("No space for Tx\n");
+		return -ENOSPC;
+	}
+
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+	tfd = &txq->bd[q->write_ptr];
+	memset(tfd, 0, sizeof(*tfd));
+
+	control_flags = (u32 *) tfd;
+
+	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+	out_cmd = &txq->cmd[idx];
+
+	out_cmd->hdr.cmd = cmd->id;
+	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+	/* At this point, the out_cmd now has all of the incoming cmd
+	 * information */
+
+	out_cmd->hdr.flags = 0;
+	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+			INDEX_TO_SEQ(q->write_ptr));
+	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+			offsetof(struct iwl3945_cmd, hdr);
+	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+	pad = U32_PAD(cmd->len);
+	count = TFD_CTL_COUNT_GET(*control_flags);
+	*control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);
+
+	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+		     "%d bytes at %d[%d]:%d\n",
+		     get_cmd_string(out_cmd->hdr.cmd),
+		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+
+	txq->need_update = 1;
+
+	/* Increment and update queue's write index */
+	q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+	ret = iwl3945_tx_queue_update_write_ptr(priv, txq);
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+	return ret ? ret : idx;
+}
+
+static int iwl3945_send_cmd_async(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
+{
+	int ret;
+
+	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+	/* An asynchronous command can not expect an SKB to be set. */
+	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+	/* An asynchronous command MUST have a callback. */
+	BUG_ON(!cmd->meta.u.callback);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EBUSY;
+
+	ret = iwl3945_enqueue_hcmd(priv, cmd);
+	if (ret < 0) {
+		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
+{
+	int cmd_idx;
+	int ret;
+	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+	BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+	 /* A synchronous command can not have a callback set. */
+	BUG_ON(cmd->meta.u.callback != NULL);
+
+	if (atomic_xchg(&entry, 1)) {
+		IWL_ERROR("Error sending %s: Already sending a host command\n",
+			  get_cmd_string(cmd->id));
+		return -EBUSY;
+	}
+
+	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+	if (cmd->meta.flags & CMD_WANT_SKB)
+		cmd->meta.source = &cmd->meta;
+
+	cmd_idx = iwl3945_enqueue_hcmd(priv, cmd);
+	if (cmd_idx < 0) {
+		ret = cmd_idx;
+		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		goto out;
+	}
+
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+			HOST_COMPLETE_TIMEOUT);
+	if (!ret) {
+		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+			IWL_ERROR("Error sending %s: time out after %dms.\n",
+				  get_cmd_string(cmd->id),
+				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+			ret = -ETIMEDOUT;
+			goto cancel;
+		}
+	}
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+			       get_cmd_string(cmd->id));
+		ret = -ECANCELED;
+		goto fail;
+	}
+	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+			       get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto fail;
+	}
+	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+		IWL_ERROR("Error: Response NULL in '%s'\n",
+			  get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = 0;
+	goto out;
+
+cancel:
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		struct iwl3945_cmd *qcmd;
+
+		/* Cancel the CMD_WANT_SKB flag for the cmd in the
+		 * TX cmd queue. Otherwise in case the cmd comes
+		 * in later, it will possibly set an invalid
+		 * address (cmd->meta.source). */
+		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+		qcmd->meta.flags &= ~CMD_WANT_SKB;
+	}
+fail:
+	if (cmd->meta.u.skb) {
+		dev_kfree_skb_any(cmd->meta.u.skb);
+		cmd->meta.u.skb = NULL;
+	}
+out:
+	atomic_set(&entry, 0);
+	return ret;
+}
+
+int iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
+{
+	if (cmd->meta.flags & CMD_ASYNC)
+		return iwl3945_send_cmd_async(priv, cmd);
+
+	return iwl3945_send_cmd_sync(priv, cmd);
+}
+
+int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, const void *data)
+{
+	struct iwl3945_host_cmd cmd = {
+		.id = id,
+		.len = len,
+		.data = data,
+	};
+
+	return iwl3945_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl3945_send_cmd_u32(struct iwl3945_priv *priv, u8 id, u32 val)
+{
+	struct iwl3945_host_cmd cmd = {
+		.id = id,
+		.len = sizeof(val),
+		.data = &val,
+	};
+
+	return iwl3945_send_cmd_sync(priv, &cmd);
+}
+
+int iwl3945_send_statistics_request(struct iwl3945_priv *priv)
+{
+	return iwl3945_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel)
+{
+	if (!iwl3945_get_channel_info(priv, phymode, channel)) {
+		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+			       channel, phymode);
+		return -EINVAL;
+	}
+
+	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+	    (priv->phymode == phymode))
+		return 0;
+
+	priv->staging_rxon.channel = cpu_to_le16(channel);
+	if (phymode == MODE_IEEE80211A)
+		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+	priv->phymode = phymode;
+
+	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+	return 0;
+}
+
+/**
+ * iwl3945_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE:  This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon)
+{
+	int error = 0;
+	int counter = 1;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		error |= le32_to_cpu(rxon->flags &
+				(RXON_FLG_TGJ_NARROW_BAND_MSK |
+				 RXON_FLG_RADAR_DETECT_MSK));
+		if (error)
+			IWL_WARNING("check 24G fields %d | %d\n",
+				    counter++, error);
+	} else {
+		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+		if (error)
+			IWL_WARNING("check 52 fields %d | %d\n",
+				    counter++, error);
+		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+		if (error)
+			IWL_WARNING("check 52 CCK %d | %d\n",
+				    counter++, error);
+	}
+	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+	if (error)
+		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+	if (error)
+		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+	if (error)
+		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+	if (error)
+		IWL_WARNING("check CCK and short slot %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+	if (error)
+		IWL_WARNING("check CCK & auto detect %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+	if (error)
+		IWL_WARNING("check TGG and auto detect %d | %d\n",
+			    counter++, error);
+
+	if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
+		error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK |
+				RXON_FLG_ANT_A_MSK)) == 0);
+	if (error)
+		IWL_WARNING("check antenna %d %d\n", counter++, error);
+
+	if (error)
+		IWL_WARNING("Tuning to channel %d\n",
+			    le16_to_cpu(rxon->channel));
+
+	if (error) {
+		IWL_ERROR("Not a valid iwl3945_rxon_assoc_cmd field values\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * iwl3945_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
+ *
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
+ */
+static int iwl3945_full_rxon_required(struct iwl3945_priv *priv)
+{
+
+	/* These items are only settable from the full RXON command */
+	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+	    compare_ether_addr(priv->staging_rxon.bssid_addr,
+			       priv->active_rxon.bssid_addr) ||
+	    compare_ether_addr(priv->staging_rxon.node_addr,
+			       priv->active_rxon.node_addr) ||
+	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+			       priv->active_rxon.wlap_bssid_addr) ||
+	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+	    (priv->staging_rxon.air_propagation !=
+	     priv->active_rxon.air_propagation) ||
+	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+		return 1;
+
+	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+	 * be updated with the RXON_ASSOC command -- however only some
+	 * flag transitions are allowed using RXON_ASSOC */
+
+	/* Check if we are not switching bands */
+	if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+	    (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+		return 1;
+
+	/* Check if we are switching association toggle */
+	if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+		(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+		return 1;
+
+	return 0;
+}
+
+static int iwl3945_send_rxon_assoc(struct iwl3945_priv *priv)
+{
+	int rc = 0;
+	struct iwl3945_rx_packet *res = NULL;
+	struct iwl3945_rxon_assoc_cmd rxon_assoc;
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_RXON_ASSOC,
+		.len = sizeof(rxon_assoc),
+		.meta.flags = CMD_WANT_SKB,
+		.data = &rxon_assoc,
+	};
+	const struct iwl3945_rxon_cmd *rxon1 = &priv->staging_rxon;
+	const struct iwl3945_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_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;
+
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl3945_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;
+}
+
+/**
+ * iwl3945_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is committed to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
+{
+	/* cast away the const for active_rxon in this function */
+	struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	int rc = 0;
+	DECLARE_MAC_BUF(mac);
+
+	if (!iwl3945_is_alive(priv))
+		return -1;
+
+	/* always get timestamp with Rx frame */
+	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+	/* select antenna */
+	priv->staging_rxon.flags &=
+	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
+	priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
+
+	rc = iwl3945_check_rxon_cmd(&priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
+		return -EINVAL;
+	}
+
+	/* If we don't need to send a full RXON, we can use
+	 * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
+	 * and other flags for the current radio configuration. */
+	if (!iwl3945_full_rxon_required(priv)) {
+		rc = iwl3945_send_rxon_assoc(priv);
+		if (rc) {
+			IWL_ERROR("Error setting RXON_ASSOC "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+
+		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+		return 0;
+	}
+
+	/* If we are currently associated and the new config requires
+	 * an RXON_ASSOC and the new config wants the associated mask enabled,
+	 * we must clear the associated from the active configuration
+	 * before we apply the new config */
+	if (iwl3945_is_associated(priv) &&
+	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl3945_rxon_cmd),
+				      &priv->active_rxon);
+
+		/* If the mask clearing failed then we set
+		 * active_rxon back to what it was previously */
+		if (rc) {
+			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+			IWL_ERROR("Error clearing ASSOC_MSK on current "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+	}
+
+	IWL_DEBUG_INFO("Sending RXON\n"
+		       "* with%s RXON_FILTER_ASSOC_MSK\n"
+		       "* channel = %d\n"
+		       "* bssid = %s\n",
+		       ((priv->staging_rxon.filter_flags &
+			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+		       le16_to_cpu(priv->staging_rxon.channel),
+		       print_mac(mac, priv->staging_rxon.bssid_addr));
+
+	/* Apply the new configuration */
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl3945_rxon_cmd), &priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Error setting new configuration (%d).\n", rc);
+		return rc;
+	}
+
+	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+	iwl3945_clear_stations_table(priv);
+
+	/* If we issue a new RXON command which required a tune then we must
+	 * send a new TXPOWER command or we won't be able to Tx any frames */
+	rc = iwl3945_hw_reg_send_txpower(priv);
+	if (rc) {
+		IWL_ERROR("Error setting Tx power (%d).\n", rc);
+		return rc;
+	}
+
+	/* Add the broadcast address so we can send broadcast frames */
+	if (iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0) ==
+	    IWL_INVALID_STATION) {
+		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+		return -EIO;
+	}
+
+	/* If we have set the ASSOC_MSK and we are in BSS mode then
+	 * add the IWL_AP_ID to the station rate table */
+	if (iwl3945_is_associated(priv) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
+		    == IWL_INVALID_STATION) {
+			IWL_ERROR("Error adding AP address for transmit.\n");
+			return -EIO;
+		}
+
+	/* Init the hardware's rate fallback order based on the
+	 * phymode */
+	rc = iwl3945_init_hw_rate_table(priv);
+	if (rc) {
+		IWL_ERROR("Error setting HW rate table: %02X\n", rc);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int iwl3945_send_bt_config(struct iwl3945_priv *priv)
+{
+	struct iwl3945_bt_cmd bt_cmd = {
+		.flags = 3,
+		.lead_time = 0xAA,
+		.max_kill = 1,
+		.kill_ack_mask = 0,
+		.kill_cts_mask = 0,
+	};
+
+	return iwl3945_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl3945_bt_cmd), &bt_cmd);
+}
+
+static int iwl3945_send_scan_abort(struct iwl3945_priv *priv)
+{
+	int rc = 0;
+	struct iwl3945_rx_packet *res;
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_SCAN_ABORT_CMD,
+		.meta.flags = CMD_WANT_SKB,
+	};
+
+	/* If there isn't a scan actively going on in the hardware
+	 * then we are in between scan bands and not actually
+	 * actively scanning, so don't send the abort command */
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return 0;
+	}
+
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
+	if (rc) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return rc;
+	}
+
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
+	if (res->u.status != CAN_ABORT_STATUS) {
+		/* The scan abort will return 1 for success or
+		 * 2 for "failure".  A failure condition can be
+		 * due to simply not being in an active scan which
+		 * can occur if we send the scan abort before we
+		 * the microcode has notified us that a scan is
+		 * completed. */
+		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv,
+					struct iwl3945_cmd *cmd,
+					struct sk_buff *skb)
+{
+	return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the device's internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl3945_send_card_state(struct iwl3945_priv *priv, u32 flags, u8 meta_flag)
+{
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_CARD_STATE_CMD,
+		.len = sizeof(u32),
+		.data = &flags,
+		.meta.flags = meta_flag,
+	};
+
+	if (meta_flag & CMD_ASYNC)
+		cmd.meta.u.callback = iwl3945_card_state_sync_callback;
+
+	return iwl3945_send_cmd(priv, &cmd);
+}
+
+static int iwl3945_add_sta_sync_callback(struct iwl3945_priv *priv,
+				     struct iwl3945_cmd *cmd, struct sk_buff *skb)
+{
+	struct iwl3945_rx_packet *res = NULL;
+
+	if (!skb) {
+		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+		return 1;
+	}
+
+	res = (struct iwl3945_rx_packet *)skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		return 1;
+	}
+
+	switch (res->u.add_sta.status) {
+	case ADD_STA_SUCCESS_MSK:
+		break;
+	default:
+		break;
+	}
+
+	/* We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+int iwl3945_send_add_station(struct iwl3945_priv *priv,
+			 struct iwl3945_addsta_cmd *sta, u8 flags)
+{
+	struct iwl3945_rx_packet *res = NULL;
+	int rc = 0;
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_ADD_STA,
+		.len = sizeof(struct iwl3945_addsta_cmd),
+		.meta.flags = flags,
+		.data = sta,
+	};
+
+	if (flags & CMD_ASYNC)
+		cmd.meta.u.callback = iwl3945_add_sta_sync_callback;
+	else
+		cmd.meta.flags |= CMD_WANT_SKB;
+
+	rc = iwl3945_send_cmd(priv, &cmd);
+
+	if (rc || (flags & CMD_ASYNC))
+		return rc;
+
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		rc = -EIO;
+	}
+
+	if (rc == 0) {
+		switch (res->u.add_sta.status) {
+		case ADD_STA_SUCCESS_MSK:
+			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+			break;
+		default:
+			rc = -EIO;
+			IWL_WARNING("REPLY_ADD_STA failed\n");
+			break;
+		}
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl3945_update_sta_key_info(struct iwl3945_priv *priv,
+				   struct ieee80211_key_conf *keyconf,
+				   u8 sta_id)
+{
+	unsigned long flags;
+	__le16 key_flags = 0;
+
+	switch (keyconf->alg) {
+	case ALG_CCMP:
+		key_flags |= STA_KEY_FLG_CCMP;
+		key_flags |= cpu_to_le16(
+				keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+		key_flags &= ~STA_KEY_FLG_INVALID;
+		break;
+	case ALG_TKIP:
+	case ALG_WEP:
+	default:
+		return -EINVAL;
+	}
+	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_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");
+	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static int iwl3945_clear_sta_key_info(struct iwl3945_priv *priv, u8 sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
+	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl3945_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");
+	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static void iwl3945_clear_free_frames(struct iwl3945_priv *priv)
+{
+	struct list_head *element;
+
+	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+		       priv->frames_count);
+
+	while (!list_empty(&priv->free_frames)) {
+		element = priv->free_frames.next;
+		list_del(element);
+		kfree(list_entry(element, struct iwl3945_frame, list));
+		priv->frames_count--;
+	}
+
+	if (priv->frames_count) {
+		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
+			    priv->frames_count);
+		priv->frames_count = 0;
+	}
+}
+
+static struct iwl3945_frame *iwl3945_get_free_frame(struct iwl3945_priv *priv)
+{
+	struct iwl3945_frame *frame;
+	struct list_head *element;
+	if (list_empty(&priv->free_frames)) {
+		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+		if (!frame) {
+			IWL_ERROR("Could not allocate frame!\n");
+			return NULL;
+		}
+
+		priv->frames_count++;
+		return frame;
+	}
+
+	element = priv->free_frames.next;
+	list_del(element);
+	return list_entry(element, struct iwl3945_frame, list);
+}
+
+static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+	list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
+				struct ieee80211_hdr *hdr,
+				const u8 *dest, int left)
+{
+
+	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
+	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+		return 0;
+
+	if (priv->ibss_beacon->len > left)
+		return 0;
+
+	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+	return priv->ibss_beacon->len;
+}
+
+static int iwl3945_rate_index_from_plcp(int plcp)
+{
+	int i = 0;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++)
+		if (iwl3945_rates[i].plcp == plcp)
+			return i;
+	return -1;
+}
+
+static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
+{
+	u8 i;
+
+	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+	     i = iwl3945_rates[i].next_ieee) {
+		if (rate_mask & (1 << i))
+			return iwl3945_rates[i].plcp;
+	}
+
+	return IWL_RATE_INVALID;
+}
+
+static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv)
+{
+	struct iwl3945_frame *frame;
+	unsigned int frame_size;
+	int rc;
+	u8 rate;
+
+	frame = iwl3945_get_free_frame(priv);
+
+	if (!frame) {
+		IWL_ERROR("Could not obtain free frame buffer for beacon "
+			  "command.\n");
+		return -ENOMEM;
+	}
+
+	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic &
+						0xFF0);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_6M_PLCP;
+	} else {
+		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_1M_PLCP;
+	}
+
+	frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
+
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+			      &frame->u.cmd[0]);
+
+	iwl3945_free_frame(priv, frame);
+
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac)
+{
+	memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl3945_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM contents from adapter into priv->eeprom
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl3945_eeprom_init(struct iwl3945_priv *priv)
+{
+	u16 *e = (u16 *)&priv->eeprom;
+	u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
+	u32 r;
+	int sz = sizeof(priv->eeprom);
+	int rc;
+	int i;
+	u16 addr;
+
+	/* The EEPROM structure has several padding buffers within it
+	 * and when adding new EEPROM maps is subject to programmer errors
+	 * which may be very difficult to identify without explicitly
+	 * checking the resulting size of the eeprom map. */
+	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+		return -ENOENT;
+	}
+
+	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
+	rc = iwl3945_eeprom_acquire_semaphore(priv);
+	if (rc < 0) {
+		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
+		return -ENOENT;
+	}
+
+	/* eeprom is an array of 16bit values */
+	for (addr = 0; addr < sz; addr += sizeof(u16)) {
+		_iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+					i += IWL_EEPROM_ACCESS_DELAY) {
+			r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
+			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+				break;
+			udelay(IWL_EEPROM_ACCESS_DELAY);
+		}
+
+		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+			IWL_ERROR("Time out reading EEPROM[%d]", addr);
+			return -ETIMEDOUT;
+		}
+		e[addr / 2] = le16_to_cpu(r >> 16);
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWL3945_DEBUG
+
+/**
+ * iwl3945_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ */
+void iwl3945_report_frame(struct iwl3945_priv *priv,
+		      struct iwl3945_rx_packet *pkt,
+		      struct ieee80211_hdr *header, int group100)
+{
+	u32 to_us;
+	u32 print_summary = 0;
+	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
+	u32 hundred = 0;
+	u32 dataframe = 0;
+	u16 fc;
+	u16 seq_ctl;
+	u16 channel;
+	u16 phy_flags;
+	int rate_sym;
+	u16 length;
+	u16 status;
+	u16 bcn_tmr;
+	u32 tsf_low;
+	u64 tsf;
+	u8 rssi;
+	u8 agc;
+	u16 sig_avg;
+	u16 noise_diff;
+	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	u8 *data = IWL_RX_DATA(pkt);
+
+	/* MAC header */
+	fc = le16_to_cpu(header->frame_control);
+	seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+	/* metadata */
+	channel = le16_to_cpu(rx_hdr->channel);
+	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	rate_sym = rx_hdr->rate;
+	length = le16_to_cpu(rx_hdr->len);
+
+	/* end-of-frame status and timestamp */
+	status = le32_to_cpu(rx_end->status);
+	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+	tsf = le64_to_cpu(rx_end->timestamp);
+
+	/* signal statistics */
+	rssi = rx_stats->rssi;
+	agc = rx_stats->agc;
+	sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+	/* if data frame is to us and all is good,
+	 *   (optionally) print summary for only 1 out of every 100 */
+	if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+	    (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+		dataframe = 1;
+		if (!group100)
+			print_summary = 1;	/* print each frame */
+		else if (priv->framecnt_to_us < 100) {
+			priv->framecnt_to_us++;
+			print_summary = 0;
+		} else {
+			priv->framecnt_to_us = 0;
+			print_summary = 1;
+			hundred = 1;
+		}
+	} else {
+		/* print summary for all other frames */
+		print_summary = 1;
+	}
+
+	if (print_summary) {
+		char *title;
+		u32 rate;
+
+		if (hundred)
+			title = "100Frames";
+		else if (fc & IEEE80211_FCTL_RETRY)
+			title = "Retry";
+		else if (ieee80211_is_assoc_response(fc))
+			title = "AscRsp";
+		else if (ieee80211_is_reassoc_response(fc))
+			title = "RasRsp";
+		else if (ieee80211_is_probe_response(fc)) {
+			title = "PrbRsp";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_beacon(fc)) {
+			title = "Beacon";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_atim(fc))
+			title = "ATIM";
+		else if (ieee80211_is_auth(fc))
+			title = "Auth";
+		else if (ieee80211_is_deauth(fc))
+			title = "DeAuth";
+		else if (ieee80211_is_disassoc(fc))
+			title = "DisAssoc";
+		else
+			title = "Frame";
+
+		rate = iwl3945_rate_index_from_plcp(rate_sym);
+		if (rate == -1)
+			rate = 0;
+		else
+			rate = iwl3945_rates[rate].ieee / 2;
+
+		/* print frame summary.
+		 * MAC addresses show just the last byte (for brevity),
+		 *    but you can hack it to show more, if you'd like to. */
+		if (dataframe)
+			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+				     title, fc, header->addr1[5],
+				     length, rssi, channel, rate);
+		else {
+			/* src/dst addresses assume managed mode */
+			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+				     "src=0x%02x, rssi=%u, tim=%lu usec, "
+				     "phy=0x%02x, chnl=%d\n",
+				     title, fc, header->addr1[5],
+				     header->addr3[5], rssi,
+				     tsf_low - priv->scan_start_tsf,
+				     phy_flags, channel);
+		}
+	}
+	if (print_dump)
+		iwl3945_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv)
+{
+	if (priv->hw_setting.shared_virt)
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct iwl3945_shared),
+				    priv->hw_setting.shared_virt,
+				    priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl3945_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+				    u16 basic_rate, int *left)
+{
+	u16 ret_rates = 0, bit;
+	int i;
+	u8 *cnt = ie;
+	u8 *rates = ie + 1;
+
+	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+		if (bit & supported_rate) {
+			ret_rates |= bit;
+			rates[*cnt] = iwl3945_rates[i].ieee |
+				((bit & basic_rate) ? 0x80 : 0x00);
+			(*cnt)++;
+			(*left)--;
+			if ((*left <= 0) ||
+			    (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
+				break;
+		}
+	}
+
+	return ret_rates;
+}
+
+/**
+ * iwl3945_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
+			      struct ieee80211_mgmt *frame,
+			      int left, int is_direct)
+{
+	int len = 0;
+	u8 *pos = NULL;
+	u16 active_rates, ret_rates, cck_rates;
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+	len += 24;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	memcpy(frame->da, iwl3945_broadcast_addr, ETH_ALEN);
+	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+	memcpy(frame->bssid, iwl3945_broadcast_addr, ETH_ALEN);
+	frame->seq_ctrl = 0;
+
+	/* fill in our indirect SSID IE */
+	/* ...next IE... */
+
+	left -= 2;
+	if (left < 0)
+		return 0;
+	len += 2;
+	pos = &(frame->u.probe_req.variable[0]);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = 0;
+
+	/* fill in our direct SSID IE... */
+	if (is_direct) {
+		/* ...next IE... */
+		left -= 2 + priv->essid_len;
+		if (left < 0)
+			return 0;
+		/* ... fill it in... */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = priv->essid_len;
+		memcpy(pos, priv->essid, priv->essid_len);
+		pos += priv->essid_len;
+		len += 2 + priv->essid_len;
+	}
+
+	/* fill in supported rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos = 0;
+
+	priv->active_rate = priv->rates_mask;
+	active_rates = priv->active_rate;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	cck_rates = IWL_CCK_RATES_MASK & active_rates;
+	ret_rates = iwl3945_supported_rate_to_ie(pos, cck_rates,
+			priv->active_rate_basic, &left);
+	active_rates &= ~ret_rates;
+
+	ret_rates = iwl3945_supported_rate_to_ie(pos, active_rates,
+				 priv->active_rate_basic, &left);
+	active_rates &= ~ret_rates;
+
+	len += 2 + *pos;
+	pos += (*pos) + 1;
+	if (active_rates == 0)
+		goto fill_end;
+
+	/* fill in supported extended rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos = 0;
+	iwl3945_supported_rate_to_ie(pos, active_rates,
+				 priv->active_rate_basic, &left);
+	if (*pos > 0)
+		len += 2 + *pos;
+
+ fill_end:
+	return (u16)len;
+}
+
+/*
+ * QoS  support
+*/
+#ifdef CONFIG_IWL3945_QOS
+static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv,
+				       struct iwl3945_qosparam_cmd *qos)
+{
+
+	return iwl3945_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl3945_qosparam_cmd), qos);
+}
+
+static void iwl3945_reset_qos(struct iwl3945_priv *priv)
+{
+	u16 cw_min = 15;
+	u16 cw_max = 1023;
+	u8 aifs = 2;
+	u8 is_legacy = 0;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.qos_active = 0;
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+		if (!(priv->active_rate & 0xfff0)) {
+			cw_min = 31;
+			is_legacy = 1;
+		}
+	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+		cw_min = 31;
+		is_legacy = 1;
+	}
+
+	if (priv->qos_data.qos_active)
+		aifs = 3;
+
+	priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+	priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+	priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+	priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+	priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+	if (priv->qos_data.qos_active) {
+		i = 1;
+		priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+		priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+		priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 2;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(6016);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3008);
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 3;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 4 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16((cw_max + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3264);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(1504);
+	} else {
+		for (i = 1; i < 4; i++) {
+			priv->qos_data.def_qos_parm.ac[i].cw_min =
+				cpu_to_le16(cw_min);
+			priv->qos_data.def_qos_parm.ac[i].cw_max =
+				cpu_to_le16(cw_max);
+			priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+			priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+			priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		}
+	}
+	IWL_DEBUG_QOS("set QoS to default \n");
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force)
+{
+	unsigned long flags;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!priv->qos_data.qos_enable)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.def_qos_parm.qos_flags = 0;
+
+	if (priv->qos_data.qos_cap.q_AP.queue_request &&
+	    !priv->qos_data.qos_cap.q_AP.txop_request)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+	if (priv->qos_data.qos_active)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (force || iwl3945_is_associated(priv)) {
+		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+			      priv->qos_data.qos_active);
+
+		iwl3945_send_qos_params_command(priv,
+				&(priv->qos_data.def_qos_parm));
+	}
+}
+
+#endif /* CONFIG_IWL3945_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le32(0)
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+				     __constant_cpu_to_le32(X1), \
+				     __constant_cpu_to_le32(X2), \
+				     __constant_cpu_to_le32(X3), \
+				     __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim  0-10 */
+static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+		 SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+		 SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl3945_power_init_handle(struct iwl3945_priv *priv)
+{
+	int rc = 0, i;
+	struct iwl3945_power_mgr *pow_data;
+	int size = sizeof(struct iwl3945_power_vec_entry) * IWL_POWER_AC;
+	u16 pci_pm;
+
+	IWL_DEBUG_POWER("Initialize power \n");
+
+	pow_data = &(priv->power_data);
+
+	memset(pow_data, 0, sizeof(*pow_data));
+
+	pow_data->active_index = IWL_POWER_RANGE_0;
+	pow_data->dtim_val = 0xffff;
+
+	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+	rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+	if (rc != 0)
+		return 0;
+	else {
+		struct iwl3945_powertable_cmd *cmd;
+
+		IWL_DEBUG_POWER("adjust power command flags\n");
+
+		for (i = 0; i < IWL_POWER_AC; i++) {
+			cmd = &pow_data->pwr_range_0[i].cmd;
+
+			if (pci_pm & 0x1)
+				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+			else
+				cmd->flags |= IWL_POWER_PCI_PM_MSK;
+		}
+	}
+	return rc;
+}
+
+static int iwl3945_update_power_cmd(struct iwl3945_priv *priv,
+				struct iwl3945_powertable_cmd *cmd, u32 mode)
+{
+	int rc = 0, i;
+	u8 skip;
+	u32 max_sleep = 0;
+	struct iwl3945_power_vec_entry *range;
+	u8 period = 0;
+	struct iwl3945_power_mgr *pow_data;
+
+	if (mode > IWL_POWER_INDEX_5) {
+		IWL_DEBUG_POWER("Error invalid power mode \n");
+		return -1;
+	}
+	pow_data = &(priv->power_data);
+
+	if (pow_data->active_index == IWL_POWER_RANGE_0)
+		range = &pow_data->pwr_range_0[0];
+	else
+		range = &pow_data->pwr_range_1[1];
+
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl3945_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+	if (priv->assoc_network != NULL) {
+		unsigned long flags;
+
+		period = priv->assoc_network->tim.tim_period;
+	}
+#endif	/*IWL_MAC80211_DISABLE */
+	skip = range[mode].no_dtim;
+
+	if (period == 0) {
+		period = 1;
+		skip = 0;
+	}
+
+	if (skip == 0) {
+		max_sleep = period;
+		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	} else {
+		__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+		max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	}
+
+	for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+		if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+			cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+	}
+
+	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+	IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+	IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+	IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+			le32_to_cpu(cmd->sleep_interval[0]),
+			le32_to_cpu(cmd->sleep_interval[1]),
+			le32_to_cpu(cmd->sleep_interval[2]),
+			le32_to_cpu(cmd->sleep_interval[3]),
+			le32_to_cpu(cmd->sleep_interval[4]));
+
+	return rc;
+}
+
+static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
+{
+	u32 uninitialized_var(final_mode);
+	int rc;
+	struct iwl3945_powertable_cmd cmd;
+
+	/* If on battery, set to 3,
+	 * if plugged into AC power, set to CAM ("continuously aware mode"),
+	 * else user level */
+	switch (mode) {
+	case IWL_POWER_BATTERY:
+		final_mode = IWL_POWER_INDEX_3;
+		break;
+	case IWL_POWER_AC:
+		final_mode = IWL_POWER_MODE_CAM;
+		break;
+	default:
+		final_mode = mode;
+		break;
+	}
+
+	iwl3945_update_power_cmd(priv, &cmd, final_mode);
+
+	rc = iwl3945_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+	if (final_mode == IWL_POWER_MODE_CAM)
+		clear_bit(STATUS_POWER_PMI, &priv->status);
+	else
+		set_bit(STATUS_POWER_PMI, &priv->status);
+
+	return rc;
+}
+
+int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
+{
+	/* Filter incoming packets to determine if they are targeted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr2, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our IBSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr3, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr3, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our BSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr2, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	}
+
+	return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static const char *iwl3945_get_tx_fail_reason(u32 status)
+{
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+		TX_STATUS_ENTRY(SHORT_LIMIT);
+		TX_STATUS_ENTRY(LONG_LIMIT);
+		TX_STATUS_ENTRY(FIFO_UNDERRUN);
+		TX_STATUS_ENTRY(MGMNT_ABORT);
+		TX_STATUS_ENTRY(NEXT_FRAG);
+		TX_STATUS_ENTRY(LIFE_EXPIRE);
+		TX_STATUS_ENTRY(DEST_PS);
+		TX_STATUS_ENTRY(ABORTED);
+		TX_STATUS_ENTRY(BT_RETRY);
+		TX_STATUS_ENTRY(STA_INVALID);
+		TX_STATUS_ENTRY(FRAG_DROPPED);
+		TX_STATUS_ENTRY(TID_DISABLE);
+		TX_STATUS_ENTRY(FRAME_FLUSHED);
+		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+		TX_STATUS_ENTRY(TX_LOCKED);
+		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * iwl3945_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl3945_scan_cancel(struct iwl3945_priv *priv)
+{
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCANNING, &priv->status);
+		return 0;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+			IWL_DEBUG_SCAN("Queuing scan abort.\n");
+			set_bit(STATUS_SCAN_ABORTING, &priv->status);
+			queue_work(priv->workqueue, &priv->abort_scan);
+
+		} else
+			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return 0;
+}
+
+/**
+ * iwl3945_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long ms)
+{
+	unsigned long now = jiffies;
+	int ret;
+
+	ret = iwl3945_scan_cancel(priv);
+	if (ret && ms) {
+		mutex_unlock(&priv->mutex);
+		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+				test_bit(STATUS_SCANNING, &priv->status))
+			msleep(1);
+		mutex_lock(&priv->mutex);
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return ret;
+}
+
+static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
+{
+	/* Reset ieee stats */
+
+	/* We don't reset the net_device_stats (ieee->stats) on
+	 * re-association */
+
+	priv->last_seq_num = -1;
+	priv->last_frag_num = -1;
+	priv->last_packet_time = 0;
+
+	iwl3945_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL	1024
+#define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
+
+static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
+{
+	u16 new_val = 0;
+	u16 beacon_factor = 0;
+
+	beacon_factor =
+	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+		/ MAX_UCODE_BEACON_INTERVAL;
+	new_val = beacon_val / beacon_factor;
+
+	return cpu_to_le16(new_val);
+}
+
+static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv)
+{
+	u64 interval_tm_unit;
+	u64 tsf, result;
+	unsigned long flags;
+	struct ieee80211_conf *conf = NULL;
+	u16 beacon_int = 0;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+	priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+	tsf = priv->timestamp1;
+	tsf = ((tsf << 32) | priv->timestamp0);
+
+	beacon_int = priv->beacon_int;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+		if (beacon_int == 0) {
+			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+		} else {
+			priv->rxon_timing.beacon_interval =
+				cpu_to_le16(beacon_int);
+			priv->rxon_timing.beacon_interval =
+			    iwl3945_adjust_beacon_interval(
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+		}
+
+		priv->rxon_timing.atim_window = 0;
+	} else {
+		priv->rxon_timing.beacon_interval =
+			iwl3945_adjust_beacon_interval(conf->beacon_int);
+		/* TODO: we need to get atim_window from upper stack
+		 * for now we set to 0 */
+		priv->rxon_timing.atim_window = 0;
+	}
+
+	interval_tm_unit =
+		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+	result = do_div(tsf, interval_tm_unit);
+	priv->rxon_timing.beacon_init_val =
+	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+	IWL_DEBUG_ASSOC
+	    ("beacon interval %d beacon timer %d beacon tim %d\n",
+		le16_to_cpu(priv->rxon_timing.beacon_interval),
+		le32_to_cpu(priv->rxon_timing.beacon_init_val),
+		le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("APs don't scan.\n");
+		return 0;
+	}
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan already in progress.\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan request while abort pending.  "
+			       "Queuing.\n");
+		return -EAGAIN;
+	}
+
+	IWL_DEBUG_INFO("Starting scan...\n");
+	priv->scan_bands = 2;
+	set_bit(STATUS_SCANNING, &priv->status);
+	priv->scan_start = jiffies;
+	priv->scan_pass_start = priv->scan_start;
+
+	queue_work(priv->workqueue, &priv->request_scan);
+
+	return 0;
+}
+
+static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt)
+{
+	struct iwl3945_rxon_cmd *rxon = &priv->staging_rxon;
+
+	if (hw_decrypt)
+		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+	else
+		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+	return 0;
+}
+
+static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode)
+{
+	if (phymode == MODE_IEEE80211A) {
+		priv->staging_rxon.flags &=
+		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+		      | RXON_FLG_CCK_MSK);
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	} else {
+		/* Copied from iwl3945_bg_post_associate() */
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+	}
+}
+
+/*
+ * initialize rxon structure with default values from eeprom
+ */
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
+{
+	const struct iwl3945_channel_info *ch_info;
+
+	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_AP:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+		break;
+
+	case IEEE80211_IF_TYPE_STA:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+						  RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+	}
+
+#if 0
+	/* TODO:  Figure out when short_preamble would be set and cache from
+	 * that */
+	if (!hw_to_local(priv->hw)->short_preamble)
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+	ch_info = iwl3945_get_channel_info(priv, priv->phymode,
+				       le16_to_cpu(priv->staging_rxon.channel));
+
+	if (!ch_info)
+		ch_info = &priv->channel_info[0];
+
+	/*
+	 * in some case A channels are all non IBSS
+	 * in this case force B/G channel
+	 */
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !(is_channel_ibss(ch_info)))
+		ch_info = &priv->channel_info[0];
+
+	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+	if (is_channel_a_band(ch_info))
+		priv->phymode = MODE_IEEE80211A;
+	else
+		priv->phymode = MODE_IEEE80211G;
+
+	iwl3945_set_flags_for_phymode(priv, priv->phymode);
+
+	priv->staging_rxon.ofdm_basic_rates =
+	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+	priv->staging_rxon.cck_basic_rates =
+	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+}
+
+static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
+{
+	if (mode == IEEE80211_IF_TYPE_IBSS) {
+		const struct iwl3945_channel_info *ch_info;
+
+		ch_info = iwl3945_get_channel_info(priv,
+			priv->phymode,
+			le16_to_cpu(priv->staging_rxon.channel));
+
+		if (!ch_info || !is_channel_ibss(ch_info)) {
+			IWL_ERROR("channel %d not IBSS channel\n",
+				  le16_to_cpu(priv->staging_rxon.channel));
+			return -EINVAL;
+		}
+	}
+
+	priv->iw_mode = mode;
+
+	iwl3945_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl3945_clear_stations_table(priv);
+
+	/* dont commit rxon if rf-kill is on*/
+	if (!iwl3945_is_ready_rf(priv))
+		return -EAGAIN;
+
+	cancel_delayed_work(&priv->scan_check);
+	if (iwl3945_scan_cancel_timeout(priv, 100)) {
+		IWL_WARNING("Aborted scan still in progress after 100ms\n");
+		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+		return -EAGAIN;
+	}
+
+	iwl3945_commit_rxon(priv);
+
+	return 0;
+}
+
+static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
+				      struct ieee80211_tx_control *ctl,
+				      struct iwl3945_cmd *cmd,
+				      struct sk_buff *skb_frag,
+				      int last_frag)
+{
+	struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+	switch (keyinfo->alg) {
+	case ALG_CCMP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		break;
+
+	case ALG_TKIP:
+#if 0
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+		if (last_frag)
+			memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+			       8);
+		else
+			memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+		break;
+
+	case ALG_WEP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+		    (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+		if (keyinfo->keylen == 13)
+			cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+		IWL_DEBUG_TX("Configuring packet for WEP encryption "
+			     "with key %d\n", ctl->key_idx);
+		break;
+
+	default:
+		printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+		break;
+	}
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
+				  struct iwl3945_cmd *cmd,
+				  struct ieee80211_tx_control *ctrl,
+				  struct ieee80211_hdr *hdr,
+				  int is_unicast, u8 std_id)
+{
+	__le16 *qc;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	__le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+	cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+	if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		tx_flags |= TX_CMD_FLG_ACK_MSK;
+		if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		if (ieee80211_is_probe_response(fc) &&
+		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+			tx_flags |= TX_CMD_FLG_TSF_MSK;
+	} else {
+		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+	}
+
+	cmd->cmd.tx.sta_id = std_id;
+	if (ieee80211_get_morefrag(hdr))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	} else
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+	if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		tx_flags |= TX_CMD_FLG_RTS_MSK;
+		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+	} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+		tx_flags |= TX_CMD_FLG_CTS_MSK;
+	}
+
+	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
+		else
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
+	} else
+		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+	cmd->cmd.tx.driver_txop = 0;
+	cmd->cmd.tx.tx_flags = tx_flags;
+	cmd->cmd.tx.next_frame_len = 0;
+}
+
+/**
+ * iwl3945_get_sta_id - Find station's index within station table
+ */
+static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr)
+{
+	int sta_id;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	/* 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;
+
+	switch (priv->iw_mode) {
+
+	/* If we are a client station in a BSS network, use the special
+	 * AP station entry (that's the only station we communicate with) */
+	case IEEE80211_IF_TYPE_STA:
+		return IWL_AP_ID;
+
+	/* If we are an AP, then find the station, or use BCAST */
+	case IEEE80211_IF_TYPE_AP:
+		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+		return priv->hw_setting.bcast_sta_id;
+
+	/* If this frame is going out to an IBSS network, find the station,
+	 * or create a new station table entry */
+	case IEEE80211_IF_TYPE_IBSS: {
+		DECLARE_MAC_BUF(mac);
+
+		/* Create new station table entry */
+		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		IWL_DEBUG_DROP("Station %s not in station map. "
+			       "Defaulting to broadcast...\n",
+			       print_mac(mac, hdr->addr1));
+		iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		return priv->hw_setting.bcast_sta_id;
+	}
+	default:
+		IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+		return priv->hw_setting.bcast_sta_id;
+	}
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl3945_tx_skb(struct iwl3945_priv *priv,
+		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl3945_tfd_frame *tfd;
+	u32 *control_flags;
+	int txq_id = ctl->queue;
+	struct iwl3945_tx_queue *txq = NULL;
+	struct iwl3945_queue *q = NULL;
+	dma_addr_t phys_addr;
+	dma_addr_t txcmd_phys;
+	struct iwl3945_cmd *out_cmd = NULL;
+	u16 len, idx, len_org;
+	u8 id, hdr_len, unicast;
+	u8 sta_id;
+	u16 seq_number = 0;
+	u16 fc;
+	__le16 *qc;
+	u8 wait_write_ptr = 0;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (iwl3945_is_rfkill(priv)) {
+		IWL_DEBUG_DROP("Dropping - RF KILL\n");
+		goto drop_unlock;
+	}
+
+	if (!priv->interface_id) {
+		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+		goto drop_unlock;
+	}
+
+	if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+		IWL_ERROR("ERROR: No TX rate available.\n");
+		goto drop_unlock;
+	}
+
+	unicast = !is_multicast_ether_addr(hdr->addr1);
+	id = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (ieee80211_is_auth(fc))
+		IWL_DEBUG_TX("Sending AUTH frame\n");
+	else if (ieee80211_is_assoc_request(fc))
+		IWL_DEBUG_TX("Sending ASSOC frame\n");
+	else if (ieee80211_is_reassoc_request(fc))
+		IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+	/* drop all data frame if we are not associated */
+	if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
+	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+		IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
+		goto drop_unlock;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	hdr_len = ieee80211_get_hdrlen(fc);
+
+	/* Find (or create) index into station table for destination station */
+	sta_id = iwl3945_get_sta_id(priv, hdr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+			       print_mac(mac, hdr->addr1));
+		goto drop;
+	}
+
+	IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+		seq_number = priv->stations[sta_id].tid[tid].seq_number &
+				IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl = cpu_to_le16(seq_number) |
+			(hdr->seq_ctrl &
+				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+		seq_number += 0x10;
+	}
+
+	/* Descriptor for chosen Tx queue */
+	txq = &priv->txq[txq_id];
+	q = &txq->q;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Set up first empty TFD within this queue's circular TFD buffer */
+	tfd = &txq->bd[q->write_ptr];
+	memset(tfd, 0, sizeof(*tfd));
+	control_flags = (u32 *) tfd;
+	idx = get_cmd_index(q, q->write_ptr, 0);
+
+	/* Set up driver data for this TFD */
+	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
+	txq->txb[q->write_ptr].skb[0] = skb;
+	memcpy(&(txq->txb[q->write_ptr].status.control),
+	       ctl, sizeof(struct ieee80211_tx_control));
+
+	/* Init first empty entry in queue's array of Tx/cmd buffers */
+	out_cmd = &txq->cmd[idx];
+	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+
+	/*
+	 * Set up the Tx-command (not MAC!) header.
+	 * Store the chosen Tx queue and TFD index within the sequence field;
+	 * after Tx, uCode's Tx response will return this value so driver can
+	 * locate the frame within the tx queue and do post-tx processing.
+	 */
+	out_cmd->hdr.cmd = REPLY_TX;
+	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+				INDEX_TO_SEQ(q->write_ptr)));
+
+	/* Copy MAC header from skb into command buffer */
+	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+	/*
+	 * Use the first empty entry in this queue's command buffer array
+	 * to contain the Tx command and MAC header concatenated together
+	 * (payload data will be in another buffer).
+	 * Size of this varies, due to varying MAC header length.
+	 * If end is not dword aligned, we'll have 2 extra bytes at the end
+	 * of the MAC header (device reads on dword boundaries).
+	 * We'll tell device about this padding later.
+	 */
+	len = priv->hw_setting.tx_cmd_len +
+		sizeof(struct iwl3945_cmd_header) + hdr_len;
+
+	len_org = len;
+	len = (len + 3) & ~3;
+
+	if (len_org != len)
+		len_org = 1;
+	else
+		len_org = 0;
+
+	/* Physical address of this Tx command's header (not MAC header!),
+	 * within command buffer array. */
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl3945_cmd) * idx +
+		     offsetof(struct iwl3945_cmd, hdr);
+
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+		iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+	/* Set up TFD's 2nd entry to point directly to remainder of skb,
+	 * if any (802.11 null frames have no payload). */
+	len = skb->len - hdr_len;
+	if (len) {
+		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+					   len, PCI_DMA_TODEVICE);
+		iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+	}
+
+	if (!len)
+		/* If there is no payload, then we use only one Tx buffer */
+		*control_flags = TFD_CTL_COUNT_SET(1);
+	else
+		/* Else use 2 buffers.
+		 * Tell 3945 about any padding after MAC header */
+		*control_flags = TFD_CTL_COUNT_SET(2) |
+			TFD_CTL_PAD_SET(U32_PAD(len));
+
+	/* Total # bytes to be transmitted */
+	len = (u16)skb->len;
+	out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+	/* TODO need this for burst mode later on */
+	iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+	/* set is_hcca to 0; it probably will never be implemented */
+	iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+
+	if (!ieee80211_get_morefrag(hdr)) {
+		txq->need_update = 1;
+		if (qc) {
+			u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+			priv->stations[sta_id].tid[tid].seq_number = seq_number;
+		}
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
+	}
+
+	iwl3945_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+			   sizeof(out_cmd->cmd.tx));
+
+	iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+			   ieee80211_get_hdrlen(fc));
+
+	/* Tell device the write index *just past* this latest filled TFD */
+	q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+	rc = iwl3945_tx_queue_update_write_ptr(priv, txq);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (rc)
+		return rc;
+
+	if ((iwl3945_queue_space(q) < q->high_mark)
+	    && priv->mac80211_registered) {
+		if (wait_write_ptr) {
+			spin_lock_irqsave(&priv->lock, flags);
+			txq->need_update = 1;
+			iwl3945_tx_queue_update_write_ptr(priv, txq);
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+
+		ieee80211_stop_queue(priv->hw, ctl->queue);
+	}
+
+	return 0;
+
+drop_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+	return -1;
+}
+
+static void iwl3945_set_rate(struct iwl3945_priv *priv)
+{
+	const struct ieee80211_hw_mode *hw = NULL;
+	struct ieee80211_rate *rate;
+	int i;
+
+	hw = iwl3945_get_hw_mode(priv, priv->phymode);
+	if (!hw) {
+		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
+		return;
+	}
+
+	priv->active_rate = 0;
+	priv->active_rate_basic = 0;
+
+	IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+		       hw->mode == MODE_IEEE80211A ?
+		       'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+	for (i = 0; i < hw->num_rates; i++) {
+		rate = &(hw->rates[i]);
+		if ((rate->val < IWL_RATE_COUNT) &&
+		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+				       rate->val, iwl3945_rates[rate->val].plcp,
+				       (rate->flags & IEEE80211_RATE_BASIC) ?
+				       "*" : "");
+			priv->active_rate |= (1 << rate->val);
+			if (rate->flags & IEEE80211_RATE_BASIC)
+				priv->active_rate_basic |= (1 << rate->val);
+		} else
+			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+				       rate->val, iwl3945_rates[rate->val].plcp);
+	}
+
+	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+		       priv->active_rate, priv->active_rate_basic);
+
+	/*
+	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+	 * OFDM
+	 */
+	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+		priv->staging_rxon.cck_basic_rates =
+		    ((priv->active_rate_basic &
+		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+	else
+		priv->staging_rxon.cck_basic_rates =
+		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+		priv->staging_rxon.ofdm_basic_rates =
+		    ((priv->active_rate_basic &
+		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+		      IWL_FIRST_OFDM_RATE) & 0xFF;
+	else
+		priv->staging_rxon.ofdm_basic_rates =
+		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio)
+{
+	unsigned long flags;
+
+	if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+		return;
+
+	IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+			  disable_radio ? "OFF" : "ON");
+
+	if (disable_radio) {
+		iwl3945_scan_cancel(priv);
+		/* FIXME: This is a workaround for AP */
+		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+			spin_lock_irqsave(&priv->lock, flags);
+			iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_SW_BIT_RFKILL);
+			spin_unlock_irqrestore(&priv->lock, flags);
+			iwl3945_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			set_bit(STATUS_RF_KILL_SW, &priv->status);
+		}
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_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);
+
+	/* wake up ucode */
+	msleep(10);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_read32(priv, CSR_UCODE_DRV_GP1);
+	if (!iwl3945_grab_nic_access(priv))
+		iwl3945_release_nic_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+				  "disabled by HW switch\n");
+		return;
+	}
+
+	queue_work(priv->workqueue, &priv->restart);
+	return;
+}
+
+void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
+			    u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+	u16 fc =
+	    le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+	if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+		return;
+
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return;
+
+	IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_ICV_MIC)
+			stats->flag |= RX_FLAG_MMIC_ERROR;
+	case RX_RES_STATUS_SEC_TYPE_WEP:
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_DECRYPT_OK) {
+			IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+			stats->flag |= RX_FLAG_DECRYPTED;
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_mem_buffer *rxb,
+				    void *data, short len,
+				    struct ieee80211_rx_status *stats,
+				    u16 phy_flags)
+{
+	struct iwl3945_rt_rx_hdr *iwl3945_rt;
+
+	/* First cache any information we need before we overwrite
+	 * the information provided in the skb from the hardware */
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+	/* We received data from the HW, so stop the watchdog */
+	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl3945_rt)) {
+		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+		return;
+	}
+
+	/* copy the frame data to write after where the radiotap header goes */
+	iwl3945_rt = (void *)rxb->skb->data;
+	memmove(iwl3945_rt->payload, data, len);
+
+	iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl3945_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+	/* total header + data */
+	iwl3945_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl3945_rt));
+
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, sizeof(*iwl3945_rt) + len);
+
+	/* Big bitfield of all the fields we provide in radiotap */
+	iwl3945_rt->rt_hdr.it_present =
+	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+			(1 << IEEE80211_RADIOTAP_FLAGS) |
+			(1 << IEEE80211_RADIOTAP_RATE) |
+			(1 << IEEE80211_RADIOTAP_CHANNEL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+			(1 << IEEE80211_RADIOTAP_ANTENNA));
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl3945_rt->rt_flags = 0;
+
+	iwl3945_rt->rt_tsf = cpu_to_le64(tsf);
+
+	/* Convert to dBm */
+	iwl3945_rt->rt_dbmsignal = signal;
+	iwl3945_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	iwl3945_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		iwl3945_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		iwl3945_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+	else	/* 802.11g */
+		iwl3945_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+	rate = iwl3945_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl3945_rt->rt_rate = 0;
+	else
+		iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
+
+	/* antenna number */
+	iwl3945_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if we have it */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
+{
+	u16 sc = le16_to_cpu(header->seq_ctrl);
+	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	u16 frag = sc & IEEE80211_SCTL_FRAG;
+	u16 *last_seq, *last_frag;
+	unsigned long *last_time;
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS:{
+		struct list_head *p;
+		struct iwl3945_ibss_seq *entry = NULL;
+		u8 *mac = header->addr2;
+		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+		__list_for_each(p, &priv->ibss_mac_hash[index]) {
+			entry = list_entry(p, struct iwl3945_ibss_seq, list);
+			if (!compare_ether_addr(entry->mac, mac))
+				break;
+		}
+		if (p == &priv->ibss_mac_hash[index]) {
+			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+			if (!entry) {
+				IWL_ERROR("Cannot malloc new mac entry\n");
+				return 0;
+			}
+			memcpy(entry->mac, mac, ETH_ALEN);
+			entry->seq_num = seq;
+			entry->frag_num = frag;
+			entry->packet_time = jiffies;
+			list_add(&entry->list, &priv->ibss_mac_hash[index]);
+			return 0;
+		}
+		last_seq = &entry->seq_num;
+		last_frag = &entry->frag_num;
+		last_time = &entry->packet_time;
+		break;
+	}
+	case IEEE80211_IF_TYPE_STA:
+		last_seq = &priv->last_seq_num;
+		last_frag = &priv->last_frag_num;
+		last_time = &priv->last_packet_time;
+		break;
+	default:
+		return 0;
+	}
+	if ((*last_seq == seq) &&
+	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+		if (*last_frag == frag)
+			goto drop;
+		if (*last_frag + 1 != frag)
+			/* out-of-order fragment */
+			goto drop;
+	} else
+		*last_seq = seq;
+
+	*last_frag = frag;
+	*last_time = jiffies;
+	return 0;
+
+ drop:
+	return 1;
+}
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW	0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH	0xFF000000
+#define TIME_UNIT		1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * 1024;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+	return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl3945_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & BEACON_TIME_MASK_LOW;
+	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & BEACON_TIME_MASK_HIGH) +
+	    (addon & BEACON_TIME_MASK_HIGH);
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << 24);
+	} else
+		res += (1 << 24);
+
+	return cpu_to_le32(res);
+}
+
+static int iwl3945_get_measurement(struct iwl3945_priv *priv,
+			       struct ieee80211_measurement_params *params,
+			       u8 type)
+{
+	struct iwl3945_spectrum_cmd spectrum;
+	struct iwl3945_rx_packet *res;
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+		.data = (void *)&spectrum,
+		.meta.flags = CMD_WANT_SKB,
+	};
+	u32 add_time = le64_to_cpu(params->start_time);
+	int rc;
+	int spectrum_resp_status;
+	int duration = le16_to_cpu(params->duration);
+
+	if (iwl3945_is_associated(priv))
+		add_time =
+		    iwl3945_usecs_to_beacons(
+			le64_to_cpu(params->start_time) - priv->last_tsf,
+			le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+	memset(&spectrum, 0, sizeof(spectrum));
+
+	spectrum.channel_count = cpu_to_le16(1);
+	spectrum.flags =
+	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+	cmd.len = sizeof(spectrum);
+	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+	if (iwl3945_is_associated(priv))
+		spectrum.start_time =
+		    iwl3945_add_beacon_time(priv->last_beacon_time,
+				add_time,
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+	else
+		spectrum.start_time = 0;
+
+	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+	spectrum.channels[0].channel = params->channel;
+	spectrum.channels[0].type = type;
+	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+	switch (spectrum_resp_status) {
+	case 0:		/* Command will be handled */
+		if (res->u.spectrum.id != 0xff) {
+			IWL_DEBUG_INFO("Replaced existing measurement: %d\n",
+						res->u.spectrum.id);
+			priv->measurement_status &= ~MEASUREMENT_READY;
+		}
+		priv->measurement_status |= MEASUREMENT_ACTIVE;
+		rc = 0;
+		break;
+
+	case 1:		/* Command will not be handled */
+		rc = -EAGAIN;
+		break;
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+#endif
+
+static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv,
+				 struct iwl3945_tx_info *tx_sta)
+{
+
+	tx_sta->status.ack_signal = 0;
+	tx_sta->status.excessive_retries = 0;
+	tx_sta->status.queue_length = 0;
+	tx_sta->status.queue_number = 0;
+
+	if (in_interrupt())
+		ieee80211_tx_status_irqsafe(priv->hw,
+					    tx_sta->skb[0], &(tx_sta->status));
+	else
+		ieee80211_tx_status(priv->hw,
+				    tx_sta->skb[0], &(tx_sta->status));
+
+	tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms. If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index)
+{
+	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl3945_queue *q = &txq->q;
+	int nfreed = 0;
+
+	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+			  "is out of range [0-%d] %d %d.\n", txq_id,
+			  index, q->n_bd, q->write_ptr, q->read_ptr);
+		return 0;
+	}
+
+	for (index = iwl3945_queue_inc_wrap(index, q->n_bd);
+		q->read_ptr != index;
+		q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+		if (txq_id != IWL_CMD_QUEUE_NUM) {
+			iwl3945_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.read_ptr]));
+			iwl3945_hw_txq_free_tfd(priv, txq);
+		} else if (nfreed > 1) {
+			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+					q->write_ptr, q->read_ptr);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+		nfreed++;
+	}
+
+	if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+			(txq_id != IWL_CMD_QUEUE_NUM) &&
+			priv->mac80211_registered)
+		ieee80211_wake_queue(priv->hw, txq_id);
+
+
+	return nfreed;
+}
+
+static int iwl3945_is_tx_success(u32 status)
+{
+	return (status & 0xFF) == 0x1;
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+/**
+ * iwl3945_rx_reply_tx - Handle Tx response
+ */
+static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
+			    struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+	struct ieee80211_tx_status *tx_status;
+	struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	u32  status = le32_to_cpu(tx_resp->status);
+
+	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+			  "is out of range [0-%d] %d %d\n", txq_id,
+			  index, txq->q.n_bd, txq->q.write_ptr,
+			  txq->q.read_ptr);
+		return;
+	}
+
+	tx_status = &(txq->txb[txq->q.read_ptr].status);
+
+	tx_status->retry_count = tx_resp->failure_frame;
+	tx_status->queue_number = status;
+	tx_status->queue_length = tx_resp->bt_kill_count;
+	tx_status->queue_length |= tx_resp->failure_rts;
+
+	tx_status->flags =
+	    iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+	tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate);
+
+	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
+			txq_id, iwl3945_get_tx_fail_reason(status), status,
+			tx_resp->rate, tx_resp->failure_frame);
+
+	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+	if (index != -1)
+		iwl3945_tx_queue_reclaim(priv, txq_id, index);
+
+	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_alive_resp *palive;
+	struct work_struct *pwork;
+
+	palive = &pkt->u.alive_frame;
+
+	IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+		IWL_DEBUG_INFO("Initialization Alive received.\n");
+		memcpy(&priv->card_alive_init,
+		       &pkt->u.alive_frame,
+		       sizeof(struct iwl3945_init_alive_resp));
+		pwork = &priv->init_alive_start;
+	} else {
+		IWL_DEBUG_INFO("Runtime Alive received.\n");
+		memcpy(&priv->card_alive, &pkt->u.alive_frame,
+		       sizeof(struct iwl3945_alive_resp));
+		pwork = &priv->alive_start;
+		iwl3945_disable_events(priv);
+	}
+
+	/* We delay the ALIVE response by 5ms to
+	 * give the HW RF Kill time to activate... */
+	if (palive->is_valid == UCODE_VALID_OK)
+		queue_delayed_work(priv->workqueue, pwork,
+				   msecs_to_jiffies(5));
+	else
+		IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl3945_rx_reply_add_sta(struct iwl3945_priv *priv,
+				 struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+	return;
+}
+
+static void iwl3945_rx_reply_error(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+		"seq 0x%04X ser 0x%08X\n",
+		le32_to_cpu(pkt->u.err_resp.error_type),
+		get_cmd_string(pkt->u.err_resp.cmd_id),
+		pkt->u.err_resp.cmd_id,
+		le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+		le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl3945_rx_csa(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl3945_csa_notification *csa = &(pkt->u.csa_notif);
+	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+	rxon->channel = csa->channel;
+	priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl3945_rx_spectrum_measure_notif(struct iwl3945_priv *priv,
+					  struct iwl3945_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+	if (!report->state) {
+		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+			  "Spectrum Measure Notification: Start\n");
+		return;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl3945_rx_pm_sleep_notif(struct iwl3945_priv *priv,
+				  struct iwl3945_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_sleep_notification *sleep = &(pkt->u.sleep_notif);
+	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl3945_rx_pm_debug_statistics_notif(struct iwl3945_priv *priv,
+					     struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+			"notification for %s:\n",
+			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+	iwl3945_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl3945_bg_beacon_update(void *p)
+{
+	struct iwl3945_priv *priv = p;
+	struct sk_buff *beacon;
+
+	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+	if (!beacon) {
+		IWL_ERROR("update beacon failed\n");
+		return;
+	}
+
+	mutex_lock(&priv->mutex);
+	/* new beacon skb is allocated every time; dispose previous.*/
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = beacon;
+	mutex_unlock(&priv->mutex);
+
+	iwl3945_send_beacon_cmd(priv);
+}
+
+static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
+	u8 rate = beacon->beacon_notify_hdr.rate;
+
+	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+		"tsf %d %d rate %d\n",
+		le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+		beacon->beacon_notify_hdr.failure_frame,
+		le32_to_cpu(beacon->ibss_mgr_status),
+		le32_to_cpu(beacon->high_tsf),
+		le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+		queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl3945_rx_reply_scan(struct iwl3945_priv *priv,
+			      struct iwl3945_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanreq_notification *notif =
+	    (struct iwl3945_scanreq_notification *)pkt->u.raw;
+
+	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl3945_rx_scan_start_notif(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanstart_notification *notif =
+	    (struct iwl3945_scanstart_notification *)pkt->u.raw;
+	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+	IWL_DEBUG_SCAN("Scan start: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       notif->tsf_high,
+		       notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl3945_rx_scan_results_notif(struct iwl3945_priv *priv,
+				      struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanresults_notification *notif =
+	    (struct iwl3945_scanresults_notification *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan ch.res: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d "
+		       "elapsed=%lu usec (%dms since last)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       le32_to_cpu(notif->statistics[0]),
+		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->last_scan_jiffies, jiffies)));
+
+	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv,
+				       struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+		       scan_notif->scanned_channels,
+		       scan_notif->tsf_low,
+		       scan_notif->tsf_high, scan_notif->status);
+
+	/* The HW is no longer scanning */
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+
+	/* The scan completion notification came in, so kill that timer... */
+	cancel_delayed_work(&priv->scan_check);
+
+	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+		       (priv->scan_bands == 2) ? "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--;
+
+	/* If a request to abort was given, or the scan did not succeed
+	 * then we reset the scan state machine and terminate,
+	 * re-queuing another scan if one has been requested */
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_INFO("Aborted scan completed.\n");
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	} else {
+		/* If there are more bands on this scan pass reschedule */
+		if (priv->scan_bands > 0)
+			goto reschedule;
+	}
+
+	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
+	IWL_DEBUG_INFO("Setting scan to off\n");
+
+	clear_bit(STATUS_SCANNING, &priv->status);
+
+	IWL_DEBUG_INFO("Scan took %dms\n",
+		jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+	queue_work(priv->workqueue, &priv->scan_completed);
+
+	return;
+
+reschedule:
+	priv->scan_pass_start = jiffies;
+	queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl3945_rx_card_state_notif(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+	unsigned long status = priv->status;
+
+	IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	if (flags & HW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+	if (flags & SW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+	iwl3945_scan_cancel(priv);
+
+	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+	    (test_bit(STATUS_RF_KILL_SW, &status) !=
+	     test_bit(STATUS_RF_KILL_SW, &priv->status)))
+		queue_work(priv->workqueue, &priv->rf_kill);
+	else
+		wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl3945_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv)
+{
+	priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl3945_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl3945_rx_csa;
+	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+	    iwl3945_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl3945_rx_pm_sleep_notif;
+	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+	    iwl3945_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif;
+
+	/*
+	 * The same handler is used for both the REPLY to a discrete
+	 * statistics request from the host as well as for the periodic
+	 * statistics notifications (after received beacons) from the uCode.
+	 */
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
+
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl3945_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl3945_rx_scan_start_notif;
+	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+	    iwl3945_rx_scan_results_notif;
+	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+	    iwl3945_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx;
+
+	/* Set up hardware specific Rx handlers */
+	iwl3945_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
+{
+	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	int huge = sequence & SEQ_HUGE_FRAME;
+	int cmd_index;
+	struct iwl3945_cmd *cmd;
+
+	/* If a Tx command is being handled and it isn't in the actual
+	 * command queue then there a command routing bug has been introduced
+	 * in the queue management code. */
+	if (txq_id != IWL_CMD_QUEUE_NUM)
+		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+			  txq_id, pkt->hdr.cmd);
+	BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+	cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+	/* Input error checking is done when commands are added to queue. */
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		cmd->meta.source->u.skb = rxb->skb;
+		rxb->skb = NULL;
+	} else if (cmd->meta.u.callback &&
+		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
+		rxb->skb = NULL;
+
+	iwl3945_tx_queue_reclaim(priv, txq_id, index);
+
+	if (!(cmd->meta.flags & CMD_ASYNC)) {
+		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
+	}
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl3945_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl3945_rx_queue_alloc()   Allocates rx_free
+ * iwl3945_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl3945_rx_queue_restock
+ * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl3945_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl3945_rx()         Detach iwl3945_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl3945_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl3945_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl3945_rx_queue_space(const struct iwl3945_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl3945_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q)
+{
+	u32 reg = 0;
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&q->lock, flags);
+
+	if (q->need_update == 0)
+		goto exit_unlock;
+
+	/* If power-saving is in use, make sure device is awake */
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			iwl3945_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			goto exit_unlock;
+		}
+
+		rc = iwl3945_grab_nic_access(priv);
+		if (rc)
+			goto exit_unlock;
+
+		/* Device expects a multiple of 8 */
+		iwl3945_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
+				     q->write & ~0x7);
+		iwl3945_release_nic_access(priv);
+
+	/* Else device is assumed to be awake */
+	} else
+		/* Device expects a multiple of 8 */
+		iwl3945_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+	q->need_update = 0;
+
+ exit_unlock:
+	spin_unlock_irqrestore(&q->lock, flags);
+	return rc;
+}
+
+/**
+ * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl3945_priv *priv,
+					  dma_addr_t dma_addr)
+{
+	return cpu_to_le32((u32)dma_addr);
+}
+
+/**
+ * iwl3945_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv)
+{
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl3945_rx_mem_buffer *rxb;
+	unsigned long flags;
+	int write, rc;
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	write = rxq->write & ~0x7;
+	while ((iwl3945_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		/* Get next free Rx buffer, remove from free list */
+		element = rxq->rx_free.next;
+		rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list);
+		list_del(element);
+
+		/* Point to Rx buffer via next RBD in circular buffer */
+		rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+		rxq->queue[rxq->write] = rxb;
+		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+		rxq->free_count--;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+	/* If the pre-allocated buffer pool is dropping low, schedule to
+	 * refill it */
+	if (rxq->free_count <= RX_LOW_WATERMARK)
+		queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+	/* If we've added more space for the firmware to place data, tell it.
+	 * Increment device's write pointer in multiples of 8. */
+	if ((write != (rxq->write & ~0x7))
+	    || (abs(rxq->write - rxq->read) > 7)) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		rxq->need_update = 1;
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		rc = iwl3945_rx_queue_update_write_ptr(priv, rxq);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * iwl3945_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl3945_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+static void iwl3945_rx_allocate(struct iwl3945_priv *priv)
+{
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl3945_rx_mem_buffer *rxb;
+	unsigned long flags;
+	spin_lock_irqsave(&rxq->lock, flags);
+	while (!list_empty(&rxq->rx_used)) {
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list);
+
+		/* Alloc a new receive buffer */
+		rxb->skb =
+		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+		if (!rxb->skb) {
+			if (net_ratelimit())
+				printk(KERN_CRIT DRV_NAME
+				       ": Can not allocate SKB buffers\n");
+			/* We don't reschedule replenish work here -- we will
+			 * call the restock method and if it still needs
+			 * more buffers it will schedule replenish */
+			break;
+		}
+		priv->alloc_rxb_skb++;
+		list_del(element);
+
+		/* Get physical address of RB/SKB */
+		rxb->dma_addr =
+		    pci_map_single(priv->pci_dev, rxb->skb->data,
+				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+ */
+static void __iwl3945_rx_replenish(void *data)
+{
+	struct iwl3945_priv *priv = data;
+
+	iwl3945_rx_allocate(priv);
+	iwl3945_rx_queue_restock(priv);
+}
+
+
+void iwl3945_rx_replenish(void *data)
+{
+	struct iwl3945_priv *priv = data;
+	unsigned long flags;
+
+	iwl3945_rx_allocate(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_rx_queue_restock(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+static void iwl3945_rx_queue_free(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
+{
+	int i;
+	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rxq->pool[i].skb);
+		}
+	}
+
+	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+			    rxq->dma_addr);
+	rxq->bd = NULL;
+}
+
+int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv)
+{
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+
+	spin_lock_init(&rxq->lock);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+
+	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
+	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+	if (!rxq->bd)
+		return -ENOMEM;
+
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	rxq->need_update = 0;
+	return 0;
+}
+
+void iwl3945_rx_queue_reset(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
+{
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb(rxq->pool[i].skb);
+			rxq->pool[i].skb = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/*	 0   1   2   3   4   5   6   7   8   9 */
+	 0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+	20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+	26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+	29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+	32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+	34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+	36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+	37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+	38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+	39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ *   (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl3945_calc_db_from_ratio(int sig_ratio)
+{
+	/* Anything above 1000:1 just report as 60 dB */
+	if (sig_ratio > 1000)
+		return 60;
+
+	/* Above 100:1, divide by 10 and use table,
+	 *   add 20 dB to make up for divide by 10 */
+	if (sig_ratio > 100)
+		return (20 + (int)ratio2dB[sig_ratio/10]);
+
+	/* We shouldn't see this */
+	if (sig_ratio < 1)
+		return 0;
+
+	/* Use table for ratios 1:1 - 99:1 */
+	return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95)   /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ *   about formulas used below. */
+int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+	int sig_qual;
+	int degradation = PERFECT_RSSI - rssi_dbm;
+
+	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
+	 * as indicator; formula is (signal dbm - noise dbm).
+	 * SNR at or above 40 is a great signal (100%).
+	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+	 * Weakest usable signal is usually 10 - 15 dB SNR. */
+	if (noise_dbm) {
+		if (rssi_dbm - noise_dbm >= 40)
+			return 100;
+		else if (rssi_dbm < noise_dbm)
+			return 0;
+		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+	/* Else use just the signal level.
+	 * This formula is a least squares fit of data points collected and
+	 *   compared with a reference system that had a percentage (%) display
+	 *   for signal quality. */
+	} else
+		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+			    (15 * RSSI_RANGE + 62 * degradation)) /
+			   (RSSI_RANGE * RSSI_RANGE);
+
+	if (sig_qual > 100)
+		sig_qual = 100;
+	else if (sig_qual < 1)
+		sig_qual = 0;
+
+	return sig_qual;
+}
+
+/**
+ * iwl3945_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl3945_rx_handle(struct iwl3945_priv *priv)
+{
+	struct iwl3945_rx_mem_buffer *rxb;
+	struct iwl3945_rx_packet *pkt;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
+	u32 r, i;
+	int reclaim;
+	unsigned long flags;
+	u8 fill_rx = 0;
+	u32 count = 0;
+
+	/* uCode's read index (stored in shared DRAM) indicates the last Rx
+	 * buffer that the driver may process (last buffer filled by ucode). */
+	r = iwl3945_hw_get_rx_read(priv);
+	i = rxq->read;
+
+	if (iwl3945_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
+	/* Rx interrupt, but nothing sent from uCode */
+	if (i == r)
+		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+	while (i != r) {
+		rxb = rxq->queue[i];
+
+		/* If an RXB doesn't have a Rx queue slot associated with it,
+		 * then a bug has been introduced in the queue refilling
+		 * routines -- catch it here */
+		BUG_ON(rxb == NULL);
+
+		rxq->queue[i] = NULL;
+
+		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+					    IWL_RX_BUF_SIZE,
+					    PCI_DMA_FROMDEVICE);
+		pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+
+		/* Reclaim a command buffer only if this packet is a response
+		 *   to a (driver-originated) command.
+		 * If the packet (e.g. Rx frame) originated from uCode,
+		 *   there is no command buffer to reclaim.
+		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+		 *   but apparently a few don't get set; catch them here. */
+		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+			(pkt->hdr.cmd != REPLY_TX);
+
+		/* Based on type of command response or notification,
+		 *   handle those that need handling via function in
+		 *   rx_handlers table.  See iwl3945_setup_rx_handlers() */
+		if (priv->rx_handlers[pkt->hdr.cmd]) {
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r = %d, i = %d, %s, 0x%02x\n", r, i,
+				get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+			priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+		} else {
+			/* No handling needed */
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r %d i %d No handler needed for %s, 0x%02x\n",
+				r, i, get_cmd_string(pkt->hdr.cmd),
+				pkt->hdr.cmd);
+		}
+
+		if (reclaim) {
+			/* Invoke any callbacks, transfer the skb to caller, and
+			 * fire off the (possibly) blocking iwl3945_send_cmd()
+			 * as we reclaim the driver command queue */
+			if (rxb && rxb->skb)
+				iwl3945_tx_cmd_complete(priv, rxb);
+			else
+				IWL_WARNING("Claim null rxb?\n");
+		}
+
+		/* For now we just don't re-use anything.  We can tweak this
+		 * later to try and re-use notification packets and SKBs that
+		 * fail to Rx correctly */
+		if (rxb->skb != NULL) {
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb_any(rxb->skb);
+			rxb->skb = NULL;
+		}
+
+		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+				 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		spin_lock_irqsave(&rxq->lock, flags);
+		list_add_tail(&rxb->list, &priv->rxq.rx_used);
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		i = (i + 1) & RX_QUEUE_MASK;
+		/* If there are a lot of unused frames,
+		 * restock the Rx queue so ucode won't assert. */
+		if (fill_rx) {
+			count++;
+			if (count >= 8) {
+				priv->rxq.read = i;
+				__iwl3945_rx_replenish(priv);
+				count = 0;
+			}
+		}
+	}
+
+	/* Backtrack one entry */
+	priv->rxq.read = i;
+	iwl3945_rx_queue_restock(priv);
+}
+
+/**
+ * iwl3945_tx_queue_update_write_ptr - Send new write index to hardware
+ */
+static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
+				  struct iwl3945_tx_queue *txq)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int txq_id = txq->q.id;
+
+	if (txq->need_update == 0)
+		return rc;
+
+	/* if we're trying to save power */
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		/* 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 = iwl3945_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);
+			iwl3945_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 = iwl3945_grab_nic_access(priv);
+		if (rc)
+			return rc;
+		iwl3945_write_direct32(priv, HBUS_TARG_WRPTR,
+				     txq->q.write_ptr | (txq_id << 8));
+		iwl3945_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
+		iwl3945_write32(priv, HBUS_TARG_WRPTR,
+			    txq->q.write_ptr | (txq_id << 8));
+
+	txq->need_update = 0;
+
+	return rc;
+}
+
+#ifdef CONFIG_IWL3945_DEBUG
+static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon)
+{
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_RADIO("RX CONFIG:\n");
+	iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+			le32_to_cpu(rxon->filter_flags));
+	IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+			rxon->ofdm_basic_rates);
+	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+			print_mac(mac, rxon->node_addr));
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
+{
+	IWL_DEBUG_ISR("Enabling interrupts\n");
+	set_bit(STATUS_INT_ENABLED, &priv->status);
+	iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv)
+{
+	clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl3945_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* acknowledge/clear/reset any interrupts still pending
+	 * from uCode or flow handler (Rx/Tx DMA) */
+	iwl3945_write32(priv, CSR_INT, 0xffffffff);
+	iwl3945_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+	switch (i) {
+	case 1:
+		return "FAIL";
+	case 2:
+		return "BAD_PARAM";
+	case 3:
+		return "BAD_CHECKSUM";
+	case 4:
+		return "NMI_INTERRUPT";
+	case 5:
+		return "SYSASSERT";
+	case 6:
+		return "FATAL_ERROR";
+	}
+
+	return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv)
+{
+	u32 i;
+	u32 desc, time, count, base, data1;
+	u32 blink1, blink2, ilink1, ilink2;
+	int rc;
+
+	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	count = iwl3945_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, Config: %08X count: %d\n",
+			  priv->status, priv->config, count);
+	}
+
+	IWL_ERROR("Desc       Time       asrtPC  blink2 "
+		  "ilink1  nmiPC   Line\n");
+	for (i = ERROR_START_OFFSET;
+	     i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
+	     i += ERROR_ELEM_SIZE) {
+		desc = iwl3945_read_targ_mem(priv, base + i);
+		time =
+		    iwl3945_read_targ_mem(priv, base + i + 1 * sizeof(u32));
+		blink1 =
+		    iwl3945_read_targ_mem(priv, base + i + 2 * sizeof(u32));
+		blink2 =
+		    iwl3945_read_targ_mem(priv, base + i + 3 * sizeof(u32));
+		ilink1 =
+		    iwl3945_read_targ_mem(priv, base + i + 4 * sizeof(u32));
+		ilink2 =
+		    iwl3945_read_targ_mem(priv, base + i + 5 * sizeof(u32));
+		data1 =
+		    iwl3945_read_targ_mem(priv, base + i + 6 * sizeof(u32));
+
+		IWL_ERROR
+		    ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+		     desc_lookup(desc), desc, time, blink1, blink2,
+		     ilink1, ilink2, data1);
+	}
+
+	iwl3945_release_nic_access(priv);
+
+}
+
+#define EVENT_START_OFFSET  (6 * sizeof(u32))
+
+/**
+ * iwl3945_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl3945_grab_nic_access() already obtained!
+ */
+static void iwl3945_print_event_log(struct iwl3945_priv *priv, u32 start_idx,
+				u32 num_events, u32 mode)
+{
+	u32 i;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 event_size;	/* 2 u32s, or 3 u32s if timestamp recorded */
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+
+	if (num_events == 0)
+		return;
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+	if (mode == 0)
+		event_size = 2 * sizeof(u32);
+	else
+		event_size = 3 * sizeof(u32);
+
+	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+	/* "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 = iwl3945_read_targ_mem(priv, ptr);
+		ptr += sizeof(u32);
+		time = iwl3945_read_targ_mem(priv, ptr);
+		ptr += sizeof(u32);
+		if (mode == 0)
+			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+		else {
+			data = iwl3945_read_targ_mem(priv, ptr);
+			ptr += sizeof(u32);
+			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+		}
+	}
+}
+
+static void iwl3945_dump_nic_event_log(struct iwl3945_priv *priv)
+{
+	int rc;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 capacity;   /* event log capacity in # entries */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	u32 num_wraps;  /* # times uCode wrapped to top of log */
+	u32 next_entry; /* index of next entry to be written by uCode */
+	u32 size;       /* # entries that we'll print */
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	/* event log header */
+	capacity = iwl3945_read_targ_mem(priv, base);
+	mode = iwl3945_read_targ_mem(priv, base + (1 * sizeof(u32)));
+	num_wraps = iwl3945_read_targ_mem(priv, base + (2 * sizeof(u32)));
+	next_entry = iwl3945_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");
+		iwl3945_release_nic_access(priv);
+		return;
+	}
+
+	IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+		  size, num_wraps);
+
+	/* if uCode has wrapped back to top of log, start at the oldest entry,
+	 * i.e the next one that uCode would fill. */
+	if (num_wraps)
+		iwl3945_print_event_log(priv, next_entry,
+				    capacity - next_entry, mode);
+
+	/* (then/else) start at top of log */
+	iwl3945_print_event_log(priv, 0, next_entry, mode);
+
+	iwl3945_release_nic_access(priv);
+}
+
+/**
+ * iwl3945_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl3945_irq_handle_error(struct iwl3945_priv *priv)
+{
+	/* Set the FW error flag -- cleared on iwl3945_down */
+	set_bit(STATUS_FW_ERROR, &priv->status);
+
+	/* Cancel currently queued command. */
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_FW_ERRORS) {
+		iwl3945_dump_nic_error_log(priv);
+		iwl3945_dump_nic_event_log(priv);
+		iwl3945_print_rx_config_cmd(&priv->staging_rxon);
+	}
+#endif
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the INIT status bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+			  "Restarting adapter due to uCode error.\n");
+
+		if (iwl3945_is_associated(priv)) {
+			memcpy(&priv->recovery_rxon, &priv->active_rxon,
+			       sizeof(priv->recovery_rxon));
+			priv->error_recovering = 1;
+		}
+		queue_work(priv->workqueue, &priv->restart);
+	}
+}
+
+static void iwl3945_error_recovery(struct iwl3945_priv *priv)
+{
+	unsigned long flags;
+
+	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+	       sizeof(priv->staging_rxon));
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl3945_commit_rxon(priv);
+
+	iwl3945_add_station(priv, priv->bssid, 1, 0);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+	priv->error_recovering = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
+{
+	u32 inta, handled = 0;
+	u32 inta_fh;
+	unsigned long flags;
+#ifdef CONFIG_IWL3945_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* 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 = iwl3945_read32(priv, CSR_INT);
+	iwl3945_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 = iwl3945_read32(priv, CSR_FH_INT_STATUS);
+	iwl3945_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_ISR) {
+		/* just for debug */
+		inta_mask = iwl3945_read32(priv, CSR_INT_MASK);
+		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+			      inta, inta_mask, inta_fh);
+	}
+#endif
+
+	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+	 * atomic, make sure that inta covers all the interrupts that
+	 * we've discovered, even if FH interrupt came in just after
+	 * reading CSR_INT. */
+	if (inta_fh & CSR_FH_INT_RX_MASK)
+		inta |= CSR_INT_BIT_FH_RX;
+	if (inta_fh & CSR_FH_INT_TX_MASK)
+		inta |= CSR_INT_BIT_FH_TX;
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl3945_disable_interrupts(priv);
+
+		iwl3945_irq_handle_error(priv);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		return;
+	}
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & (IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+			IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE)
+			IWL_DEBUG_ISR("Alive interrupt\n");
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled (4965 only) */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		int hw_rf_kill = 0;
+		if (!(iwl3945_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+			hw_rf_kill = 1;
+
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+				"RF_KILL bit toggled to %s.\n",
+				hw_rf_kill ? "disable radio":"enable radio");
+
+		/* Queue restart only if RF_KILL switch was set to "kill"
+		 *   when we loaded driver, and is now set to "enable".
+		 * After we're Alive, RF_KILL gets handled by
+		 *   iwl3945_rx_card_state_notif() */
+		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
+			clear_bit(STATUS_RF_KILL_HW, &priv->status);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself (4965 only) */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERROR("Microcode CT kill error detected.\n");
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
+			  inta);
+		iwl3945_irq_handle_error(priv);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR("Wakeup interrupt\n");
+		iwl3945_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+		iwl3945_rx_handle(priv);
+		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+	}
+
+	if (inta & CSR_INT_BIT_FH_TX) {
+		IWL_DEBUG_ISR("Tx interrupt\n");
+
+		iwl3945_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
+		if (!iwl3945_grab_nic_access(priv)) {
+			iwl3945_write_direct32(priv,
+					     FH_TCSR_CREDIT
+					     (ALM_FH_SRVC_CHNL), 0x0);
+			iwl3945_release_nic_access(priv);
+		}
+		handled |= CSR_INT_BIT_FH_TX;
+	}
+
+	if (inta & ~handled)
+		IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+	if (inta & ~CSR_INI_SET_MASK) {
+		IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~CSR_INI_SET_MASK);
+		IWL_WARNING("   with FH_INT = 0x%08x\n", inta_fh);
+	}
+
+	/* Re-enable all interrupts */
+	iwl3945_enable_interrupts(priv);
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & (IWL_DL_ISR)) {
+		inta = iwl3945_read32(priv, CSR_INT);
+		inta_mask = iwl3945_read32(priv, CSR_INT_MASK);
+		inta_fh = iwl3945_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);
+	}
+#endif
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl3945_isr(int irq, void *data, struct pt_regs *regs)
+{
+	struct iwl3945_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 inta_fh;
+	if (!priv)
+		return IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    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 = iwl3945_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl3945_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl3945_read32(priv, CSR_INT);
+	inta_fh = iwl3945_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,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta && !inta_fh) {
+		IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared */
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		goto unplugged;
+	}
+
+	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+		      inta, inta_mask, inta_fh);
+
+	/* iwl3945_irq_tasklet() will service interrupts and re-enable them */
+	tasklet_schedule(&priv->irq_tasklet);
+unplugged:
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	iwl3945_enable_interrupts(priv);
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl3945_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl3945_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel.  We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware.  This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel.  There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl3945_eeprom_band_1[14] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl3945_eeprom_band_2[] = {	/* 4915-5080MHz */
+	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl3945_eeprom_band_3[] = {	/* 5170-5320MHz */
+	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl3945_eeprom_band_4[] = {	/* 5500-5700MHz */
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl3945_eeprom_band_5[] = {	/* 5725-5825MHz */
+	145, 149, 153, 157, 161, 165
+};
+
+static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int band,
+				    int *eeprom_ch_count,
+				    const struct iwl3945_eeprom_channel
+				    **eeprom_ch_info,
+				    const u8 **eeprom_ch_index)
+{
+	switch (band) {
+	case 1:		/* 2.4GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_1);
+		*eeprom_ch_info = priv->eeprom.band_1_channels;
+		*eeprom_ch_index = iwl3945_eeprom_band_1;
+		break;
+	case 2:		/* 4.9GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_2);
+		*eeprom_ch_info = priv->eeprom.band_2_channels;
+		*eeprom_ch_index = iwl3945_eeprom_band_2;
+		break;
+	case 3:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_3);
+		*eeprom_ch_info = priv->eeprom.band_3_channels;
+		*eeprom_ch_index = iwl3945_eeprom_band_3;
+		break;
+	case 4:		/* 5.5GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_4);
+		*eeprom_ch_info = priv->eeprom.band_4_channels;
+		*eeprom_ch_index = iwl3945_eeprom_band_4;
+		break;
+	case 5:		/* 5.7GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_5);
+		*eeprom_ch_info = priv->eeprom.band_5_channels;
+		*eeprom_ch_index = iwl3945_eeprom_band_5;
+		break;
+	default:
+		BUG();
+		return;
+	}
+}
+
+/**
+ * iwl3945_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
+const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv,
+						    int phymode, u16 channel)
+{
+	int i;
+
+	switch (phymode) {
+	case MODE_IEEE80211A:
+		for (i = 14; i < priv->channel_count; i++) {
+			if (priv->channel_info[i].channel == channel)
+				return &priv->channel_info[i];
+		}
+		break;
+
+	case MODE_IEEE80211B:
+	case MODE_IEEE80211G:
+		if (channel >= 1 && channel <= 14)
+			return &priv->channel_info[channel - 1];
+		break;
+
+	}
+
+	return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+			    ? # x " " : "")
+
+/**
+ * iwl3945_init_channel_map - Set up driver's info for all possible channels
+ */
+static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
+{
+	int eeprom_ch_count = 0;
+	const u8 *eeprom_ch_index = NULL;
+	const struct iwl3945_eeprom_channel *eeprom_ch_info = NULL;
+	int band, ch;
+	struct iwl3945_channel_info *ch_info;
+
+	if (priv->channel_count) {
+		IWL_DEBUG_INFO("Channel map already initialized.\n");
+		return 0;
+	}
+
+	if (priv->eeprom.version < 0x2f) {
+		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+			    priv->eeprom.version);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+	priv->channel_count =
+	    ARRAY_SIZE(iwl3945_eeprom_band_1) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_2) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_3) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_4) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_5);
+
+	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+	priv->channel_info = kzalloc(sizeof(struct iwl3945_channel_info) *
+				     priv->channel_count, GFP_KERNEL);
+	if (!priv->channel_info) {
+		IWL_ERROR("Could not allocate channel_info\n");
+		priv->channel_count = 0;
+		return -ENOMEM;
+	}
+
+	ch_info = priv->channel_info;
+
+	/* Loop through the 5 EEPROM bands adding them in order to the
+	 * channel map we maintain (that contains additional information than
+	 * what just in the EEPROM) */
+	for (band = 1; band <= 5; band++) {
+
+		iwl3945_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+			ch_info->channel = eeprom_ch_index[ch];
+			ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+			    MODE_IEEE80211A;
+
+			/* permanently store EEPROM's channel regulatory flags
+			 *   and max power in channel info database. */
+			ch_info->eeprom = eeprom_ch_info[ch];
+
+			/* Copy the run-time flags so they are there even on
+			 * invalid channels */
+			ch_info->flags = eeprom_ch_info[ch].flags;
+
+			if (!(is_channel_valid(ch_info))) {
+				IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+					       "No traffic\n",
+					       ch_info->channel,
+					       ch_info->flags,
+					       is_channel_a_band(ch_info) ?
+					       "5.2" : "2.4");
+				ch_info++;
+				continue;
+			}
+
+			/* Initialize regulatory-based run-time data */
+			ch_info->max_power_avg = ch_info->curr_txpow =
+			    eeprom_ch_info[ch].max_power_avg;
+			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+			ch_info->min_power = 0;
+
+			IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+				       " %ddBm): Ad-Hoc %ssupported\n",
+				       ch_info->channel,
+				       is_channel_a_band(ch_info) ?
+				       "5.2" : "2.4",
+				       CHECK_AND_PRINT(IBSS),
+				       CHECK_AND_PRINT(ACTIVE),
+				       CHECK_AND_PRINT(RADAR),
+				       CHECK_AND_PRINT(WIDE),
+				       CHECK_AND_PRINT(NARROW),
+				       CHECK_AND_PRINT(DFS),
+				       eeprom_ch_info[ch].flags,
+				       eeprom_ch_info[ch].max_power_avg,
+				       ((eeprom_ch_info[ch].
+					 flags & EEPROM_CHANNEL_IBSS)
+					&& !(eeprom_ch_info[ch].
+					     flags & EEPROM_CHANNEL_RADAR))
+				       ? "" : "not ");
+
+			/* Set the user_txpower_limit to the highest power
+			 * supported by any channel */
+			if (eeprom_ch_info[ch].max_power_avg >
+			    priv->user_txpower_limit)
+				priv->user_txpower_limit =
+				    eeprom_ch_info[ch].max_power_avg;
+
+			ch_info++;
+		}
+	}
+
+	/* Set up txpower settings in driver for all channels */
+	if (iwl3945_txpower_set_from_eeprom(priv))
+		return -EIO;
+
+	return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)	/* packets */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)	/* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)	/* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+
+static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode)
+{
+	if (phymode == MODE_IEEE80211A)
+		return IWL_ACTIVE_DWELL_TIME_52;
+	else
+		return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode)
+{
+	u16 active = iwl3945_get_active_dwell_time(priv, phymode);
+	u16 passive = (phymode != MODE_IEEE80211A) ?
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+	if (iwl3945_is_associated(priv)) {
+		/* If we're associated, we clamp the maximum passive
+		 * dwell time to be 98% of the beacon interval (minus
+		 * 2 * channel tune time) */
+		passive = priv->beacon_int;
+		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+			passive = IWL_PASSIVE_DWELL_BASE;
+		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+	}
+
+	if (passive <= active)
+		passive = active + 1;
+
+	return passive;
+}
+
+static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode,
+				     u8 is_active, u8 direct_mask,
+				     struct iwl3945_scan_channel *scan_ch)
+{
+	const struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode;
+	const struct iwl3945_channel_info *ch_info;
+	u16 passive_dwell = 0;
+	u16 active_dwell = 0;
+	int added, i;
+
+	hw_mode = iwl3945_get_hw_mode(priv, phymode);
+	if (!hw_mode)
+		return 0;
+
+	channels = hw_mode->channels;
+
+	active_dwell = iwl3945_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode);
+
+	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+		if (channels[i].chan ==
+		    le16_to_cpu(priv->active_rxon.channel)) {
+			if (iwl3945_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 = channels[i].chan;
+
+		ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel);
+		if (!is_channel_valid(ch_info)) {
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+				       scan_ch->channel);
+			continue;
+		}
+
+		if (!is_active || is_channel_passive(ch_info) ||
+		    !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+			scan_ch->type = 0;	/* passive */
+		else
+			scan_ch->type = 1;	/* active */
+
+		if (scan_ch->type & 1)
+			scan_ch->type |= (direct_mask << 1);
+
+		if (is_channel_narrow(ch_info))
+			scan_ch->type |= (1 << 7);
+
+		scan_ch->active_dwell = cpu_to_le16(active_dwell);
+		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+		/* Set txpower levels to defaults */
+		scan_ch->tpc.dsp_atten = 110;
+		/* scan_pwr_info->tpc.dsp_atten; */
+
+		/*scan_pwr_info->tpc.tx_gain; */
+		if (phymode == MODE_IEEE80211A)
+			scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else {
+			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+			 * power level:
+			 * scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 */
+		}
+
+		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+			       scan_ch->channel,
+			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+			       (scan_ch->type & 1) ?
+			       active_dwell : passive_dwell);
+
+		scan_ch++;
+		added++;
+	}
+
+	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+	return added;
+}
+
+static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv)
+{
+	int i, j;
+	for (i = 0; i < 3; i++) {
+		struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+		for (j = 0; j < hw_mode->num_channels; j++)
+			hw_mode->channels[j].flag = hw_mode->channels[j].val;
+	}
+}
+
+static void iwl3945_init_hw_rates(struct iwl3945_priv *priv,
+			      struct ieee80211_rate *rates)
+{
+	int i;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++) {
+		rates[i].rate = iwl3945_rates[i].ieee * 5;
+		rates[i].val = i; /* Rate scaling will work on indexes */
+		rates[i].val2 = i;
+		rates[i].flags = IEEE80211_RATE_SUPPORTED;
+		/* Only OFDM have the bits-per-symbol set */
+		if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+			rates[i].flags |= IEEE80211_RATE_OFDM;
+		else {
+			/*
+			 * If CCK 1M then set rate flag to CCK else CCK_2
+			 * which is CCK | PREAMBLE2
+			 */
+			rates[i].flags |= (iwl3945_rates[i].plcp == 10) ?
+				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+		}
+
+		/* Set up which ones are basic rates... */
+		if (IWL_BASIC_RATES_MASK & (1 << i))
+			rates[i].flags |= IEEE80211_RATE_BASIC;
+	}
+}
+
+/**
+ * iwl3945_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl3945_init_geos(struct iwl3945_priv *priv)
+{
+	struct iwl3945_channel_info *ch;
+	struct ieee80211_hw_mode *modes;
+	struct ieee80211_channel *channels;
+	struct ieee80211_channel *geo_ch;
+	struct ieee80211_rate *rates;
+	int i = 0;
+	enum {
+		A = 0,
+		B = 1,
+		G = 2,
+	};
+	int mode_count = 3;
+
+	if (priv->modes) {
+		IWL_DEBUG_INFO("Geography modes already initialized.\n");
+		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+		return 0;
+	}
+
+	modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+			GFP_KERNEL);
+	if (!modes)
+		return -ENOMEM;
+
+	channels = kzalloc(sizeof(struct ieee80211_channel) *
+			   priv->channel_count, GFP_KERNEL);
+	if (!channels) {
+		kfree(modes);
+		return -ENOMEM;
+	}
+
+	rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+			GFP_KERNEL);
+	if (!rates) {
+		kfree(modes);
+		kfree(channels);
+		return -ENOMEM;
+	}
+
+	/* 0 = 802.11a
+	 * 1 = 802.11b
+	 * 2 = 802.11g
+	 */
+
+	/* 5.2GHz channels start after the 2.4GHz channels */
+	modes[A].mode = MODE_IEEE80211A;
+	modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)];
+	modes[A].rates = &rates[4];
+	modes[A].num_rates = 8;	/* just OFDM */
+	modes[A].num_channels = 0;
+
+	modes[B].mode = MODE_IEEE80211B;
+	modes[B].channels = channels;
+	modes[B].rates = rates;
+	modes[B].num_rates = 4;	/* just CCK */
+	modes[B].num_channels = 0;
+
+	modes[G].mode = MODE_IEEE80211G;
+	modes[G].channels = channels;
+	modes[G].rates = rates;
+	modes[G].num_rates = 12;	/* OFDM & CCK */
+	modes[G].num_channels = 0;
+
+	priv->ieee_channels = channels;
+	priv->ieee_rates = rates;
+
+	iwl3945_init_hw_rates(priv, rates);
+
+	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+		ch = &priv->channel_info[i];
+
+		if (!is_channel_valid(ch)) {
+			IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+				    "skipping.\n",
+				    ch->channel, is_channel_a_band(ch) ?
+				    "5.2" : "2.4");
+			continue;
+		}
+
+		if (is_channel_a_band(ch))
+			geo_ch = &modes[A].channels[modes[A].num_channels++];
+		else {
+			geo_ch = &modes[B].channels[modes[B].num_channels++];
+			modes[G].num_channels++;
+		}
+
+		geo_ch->freq = ieee80211chan2mhz(ch->channel);
+		geo_ch->chan = ch->channel;
+		geo_ch->power_level = ch->max_power_avg;
+		geo_ch->antenna_max = 0xff;
+
+		if (is_channel_valid(ch)) {
+			geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+			if (ch->flags & EEPROM_CHANNEL_IBSS)
+				geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+			if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+				geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+			if (ch->flags & EEPROM_CHANNEL_RADAR)
+				geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+			if (ch->max_power_avg > priv->max_channel_txpower_limit)
+				priv->max_channel_txpower_limit =
+				    ch->max_power_avg;
+		}
+
+		geo_ch->val = geo_ch->flag;
+	}
+
+	if ((modes[A].num_channels == 0) && priv->is_abg) {
+		printk(KERN_INFO DRV_NAME
+		       ": Incorrectly detected BG card as ABG.  Please send "
+		       "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+		       priv->pci_dev->device, priv->pci_dev->subsystem_device);
+		priv->is_abg = 0;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+	       modes[G].num_channels, modes[A].num_channels);
+
+	/*
+	 * NOTE:  We register these in preference of order -- the
+	 * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+	 * a phymode based on rates or AP capabilities but seems to
+	 * configure it purely on if the channel being configured
+	 * is supported by a mode -- and the first match is taken
+	 */
+
+	if (modes[G].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[G]);
+	if (modes[B].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[B]);
+	if (modes[A].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+	priv->modes = modes;
+	set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv)
+{
+	if (priv->ucode_code.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_code.len,
+				    priv->ucode_code.v_addr,
+				    priv->ucode_code.p_addr);
+		priv->ucode_code.v_addr = NULL;
+	}
+	if (priv->ucode_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data.len,
+				    priv->ucode_data.v_addr,
+				    priv->ucode_data.p_addr);
+		priv->ucode_data.v_addr = NULL;
+	}
+	if (priv->ucode_data_backup.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data_backup.len,
+				    priv->ucode_data_backup.v_addr,
+				    priv->ucode_data_backup.p_addr);
+		priv->ucode_data_backup.v_addr = NULL;
+	}
+	if (priv->ucode_init.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init.len,
+				    priv->ucode_init.v_addr,
+				    priv->ucode_init.p_addr);
+		priv->ucode_init.v_addr = NULL;
+	}
+	if (priv->ucode_init_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init_data.len,
+				    priv->ucode_init_data.v_addr,
+				    priv->ucode_init_data.p_addr);
+		priv->ucode_init_data.v_addr = NULL;
+	}
+	if (priv->ucode_boot.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_boot.len,
+				    priv->ucode_boot.v_addr,
+				    priv->ucode_boot.p_addr);
+		priv->ucode_boot.v_addr = NULL;
+	}
+}
+
+/**
+ * iwl3945_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 * image, u32 len)
+{
+	u32 val;
+	u32 save_len = len;
+	int rc = 0;
+	u32 errcnt;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc)
+		return rc;
+
+	iwl3945_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 = _iwl3945_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",
+				  save_len - len, val, le32_to_cpu(*image));
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 20)
+				break;
+		}
+	}
+
+	iwl3945_release_nic_access(priv);
+
+	if (!errcnt)
+		IWL_DEBUG_INFO("ucode image in INSTRUCTION memory is good\n");
+
+	return rc;
+}
+
+
+/**
+ * iwl3945_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl3945_verify_inst_sparse(struct iwl3945_priv *priv, __le32 *image, u32 len)
+{
+	u32 val;
+	int rc = 0;
+	u32 errcnt = 0;
+	u32 i;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < len; i += 100, image += 100/sizeof(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 */
+		iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+			i + RTC_INST_LOWER_BOUND);
+		val = _iwl3945_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 "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  i, val, *image);
+#endif
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 3)
+				break;
+		}
+	}
+
+	iwl3945_release_nic_access(priv);
+
+	return rc;
+}
+
+
+/**
+ * iwl3945_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl3945_verify_ucode(struct iwl3945_priv *priv)
+{
+	__le32 *image;
+	u32 len;
+	int rc = 0;
+
+	/* Try bootstrap */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try initialize */
+	image = (__le32 *)priv->ucode_init.v_addr;
+	len = priv->ucode_init.len;
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try runtime/protocol */
+	image = (__le32 *)priv->ucode_code.v_addr;
+	len = priv->ucode_code.len;
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+	/* Since nothing seems to match, show first several data entries in
+	 * instruction SRAM, so maybe visual inspection will give a clue.
+	 * Selection of bootstrap image (vs. other images) is arbitrary. */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl3945_verify_inst_full(priv, image, len);
+
+	return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl3945_verify_bsm(struct iwl3945_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	u32 reg;
+	u32 val;
+
+	IWL_DEBUG_INFO("Begin verify bsm\n");
+
+	/* verify BSM SRAM contents */
+	val = iwl3945_read_prph(priv, BSM_WR_DWCOUNT_REG);
+	for (reg = BSM_SRAM_LOWER_BOUND;
+	     reg < BSM_SRAM_LOWER_BOUND + len;
+	     reg += sizeof(u32), image ++) {
+		val = iwl3945_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",
+				  BSM_SRAM_LOWER_BOUND,
+				  reg - BSM_SRAM_LOWER_BOUND, len,
+				  val, le32_to_cpu(*image));
+			return -EIO;
+		}
+	}
+
+	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+	return 0;
+}
+
+/**
+ * iwl3945_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL.  When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers.  Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image.  This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl3945_load_bsm(struct iwl3945_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	u32 inst_len;
+	u32 data_len;
+	int rc;
+	int i;
+	u32 done;
+	u32 reg_offset;
+
+	IWL_DEBUG_INFO("Begin load bsm\n");
+
+	/* make sure bootstrap program is no larger than BSM's SRAM size */
+	if (len > IWL_MAX_BSM_SIZE)
+		return -EINVAL;
+
+	/* Tell bootstrap uCode where to find the "Initialize" uCode
+	 *   in host DRAM ... host DRAM physical address bits 31:0 for 3945.
+	 * NOTE:  iwl3945_initialize_alive_start() will replace these values,
+	 *        after the "initialize" uCode has run, to point to
+	 *        runtime/protocol instructions and backup data cache. */
+	pinst = priv->ucode_init.p_addr;
+	pdata = priv->ucode_init_data.p_addr;
+	inst_len = priv->ucode_init.len;
+	data_len = priv->ucode_init_data.len;
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc)
+		return rc;
+
+	iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+	iwl3945_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++)
+		_iwl3945_write_prph(priv, reg_offset,
+					  le32_to_cpu(*image));
+
+	rc = iwl3945_verify_bsm(priv);
+	if (rc) {
+		iwl3945_release_nic_access(priv);
+		return rc;
+	}
+
+	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+	iwl3945_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
+	iwl3945_write_prph(priv, BSM_WR_MEM_DST_REG,
+				 RTC_INST_LOWER_BOUND);
+	iwl3945_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+	/* Load bootstrap code into instruction SRAM now,
+	 *   to prepare to load "initialize" uCode */
+	iwl3945_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 = iwl3945_read_prph(priv, BSM_WR_CTRL_REG);
+		if (!(done & BSM_WR_CTRL_REG_BIT_START))
+			break;
+		udelay(10);
+	}
+	if (i < 100)
+		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+	else {
+		IWL_ERROR("BSM write did not complete!\n");
+		return -EIO;
+	}
+
+	/* Enable future boot loads whenever power management unit triggers it
+	 *   (e.g. when powering back up after power-save shutdown) */
+	iwl3945_write_prph(priv, BSM_WR_CTRL_REG,
+		BSM_WR_CTRL_REG_BIT_START_EN);
+
+	iwl3945_release_nic_access(priv);
+
+	return 0;
+}
+
+static void iwl3945_nic_start(struct iwl3945_priv *priv)
+{
+	/* Remove all resets to allow NIC to operate */
+	iwl3945_write32(priv, CSR_RESET, 0);
+}
+
+static int iwl3945_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
+{
+	desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
+	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
+}
+
+/**
+ * iwl3945_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl3945_read_ucode(struct iwl3945_priv *priv)
+{
+	struct iwl3945_ucode *ucode;
+	int ret = 0;
+	const struct firmware *ucode_raw;
+	/* firmware file name contains uCode/driver compatibility version */
+	const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
+	u8 *src;
+	size_t len;
+	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+	/* Ask kernel firmware_class module to get the boot firmware off disk.
+	 * request_firmware() is synchronous, file is in memory on return. */
+	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (ret < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n",
+				name, ret);
+		goto error;
+	}
+
+	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+		       name, ucode_raw->size);
+
+	/* Make sure that we got at least our header! */
+	if (ucode_raw->size < sizeof(*ucode)) {
+		IWL_ERROR("File size way too small!\n");
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Data from ucode file:  header followed by uCode images */
+	ucode = (void *)ucode_raw->data;
+
+	ver = le32_to_cpu(ucode->ver);
+	inst_size = le32_to_cpu(ucode->inst_size);
+	data_size = le32_to_cpu(ucode->data_size);
+	init_size = le32_to_cpu(ucode->init_size);
+	init_data_size = le32_to_cpu(ucode->init_data_size);
+	boot_size = le32_to_cpu(ucode->boot_size);
+
+	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size);
+	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size);
+	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size);
+	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size);
+
+	/* Verify size of file vs. image size info in file's header */
+	if (ucode_raw->size < sizeof(*ucode) +
+		inst_size + data_size + init_size +
+		init_data_size + boot_size) {
+
+		IWL_DEBUG_INFO("uCode file size %d too small\n",
+			       (int)ucode_raw->size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Verify that uCode images will fit in card's SRAM */
+	if (inst_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
+			       inst_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	if (data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
+			       data_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (init_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO("uCode init instr len %d too large to fit in\n",
+				init_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (init_data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO("uCode init data len %d too large to fit in\n",
+				init_data_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (boot_size > IWL_MAX_BSM_SIZE) {
+		IWL_DEBUG_INFO("uCode boot instr len %d too large to fit in\n",
+				boot_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Allocate ucode buffers for card's bus-master loading ... */
+
+	/* Runtime instructions and 2 copies of data:
+	 * 1) unmodified from disk
+	 * 2) backup cache for save/restore during power-downs */
+	priv->ucode_code.len = inst_size;
+	iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
+
+	priv->ucode_data.len = data_size;
+	iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
+
+	priv->ucode_data_backup.len = data_size;
+	iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+
+	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+	    !priv->ucode_data_backup.v_addr)
+		goto err_pci_alloc;
+
+	/* Initialization instructions and data */
+	if (init_size && init_data_size) {
+		priv->ucode_init.len = init_size;
+		iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+		priv->ucode_init_data.len = init_data_size;
+		iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+
+		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+			goto err_pci_alloc;
+	}
+
+	/* Bootstrap (instructions only, no data) */
+	if (boot_size) {
+		priv->ucode_boot.len = boot_size;
+		iwl3945_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
+
+		if (!priv->ucode_boot.v_addr)
+			goto err_pci_alloc;
+	}
+
+	/* Copy images into buffers for card's bus-master reads ... */
+
+	/* Runtime instructions (first block of data in file) */
+	src = &ucode->data[0];
+	len = priv->ucode_code.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len);
+	memcpy(priv->ucode_code.v_addr, src, len);
+	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+	/* Runtime data (2nd block)
+	 * NOTE:  Copy into backup buffer will be done in iwl3945_up()  */
+	src = &ucode->data[inst_size];
+	len = priv->ucode_data.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
+	memcpy(priv->ucode_data.v_addr, src, len);
+	memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+	/* Initialization instructions (3rd block) */
+	if (init_size) {
+		src = &ucode->data[inst_size + data_size];
+		len = priv->ucode_init.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+			       len);
+		memcpy(priv->ucode_init.v_addr, src, len);
+	}
+
+	/* Initialization data (4th block) */
+	if (init_data_size) {
+		src = &ucode->data[inst_size + data_size + init_size];
+		len = priv->ucode_init_data.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+			       (int)len);
+		memcpy(priv->ucode_init_data.v_addr, src, len);
+	}
+
+	/* Bootstrap instructions (5th block) */
+	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+	len = priv->ucode_boot.len;
+	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_boot.v_addr, src, len);
+
+	/* We have our copies now, allow OS release its copies */
+	release_firmware(ucode_raw);
+	return 0;
+
+ err_pci_alloc:
+	IWL_ERROR("failed to allocate pci memory\n");
+	ret = -ENOMEM;
+	iwl3945_dealloc_ucode_pci(priv);
+
+ err_release:
+	release_firmware(ucode_raw);
+
+ error:
+	return ret;
+}
+
+
+/**
+ * iwl3945_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv)
+{
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	int rc = 0;
+	unsigned long flags;
+
+	/* bits 31:0 for 3945 */
+	pinst = priv->ucode_code.p_addr;
+	pdata = priv->ucode_data_backup.p_addr;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* Tell bootstrap uCode where to find image to load */
+	iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl3945_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 */
+	iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+	iwl3945_release_nic_access(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+	return rc;
+}
+
+/**
+ * iwl3945_init_alive_start - Called after REPLY_ALIVE notification received
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+ */
+static void iwl3945_init_alive_start(struct iwl3945_priv *priv)
+{
+	/* Check alive response for "valid" sign from uCode */
+	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Initialize Alive failed.\n");
+		goto restart;
+	}
+
+	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "initialize" alive if code weren't properly loaded.  */
+	if (iwl3945_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+		goto restart;
+	}
+
+	/* Send pointers to protocol/runtime uCode image ... init code will
+	 * load and launch runtime uCode, which will send us another "Alive"
+	 * notification. */
+	IWL_DEBUG_INFO("Initialization Alive received.\n");
+	if (iwl3945_set_ucode_ptrs(priv)) {
+		/* Runtime instruction load won't happen;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+		goto restart;
+	}
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl3945_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl3945_init_alive_start()).
+ */
+static void iwl3945_alive_start(struct iwl3945_priv *priv)
+{
+	int rc = 0;
+	int thermal_spin = 0;
+	u32 rfkill;
+
+	IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+	if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Alive failed.\n");
+		goto restart;
+	}
+
+	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "runtime" alive if code weren't properly loaded.  */
+	if (iwl3945_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+		goto restart;
+	}
+
+	iwl3945_clear_stations_table(priv);
+
+	rc = iwl3945_grab_nic_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read rfkill status from adapter\n");
+		return;
+	}
+
+	rfkill = iwl3945_read_prph(priv, APMG_RFKILL_REG);
+	IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
+	iwl3945_release_nic_access(priv);
+
+	if (rfkill & 0x1) {
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+		/* if rfkill is not on, then wait for thermal
+		 * sensor in adapter to kick in */
+		while (iwl3945_hw_get_temperature(priv) == 0) {
+			thermal_spin++;
+			udelay(10);
+		}
+
+		if (thermal_spin)
+			IWL_DEBUG_INFO("Thermal calibration took %dus\n",
+				       thermal_spin * 10);
+	} else
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+	/* After the ALIVE response, we can send commands to 3945 uCode */
+	set_bit(STATUS_ALIVE, &priv->status);
+
+	/* Clear out the uCode error bit if it is set */
+	clear_bit(STATUS_FW_ERROR, &priv->status);
+
+	rc = iwl3945_init_channel_map(priv);
+	if (rc) {
+		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+		return;
+	}
+
+	iwl3945_init_geos(priv);
+
+	if (iwl3945_is_rfkill(priv))
+		return;
+
+	if (!priv->mac80211_registered) {
+		/* Unlock so any user space entry points can call back into
+		 * the driver without a deadlock... */
+		mutex_unlock(&priv->mutex);
+		iwl3945_rate_control_register(priv->hw);
+		rc = ieee80211_register_hw(priv->hw);
+		priv->hw->conf.beacon_int = 100;
+		mutex_lock(&priv->mutex);
+
+		if (rc) {
+			iwl3945_rate_control_unregister(priv->hw);
+			IWL_ERROR("Failed to register network "
+				  "device (error %d)\n", rc);
+			return;
+		}
+
+		priv->mac80211_registered = 1;
+
+		iwl3945_reset_channel_flag(priv);
+	} else
+		ieee80211_start_queues(priv->hw);
+
+	priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+	if (iwl3945_is_associated(priv)) {
+		struct iwl3945_rxon_cmd *active_rxon =
+				(struct iwl3945_rxon_cmd *)(&priv->active_rxon);
+
+		memcpy(&priv->staging_rxon, &priv->active_rxon,
+		       sizeof(priv->staging_rxon));
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	} else {
+		/* Initialize our rx_config data */
+		iwl3945_connection_init_rx_config(priv);
+		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	}
+
+	/* Configure Bluetooth device coexistence support */
+	iwl3945_send_bt_config(priv);
+
+	/* Configure the adapter for unassociated operation */
+	iwl3945_commit_rxon(priv);
+
+	/* At this point, the NIC is initialized and operational */
+	priv->notif_missed_beacons = 0;
+	set_bit(STATUS_READY, &priv->status);
+
+	iwl3945_reg_txpower_periodic(priv);
+
+	IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+	if (priv->error_recovering)
+		iwl3945_error_recovery(priv);
+
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv);
+
+static void __iwl3945_down(struct iwl3945_priv *priv)
+{
+	unsigned long flags;
+	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	struct ieee80211_conf *conf = NULL;
+
+	IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	if (!exit_pending)
+		set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	iwl3945_clear_stations_table(priv);
+
+	/* Unblock any waiting calls */
+	wake_up_interruptible_all(&priv->wait_command_queue);
+
+	iwl3945_cancel_deferred_work(priv);
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	/* stop and reset the on-board processor */
+	iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+	/* tell the device to stop sending interrupts */
+	iwl3945_disable_interrupts(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	/* If we have not previously called iwl3945_init() then
+	 * clear all bits but the RF Kill and SUSPEND bits and return */
+	if (!iwl3945_is_init(priv)) {
+		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+					STATUS_RF_KILL_HW |
+			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+					STATUS_IN_SUSPEND;
+		goto exit;
+	}
+
+	/* ...otherwise clear out all the status bits but the RF Kill and
+	 * SUSPEND bits and continue taking the NIC down. */
+	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+				STATUS_RF_KILL_HW |
+			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+				STATUS_RF_KILL_SW |
+			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+				STATUS_IN_SUSPEND |
+			test_bit(STATUS_FW_ERROR, &priv->status) <<
+				STATUS_FW_ERROR;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl3945_hw_txq_ctx_stop(priv);
+	iwl3945_hw_rxq_stop(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!iwl3945_grab_nic_access(priv)) {
+		iwl3945_write_prph(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl3945_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl3945_hw_nic_stop_master(priv);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl3945_hw_nic_reset(priv);
+
+ exit:
+	memset(&priv->card_alive, 0, sizeof(struct iwl3945_alive_resp));
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+	priv->ibss_beacon = NULL;
+
+	/* clear out any free frames */
+	iwl3945_clear_free_frames(priv);
+}
+
+static void iwl3945_down(struct iwl3945_priv *priv)
+{
+	mutex_lock(&priv->mutex);
+	__iwl3945_down(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl3945_up(struct iwl3945_priv *priv)
+{
+	DECLARE_MAC_BUF(mac);
+	int rc, i;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_WARNING("Exit pending; will not bring the NIC up\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("Radio disabled by SW RF kill (module "
+			    "parameter)\n");
+		return 0;
+	}
+
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	rc = iwl3945_hw_nic_init(priv);
+	if (rc) {
+		IWL_ERROR("Unable to int nic\n");
+		return rc;
+	}
+
+	/* make sure rfkill handshake bits are cleared */
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl3945_enable_interrupts(priv);
+
+	/* really make sure rfkill handshake bits are cleared */
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_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
+	 * data SRAM for a clean start when the runtime program first loads. */
+	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+			priv->ucode_data.len);
+
+	for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+		iwl3945_clear_stations_table(priv);
+
+		/* load bootstrap state machine,
+		 * load bootstrap program into processor's memory,
+		 * prepare to load the "initialize" uCode */
+		rc = iwl3945_load_bsm(priv);
+
+		if (rc) {
+			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+			continue;
+		}
+
+		/* start card; "initialize" will load runtime ucode */
+		iwl3945_nic_start(priv);
+
+		/* MAC Address location in EEPROM is same for 3945/4965 */
+		get_eeprom_mac(priv, priv->mac_addr);
+		IWL_DEBUG_INFO("MAC address: %s\n",
+			       print_mac(mac, priv->mac_addr));
+
+		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+		return 0;
+	}
+
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl3945_down(priv);
+
+	/* tried to restart and config the device for as long as our
+	 * patience could withstand */
+	IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+	return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl3945_bg_init_alive_start(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl3945_init_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_alive_start(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl3945_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_rf_kill(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl3945_is_rfkill(priv)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+			  "HW and/or SW RF Kill no longer active, restarting "
+			  "device\n");
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	} else {
+
+		if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+			IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+					  "disabled by SW switch\n");
+		else
+			IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+				    "Kill switch must be turned off for "
+				    "wireless networking to work.\n");
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl3945_bg_scan_check(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	if (test_bit(STATUS_SCANNING, &priv->status) ||
+	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+			  "Scan completion watchdog resetting adapter (%dms)\n",
+			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			iwl3945_send_scan_abort(priv);
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_request_scan(void *p)
+{
+	struct iwl3945_priv *priv = p;
+	struct iwl3945_host_cmd cmd = {
+		.id = REPLY_SCAN_CMD,
+		.len = sizeof(struct iwl3945_scan_cmd),
+		.meta.flags = CMD_SIZE_HUGE,
+	};
+	int rc = 0;
+	struct iwl3945_scan_cmd *scan;
+	struct ieee80211_conf *conf = NULL;
+	u8 direct_mask;
+	int phymode;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl3945_is_ready(priv)) {
+		IWL_WARNING("request scan called when driver not ready.\n");
+		goto done;
+	}
+
+	/* Make sure the scan wasn't cancelled before this queued work
+	 * was given the chance to run... */
+	if (!test_bit(STATUS_SCANNING, &priv->status))
+		goto done;
+
+	/* This should never be called or scheduled if there is currently
+	 * a scan active in the hardware. */
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+			       "Ignoring second request.\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+		goto done;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+		goto done;
+	}
+
+	if (iwl3945_is_rfkill(priv)) {
+		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+		goto done;
+	}
+
+	if (!test_bit(STATUS_READY, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
+		goto done;
+	}
+
+	if (!priv->scan_bands) {
+		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+		goto done;
+	}
+
+	if (!priv->scan) {
+		priv->scan = kmalloc(sizeof(struct iwl3945_scan_cmd) +
+				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+		if (!priv->scan) {
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+	scan = priv->scan;
+	memset(scan, 0, sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+	if (iwl3945_is_associated(priv)) {
+		u16 interval = 0;
+		u32 extra;
+		u32 suspend_time = 100;
+		u32 scan_suspend_time = 100;
+		unsigned long flags;
+
+		IWL_DEBUG_INFO("Scanning while associated...\n");
+
+		spin_lock_irqsave(&priv->lock, flags);
+		interval = priv->beacon_int;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		scan->suspend_time = 0;
+		scan->max_out_time = cpu_to_le32(200 * 1024);
+		if (!interval)
+			interval = suspend_time;
+		/*
+		 * suspend time format:
+		 *  0-19: beacon interval in usec (time before exec.)
+		 * 20-23: 0
+		 * 24-31: number of beacons (suspend between channels)
+		 */
+
+		extra = (suspend_time / interval) << 24;
+		scan_suspend_time = 0xFF0FFFFF &
+		    (extra | ((suspend_time % interval) * 1024));
+
+		scan->suspend_time = cpu_to_le32(scan_suspend_time);
+		IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+			       scan_suspend_time, interval);
+	}
+
+	/* We should add the ability for user to lock to PASSIVE ONLY */
+	if (priv->one_direct_scan) {
+		IWL_DEBUG_SCAN
+		    ("Kicking off one direct scan for '%s'\n",
+		     iwl3945_escape_essid(priv->direct_ssid,
+				      priv->direct_ssid_len));
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->direct_ssid_len;
+		memcpy(scan->direct_scan[0].ssid,
+		       priv->direct_ssid, priv->direct_ssid_len);
+		direct_mask = 1;
+	} else if (!iwl3945_is_associated(priv) && 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
+		direct_mask = 0;
+
+	/* We don't build a direct scan probe request; the uCode will do
+	 * that based on the direct_mask added to each channel entry */
+	scan->tx_cmd.len = cpu_to_le16(
+		iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+			IWL_MAX_SCAN_SIZE - sizeof(scan), 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.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	/* flags + rate selection */
+
+	switch (priv->scan_bands) {
+	case 2:
+		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+		scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
+		scan->good_CRC_th = 0;
+		phymode = MODE_IEEE80211G;
+		break;
+
+	case 1:
+		scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
+		scan->good_CRC_th = IWL_GOOD_CRC_TH;
+		phymode = MODE_IEEE80211A;
+		break;
+
+	default:
+		IWL_WARNING("Invalid scan band count\n");
+		goto done;
+	}
+
+	/* select Rx antennas */
+	scan->flags |= iwl3945_get_antenna_flags(priv);
+
+	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",
+		     iwl3945_escape_essid(priv->essid, priv->essid_len));
+	else
+		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+	scan->channel_count =
+		iwl3945_get_channels_for_scan(
+			priv, phymode, 1, /* active */
+			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 iwl3945_scan_channel);
+	cmd.data = scan;
+	scan->len = cpu_to_le16(cmd.len);
+
+	set_bit(STATUS_SCAN_HW, &priv->status);
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
+	if (rc)
+		goto done;
+
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IWL_SCAN_CHECK_WATCHDOG);
+
+	mutex_unlock(&priv->mutex);
+	return;
+
+ done:
+	/* inform mac80211 scan aborted */
+	queue_work(priv->workqueue, &priv->scan_completed);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_up(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	__iwl3945_up(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_restart(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	iwl3945_down(priv);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl3945_bg_rx_replenish(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl3945_rx_replenish(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
+static void iwl3945_bg_post_associate(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	int rc = 0;
+	struct ieee80211_conf *conf = NULL;
+	DECLARE_MAC_BUF(mac);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+		return;
+	}
+
+
+	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+			priv->assoc_id,
+			print_mac(mac, priv->active_rxon.bssid_addr));
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!priv->interface_id || !priv->is_open) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+	iwl3945_scan_cancel_timeout(priv, 200);
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl3945_commit_rxon(priv);
+
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd));
+	iwl3945_setup_rxon_timing(priv);
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+			      sizeof(priv->rxon_timing), &priv->rxon_timing);
+	if (rc)
+		IWL_WARNING("REPLY_RXON_TIMING failed - "
+			    "Attempting to continue.\n");
+
+	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+	IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+			priv->assoc_id, priv->beacon_int);
+
+	if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+	}
+
+	iwl3945_commit_rxon(priv);
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_STA:
+		iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+
+		/* clear out the station table */
+		iwl3945_clear_stations_table(priv);
+
+		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+		iwl3945_add_station(priv, priv->bssid, 0, 0);
+		iwl3945_sync_sta(priv, IWL_STA_ID,
+				 (priv->phymode == MODE_IEEE80211A)?
+				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+				 CMD_ASYNC);
+		iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl3945_send_beacon_cmd(priv);
+
+		break;
+
+	default:
+		 IWL_ERROR("%s Should not be called in %d mode\n",
+			   __FUNCTION__, priv->iw_mode);
+		break;
+	}
+
+	iwl3945_sequence_reset(priv);
+
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_activate_qos(priv, 0);
+#endif /* CONFIG_IWL3945_QOS */
+	/* we have just associated, don't start scan too early */
+	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl3945_bg_abort_scan(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	if (!iwl3945_is_ready(priv))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_SCAN_ABORTING, &priv->status);
+	iwl3945_send_scan_abort(priv);
+
+	mutex_unlock(&priv->mutex);
+}
+
+static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+static void iwl3945_bg_scan_completed(void *p)
+{
+	struct iwl3945_priv *priv = p;
+
+	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (priv->cache_conf)
+		iwl3945_mac_config(priv->hw, priv->cache_conf);
+
+	ieee80211_scan_completed(priv->hw);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	mutex_lock(&priv->mutex);
+	iwl3945_hw_reg_send_txpower(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl3945_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	/* we should be verifying the device is ready to be opened */
+	mutex_lock(&priv->mutex);
+
+	priv->is_open = 1;
+
+	if (!iwl3945_is_rfkill(priv))
+		ieee80211_start_queues(priv->hw);
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static void iwl3945_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+
+	mutex_lock(&priv->mutex);
+	/* stop mac, cancel any scan request and clear
+	 * RXON_FILTER_ASSOC_MSK BIT
+	 */
+	priv->is_open = 0;
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	iwl3945_scan_cancel_timeout(priv, 100);
+	cancel_delayed_work(&priv->post_associate);
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl3945_commit_rxon(priv);
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct ieee80211_tx_control *ctl)
+{
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		IWL_DEBUG_MAC80211("leave - monitor\n");
+		return -1;
+	}
+
+	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+		     ctl->tx_rate);
+
+	if (iwl3945_tx_skb(priv, skb, ctl))
+		dev_kfree_skb_any(skb);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+
+	if (priv->interface_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+		return -EOPNOTSUPP;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->interface_id = conf->if_id;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+
+	if (conf->mac_addr) {
+		IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr));
+		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+	}
+
+	iwl3945_set_mode(priv, conf->type);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/**
+ * iwl3945_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	const struct iwl3945_channel_info *ch_info;
+	unsigned long flags;
+	int ret = 0;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+	if (!iwl3945_is_ready(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+	 * what is exposed through include/ declarations */
+	if (unlikely(!iwl3945_param_disable_hw_scan &&
+		     test_bit(STATUS_SCANNING, &priv->status))) {
+
+		if (priv->cache_conf)
+			IWL_DEBUG_MAC80211("leave - still scanning\n");
+		else {
+			/* Cache the configuration now so that we can
+			 * replay it after the hardware scan is finished. */
+			priv->cache_conf = kmalloc(sizeof(*conf), GFP_KERNEL);
+			if (priv->cache_conf) {
+				memcpy(priv->cache_conf, conf, sizeof(*conf));
+				IWL_DEBUG_MAC80211("leave - scanning\n");
+			} else {
+				IWL_DEBUG_MAC80211("leave - no memory\n");
+				ret = -ENOMEM;
+			}
+		}
+		mutex_unlock(&priv->mutex);
+		return ret;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel);
+	if (!is_channel_valid(ch_info)) {
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+			       conf->channel, conf->phymode);
+		IWL_DEBUG_MAC80211("leave - invalid channel\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+	iwl3945_set_flags_for_phymode(priv, conf->phymode);
+
+	/* The list of supported rates and rate mask can be different
+	 * for each phymode; since the phymode may have changed, reset
+	 * the rate mask to what mac80211 lists */
+	iwl3945_set_rate(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+		iwl3945_hw_channel_switch(priv, conf->channel);
+		goto out;
+	}
+#endif
+
+	iwl3945_radio_kill_sw(priv, !conf->radio_enabled);
+
+	if (!conf->radio_enabled) {
+		IWL_DEBUG_MAC80211("leave - radio disabled\n");
+		goto out;
+	}
+
+	if (iwl3945_is_rfkill(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF kill\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	iwl3945_set_rate(priv);
+
+	if (memcmp(&priv->active_rxon,
+		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
+		iwl3945_commit_rxon(priv);
+	else
+		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out:
+	if (priv->cache_conf) {
+		kfree(priv->cache_conf);
+		priv->cache_conf = NULL;
+	}
+	mutex_unlock(&priv->mutex);
+	return ret;
+}
+
+static void iwl3945_config_ap(struct iwl3945_priv *priv)
+{
+	int rc = 0;
+
+	if (priv->status & STATUS_EXIT_PENDING)
+		return;
+
+	/* The following should be done only at AP bring up */
+	if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+		/* RXON - unassoc (to set timing command) */
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+
+		/* RXON Timing */
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd));
+		iwl3945_setup_rxon_timing(priv);
+		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+				sizeof(priv->rxon_timing), &priv->rxon_timing);
+		if (rc)
+			IWL_WARNING("REPLY_RXON_TIMING failed - "
+					"Attempting to continue.\n");
+
+		/* FIXME: what should be the assoc_id for AP? */
+		priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+			priv->staging_rxon.flags |=
+				RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &=
+				~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+			if (priv->assoc_capability &
+				WLAN_CAPABILITY_SHORT_SLOT_TIME)
+				priv->staging_rxon.flags |=
+					RXON_FLG_SHORT_SLOT_MSK;
+			else
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+
+			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+		}
+		/* restore RXON assoc */
+		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+	}
+	iwl3945_send_beacon_cmd(priv);
+
+	/* FIXME - we need to add code here to detect a totally new
+	 * configuration, reset the AP, unassoc, rxon timing, assoc,
+	 * clear sta table, add BCAST sta... */
+}
+
+static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
+	int rc;
+
+	if (conf == NULL)
+		return -EIO;
+
+	/* XXX: this MUST use conf->mac_addr */
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!conf->beacon || !conf->ssid_len)) {
+		IWL_DEBUG_MAC80211
+		    ("Leaving in AP mode because HostAPD is not ready.\n");
+		return 0;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+	if (conf->bssid)
+		IWL_DEBUG_MAC80211("bssid: %s\n",
+				   print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->interface_id != if_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (!conf->bssid) {
+			conf->bssid = priv->mac_addr;
+			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+					   print_mac(mac, conf->bssid));
+		}
+		if (priv->ibss_beacon)
+			dev_kfree_skb(priv->ibss_beacon);
+
+		priv->ibss_beacon = conf->beacon;
+	}
+
+	if (iwl3945_is_rfkill(priv))
+		goto done;
+
+	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+	    !is_multicast_ether_addr(conf->bssid)) {
+		/* If there is currently a HW scan going on in the background
+		 * then we need to cancel it else the RXON below will fail. */
+		if (iwl3945_scan_cancel_timeout(priv, 100)) {
+			IWL_WARNING("Aborted scan still in progress "
+				    "after 100ms\n");
+			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+			mutex_unlock(&priv->mutex);
+			return -EAGAIN;
+		}
+		memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+		/* TODO: Audit driver for usage of these members and see
+		 * if mac80211 deprecates them (priv->bssid looks like it
+		 * shouldn't be there, but I haven't scanned the IBSS code
+		 * to verify) - jpk */
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl3945_config_ap(priv);
+		else {
+			rc = iwl3945_commit_rxon(priv);
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+				iwl3945_add_station(priv,
+					priv->active_rxon.bssid_addr, 1, 0);
+		}
+
+	} else {
+		iwl3945_scan_cancel_timeout(priv, 100);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+	}
+
+ done:
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!conf->ssid_len)
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+	else
+		memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+	priv->essid_len = conf->ssid_len;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl3945_configure_filter(struct ieee80211_hw *hw,
+				 unsigned int changed_flags,
+				 unsigned int *total_flags,
+				 int mc_count, struct dev_addr_list *mc_list)
+{
+	/*
+	 * XXX: dummy
+	 * see also iwl3945_connection_init_rx_config
+	 */
+	*total_flags = 0;
+}
+
+static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+
+	if (iwl3945_is_ready_rf(priv)) {
+		iwl3945_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+	}
+	if (priv->interface_id == conf->if_id) {
+		priv->interface_id = 0;
+		memset(priv->bssid, 0, ETH_ALEN);
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+		priv->essid_len = 0;
+	}
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct iwl3945_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		rc = -EIO;
+		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+		goto out_unlock;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
+		rc = -EIO;
+		IWL_ERROR("ERROR: APs don't scan\n");
+		goto out_unlock;
+	}
+
+	/* we don't schedule scan within next_scan_jiffies period */
+	if (priv->next_scan_jiffies &&
+			time_after(priv->next_scan_jiffies, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	/* if we just finished scan ask for delay */
+	if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
+				IWL_DELAY_NEXT_SCAN, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	if (len) {
+		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
+			       iwl3945_escape_essid(ssid, len), (int)len);
+
+		priv->one_direct_scan = 1;
+		priv->direct_ssid_len = (u8)
+		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+	} else
+		priv->one_direct_scan = 0;
+
+	rc = iwl3945_scan_initiate(priv);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   const u8 *local_addr, const u8 *addr,
+			   struct ieee80211_key_conf *key)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	int rc = 0;
+	u8 sta_id;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl3945_param_hwcrypto) {
+		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (is_zero_ether_addr(addr))
+		/* only support pairwise keys */
+		return -EOPNOTSUPP;
+
+	sta_id = iwl3945_hw_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+				   print_mac(mac, addr));
+		return -EINVAL;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	iwl3945_scan_cancel_timeout(priv, 100);
+
+	switch (cmd) {
+	case  SET_KEY:
+		rc = iwl3945_update_sta_key_info(priv, key, sta_id);
+		if (!rc) {
+			iwl3945_set_rxon_hwcrypto(priv, 1);
+			iwl3945_commit_rxon(priv);
+			key->hw_key_idx = sta_id;
+			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		}
+		break;
+	case DISABLE_KEY:
+		rc = iwl3945_clear_sta_key_info(priv, sta_id);
+		if (!rc) {
+			iwl3945_set_rxon_hwcrypto(priv, 0);
+			iwl3945_commit_rxon(priv);
+			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl3945_priv *priv = hw->priv;
+#ifdef CONFIG_IWL3945_QOS
+	unsigned long flags;
+	int q;
+#endif /* CONFIG_IWL3945_QOS */
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	if (queue >= AC_NUM) {
+		IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+		return 0;
+	}
+
+#ifdef CONFIG_IWL3945_QOS
+	if (!priv->qos_data.qos_enable) {
+		priv->qos_data.qos_active = 0;
+		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+		return 0;
+	}
+	q = AC_NUM - 1 - queue;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+	priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+	priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+	priv->qos_data.def_qos_parm.ac[q].edca_txop =
+			cpu_to_le16((params->burst_time * 100));
+
+	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+	priv->qos_data.qos_active = 1;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		iwl3945_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl3945_is_associated(priv))
+		iwl3945_activate_qos(priv, 0);
+
+	mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWL3945_QOS */
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	int i, avail;
+	struct iwl3945_tx_queue *txq;
+	struct iwl3945_queue *q;
+	unsigned long flags;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (i = 0; i < AC_NUM; i++) {
+		txq = &priv->txq[i];
+		q = &txq->q;
+		avail = iwl3945_queue_space(q);
+
+		stats->data[i].len = q->n_window - avail;
+		stats->data[i].limit = q->n_window - q->high_mark;
+		stats->data[i].count = q->n_window;
+
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static int iwl3945_mac_get_stats(struct ieee80211_hw *hw,
+			     struct ieee80211_low_level_stats *stats)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_reset_qos(priv);
+#endif
+	cancel_delayed_work(&priv->post_associate);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = 0;
+	priv->assoc_capability = 0;
+	priv->call_post_assoc_from_beacon = 0;
+
+	/* new association get rid of ibss beacon skb */
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = NULL;
+
+	priv->beacon_int = priv->hw->conf.beacon_int;
+	priv->timestamp1 = 0;
+	priv->timestamp0 = 0;
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		priv->beacon_int = 0;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	/* we are restarting association process
+	 * clear RXON_FILTER_ASSOC_MSK bit
+	*/
+	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+		iwl3945_scan_cancel_timeout(priv, 100);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+	}
+
+	/* Per mac80211.h: This is only used in IBSS mode... */
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+
+		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	priv->only_active_channel = 0;
+
+	iwl3945_set_rate(priv);
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+				 struct ieee80211_tx_control *control)
+{
+	struct iwl3945_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = skb;
+
+	priv->assoc_id = 0;
+
+	IWL_DEBUG_MAC80211("leave\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_reset_qos(priv);
+#endif
+
+	queue_work(priv->workqueue, &priv->post_associate);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWL3945_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+	return sprintf(buf, "0x%08X\n", iwl3945_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+				 const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 0);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in hex or decimal form.\n", buf);
+	else
+		iwl3945_debug_level = val;
+
+	return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+		   show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWL3945_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 iwl3945_priv *priv = (struct iwl3945_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 iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+
+	mutex_lock(&priv->mutex);
+	iwl3945_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)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+
+	if (!iwl3945_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", iwl3945_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct iwl3945_priv *priv = d->driver_data;
+	return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 10);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in decimal form.\n", buf);
+	else
+		iwl3945_hw_reg_set_txpower(priv, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	u32 flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+		/* Cancel any currently running scans... */
+		if (iwl3945_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+				       flags);
+			priv->staging_rxon.flags = cpu_to_le32(flags);
+			iwl3945_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+		/* Cancel any currently running scans... */
+		if (iwl3945_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+				       "0x%04X\n", filter_flags);
+			priv->staging_rxon.filter_flags =
+				cpu_to_le32(filter_flags);
+			iwl3945_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+		   store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		       (priv->phymode << 8) |
+			le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+			  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u16 tune = simple_strtoul(p, &p, 0);
+	u8 phymode = (tune >> 8) & 0xff;
+	u16 channel = tune & 0xff;
+
+	IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+	mutex_lock(&priv->mutex);
+	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+	    (priv->phymode != phymode)) {
+		const struct iwl3945_channel_info *ch_info;
+
+		ch_info = iwl3945_get_channel_info(priv, phymode, channel);
+		if (!ch_info) {
+			IWL_WARNING("Requested invalid phymode/channel "
+				    "combination: %d %d\n", phymode, channel);
+			mutex_unlock(&priv->mutex);
+			return -EINVAL;
+		}
+
+		/* Cancel any currently running scans... */
+		if (iwl3945_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing phymode and "
+				       "rxon.channel = %d %d\n",
+				       phymode, channel);
+
+			iwl3945_set_rxon_channel(priv, phymode, channel);
+			iwl3945_set_flags_for_phymode(priv, phymode);
+
+			iwl3945_set_rate(priv);
+			iwl3945_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_spectrum_notification measure_report;
+	u32 size = sizeof(measure_report), len = 0, ofs = 0;
+	u8 *data = (u8 *) & measure_report;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!(priv->measurement_status & MEASUREMENT_READY)) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return 0;
+	}
+	memcpy(&measure_report, &priv->measure_report, size);
+	priv->measurement_status = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	struct ieee80211_measurement_params params = {
+		.channel = le16_to_cpu(priv->active_rxon.channel),
+		.start_time = cpu_to_le64(priv->last_tsf),
+		.duration = cpu_to_le16(1),
+	};
+	u8 type = IWL_MEASURE_BASIC;
+	u8 buffer[32];
+	u8 channel;
+
+	if (count) {
+		char *p = buffer;
+		strncpy(buffer, buf, min(sizeof(buffer), count));
+		channel = simple_strtoul(p, NULL, 0);
+		if (channel)
+			params.channel = channel;
+
+		p = buffer;
+		while (*p && *p != ' ')
+			p++;
+		if (*p)
+			type = simple_strtoul(p + 1, NULL, 0);
+	}
+
+	IWL_DEBUG_INFO("Invoking measurement of type %d on "
+		       "channel %d (for '%s')\n", type, params.channel, buf);
+	iwl3945_get_measurement(priv, &params, type);
+
+	return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+		   show_measurement, store_measurement);
+#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
+
+static ssize_t show_rate(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+		i = priv->stations[IWL_AP_ID].current_rate.s.rate;
+	else
+		i = priv->stations[IWL_STA_ID].current_rate.s.rate;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	i = iwl3945_rate_index_from_plcp(i);
+	if (i == -1)
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d%s\n",
+		       (iwl3945_rates[i].ieee >> 1),
+		       (iwl3945_rates[i].ieee & 0x1) ? ".5" : "");
+}
+
+static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
+
+static ssize_t store_retry_rate(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+
+	priv->retry_rate = simple_strtoul(buf, NULL, 0);
+	if (priv->retry_rate <= 0)
+		priv->retry_rate = 1;
+
+	return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+		   store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	int rc;
+	int mode;
+
+	mode = simple_strtoul(buf, NULL, 0);
+	mutex_lock(&priv->mutex);
+
+	if (!iwl3945_is_ready(priv)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+		mode = IWL_POWER_AC;
+	else
+		mode |= IWL_POWER_ENABLED;
+
+	if (mode != priv->power_mode) {
+		rc = iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		if (rc) {
+			IWL_DEBUG_MAC80211("failed setting power mode.\n");
+			goto out;
+		}
+		priv->power_mode = mode;
+	}
+
+	rc = count;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+	350000,
+	250000,
+	75000,
+	37000,
+	25000,
+};
+static const s32 period_duration[] = {
+	400000,
+	700000,
+	1000000,
+	1000000,
+	1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	int level = IWL_POWER_LEVEL(priv->power_mode);
+	char *p = buf;
+
+	p += sprintf(p, "%d ", level);
+	switch (level) {
+	case IWL_POWER_MODE_CAM:
+	case IWL_POWER_AC:
+		p += sprintf(p, "(AC)");
+		break;
+	case IWL_POWER_BATTERY:
+		p += sprintf(p, "(BATTERY)");
+		break;
+	default:
+		p += sprintf(p,
+			     "(Timeout %dms, Period %dms)",
+			     timeout_duration[level - 1] / 1000,
+			     period_duration[level - 1] / 1000);
+	}
+
+	if (!(priv->power_mode & IWL_POWER_ENABLED))
+		p += sprintf(p, " OFF\n");
+	else
+		p += sprintf(p, " \n");
+
+	return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+		   store_power_level);
+
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	int len = 0, i;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode = NULL;
+	int count = 0;
+
+	if (!iwl3945_is_ready(priv))
+		return -EAGAIN;
+
+	hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G);
+	if (!hw_mode)
+		hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	}
+
+	len +=
+	    sprintf(&buf[len],
+		    "Displaying %d channels in 2.4GHz band "
+		    "(802.11bg):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	} else {
+		channels = NULL;
+		count = 0;
+	}
+
+	len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+		       "(802.11a):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl3945_notif_statistics);
+	u32 len = 0, ofs = 0;
+	u8 *data = (u8 *) & priv->statistics;
+	int rc = 0;
+
+	if (!iwl3945_is_alive(priv))
+		return -EAGAIN;
+
+	mutex_lock(&priv->mutex);
+	rc = iwl3945_send_statistics_request(priv);
+	mutex_unlock(&priv->mutex);
+
+	if (rc) {
+		len = sprintf(buf,
+			      "Error sending statistics request: 0x%08X\n", rc);
+		return len;
+	}
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+
+	if (!iwl3945_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int ant;
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+
+	if (count == 0)
+		return 0;
+
+	if (sscanf(buf, "%1i", &ant) != 1) {
+		IWL_DEBUG_INFO("not in hex or decimal form.\n");
+		return count;
+	}
+
+	if ((ant >= 0) && (ant <= 2)) {
+		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+		priv->antenna = (enum iwl3945_antenna)ant;
+	} else
+		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+	return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+			   struct device_attribute *attr, char *buf)
+{
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	if (!iwl3945_is_alive(priv))
+		return -EAGAIN;
+	return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl3945_dump_nic_error_log((struct iwl3945_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl3945_dump_nic_event_log((struct iwl3945_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
+{
+	priv->workqueue = create_workqueue(DRV_NAME);
+
+	init_waitqueue_head(&priv->wait_command_queue);
+
+	INIT_WORK(&priv->up, iwl3945_bg_up, priv);
+	INIT_WORK(&priv->restart, iwl3945_bg_restart, priv);
+	INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish, priv);
+	INIT_WORK(&priv->scan_completed, iwl3945_bg_scan_completed, priv);
+	INIT_WORK(&priv->request_scan, iwl3945_bg_request_scan, priv);
+	INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan, priv);
+	INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill, priv);
+	INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update, priv);
+	INIT_WORK(&priv->post_associate, iwl3945_bg_post_associate, priv);
+	INIT_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start, priv);
+	INIT_WORK(&priv->alive_start, iwl3945_bg_alive_start, priv);
+	INIT_WORK(&priv->scan_check, iwl3945_bg_scan_check, priv);
+
+	iwl3945_hw_setup_deferred_work(priv);
+
+	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+		     iwl3945_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv)
+{
+	iwl3945_hw_cancel_deferred_work(priv);
+
+#if 0 /* Not in RHEL5...(and probably wrong upstream...) */
+	cancel_delayed_work_sync(&priv->init_alive_start);
+#else
+	cancel_delayed_work(&priv->init_alive_start);
+	/* Make sure he has completed, since he can schedule other work */
+	flush_workqueue(priv->workqueue);
+#endif
+	cancel_delayed_work(&priv->scan_check);
+	cancel_delayed_work(&priv->alive_start);
+	cancel_delayed_work(&priv->post_associate);
+#if 0 /* Not in RHEL5... */
+	cancel_work_sync(&priv->beacon_update);
+#else
+	flush_workqueue(priv->workqueue);
+#endif
+}
+
+static struct attribute *iwl3945_sysfs_entries[] = {
+	&dev_attr_antenna.attr,
+	&dev_attr_channels.attr,
+	&dev_attr_dump_errors.attr,
+	&dev_attr_dump_events.attr,
+	&dev_attr_flags.attr,
+	&dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+	&dev_attr_measurement.attr,
+#endif
+	&dev_attr_power_level.attr,
+	&dev_attr_rate.attr,
+	&dev_attr_retry_rate.attr,
+	&dev_attr_rf_kill.attr,
+	&dev_attr_rs_window.attr,
+	&dev_attr_statistics.attr,
+	&dev_attr_status.attr,
+	&dev_attr_temperature.attr,
+	&dev_attr_tune.attr,
+	&dev_attr_tx_power.attr,
+
+	NULL
+};
+
+static struct attribute_group iwl3945_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = iwl3945_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl3945_hw_ops = {
+	.tx = iwl3945_mac_tx,
+	.start = iwl3945_mac_start,
+	.stop = iwl3945_mac_stop,
+	.add_interface = iwl3945_mac_add_interface,
+	.remove_interface = iwl3945_mac_remove_interface,
+	.config = iwl3945_mac_config,
+	.config_interface = iwl3945_mac_config_interface,
+	.configure_filter = iwl3945_configure_filter,
+	.set_key = iwl3945_mac_set_key,
+	.get_stats = iwl3945_mac_get_stats,
+	.get_tx_stats = iwl3945_mac_get_tx_stats,
+	.conf_tx = iwl3945_mac_conf_tx,
+	.get_tsf = iwl3945_mac_get_tsf,
+	.reset_tsf = iwl3945_mac_reset_tsf,
+	.beacon_update = iwl3945_mac_beacon_update,
+	.hw_scan = iwl3945_mac_hw_scan
+};
+
+static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = 0;
+	u32 pci_id;
+	struct iwl3945_priv *priv;
+	struct ieee80211_hw *hw;
+	int i;
+
+	/* Disabling hardware scan means that mac80211 will perform scans
+	 * "the hard way", rather than using device's scan. */
+	if (iwl3945_param_disable_hw_scan) {
+		IWL_DEBUG_INFO("Disabling hw_scan\n");
+		iwl3945_hw_ops.hw_scan = NULL;
+	}
+
+	if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	hw = ieee80211_alloc_hw(sizeof(struct iwl3945_priv), &iwl3945_hw_ops);
+	if (hw == NULL) {
+		IWL_ERROR("Can not allocate network device\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+
+	hw->rate_control_algorithm = "iwl-3945-rs";
+
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	priv = hw->priv;
+	priv->hw = hw;
+
+	priv->pci_dev = pdev;
+
+	/* Select antenna (may be helpful if only one antenna is connected) */
+	priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
+#ifdef CONFIG_IWL3945_DEBUG
+	iwl3945_debug_level = iwl3945_param_debug;
+	atomic_set(&priv->restrict_refcnt, 0);
+#endif
+	priv->retry_rate = 1;
+
+	priv->ibss_beacon = NULL;
+
+	/* Tell mac80211 and its clients (e.g. Wireless Extensions)
+	 *   the range of signal quality values that we'll provide.
+	 * Negative values for level/noise indicate that we'll provide dBm.
+	 * For WE, at least, non-0 values here *enable* display of values
+	 *   in app (iwconfig). */
+	hw->max_rssi = -20;	/* signal level, negative indicates dBm */
+	hw->max_noise = -20;	/* noise level, negative indicates dBm */
+	hw->max_signal = 100;	/* link quality indication (%) */
+
+	/* Tell mac80211 our Tx characteristics */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+	/* 4 EDCA QOS priorities */
+	hw->queues = 4;
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+
+	mutex_init(&priv->mutex);
+	if (pci_enable_device(pdev)) {
+		err = -ENODEV;
+		goto out_ieee80211_free_hw;
+	}
+
+	pci_set_master(pdev);
+
+	/* Clear the driver's (not device's) station table */
+	iwl3945_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->phymode = -1;
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err) {
+		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+		goto out_pci_disable_device;
+	}
+
+	pci_set_drvdata(pdev, priv);
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err)
+		goto out_pci_disable_device;
+
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	priv->hw_base = pci_iomap(pdev, 0, 0);
+	if (!priv->hw_base) {
+		err = -ENODEV;
+		goto out_pci_release_regions;
+	}
+
+	IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+			(unsigned long long) pci_resource_len(pdev, 0));
+	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+	/* Initialize module parameter values here */
+
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl3945_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
+	}
+
+	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+	pci_id =
+	    (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
+
+	switch (pci_id) {
+	case 0x42221005:	/* 0x4222 0x8086 0x1005 is BG SKU */
+	case 0x42221034:	/* 0x4222 0x8086 0x1034 is BG SKU */
+	case 0x42271014:	/* 0x4227 0x8086 0x1014 is BG SKU */
+	case 0x42221044:	/* 0x4222 0x8086 0x1044 is BG SKU */
+		priv->is_abg = 0;
+		break;
+
+	/*
+	 * Rest are assumed ABG SKU -- if this is not the
+	 * case then the card will get the wrong 'Detected'
+	 * line in the kernel log however the code that
+	 * initializes the GEO table will detect no A-band
+	 * channels and remove the is_abg mask.
+	 */
+	default:
+		priv->is_abg = 1;
+		break;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
+	       priv->is_abg ? "A" : "");
+
+	/* Device-specific setup */
+	if (iwl3945_hw_set_hw_setting(priv)) {
+		IWL_ERROR("failed to set hw settings\n");
+		mutex_unlock(&priv->mutex);
+		goto out_iounmap;
+	}
+
+#ifdef CONFIG_IWL3945_QOS
+	if (iwl3945_param_qos_enable)
+		priv->qos_data.qos_enable = 1;
+
+	iwl3945_reset_qos(priv);
+
+	priv->qos_data.qos_active = 0;
+	priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWL3945_QOS */
+
+	iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl3945_setup_deferred_work(priv);
+	iwl3945_setup_rx_handlers(priv);
+
+	priv->rates_mask = IWL_RATES_MASK;
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IWL_POWER_AC;
+	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+	iwl3945_disable_interrupts(priv);
+
+	pci_enable_msi(pdev);
+
+	err = request_irq(pdev->irq, iwl3945_isr, IRQF_SHARED, DRV_NAME, priv);
+	if (err) {
+		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+		goto out_disable_msi;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+	if (err) {
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		mutex_unlock(&priv->mutex);
+		goto out_release_irq;
+	}
+
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
+	err = iwl3945_read_ucode(priv);
+	if (err) {
+		IWL_ERROR("Could not read microcode: %d\n", err);
+		mutex_unlock(&priv->mutex);
+		goto out_pci_alloc;
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_INFO("Queueing UP work.\n");
+
+	queue_work(priv->workqueue, &priv->up);
+
+	return 0;
+
+ out_pci_alloc:
+	iwl3945_dealloc_ucode_pci(priv);
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
+ out_release_irq:
+	free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+	pci_disable_msi(pdev);
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+	iwl3945_unset_hw_setting(priv);
+
+ out_iounmap:
+	pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+	pci_release_regions(pdev);
+ out_pci_disable_device:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+	ieee80211_free_hw(priv->hw);
+ out:
+	return err;
+}
+
+static void iwl3945_pci_remove(struct pci_dev *pdev)
+{
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
+	struct list_head *p, *q;
+	int i;
+
+	if (!priv)
+		return;
+
+	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+	mutex_lock(&priv->mutex);
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl3945_down(priv);
+	mutex_unlock(&priv->mutex);
+
+	/* 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]) {
+			list_del(p);
+			kfree(list_entry(p, struct iwl3945_ibss_seq, list));
+		}
+	}
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
+
+	iwl3945_dealloc_ucode_pci(priv);
+
+	if (priv->rxq.bd)
+		iwl3945_rx_queue_free(priv, &priv->rxq);
+	iwl3945_hw_txq_ctx_free(priv);
+
+	iwl3945_unset_hw_setting(priv);
+	iwl3945_clear_stations_table(priv);
+
+	if (priv->mac80211_registered) {
+		ieee80211_unregister_hw(priv->hw);
+		iwl3945_rate_control_unregister(priv->hw);
+	}
+
+	/*netif_stop_queue(dev); */
+	flush_workqueue(priv->workqueue);
+
+	/* ieee80211_unregister_hw calls iwl3945_mac_stop, which flushes
+	 * priv->workqueue... so we can't take down the workqueue
+	 * until now... */
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	free_irq(pdev->irq, priv);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, priv->hw_base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(priv->channel_info);
+
+	kfree(priv->ieee_channels);
+	kfree(priv->ieee_rates);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+	/* Take down the device; powers it off, etc. */
+	__iwl3945_down(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl3945_resume(struct iwl3945_priv *priv)
+{
+	unsigned long flags;
+
+	/* The following it a temporary work around due to the
+	 * suspend / resume not fully initializing the NIC correctly.
+	 * Without all of the following, resume will not attempt to take
+	 * down the NIC (it shouldn't really need to) and will just try
+	 * and bring the NIC back up.  However that fails during the
+	 * ucode verification process.  This then causes iwl3945_down to be
+	 * called *after* iwl3945_hw_nic_init() has succeeded -- which
+	 * then lets the next init sequence succeed.  So, we've
+	 * replicated all of that NIC init code here... */
+
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	iwl3945_hw_nic_init(priv);
+
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* tell the device to stop sending interrupts */
+	iwl3945_disable_interrupts(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	if (!iwl3945_grab_nic_access(priv)) {
+		iwl3945_write_prph(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl3945_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl3945_hw_nic_reset(priv);
+
+	/* Bring the device back up */
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl3945_pci_resume(struct pci_dev *pdev)
+{
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
+	int err;
+
+	printk(KERN_INFO "Coming out of suspend...\n");
+
+	mutex_lock(&priv->mutex);
+
+	pci_set_power_state(pdev, PCI_D0);
+	err = pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	/*
+	 * Suspend/Resume resets the PCI configuration space, so we have to
+	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+	 * from interfering with C3 CPU state. pci_restore_state won't help
+	 * here since it only restores the first 64 bytes pci config header.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	iwl3945_resume(priv);
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl3945_driver = {
+	.name = DRV_NAME,
+	.id_table = iwl3945_hw_card_ids,
+	.probe = iwl3945_pci_probe,
+	.remove = __devexit_p(iwl3945_pci_remove),
+#ifdef CONFIG_PM
+	.suspend = iwl3945_pci_suspend,
+	.resume = iwl3945_pci_resume,
+#endif
+};
+
+static int __init iwl3945_init(void)
+{
+
+	int ret;
+	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+	ret = pci_register_driver(&iwl3945_driver);
+	if (ret) {
+		IWL_ERROR("Unable to initialize PCI module\n");
+		return ret;
+	}
+#ifdef CONFIG_IWL3945_DEBUG
+	ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level);
+	if (ret) {
+		IWL_ERROR("Unable to create driver sysfs file\n");
+		pci_unregister_driver(&iwl3945_driver);
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static void __exit iwl3945_exit(void)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level);
+#endif
+	pci_unregister_driver(&iwl3945_driver);
+}
+
+module_param_named(antenna, iwl3945_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl3945_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+		 "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl3945_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl3945_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl3945_exit);
+module_init(iwl3945_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
new file mode 100644
index 0000000..0466f61
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -0,0 +1,9538 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWL4965_DEBUG
+u32 iwl4965_debug_level;
+#endif
+
+static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
+				  struct iwl4965_tx_queue *txq);
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */
+static int iwl4965_param_debug;    /* def: 0 = minimal debug log messages */
+static int iwl4965_param_disable;  /* def: enable radio */
+static int iwl4965_param_antenna;  /* def: 0 = both antennas (use diversity) */
+int iwl4965_param_hwcrypto;        /* def: using software encryption */
+static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K;   /* def: enable 8K amsdu size */
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
+
+#ifdef CONFIG_IWL4965_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.2.22k" VD VS
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION     IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ *   *only* when uCode interface or architecture changes so that it
+ *   is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	int hdr_len = ieee80211_get_hdrlen(fc);
+
+	if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+		return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+	return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl4965_get_hw_mode(
+		struct iwl4965_priv *priv, int mode)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		if (priv->modes[i].mode == mode)
+			return &priv->modes[i];
+
+	return NULL;
+}
+
+static int iwl4965_is_empty_essid(const char *essid, int essid_len)
+{
+	/* Single white space is for Linksys APs */
+	if (essid_len == 1 && essid[0] == ' ')
+		return 1;
+
+	/* Otherwise, if the entire essid is 0, we assume it is hidden */
+	while (essid_len) {
+		essid_len--;
+		if (essid[essid_len] != '\0')
+			return 0;
+	}
+
+	return 1;
+}
+
+static const char *iwl4965_escape_essid(const char *essid, u8 essid_len)
+{
+	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+	const char *s = essid;
+	char *d = escaped;
+
+	if (iwl4965_is_empty_essid(essid, essid_len)) {
+		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+		return escaped;
+	}
+
+	essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+	while (essid_len--) {
+		if (*s == '\0') {
+			*d++ = '\\';
+			*d++ = '0';
+			s++;
+		} else
+			*d++ = *s++;
+	}
+	*d = '\0';
+	return escaped;
+}
+
+static void iwl4965_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	if (!(iwl4965_debug_level & level))
+		return;
+
+	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The 4965 operates with up to 17 queues:  One receive queue, one transmit
+ * queue (#4) for sending commands to the device firmware, and 15 other
+ * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
+ *
+ * See more detailed info in iwl-4965-hw.h.
+ ***************************************************/
+
+static int iwl4965_queue_space(const struct iwl4965_queue *q)
+{
+	int s = q->read_ptr - q->write_ptr;
+
+	if (q->read_ptr > q->write_ptr)
+		s -= q->n_bd;
+
+	if (s <= 0)
+		s += q->n_window;
+	/* keep some reserve to not confuse empty and full situations */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl4965_queue_inc_wrap(int index, int n_bd)
+{
+	return ++index & (n_bd - 1);
+}
+
+/**
+ * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
+{
+	return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
+{
+	return q->write_ptr > q->read_ptr ?
+		(i >= q->read_ptr && i < q->write_ptr) :
+		!(i < q->read_ptr && i >= q->write_ptr);
+}
+
+static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
+{
+	/* This is for scan command, the big buffer at end of command array */
+	if (is_huge)
+		return q->n_window;	/* must be power of 2 */
+
+	/* Otherwise, use normal size buffers */
+	return index & (q->n_window - 1);
+}
+
+/**
+ * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q,
+			  int count, int slots_num, u32 id)
+{
+	q->n_bd = count;
+	q->n_window = slots_num;
+	q->id = id;
+
+	/* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap
+	 * and iwl4965_queue_dec_wrap are broken. */
+	BUG_ON(!is_power_of_2(count));
+
+	/* slots_num must be power-of-two size, otherwise
+	 * get_cmd_index is broken. */
+	BUG_ON(!is_power_of_2(slots_num));
+
+	q->low_mark = q->n_window / 4;
+	if (q->low_mark < 4)
+		q->low_mark = 4;
+
+	q->high_mark = q->n_window / 8;
+	if (q->high_mark < 2)
+		q->high_mark = 2;
+
+	q->write_ptr = q->read_ptr = 0;
+
+	return 0;
+}
+
+/**
+ * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
+			      struct iwl4965_tx_queue *txq, u32 id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+
+	/* Driver private data, only for Tx (not command) queues,
+	 * not shared with device. */
+	if (id != IWL_CMD_QUEUE_NUM) {
+		txq->txb = kmalloc(sizeof(txq->txb[0]) *
+				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+		if (!txq->txb) {
+			IWL_ERROR("kmalloc for auxiliary BD "
+				  "structures failed\n");
+			goto error;
+		}
+	} else
+		txq->txb = NULL;
+
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
+	txq->bd = pci_alloc_consistent(dev,
+			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+			&txq->q.dma_addr);
+
+	if (!txq->bd) {
+		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+		goto error;
+	}
+	txq->q.id = id;
+
+	return 0;
+
+ error:
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+/**
+ * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
+		      struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+	int rc = 0;
+
+	/*
+	 * Alloc buffer array for commands (Tx or other types of commands).
+	 * For the command queue (#4), allocate command space + one big
+	 * command for scan, since scan command is very huge; the system will
+	 * not have two scans at the same time, so only one is needed.
+	 * For normal Tx queues (all other queues), no super-size command
+	 * space is needed.
+	 */
+	len = sizeof(struct iwl4965_cmd) * slots_num;
+	if (txq_id == IWL_CMD_QUEUE_NUM)
+		len +=  IWL_MAX_SCAN_SIZE;
+	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+	if (!txq->cmd)
+		return -ENOMEM;
+
+	/* Alloc driver data array and TFD circular buffer */
+	rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
+	if (rc) {
+		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+		return -ENOMEM;
+	}
+	txq->need_update = 0;
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+	/* Initialize queue's high/low-water marks, and head/tail indexes */
+	iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	/* Tell device where to find queue */
+	iwl4965_hw_tx_queue_init(priv, txq);
+
+	return 0;
+}
+
+/**
+ * iwl4965_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
+{
+	struct iwl4965_queue *q = &txq->q;
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+
+	if (q->n_bd == 0)
+		return;
+
+	/* first, empty all BD's */
+	for (; q->write_ptr != q->read_ptr;
+	     q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd))
+		iwl4965_hw_txq_free_tfd(priv, txq);
+
+	len = sizeof(struct iwl4965_cmd) * q->n_window;
+	if (q->id == IWL_CMD_QUEUE_NUM)
+		len += IWL_MAX_SCAN_SIZE;
+
+	/* De-alloc array of command/tx buffers */
+	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+	/* De-alloc circular buffer of TFDs */
+	if (txq->q.n_bd)
+		pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) *
+				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+	/* De-alloc array of per-TFD driver data */
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	/* 0-fill queue descriptor structure */
+	memset(txq, 0, sizeof(*txq));
+}
+
+const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ * mac80211 should be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+
+#if 0 /* temporary disable till we add real remove station */
+/**
+ * iwl4965_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE:  This does not remove station from device's station table.
+ */
+static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
+{
+	int index = IWL_INVALID_STATION;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+			if (priv->stations[i].used &&
+			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+	if (unlikely(index == IWL_INVALID_STATION))
+		goto out;
+
+	if (priv->stations[index].used) {
+		priv->stations[index].used = 0;
+		priv->num_stations--;
+	}
+
+	BUG_ON(priv->num_stations < 0);
+
+out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return 0;
+}
+#endif
+
+/**
+ * iwl4965_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+/**
+ * iwl4965_add_station_flags - Add station to tables in driver and device
+ */
+u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+				int is_ap, u8 flags, void *ht_data)
+{
+	int i;
+	int index = IWL_INVALID_STATION;
+	struct iwl4965_station_entry *station;
+	unsigned long flags_spin;
+	DECLARE_MAC_BUF(mac);
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+			if (!priv->stations[i].used &&
+			    index == IWL_INVALID_STATION)
+				index = i;
+		}
+
+
+	/* These two conditions have the same outcome, but keep them separate
+	  since they have different meanings */
+	if (unlikely(index == IWL_INVALID_STATION)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	if (priv->stations[index].used &&
+	    !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+
+	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+	station = &priv->stations[index];
+	station->used = 1;
+	priv->num_stations++;
+
+	/* Set up the REPLY_ADD_STA command to send to device */
+	memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
+	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+	station->sta.mode = 0;
+	station->sta.sta.sta_id = index;
+	station->sta.station_flags = 0;
+
+#ifdef CONFIG_IWL4965_HT
+	/* BCAST station and IBSS stations do not work in HT mode */
+	if (index != priv->hw_setting.bcast_sta_id &&
+	    priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+		iwl4965_set_ht_add_station(priv, index,
+				 (struct ieee80211_ht_info *) ht_data);
+#endif /*CONFIG_IWL4965_HT*/
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+	/* Add station to device's station table */
+	iwl4965_send_add_station(priv, &station->sta, flags);
+	return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS   *****/
+
+static inline int iwl4965_is_ready(struct iwl4965_priv *priv)
+{
+	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+	 * set but EXIT_PENDING is not */
+	return test_bit(STATUS_READY, &priv->status) &&
+	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl4965_is_alive(struct iwl4965_priv *priv)
+{
+	return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl4965_is_init(struct iwl4965_priv *priv)
+{
+	return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl4965_is_rfkill(struct iwl4965_priv *priv)
+{
+	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	       test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl4965_is_ready_rf(struct iwl4965_priv *priv)
+{
+
+	if (iwl4965_is_rfkill(priv))
+		return 0;
+
+	return iwl4965_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+		IWL_CMD(REPLY_ALIVE);
+		IWL_CMD(REPLY_ERROR);
+		IWL_CMD(REPLY_RXON);
+		IWL_CMD(REPLY_RXON_ASSOC);
+		IWL_CMD(REPLY_QOS_PARAM);
+		IWL_CMD(REPLY_RXON_TIMING);
+		IWL_CMD(REPLY_ADD_STA);
+		IWL_CMD(REPLY_REMOVE_STA);
+		IWL_CMD(REPLY_REMOVE_ALL_STA);
+		IWL_CMD(REPLY_TX);
+		IWL_CMD(REPLY_RATE_SCALE);
+		IWL_CMD(REPLY_LEDS_CMD);
+		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+		IWL_CMD(RADAR_NOTIFICATION);
+		IWL_CMD(REPLY_QUIET_CMD);
+		IWL_CMD(REPLY_CHANNEL_SWITCH);
+		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+		IWL_CMD(POWER_TABLE_CMD);
+		IWL_CMD(PM_SLEEP_NOTIFICATION);
+		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+		IWL_CMD(REPLY_SCAN_CMD);
+		IWL_CMD(REPLY_SCAN_ABORT_CMD);
+		IWL_CMD(SCAN_START_NOTIFICATION);
+		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+		IWL_CMD(BEACON_NOTIFICATION);
+		IWL_CMD(REPLY_TX_BEACON);
+		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+		IWL_CMD(QUIET_NOTIFICATION);
+		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+		IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+		IWL_CMD(REPLY_BT_CONFIG);
+		IWL_CMD(REPLY_STATISTICS_CMD);
+		IWL_CMD(STATISTICS_NOTIFICATION);
+		IWL_CMD(REPLY_CARD_STATE_CMD);
+		IWL_CMD(CARD_STATE_NOTIFICATION);
+		IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+		IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+		IWL_CMD(SENSITIVITY_CMD);
+		IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+		IWL_CMD(REPLY_RX_PHY_CMD);
+		IWL_CMD(REPLY_RX_MPDU_CMD);
+		IWL_CMD(REPLY_4965_RX);
+		IWL_CMD(REPLY_COMPRESSED_BA);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl4965_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
+{
+	struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl4965_queue *q = &txq->q;
+	struct iwl4965_tfd_frame *tfd;
+	u32 *control_flags;
+	struct iwl4965_cmd *out_cmd;
+	u32 idx;
+	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+	dma_addr_t phys_addr;
+	int ret;
+	unsigned long flags;
+
+	/* If any of the command structures end up being larger than
+	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+	 * we will need to increase the size of the TFD entries */
+	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+	       !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+	if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+		IWL_ERROR("No space for Tx\n");
+		return -ENOSPC;
+	}
+
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+	tfd = &txq->bd[q->write_ptr];
+	memset(tfd, 0, sizeof(*tfd));
+
+	control_flags = (u32 *) tfd;
+
+	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+	out_cmd = &txq->cmd[idx];
+
+	out_cmd->hdr.cmd = cmd->id;
+	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+	/* At this point, the out_cmd now has all of the incoming cmd
+	 * information */
+
+	out_cmd->hdr.flags = 0;
+	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+			INDEX_TO_SEQ(q->write_ptr));
+	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+			offsetof(struct iwl4965_cmd, hdr);
+	iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+		     "%d bytes at %d[%d]:%d\n",
+		     get_cmd_string(out_cmd->hdr.cmd),
+		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+
+	txq->need_update = 1;
+
+	/* Set up entry in queue's byte count circular buffer */
+	ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+
+	/* Increment and update queue's write index */
+	q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+	iwl4965_tx_queue_update_write_ptr(priv, txq);
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+	return ret ? ret : idx;
+}
+
+static int iwl4965_send_cmd_async(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
+{
+	int ret;
+
+	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+	/* An asynchronous command can not expect an SKB to be set. */
+	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+	/* An asynchronous command MUST have a callback. */
+	BUG_ON(!cmd->meta.u.callback);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EBUSY;
+
+	ret = iwl4965_enqueue_hcmd(priv, cmd);
+	if (ret < 0) {
+		IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int iwl4965_send_cmd_sync(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
+{
+	int cmd_idx;
+	int ret;
+	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+	BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+	 /* A synchronous command can not have a callback set. */
+	BUG_ON(cmd->meta.u.callback != NULL);
+
+	if (atomic_xchg(&entry, 1)) {
+		IWL_ERROR("Error sending %s: Already sending a host command\n",
+			  get_cmd_string(cmd->id));
+		return -EBUSY;
+	}
+
+	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+	if (cmd->meta.flags & CMD_WANT_SKB)
+		cmd->meta.source = &cmd->meta;
+
+	cmd_idx = iwl4965_enqueue_hcmd(priv, cmd);
+	if (cmd_idx < 0) {
+		ret = cmd_idx;
+		IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		goto out;
+	}
+
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+			HOST_COMPLETE_TIMEOUT);
+	if (!ret) {
+		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+			IWL_ERROR("Error sending %s: time out after %dms.\n",
+				  get_cmd_string(cmd->id),
+				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+			ret = -ETIMEDOUT;
+			goto cancel;
+		}
+	}
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+			       get_cmd_string(cmd->id));
+		ret = -ECANCELED;
+		goto fail;
+	}
+	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+			       get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto fail;
+	}
+	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+		IWL_ERROR("Error: Response NULL in '%s'\n",
+			  get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = 0;
+	goto out;
+
+cancel:
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		struct iwl4965_cmd *qcmd;
+
+		/* Cancel the CMD_WANT_SKB flag for the cmd in the
+		 * TX cmd queue. Otherwise in case the cmd comes
+		 * in later, it will possibly set an invalid
+		 * address (cmd->meta.source). */
+		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+		qcmd->meta.flags &= ~CMD_WANT_SKB;
+	}
+fail:
+	if (cmd->meta.u.skb) {
+		dev_kfree_skb_any(cmd->meta.u.skb);
+		cmd->meta.u.skb = NULL;
+	}
+out:
+	atomic_set(&entry, 0);
+	return ret;
+}
+
+int iwl4965_send_cmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
+{
+	if (cmd->meta.flags & CMD_ASYNC)
+		return iwl4965_send_cmd_async(priv, cmd);
+
+	return iwl4965_send_cmd_sync(priv, cmd);
+}
+
+int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, const void *data)
+{
+	struct iwl4965_host_cmd cmd = {
+		.id = id,
+		.len = len,
+		.data = data,
+	};
+
+	return iwl4965_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl4965_send_cmd_u32(struct iwl4965_priv *priv, u8 id, u32 val)
+{
+	struct iwl4965_host_cmd cmd = {
+		.id = id,
+		.len = sizeof(val),
+		.data = &val,
+	};
+
+	return iwl4965_send_cmd_sync(priv, &cmd);
+}
+
+int iwl4965_send_statistics_request(struct iwl4965_priv *priv)
+{
+	return iwl4965_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl4965_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling this fnction
+ */
+static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
+				const u8 *addr, int is_ap)
+{
+	u8 sta_id;
+
+	/* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+	struct ieee80211_conf *conf = &priv->hw->conf;
+	struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+	if ((is_ap) &&
+	    (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+						   0, cur_ht_config);
+	else
+#endif /* CONFIG_IWL4965_HT */
+		sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+						   0, NULL);
+
+	/* Set up default rate scaling table in device's station table */
+	iwl4965_add_station(priv, addr, is_ap);
+
+	return sta_id;
+}
+
+/**
+ * iwl4965_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode,
+				 u16 channel)
+{
+	if (!iwl4965_get_channel_info(priv, phymode, channel)) {
+		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+			       channel, phymode);
+		return -EINVAL;
+	}
+
+	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+	    (priv->phymode == phymode))
+		return 0;
+
+	priv->staging_rxon.channel = cpu_to_le16(channel);
+	if (phymode == MODE_IEEE80211A)
+		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+	priv->phymode = phymode;
+
+	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+	return 0;
+}
+
+/**
+ * iwl4965_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE:  This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon)
+{
+	int error = 0;
+	int counter = 1;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		error |= le32_to_cpu(rxon->flags &
+				(RXON_FLG_TGJ_NARROW_BAND_MSK |
+				 RXON_FLG_RADAR_DETECT_MSK));
+		if (error)
+			IWL_WARNING("check 24G fields %d | %d\n",
+				    counter++, error);
+	} else {
+		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+		if (error)
+			IWL_WARNING("check 52 fields %d | %d\n",
+				    counter++, error);
+		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+		if (error)
+			IWL_WARNING("check 52 CCK %d | %d\n",
+				    counter++, error);
+	}
+	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+	if (error)
+		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+	if (error)
+		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+	if (error)
+		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+	if (error)
+		IWL_WARNING("check CCK and short slot %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+	if (error)
+		IWL_WARNING("check CCK & auto detect %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+	if (error)
+		IWL_WARNING("check TGG and auto detect %d | %d\n",
+			    counter++, error);
+
+	if (error)
+		IWL_WARNING("Tuning to channel %d\n",
+			    le16_to_cpu(rxon->channel));
+
+	if (error) {
+		IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
+ *
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
+ */
+static int iwl4965_full_rxon_required(struct iwl4965_priv *priv)
+{
+
+	/* These items are only settable from the full RXON command */
+	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+	    compare_ether_addr(priv->staging_rxon.bssid_addr,
+			       priv->active_rxon.bssid_addr) ||
+	    compare_ether_addr(priv->staging_rxon.node_addr,
+			       priv->active_rxon.node_addr) ||
+	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+			       priv->active_rxon.wlap_bssid_addr) ||
+	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+	    (priv->staging_rxon.air_propagation !=
+	     priv->active_rxon.air_propagation) ||
+	    (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
+	     priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
+	    (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
+	     priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+	    (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
+	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+		return 1;
+
+	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+	 * be updated with the RXON_ASSOC command -- however only some
+	 * flag transitions are allowed using RXON_ASSOC */
+
+	/* Check if we are not switching bands */
+	if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+	    (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+		return 1;
+
+	/* Check if we are switching association toggle */
+	if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+		(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+		return 1;
+
+	return 0;
+}
+
+static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv)
+{
+	int rc = 0;
+	struct iwl4965_rx_packet *res = NULL;
+	struct iwl4965_rxon_assoc_cmd rxon_assoc;
+	struct iwl4965_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 = iwl4965_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
+ *
+ * The RXON command in staging_rxon is committed to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl4965_commit_rxon(struct iwl4965_priv *priv)
+{
+	/* cast away the const for active_rxon in this function */
+	struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	DECLARE_MAC_BUF(mac);
+	int rc = 0;
+
+	if (!iwl4965_is_alive(priv))
+		return -1;
+
+	/* always get timestamp with Rx frame */
+	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+	rc = iwl4965_check_rxon_cmd(&priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
+		return -EINVAL;
+	}
+
+	/* If we don't need to send a full RXON, we can use
+	 * 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);
+		if (rc) {
+			IWL_ERROR("Error setting RXON_ASSOC "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+
+		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+		return 0;
+	}
+
+	/* station table will be cleared */
+	priv->assoc_station_added = 0;
+
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+	if (!priv->error_recovering)
+		priv->start_calib = 0;
+
+	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWL4965_SENSITIVITY */
+
+	/* If we are currently associated and the new config requires
+	 * an RXON_ASSOC and the new config wants the associated mask enabled,
+	 * we must clear the associated from the active configuration
+	 * before we apply the new config */
+	if (iwl4965_is_associated(priv) &&
+	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl4965_rxon_cmd),
+				      &priv->active_rxon);
+
+		/* If the mask clearing failed then we set
+		 * active_rxon back to what it was previously */
+		if (rc) {
+			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+			IWL_ERROR("Error clearing ASSOC_MSK on current "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+	}
+
+	IWL_DEBUG_INFO("Sending RXON\n"
+		       "* with%s RXON_FILTER_ASSOC_MSK\n"
+		       "* channel = %d\n"
+		       "* bssid = %s\n",
+		       ((priv->staging_rxon.filter_flags &
+			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+		       le16_to_cpu(priv->staging_rxon.channel),
+		       print_mac(mac, priv->staging_rxon.bssid_addr));
+
+	/* Apply the new configuration */
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Error setting new configuration (%d).\n", rc);
+		return rc;
+	}
+
+	iwl4965_clear_stations_table(priv);
+
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	if (!priv->error_recovering)
+		priv->start_calib = 0;
+
+	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWL4965_SENSITIVITY */
+
+	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+	/* If we issue a new RXON command which required a tune then we must
+	 * send a new TXPOWER command or we won't be able to Tx any frames */
+	rc = iwl4965_hw_reg_send_txpower(priv);
+	if (rc) {
+		IWL_ERROR("Error setting Tx power (%d).\n", rc);
+		return rc;
+	}
+
+	/* Add the broadcast address so we can send broadcast frames */
+	if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) ==
+	    IWL_INVALID_STATION) {
+		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+		return -EIO;
+	}
+
+	/* If we have set the ASSOC_MSK and we are in BSS mode then
+	 * add the IWL_AP_ID to the station rate table */
+	if (iwl4965_is_associated(priv) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+		if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+		    == IWL_INVALID_STATION) {
+			IWL_ERROR("Error adding AP address for transmit.\n");
+			return -EIO;
+		}
+		priv->assoc_station_added = 1;
+	}
+
+	return 0;
+}
+
+static int iwl4965_send_bt_config(struct iwl4965_priv *priv)
+{
+	struct iwl4965_bt_cmd bt_cmd = {
+		.flags = 3,
+		.lead_time = 0xAA,
+		.max_kill = 1,
+		.kill_ack_mask = 0,
+		.kill_cts_mask = 0,
+	};
+
+	return iwl4965_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl4965_bt_cmd), &bt_cmd);
+}
+
+static int iwl4965_send_scan_abort(struct iwl4965_priv *priv)
+{
+	int rc = 0;
+	struct iwl4965_rx_packet *res;
+	struct iwl4965_host_cmd cmd = {
+		.id = REPLY_SCAN_ABORT_CMD,
+		.meta.flags = CMD_WANT_SKB,
+	};
+
+	/* If there isn't a scan actively going on in the hardware
+	 * then we are in between scan bands and not actually
+	 * actively scanning, so don't send the abort command */
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return 0;
+	}
+
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
+	if (rc) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return rc;
+	}
+
+	res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
+	if (res->u.status != CAN_ABORT_STATUS) {
+		/* The scan abort will return 1 for success or
+		 * 2 for "failure".  A failure condition can be
+		 * due to simply not being in an active scan which
+		 * can occur if we send the scan abort before we
+		 * the microcode has notified us that a scan is
+		 * completed. */
+		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv,
+					struct iwl4965_cmd *cmd,
+					struct sk_buff *skb)
+{
+	return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the device's internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl4965_send_card_state(struct iwl4965_priv *priv, u32 flags, u8 meta_flag)
+{
+	struct iwl4965_host_cmd cmd = {
+		.id = REPLY_CARD_STATE_CMD,
+		.len = sizeof(u32),
+		.data = &flags,
+		.meta.flags = meta_flag,
+	};
+
+	if (meta_flag & CMD_ASYNC)
+		cmd.meta.u.callback = iwl4965_card_state_sync_callback;
+
+	return iwl4965_send_cmd(priv, &cmd);
+}
+
+static int iwl4965_add_sta_sync_callback(struct iwl4965_priv *priv,
+				     struct iwl4965_cmd *cmd, struct sk_buff *skb)
+{
+	struct iwl4965_rx_packet *res = NULL;
+
+	if (!skb) {
+		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+		return 1;
+	}
+
+	res = (struct iwl4965_rx_packet *)skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		return 1;
+	}
+
+	switch (res->u.add_sta.status) {
+	case ADD_STA_SUCCESS_MSK:
+		break;
+	default:
+		break;
+	}
+
+	/* We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+int iwl4965_send_add_station(struct iwl4965_priv *priv,
+			 struct iwl4965_addsta_cmd *sta, u8 flags)
+{
+	struct iwl4965_rx_packet *res = NULL;
+	int rc = 0;
+	struct iwl4965_host_cmd cmd = {
+		.id = REPLY_ADD_STA,
+		.len = sizeof(struct iwl4965_addsta_cmd),
+		.meta.flags = flags,
+		.data = sta,
+	};
+
+	if (flags & CMD_ASYNC)
+		cmd.meta.u.callback = iwl4965_add_sta_sync_callback;
+	else
+		cmd.meta.flags |= CMD_WANT_SKB;
+
+	rc = iwl4965_send_cmd(priv, &cmd);
+
+	if (rc || (flags & CMD_ASYNC))
+		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_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		rc = -EIO;
+	}
+
+	if (rc == 0) {
+		switch (res->u.add_sta.status) {
+		case ADD_STA_SUCCESS_MSK:
+			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+			break;
+		default:
+			rc = -EIO;
+			IWL_WARNING("REPLY_ADD_STA failed\n");
+			break;
+		}
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl4965_update_sta_key_info(struct iwl4965_priv *priv,
+				   struct ieee80211_key_conf *keyconf,
+				   u8 sta_id)
+{
+	unsigned long flags;
+	__le16 key_flags = 0;
+
+	switch (keyconf->alg) {
+	case ALG_CCMP:
+		key_flags |= STA_KEY_FLG_CCMP;
+		key_flags |= cpu_to_le16(
+				keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+		key_flags &= ~STA_KEY_FLG_INVALID;
+		break;
+	case ALG_TKIP:
+	case ALG_WEP:
+	default:
+		return -EINVAL;
+	}
+	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_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");
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static int iwl4965_clear_sta_key_info(struct iwl4965_priv *priv, u8 sta_id)
+{
+	unsigned long flags;
+
+	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 void iwl4965_clear_free_frames(struct iwl4965_priv *priv)
+{
+	struct list_head *element;
+
+	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+		       priv->frames_count);
+
+	while (!list_empty(&priv->free_frames)) {
+		element = priv->free_frames.next;
+		list_del(element);
+		kfree(list_entry(element, struct iwl4965_frame, list));
+		priv->frames_count--;
+	}
+
+	if (priv->frames_count) {
+		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
+			    priv->frames_count);
+		priv->frames_count = 0;
+	}
+}
+
+static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl4965_priv *priv)
+{
+	struct iwl4965_frame *frame;
+	struct list_head *element;
+	if (list_empty(&priv->free_frames)) {
+		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+		if (!frame) {
+			IWL_ERROR("Could not allocate frame!\n");
+			return NULL;
+		}
+
+		priv->frames_count++;
+		return frame;
+	}
+
+	element = priv->free_frames.next;
+	list_del(element);
+	return list_entry(element, struct iwl4965_frame, list);
+}
+
+static void iwl4965_free_frame(struct iwl4965_priv *priv, struct iwl4965_frame *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+	list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv,
+				struct ieee80211_hdr *hdr,
+				const u8 *dest, int left)
+{
+
+	if (!iwl4965_is_associated(priv) || !priv->ibss_beacon ||
+	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+		return 0;
+
+	if (priv->ibss_beacon->len > left)
+		return 0;
+
+	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+	return priv->ibss_beacon->len;
+}
+
+int iwl4965_rate_index_from_plcp(int plcp)
+{
+	int i = 0;
+
+	/* 4965 HT rate format */
+	if (plcp & RATE_MCS_HT_MSK) {
+		i = (plcp & 0xff);
+
+		if (i >= IWL_RATE_MIMO_6M_PLCP)
+			i = i - IWL_RATE_MIMO_6M_PLCP;
+
+		i += IWL_FIRST_OFDM_RATE;
+		/* skip 9M not supported in ht*/
+		if (i >= IWL_RATE_9M_INDEX)
+			i += 1;
+		if ((i >= IWL_FIRST_OFDM_RATE) &&
+		    (i <= IWL_LAST_OFDM_RATE))
+			return i;
+
+	/* 4965 legacy rate format, search for match in table */
+	} else {
+		for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++)
+			if (iwl4965_rates[i].plcp == (plcp &0xFF))
+				return i;
+	}
+	return -1;
+}
+
+static u8 iwl4965_rate_get_lowest_plcp(int rate_mask)
+{
+	u8 i;
+
+	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+	     i = iwl4965_rates[i].next_ieee) {
+		if (rate_mask & (1 << i))
+			return iwl4965_rates[i].plcp;
+	}
+
+	return IWL_RATE_INVALID;
+}
+
+static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv)
+{
+	struct iwl4965_frame *frame;
+	unsigned int frame_size;
+	int rc;
+	u8 rate;
+
+	frame = iwl4965_get_free_frame(priv);
+
+	if (!frame) {
+		IWL_ERROR("Could not obtain free frame buffer for beacon "
+			  "command.\n");
+		return -ENOMEM;
+	}
+
+	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+		rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic &
+						0xFF0);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_6M_PLCP;
+	} else {
+		rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_1M_PLCP;
+	}
+
+	frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
+
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+			      &frame->u.cmd[0]);
+
+	iwl4965_free_frame(priv, frame);
+
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
+{
+	memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl4965_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM contents from adapter into priv->eeprom
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl4965_eeprom_init(struct iwl4965_priv *priv)
+{
+	u16 *e = (u16 *)&priv->eeprom;
+	u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
+	u32 r;
+	int sz = sizeof(priv->eeprom);
+	int rc;
+	int i;
+	u16 addr;
+
+	/* The EEPROM structure has several padding buffers within it
+	 * and when adding new EEPROM maps is subject to programmer errors
+	 * which may be very difficult to identify without explicitly
+	 * checking the resulting size of the eeprom map. */
+	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+		return -ENOENT;
+	}
+
+	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
+	rc = iwl4965_eeprom_acquire_semaphore(priv);
+	if (rc < 0) {
+		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
+		return -ENOENT;
+	}
+
+	/* eeprom is an array of 16bit values */
+	for (addr = 0; addr < sz; addr += sizeof(u16)) {
+		_iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+					i += IWL_EEPROM_ACCESS_DELAY) {
+			r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG);
+			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+				break;
+			udelay(IWL_EEPROM_ACCESS_DELAY);
+		}
+
+		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+			IWL_ERROR("Time out reading EEPROM[%d]", addr);
+			rc = -ETIMEDOUT;
+			goto done;
+		}
+		e[addr / 2] = le16_to_cpu(r >> 16);
+	}
+	rc = 0;
+
+done:
+	iwl4965_eeprom_release_semaphore(priv);
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWL4965_DEBUG
+
+/**
+ * iwl4965_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO:  This was originally written for 3945, need to audit for
+ *        proper operation with 4965.
+ */
+void iwl4965_report_frame(struct iwl4965_priv *priv,
+		      struct iwl4965_rx_packet *pkt,
+		      struct ieee80211_hdr *header, int group100)
+{
+	u32 to_us;
+	u32 print_summary = 0;
+	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
+	u32 hundred = 0;
+	u32 dataframe = 0;
+	u16 fc;
+	u16 seq_ctl;
+	u16 channel;
+	u16 phy_flags;
+	int rate_sym;
+	u16 length;
+	u16 status;
+	u16 bcn_tmr;
+	u32 tsf_low;
+	u64 tsf;
+	u8 rssi;
+	u8 agc;
+	u16 sig_avg;
+	u16 noise_diff;
+	struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	u8 *data = IWL_RX_DATA(pkt);
+
+	/* MAC header */
+	fc = le16_to_cpu(header->frame_control);
+	seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+	/* metadata */
+	channel = le16_to_cpu(rx_hdr->channel);
+	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	rate_sym = rx_hdr->rate;
+	length = le16_to_cpu(rx_hdr->len);
+
+	/* end-of-frame status and timestamp */
+	status = le32_to_cpu(rx_end->status);
+	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+	tsf = le64_to_cpu(rx_end->timestamp);
+
+	/* signal statistics */
+	rssi = rx_stats->rssi;
+	agc = rx_stats->agc;
+	sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+	/* if data frame is to us and all is good,
+	 *   (optionally) print summary for only 1 out of every 100 */
+	if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+	    (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+		dataframe = 1;
+		if (!group100)
+			print_summary = 1;	/* print each frame */
+		else if (priv->framecnt_to_us < 100) {
+			priv->framecnt_to_us++;
+			print_summary = 0;
+		} else {
+			priv->framecnt_to_us = 0;
+			print_summary = 1;
+			hundred = 1;
+		}
+	} else {
+		/* print summary for all other frames */
+		print_summary = 1;
+	}
+
+	if (print_summary) {
+		char *title;
+		u32 rate;
+
+		if (hundred)
+			title = "100Frames";
+		else if (fc & IEEE80211_FCTL_RETRY)
+			title = "Retry";
+		else if (ieee80211_is_assoc_response(fc))
+			title = "AscRsp";
+		else if (ieee80211_is_reassoc_response(fc))
+			title = "RasRsp";
+		else if (ieee80211_is_probe_response(fc)) {
+			title = "PrbRsp";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_beacon(fc)) {
+			title = "Beacon";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_atim(fc))
+			title = "ATIM";
+		else if (ieee80211_is_auth(fc))
+			title = "Auth";
+		else if (ieee80211_is_deauth(fc))
+			title = "DeAuth";
+		else if (ieee80211_is_disassoc(fc))
+			title = "DisAssoc";
+		else
+			title = "Frame";
+
+		rate = iwl4965_rate_index_from_plcp(rate_sym);
+		if (rate == -1)
+			rate = 0;
+		else
+			rate = iwl4965_rates[rate].ieee / 2;
+
+		/* print frame summary.
+		 * MAC addresses show just the last byte (for brevity),
+		 *    but you can hack it to show more, if you'd like to. */
+		if (dataframe)
+			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+				     title, fc, header->addr1[5],
+				     length, rssi, channel, rate);
+		else {
+			/* src/dst addresses assume managed mode */
+			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+				     "src=0x%02x, rssi=%u, tim=%lu usec, "
+				     "phy=0x%02x, chnl=%d\n",
+				     title, fc, header->addr1[5],
+				     header->addr3[5], rssi,
+				     tsf_low - priv->scan_start_tsf,
+				     phy_flags, channel);
+		}
+	}
+	if (print_dump)
+		iwl4965_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv)
+{
+	if (priv->hw_setting.shared_virt)
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct iwl4965_shared),
+				    priv->hw_setting.shared_virt,
+				    priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl4965_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+				    u16 basic_rate, int *left)
+{
+	u16 ret_rates = 0, bit;
+	int i;
+	u8 *cnt = ie;
+	u8 *rates = ie + 1;
+
+	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+		if (bit & supported_rate) {
+			ret_rates |= bit;
+			rates[*cnt] = iwl4965_rates[i].ieee |
+				((bit & basic_rate) ? 0x80 : 0x00);
+			(*cnt)++;
+			(*left)--;
+			if ((*left <= 0) ||
+			    (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
+				break;
+		}
+	}
+
+	return ret_rates;
+}
+
+#ifdef CONFIG_IWL4965_HT
+void static iwl4965_set_ht_capab(struct ieee80211_hw *hw,
+			     struct ieee80211_ht_cap *ht_cap,
+			     u8 use_current_config);
+#endif
+
+/**
+ * iwl4965_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv,
+			      struct ieee80211_mgmt *frame,
+			      int left, int is_direct)
+{
+	int len = 0;
+	u8 *pos = NULL;
+	u16 active_rates, ret_rates, cck_rates, active_rate_basic;
+#ifdef CONFIG_IWL4965_HT
+	struct ieee80211_hw_mode *mode;
+#endif /* CONFIG_IWL4965_HT */
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+	len += 24;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN);
+	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+	memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN);
+	frame->seq_ctrl = 0;
+
+	/* fill in our indirect SSID IE */
+	/* ...next IE... */
+
+	left -= 2;
+	if (left < 0)
+		return 0;
+	len += 2;
+	pos = &(frame->u.probe_req.variable[0]);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = 0;
+
+	/* fill in our direct SSID IE... */
+	if (is_direct) {
+		/* ...next IE... */
+		left -= 2 + priv->essid_len;
+		if (left < 0)
+			return 0;
+		/* ... fill it in... */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = priv->essid_len;
+		memcpy(pos, priv->essid, priv->essid_len);
+		pos += priv->essid_len;
+		len += 2 + priv->essid_len;
+	}
+
+	/* fill in supported rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos = 0;
+
+	/* exclude 60M rate */
+	active_rates = priv->rates_mask;
+	active_rates &= ~IWL_RATE_60M_MASK;
+
+	active_rate_basic = active_rates & IWL_BASIC_RATES_MASK;
+
+	cck_rates = IWL_CCK_RATES_MASK & active_rates;
+	ret_rates = iwl4965_supported_rate_to_ie(pos, cck_rates,
+			active_rate_basic, &left);
+	active_rates &= ~ret_rates;
+
+	ret_rates = iwl4965_supported_rate_to_ie(pos, active_rates,
+				 active_rate_basic, &left);
+	active_rates &= ~ret_rates;
+
+	len += 2 + *pos;
+	pos += (*pos) + 1;
+	if (active_rates == 0)
+		goto fill_end;
+
+	/* fill in supported extended rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos = 0;
+	iwl4965_supported_rate_to_ie(pos, active_rates,
+				 active_rate_basic, &left);
+	if (*pos > 0)
+		len += 2 + *pos;
+
+#ifdef CONFIG_IWL4965_HT
+	mode = priv->hw->conf.mode;
+	if (mode->ht_info.ht_supported) {
+		pos += (*pos) + 1;
+		*pos++ = WLAN_EID_HT_CAPABILITY;
+		*pos++ = sizeof(struct ieee80211_ht_cap);
+		iwl4965_set_ht_capab(priv->hw,
+				(struct ieee80211_ht_cap *)pos, 0);
+		len += 2 + sizeof(struct ieee80211_ht_cap);
+	}
+#endif  /*CONFIG_IWL4965_HT */
+
+ fill_end:
+	return (u16)len;
+}
+
+/*
+ * QoS  support
+*/
+#ifdef CONFIG_IWL4965_QOS
+static int iwl4965_send_qos_params_command(struct iwl4965_priv *priv,
+				       struct iwl4965_qosparam_cmd *qos)
+{
+
+	return iwl4965_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl4965_qosparam_cmd), qos);
+}
+
+static void iwl4965_reset_qos(struct iwl4965_priv *priv)
+{
+	u16 cw_min = 15;
+	u16 cw_max = 1023;
+	u8 aifs = 2;
+	u8 is_legacy = 0;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.qos_active = 0;
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+		if (!(priv->active_rate & 0xfff0)) {
+			cw_min = 31;
+			is_legacy = 1;
+		}
+	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+		cw_min = 31;
+		is_legacy = 1;
+	}
+
+	if (priv->qos_data.qos_active)
+		aifs = 3;
+
+	priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+	priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+	priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+	priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+	priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+	if (priv->qos_data.qos_active) {
+		i = 1;
+		priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+		priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+		priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 2;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(6016);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3008);
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 3;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 4 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16((cw_max + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3264);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(1504);
+	} else {
+		for (i = 1; i < 4; i++) {
+			priv->qos_data.def_qos_parm.ac[i].cw_min =
+				cpu_to_le16(cw_min);
+			priv->qos_data.def_qos_parm.ac[i].cw_max =
+				cpu_to_le16(cw_max);
+			priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+			priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+			priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		}
+	}
+	IWL_DEBUG_QOS("set QoS to default \n");
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force)
+{
+	unsigned long flags;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!priv->qos_data.qos_enable)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.def_qos_parm.qos_flags = 0;
+
+	if (priv->qos_data.qos_cap.q_AP.queue_request &&
+	    !priv->qos_data.qos_cap.q_AP.txop_request)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_TXOP_TYPE_MSK;
+	if (priv->qos_data.qos_active)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+#ifdef CONFIG_IWL4965_HT
+	if (priv->current_ht_config.is_ht)
+		priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+#endif /* CONFIG_IWL4965_HT */
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (force || iwl4965_is_associated(priv)) {
+		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+				priv->qos_data.qos_active,
+				priv->qos_data.def_qos_parm.qos_flags);
+
+		iwl4965_send_qos_params_command(priv,
+				&(priv->qos_data.def_qos_parm));
+	}
+}
+
+#endif /* CONFIG_IWL4965_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+				     __constant_cpu_to_le32(X1), \
+				     __constant_cpu_to_le32(X2), \
+				     __constant_cpu_to_le32(X3), \
+				     __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim  0-10 */
+static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+		 SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+		 SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl4965_power_init_handle(struct iwl4965_priv *priv)
+{
+	int rc = 0, i;
+	struct iwl4965_power_mgr *pow_data;
+	int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
+	u16 pci_pm;
+
+	IWL_DEBUG_POWER("Initialize power \n");
+
+	pow_data = &(priv->power_data);
+
+	memset(pow_data, 0, sizeof(*pow_data));
+
+	pow_data->active_index = IWL_POWER_RANGE_0;
+	pow_data->dtim_val = 0xffff;
+
+	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+	rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+	if (rc != 0)
+		return 0;
+	else {
+		struct iwl4965_powertable_cmd *cmd;
+
+		IWL_DEBUG_POWER("adjust power command flags\n");
+
+		for (i = 0; i < IWL_POWER_AC; i++) {
+			cmd = &pow_data->pwr_range_0[i].cmd;
+
+			if (pci_pm & 0x1)
+				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+			else
+				cmd->flags |= IWL_POWER_PCI_PM_MSK;
+		}
+	}
+	return rc;
+}
+
+static int iwl4965_update_power_cmd(struct iwl4965_priv *priv,
+				struct iwl4965_powertable_cmd *cmd, u32 mode)
+{
+	int rc = 0, i;
+	u8 skip;
+	u32 max_sleep = 0;
+	struct iwl4965_power_vec_entry *range;
+	u8 period = 0;
+	struct iwl4965_power_mgr *pow_data;
+
+	if (mode > IWL_POWER_INDEX_5) {
+		IWL_DEBUG_POWER("Error invalid power mode \n");
+		return -1;
+	}
+	pow_data = &(priv->power_data);
+
+	if (pow_data->active_index == IWL_POWER_RANGE_0)
+		range = &pow_data->pwr_range_0[0];
+	else
+		range = &pow_data->pwr_range_1[1];
+
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+	if (priv->assoc_network != NULL) {
+		unsigned long flags;
+
+		period = priv->assoc_network->tim.tim_period;
+	}
+#endif	/*IWL_MAC80211_DISABLE */
+	skip = range[mode].no_dtim;
+
+	if (period == 0) {
+		period = 1;
+		skip = 0;
+	}
+
+	if (skip == 0) {
+		max_sleep = period;
+		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	} else {
+		__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+		max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	}
+
+	for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+		if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+			cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+	}
+
+	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+	IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+	IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+	IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+			le32_to_cpu(cmd->sleep_interval[0]),
+			le32_to_cpu(cmd->sleep_interval[1]),
+			le32_to_cpu(cmd->sleep_interval[2]),
+			le32_to_cpu(cmd->sleep_interval[3]),
+			le32_to_cpu(cmd->sleep_interval[4]));
+
+	return rc;
+}
+
+static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode)
+{
+	u32 uninitialized_var(final_mode);
+	int rc;
+	struct iwl4965_powertable_cmd cmd;
+
+	/* If on battery, set to 3,
+	 * if plugged into AC power, set to CAM ("continuously aware mode"),
+	 * else user level */
+	switch (mode) {
+	case IWL_POWER_BATTERY:
+		final_mode = IWL_POWER_INDEX_3;
+		break;
+	case IWL_POWER_AC:
+		final_mode = IWL_POWER_MODE_CAM;
+		break;
+	default:
+		final_mode = mode;
+		break;
+	}
+
+	cmd.keep_alive_beacons = 0;
+
+	iwl4965_update_power_cmd(priv, &cmd, final_mode);
+
+	rc = iwl4965_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+	if (final_mode == IWL_POWER_MODE_CAM)
+		clear_bit(STATUS_POWER_PMI, &priv->status);
+	else
+		set_bit(STATUS_POWER_PMI, &priv->status);
+
+	return rc;
+}
+
+int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header)
+{
+	/* Filter incoming packets to determine if they are targeted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr2, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our IBSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr3, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr3, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our BSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr2, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	}
+
+	return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static const char *iwl4965_get_tx_fail_reason(u32 status)
+{
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+		TX_STATUS_ENTRY(SHORT_LIMIT);
+		TX_STATUS_ENTRY(LONG_LIMIT);
+		TX_STATUS_ENTRY(FIFO_UNDERRUN);
+		TX_STATUS_ENTRY(MGMNT_ABORT);
+		TX_STATUS_ENTRY(NEXT_FRAG);
+		TX_STATUS_ENTRY(LIFE_EXPIRE);
+		TX_STATUS_ENTRY(DEST_PS);
+		TX_STATUS_ENTRY(ABORTED);
+		TX_STATUS_ENTRY(BT_RETRY);
+		TX_STATUS_ENTRY(STA_INVALID);
+		TX_STATUS_ENTRY(FRAG_DROPPED);
+		TX_STATUS_ENTRY(TID_DISABLE);
+		TX_STATUS_ENTRY(FRAME_FLUSHED);
+		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+		TX_STATUS_ENTRY(TX_LOCKED);
+		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * iwl4965_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl4965_scan_cancel(struct iwl4965_priv *priv)
+{
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCANNING, &priv->status);
+		return 0;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+			IWL_DEBUG_SCAN("Queuing scan abort.\n");
+			set_bit(STATUS_SCAN_ABORTING, &priv->status);
+			queue_work(priv->workqueue, &priv->abort_scan);
+
+		} else
+			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return 0;
+}
+
+/**
+ * iwl4965_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl4965_scan_cancel_timeout(struct iwl4965_priv *priv, unsigned long ms)
+{
+	unsigned long now = jiffies;
+	int ret;
+
+	ret = iwl4965_scan_cancel(priv);
+	if (ret && ms) {
+		mutex_unlock(&priv->mutex);
+		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+				test_bit(STATUS_SCANNING, &priv->status))
+			msleep(1);
+		mutex_lock(&priv->mutex);
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return ret;
+}
+
+static void iwl4965_sequence_reset(struct iwl4965_priv *priv)
+{
+	/* Reset ieee stats */
+
+	/* We don't reset the net_device_stats (ieee->stats) on
+	 * re-association */
+
+	priv->last_seq_num = -1;
+	priv->last_frag_num = -1;
+	priv->last_packet_time = 0;
+
+	iwl4965_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL	4096
+#define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
+
+static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
+{
+	u16 new_val = 0;
+	u16 beacon_factor = 0;
+
+	beacon_factor =
+	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+		/ MAX_UCODE_BEACON_INTERVAL;
+	new_val = beacon_val / beacon_factor;
+
+	return cpu_to_le16(new_val);
+}
+
+static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv)
+{
+	u64 interval_tm_unit;
+	u64 tsf, result;
+	unsigned long flags;
+	struct ieee80211_conf *conf = NULL;
+	u16 beacon_int = 0;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+	priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+	tsf = priv->timestamp1;
+	tsf = ((tsf << 32) | priv->timestamp0);
+
+	beacon_int = priv->beacon_int;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+		if (beacon_int == 0) {
+			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+		} else {
+			priv->rxon_timing.beacon_interval =
+				cpu_to_le16(beacon_int);
+			priv->rxon_timing.beacon_interval =
+			    iwl4965_adjust_beacon_interval(
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+		}
+
+		priv->rxon_timing.atim_window = 0;
+	} else {
+		priv->rxon_timing.beacon_interval =
+			iwl4965_adjust_beacon_interval(conf->beacon_int);
+		/* TODO: we need to get atim_window from upper stack
+		 * for now we set to 0 */
+		priv->rxon_timing.atim_window = 0;
+	}
+
+	interval_tm_unit =
+		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+	result = do_div(tsf, interval_tm_unit);
+	priv->rxon_timing.beacon_init_val =
+	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+	IWL_DEBUG_ASSOC
+	    ("beacon interval %d beacon timer %d beacon tim %d\n",
+		le16_to_cpu(priv->rxon_timing.beacon_interval),
+		le32_to_cpu(priv->rxon_timing.beacon_init_val),
+		le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl4965_scan_initiate(struct iwl4965_priv *priv)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("APs don't scan.\n");
+		return 0;
+	}
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan already in progress.\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan request while abort pending.  "
+			       "Queuing.\n");
+		return -EAGAIN;
+	}
+
+	IWL_DEBUG_INFO("Starting scan...\n");
+	priv->scan_bands = 2;
+	set_bit(STATUS_SCANNING, &priv->status);
+	priv->scan_start = jiffies;
+	priv->scan_pass_start = priv->scan_start;
+
+	queue_work(priv->workqueue, &priv->request_scan);
+
+	return 0;
+}
+
+static int iwl4965_set_rxon_hwcrypto(struct iwl4965_priv *priv, int hw_decrypt)
+{
+	struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
+
+	if (hw_decrypt)
+		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+	else
+		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+	return 0;
+}
+
+static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode)
+{
+	if (phymode == MODE_IEEE80211A) {
+		priv->staging_rxon.flags &=
+		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+		      | RXON_FLG_CCK_MSK);
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	} else {
+		/* Copied from iwl4965_bg_post_associate() */
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+	}
+}
+
+/*
+ * initialize rxon structure with default values from eeprom
+ */
+static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv)
+{
+	const struct iwl4965_channel_info *ch_info;
+
+	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_AP:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+		break;
+
+	case IEEE80211_IF_TYPE_STA:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+						  RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+	}
+
+#if 0
+	/* TODO:  Figure out when short_preamble would be set and cache from
+	 * that */
+	if (!hw_to_local(priv->hw)->short_preamble)
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+	ch_info = iwl4965_get_channel_info(priv, priv->phymode,
+				       le16_to_cpu(priv->staging_rxon.channel));
+
+	if (!ch_info)
+		ch_info = &priv->channel_info[0];
+
+	/*
+	 * in some case A channels are all non IBSS
+	 * in this case force B/G channel
+	 */
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !(is_channel_ibss(ch_info)))
+		ch_info = &priv->channel_info[0];
+
+	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+	if (is_channel_a_band(ch_info))
+		priv->phymode = MODE_IEEE80211A;
+	else
+		priv->phymode = MODE_IEEE80211G;
+
+	iwl4965_set_flags_for_phymode(priv, priv->phymode);
+
+	priv->staging_rxon.ofdm_basic_rates =
+	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+	priv->staging_rxon.cck_basic_rates =
+	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+					RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
+	priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+	iwl4965_set_rxon_chain(priv);
+}
+
+static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
+{
+	if (mode == IEEE80211_IF_TYPE_IBSS) {
+		const struct iwl4965_channel_info *ch_info;
+
+		ch_info = iwl4965_get_channel_info(priv,
+			priv->phymode,
+			le16_to_cpu(priv->staging_rxon.channel));
+
+		if (!ch_info || !is_channel_ibss(ch_info)) {
+			IWL_ERROR("channel %d not IBSS channel\n",
+				  le16_to_cpu(priv->staging_rxon.channel));
+			return -EINVAL;
+		}
+	}
+
+	priv->iw_mode = mode;
+
+	iwl4965_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl4965_clear_stations_table(priv);
+
+	/* dont commit rxon if rf-kill is on*/
+	if (!iwl4965_is_ready_rf(priv))
+		return -EAGAIN;
+
+	cancel_delayed_work(&priv->scan_check);
+	if (iwl4965_scan_cancel_timeout(priv, 100)) {
+		IWL_WARNING("Aborted scan still in progress after 100ms\n");
+		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+		return -EAGAIN;
+	}
+
+	iwl4965_commit_rxon(priv);
+
+	return 0;
+}
+
+static void iwl4965_build_tx_cmd_hwcrypto(struct iwl4965_priv *priv,
+				      struct ieee80211_tx_control *ctl,
+				      struct iwl4965_cmd *cmd,
+				      struct sk_buff *skb_frag,
+				      int last_frag)
+{
+	struct iwl4965_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+	switch (keyinfo->alg) {
+	case ALG_CCMP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		break;
+
+	case ALG_TKIP:
+#if 0
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+		if (last_frag)
+			memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+			       8);
+		else
+			memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+		break;
+
+	case ALG_WEP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+			(ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+		if (keyinfo->keylen == 13)
+			cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+		IWL_DEBUG_TX("Configuring packet for WEP encryption "
+			     "with key %d\n", ctl->key_idx);
+		break;
+
+	default:
+		printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+		break;
+	}
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv,
+				  struct iwl4965_cmd *cmd,
+				  struct ieee80211_tx_control *ctrl,
+				  struct ieee80211_hdr *hdr,
+				  int is_unicast, u8 std_id)
+{
+	__le16 *qc;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	__le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+	cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+	if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		tx_flags |= TX_CMD_FLG_ACK_MSK;
+		if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		if (ieee80211_is_probe_response(fc) &&
+		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+			tx_flags |= TX_CMD_FLG_TSF_MSK;
+	} else {
+		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+	}
+
+	cmd->cmd.tx.sta_id = std_id;
+	if (ieee80211_get_morefrag(hdr))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	} else
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+	if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		tx_flags |= TX_CMD_FLG_RTS_MSK;
+		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+	} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+		tx_flags |= TX_CMD_FLG_CTS_MSK;
+	}
+
+	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
+		else
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
+	} else
+		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+	cmd->cmd.tx.driver_txop = 0;
+	cmd->cmd.tx.tx_flags = tx_flags;
+	cmd->cmd.tx.next_frame_len = 0;
+}
+
+/**
+ * iwl4965_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+static int iwl4965_get_sta_id(struct iwl4965_priv *priv,
+				struct ieee80211_hdr *hdr)
+{
+	int sta_id;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	DECLARE_MAC_BUF(mac);
+
+	/* 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;
+
+	switch (priv->iw_mode) {
+
+	/* If we are a client station in a BSS network, use the special
+	 * AP station entry (that's the only station we communicate with) */
+	case IEEE80211_IF_TYPE_STA:
+		return IWL_AP_ID;
+
+	/* If we are an AP, then find the station, or use BCAST */
+	case IEEE80211_IF_TYPE_AP:
+		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;
+
+	/* If this frame is going out to an IBSS network, find the station,
+	 * or create a new station table entry */
+	case IEEE80211_IF_TYPE_IBSS:
+		sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		/* Create new station table entry */
+		sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+						   0, CMD_ASYNC, NULL);
+
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		IWL_DEBUG_DROP("Station %s not in station map. "
+			       "Defaulting to broadcast...\n",
+			       print_mac(mac, hdr->addr1));
+		iwl4965_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		return priv->hw_setting.bcast_sta_id;
+
+	default:
+		IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+		return priv->hw_setting.bcast_sta_id;
+	}
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl4965_tx_skb(struct iwl4965_priv *priv,
+		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl4965_tfd_frame *tfd;
+	u32 *control_flags;
+	int txq_id = ctl->queue;
+	struct iwl4965_tx_queue *txq = NULL;
+	struct iwl4965_queue *q = NULL;
+	dma_addr_t phys_addr;
+	dma_addr_t txcmd_phys;
+	struct iwl4965_cmd *out_cmd = NULL;
+	u16 len, idx, len_org;
+	u8 id, hdr_len, unicast;
+	u8 sta_id;
+	u16 seq_number = 0;
+	u16 fc;
+	__le16 *qc;
+	u8 wait_write_ptr = 0;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (iwl4965_is_rfkill(priv)) {
+		IWL_DEBUG_DROP("Dropping - RF KILL\n");
+		goto drop_unlock;
+	}
+
+	if (!priv->interface_id) {
+		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+		goto drop_unlock;
+	}
+
+	if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+		IWL_ERROR("ERROR: No TX rate available.\n");
+		goto drop_unlock;
+	}
+
+	unicast = !is_multicast_ether_addr(hdr->addr1);
+	id = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (ieee80211_is_auth(fc))
+		IWL_DEBUG_TX("Sending AUTH frame\n");
+	else if (ieee80211_is_assoc_request(fc))
+		IWL_DEBUG_TX("Sending ASSOC frame\n");
+	else if (ieee80211_is_reassoc_request(fc))
+		IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+	/* drop all data frame if we are not associated */
+	if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
+	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+		IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
+		goto drop_unlock;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	hdr_len = ieee80211_get_hdrlen(fc);
+
+	/* Find (or create) index into station table for destination station */
+	sta_id = iwl4965_get_sta_id(priv, hdr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+			       print_mac(mac, hdr->addr1));
+		goto drop;
+	}
+
+	IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+		seq_number = priv->stations[sta_id].tid[tid].seq_number &
+				IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl = cpu_to_le16(seq_number) |
+			(hdr->seq_ctrl &
+				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+		seq_number += 0x10;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+		/* aggregation is on for this <sta,tid> */
+		if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
+			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+	}
+
+	/* Descriptor for chosen Tx queue */
+	txq = &priv->txq[txq_id];
+	q = &txq->q;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Set up first empty TFD within this queue's circular TFD buffer */
+	tfd = &txq->bd[q->write_ptr];
+	memset(tfd, 0, sizeof(*tfd));
+	control_flags = (u32 *) tfd;
+	idx = get_cmd_index(q, q->write_ptr, 0);
+
+	/* Set up driver data for this TFD */
+	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info));
+	txq->txb[q->write_ptr].skb[0] = skb;
+	memcpy(&(txq->txb[q->write_ptr].status.control),
+	       ctl, sizeof(struct ieee80211_tx_control));
+
+	/* Set up first empty entry in queue's array of Tx/cmd buffers */
+	out_cmd = &txq->cmd[idx];
+	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+
+	/*
+	 * Set up the Tx-command (not MAC!) header.
+	 * Store the chosen Tx queue and TFD index within the sequence field;
+	 * after Tx, uCode's Tx response will return this value so driver can
+	 * locate the frame within the tx queue and do post-tx processing.
+	 */
+	out_cmd->hdr.cmd = REPLY_TX;
+	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+				INDEX_TO_SEQ(q->write_ptr)));
+
+	/* Copy MAC header from skb into command buffer */
+	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+	/*
+	 * Use the first empty entry in this queue's command buffer array
+	 * to contain the Tx command and MAC header concatenated together
+	 * (payload data will be in another buffer).
+	 * Size of this varies, due to varying MAC header length.
+	 * If end is not dword aligned, we'll have 2 extra bytes at the end
+	 * of the MAC header (device reads on dword boundaries).
+	 * We'll tell device about this padding later.
+	 */
+	len = priv->hw_setting.tx_cmd_len +
+		sizeof(struct iwl4965_cmd_header) + hdr_len;
+
+	len_org = len;
+	len = (len + 3) & ~3;
+
+	if (len_org != len)
+		len_org = 1;
+	else
+		len_org = 0;
+
+	/* Physical address of this Tx command's header (not MAC header!),
+	 * within command buffer array. */
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx +
+		     offsetof(struct iwl4965_cmd, hdr);
+
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+		iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+	/* Set up TFD's 2nd entry to point directly to remainder of skb,
+	 * if any (802.11 null frames have no payload). */
+	len = skb->len - hdr_len;
+	if (len) {
+		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+					   len, PCI_DMA_TODEVICE);
+		iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+	}
+
+	/* Tell 4965 about any 2-byte padding after MAC header */
+	if (len_org)
+		out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+	/* Total # bytes to be transmitted */
+	len = (u16)skb->len;
+	out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+	/* TODO need this for burst mode later on */
+	iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+	/* set is_hcca to 0; it probably will never be implemented */
+	iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+	iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
+		       hdr, hdr_len, ctl, NULL);
+
+	if (!ieee80211_get_morefrag(hdr)) {
+		txq->need_update = 1;
+		if (qc) {
+			u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+			priv->stations[sta_id].tid[tid].seq_number = seq_number;
+		}
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
+	}
+
+	iwl4965_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+			   sizeof(out_cmd->cmd.tx));
+
+	iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+			   ieee80211_get_hdrlen(fc));
+
+	/* Set up entry for this TFD in Tx byte-count array */
+	iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+
+	/* Tell device the write index *just past* this latest filled TFD */
+	q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+	rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (rc)
+		return rc;
+
+	if ((iwl4965_queue_space(q) < q->high_mark)
+	    && priv->mac80211_registered) {
+		if (wait_write_ptr) {
+			spin_lock_irqsave(&priv->lock, flags);
+			txq->need_update = 1;
+			iwl4965_tx_queue_update_write_ptr(priv, txq);
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+
+		ieee80211_stop_queue(priv->hw, ctl->queue);
+	}
+
+	return 0;
+
+drop_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+	return -1;
+}
+
+static void iwl4965_set_rate(struct iwl4965_priv *priv)
+{
+	const struct ieee80211_hw_mode *hw = NULL;
+	struct ieee80211_rate *rate;
+	int i;
+
+	hw = iwl4965_get_hw_mode(priv, priv->phymode);
+	if (!hw) {
+		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
+		return;
+	}
+
+	priv->active_rate = 0;
+	priv->active_rate_basic = 0;
+
+	IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+		       hw->mode == MODE_IEEE80211A ?
+		       'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+	for (i = 0; i < hw->num_rates; i++) {
+		rate = &(hw->rates[i]);
+		if ((rate->val < IWL_RATE_COUNT) &&
+		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+				       rate->val, iwl4965_rates[rate->val].plcp,
+				       (rate->flags & IEEE80211_RATE_BASIC) ?
+				       "*" : "");
+			priv->active_rate |= (1 << rate->val);
+			if (rate->flags & IEEE80211_RATE_BASIC)
+				priv->active_rate_basic |= (1 << rate->val);
+		} else
+			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+				       rate->val, iwl4965_rates[rate->val].plcp);
+	}
+
+	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+		       priv->active_rate, priv->active_rate_basic);
+
+	/*
+	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+	 * OFDM
+	 */
+	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+		priv->staging_rxon.cck_basic_rates =
+		    ((priv->active_rate_basic &
+		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+	else
+		priv->staging_rxon.cck_basic_rates =
+		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+		priv->staging_rxon.ofdm_basic_rates =
+		    ((priv->active_rate_basic &
+		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+		      IWL_FIRST_OFDM_RATE) & 0xFF;
+	else
+		priv->staging_rxon.ofdm_basic_rates =
+		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio)
+{
+	unsigned long flags;
+
+	if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+		return;
+
+	IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+			  disable_radio ? "OFF" : "ON");
+
+	if (disable_radio) {
+		iwl4965_scan_cancel(priv);
+		/* 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,
+				    CSR_UCODE_SW_BIT_RFKILL);
+			spin_unlock_irqrestore(&priv->lock, flags);
+			iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			set_bit(STATUS_RF_KILL_SW, &priv->status);
+		}
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl4965_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);
+
+	/* wake up ucode */
+	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);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+				  "disabled by HW switch\n");
+		return;
+	}
+
+	queue_work(priv->workqueue, &priv->restart);
+	return;
+}
+
+void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
+			    u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+	u16 fc =
+	    le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+	if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+		return;
+
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return;
+
+	IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_ICV_MIC)
+			stats->flag |= RX_FLAG_MMIC_ERROR;
+	case RX_RES_STATUS_SEC_TYPE_WEP:
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_DECRYPT_OK) {
+			IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+			stats->flag |= RX_FLAG_DECRYPTED;
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb,
+				    void *data, short len,
+				    struct ieee80211_rx_status *stats,
+				    u16 phy_flags)
+{
+	struct iwl4965_rt_rx_hdr *iwl4965_rt;
+
+	/* First cache any information we need before we overwrite
+	 * the information provided in the skb from the hardware */
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+	/* We received data from the HW, so stop the watchdog */
+	if (len > priv->hw_setting.rx_buf_size - sizeof(*iwl4965_rt)) {
+		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+		return;
+	}
+
+	/* copy the frame data to write after where the radiotap header goes */
+	iwl4965_rt = (void *)rxb->skb->data;
+	memmove(iwl4965_rt->payload, data, len);
+
+	iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl4965_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+	/* total header + data */
+	iwl4965_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl4965_rt));
+
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, sizeof(*iwl4965_rt) + len);
+
+	/* Big bitfield of all the fields we provide in radiotap */
+	iwl4965_rt->rt_hdr.it_present =
+	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+			(1 << IEEE80211_RADIOTAP_FLAGS) |
+			(1 << IEEE80211_RADIOTAP_RATE) |
+			(1 << IEEE80211_RADIOTAP_CHANNEL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+			(1 << IEEE80211_RADIOTAP_ANTENNA));
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl4965_rt->rt_flags = 0;
+
+	iwl4965_rt->rt_tsf = cpu_to_le64(tsf);
+
+	/* Convert to dBm */
+	iwl4965_rt->rt_dbmsignal = signal;
+	iwl4965_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	iwl4965_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		iwl4965_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		iwl4965_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+	else	/* 802.11g */
+		iwl4965_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+	rate = iwl4965_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl4965_rt->rt_rate = 0;
+	else
+		iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+
+	/* antenna number */
+	iwl4965_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if we have it */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header)
+{
+	u16 sc = le16_to_cpu(header->seq_ctrl);
+	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	u16 frag = sc & IEEE80211_SCTL_FRAG;
+	u16 *last_seq, *last_frag;
+	unsigned long *last_time;
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS:{
+		struct list_head *p;
+		struct iwl4965_ibss_seq *entry = NULL;
+		u8 *mac = header->addr2;
+		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+		__list_for_each(p, &priv->ibss_mac_hash[index]) {
+			entry = list_entry(p, struct iwl4965_ibss_seq, list);
+			if (!compare_ether_addr(entry->mac, mac))
+				break;
+		}
+		if (p == &priv->ibss_mac_hash[index]) {
+			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+			if (!entry) {
+				IWL_ERROR("Cannot malloc new mac entry\n");
+				return 0;
+			}
+			memcpy(entry->mac, mac, ETH_ALEN);
+			entry->seq_num = seq;
+			entry->frag_num = frag;
+			entry->packet_time = jiffies;
+			list_add(&entry->list, &priv->ibss_mac_hash[index]);
+			return 0;
+		}
+		last_seq = &entry->seq_num;
+		last_frag = &entry->frag_num;
+		last_time = &entry->packet_time;
+		break;
+	}
+	case IEEE80211_IF_TYPE_STA:
+		last_seq = &priv->last_seq_num;
+		last_frag = &priv->last_frag_num;
+		last_time = &priv->last_packet_time;
+		break;
+	default:
+		return 0;
+	}
+	if ((*last_seq == seq) &&
+	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+		if (*last_frag == frag)
+			goto drop;
+		if (*last_frag + 1 != frag)
+			/* out-of-order fragment */
+			goto drop;
+	} else
+		*last_seq = seq;
+
+	*last_frag = frag;
+	*last_time = jiffies;
+	return 0;
+
+ drop:
+	return 1;
+}
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW	0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH	0xFF000000
+#define TIME_UNIT		1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * 1024;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+	return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & BEACON_TIME_MASK_LOW;
+	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & BEACON_TIME_MASK_HIGH) +
+	    (addon & BEACON_TIME_MASK_HIGH);
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << 24);
+	} else
+		res += (1 << 24);
+
+	return cpu_to_le32(res);
+}
+
+static int iwl4965_get_measurement(struct iwl4965_priv *priv,
+			       struct ieee80211_measurement_params *params,
+			       u8 type)
+{
+	struct iwl4965_spectrum_cmd spectrum;
+	struct iwl4965_rx_packet *res;
+	struct iwl4965_host_cmd cmd = {
+		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+		.data = (void *)&spectrum,
+		.meta.flags = CMD_WANT_SKB,
+	};
+	u32 add_time = le64_to_cpu(params->start_time);
+	int rc;
+	int spectrum_resp_status;
+	int duration = le16_to_cpu(params->duration);
+
+	if (iwl4965_is_associated(priv))
+		add_time =
+		    iwl4965_usecs_to_beacons(
+			le64_to_cpu(params->start_time) - priv->last_tsf,
+			le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+	memset(&spectrum, 0, sizeof(spectrum));
+
+	spectrum.channel_count = cpu_to_le16(1);
+	spectrum.flags =
+	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+	cmd.len = sizeof(spectrum);
+	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+	if (iwl4965_is_associated(priv))
+		spectrum.start_time =
+		    iwl4965_add_beacon_time(priv->last_beacon_time,
+				add_time,
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+	else
+		spectrum.start_time = 0;
+
+	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+	spectrum.channels[0].channel = params->channel;
+	spectrum.channels[0].type = type;
+	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+	rc = iwl4965_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_RX_ON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+	switch (spectrum_resp_status) {
+	case 0:		/* Command will be handled */
+		if (res->u.spectrum.id != 0xff) {
+			IWL_DEBUG_INFO
+			    ("Replaced existing measurement: %d\n",
+			     res->u.spectrum.id);
+			priv->measurement_status &= ~MEASUREMENT_READY;
+		}
+		priv->measurement_status |= MEASUREMENT_ACTIVE;
+		rc = 0;
+		break;
+
+	case 1:		/* Command will not be handled */
+		rc = -EAGAIN;
+		break;
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+#endif
+
+static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv,
+				 struct iwl4965_tx_info *tx_sta)
+{
+
+	tx_sta->status.ack_signal = 0;
+	tx_sta->status.excessive_retries = 0;
+	tx_sta->status.queue_length = 0;
+	tx_sta->status.queue_number = 0;
+
+	if (in_interrupt())
+		ieee80211_tx_status_irqsafe(priv->hw,
+					    tx_sta->skb[0], &(tx_sta->status));
+	else
+		ieee80211_tx_status(priv->hw,
+				    tx_sta->skb[0], &(tx_sta->status));
+
+	tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index)
+{
+	struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl4965_queue *q = &txq->q;
+	int nfreed = 0;
+
+	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+			  "is out of range [0-%d] %d %d.\n", txq_id,
+			  index, q->n_bd, q->write_ptr, q->read_ptr);
+		return 0;
+	}
+
+	for (index = iwl4965_queue_inc_wrap(index, q->n_bd);
+		q->read_ptr != index;
+		q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+		if (txq_id != IWL_CMD_QUEUE_NUM) {
+			iwl4965_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.read_ptr]));
+			iwl4965_hw_txq_free_tfd(priv, txq);
+		} else if (nfreed > 1) {
+			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+					q->write_ptr, q->read_ptr);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+		nfreed++;
+	}
+
+	if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+			(txq_id != IWL_CMD_QUEUE_NUM) &&
+			priv->mac80211_registered)
+		ieee80211_wake_queue(priv->hw, txq_id);
+
+
+	return nfreed;
+}
+
+static int iwl4965_is_tx_success(u32 status)
+{
+	status &= TX_STATUS_MSK;
+	return (status == TX_STATUS_SUCCESS)
+	    || (status == TX_STATUS_DIRECT_DONE);
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+
+static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv,
+				    struct ieee80211_hdr *hdr)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+		return IWL_AP_ID;
+	else {
+		u8 *da = ieee80211_get_DA(hdr);
+		return iwl4965_hw_find_station(priv, da);
+	}
+}
+
+static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr(
+	struct iwl4965_priv *priv, int txq_id, int idx)
+{
+	if (priv->txq[txq_id].txb[idx].skb[0])
+		return (struct ieee80211_hdr *)priv->txq[txq_id].
+				txb[idx].skb[0]->data;
+	return NULL;
+}
+
+static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
+{
+	__le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+				tx_resp->frame_count);
+	return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
+static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
+				      struct iwl4965_ht_agg *agg,
+				      struct iwl4965_tx_resp *tx_resp,
+				      u16 start_idx)
+{
+	u32 status;
+	__le32 *frame_status = &tx_resp->status;
+	struct ieee80211_tx_status *tx_status = NULL;
+	struct ieee80211_hdr *hdr = NULL;
+	int i, sh;
+	int txq_id, idx;
+	u16 seq;
+
+	if (agg->wait_for_ba)
+		IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
+
+	agg->frame_count = tx_resp->frame_count;
+	agg->start_idx = start_idx;
+	agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+	agg->bitmap0 = agg->bitmap1 = 0;
+
+	/* # frames attempted by Tx command */
+	if (agg->frame_count == 1) {
+		/* Only one frame was attempted; no block-ack will arrive */
+		struct iwl4965_tx_queue *txq ;
+		status = le32_to_cpu(frame_status[0]);
+
+		txq_id = agg->txq_id;
+		txq = &priv->txq[txq_id];
+		/* FIXME: code repetition */
+		IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
+				   agg->frame_count, agg->start_idx);
+
+		tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status);
+		tx_status->retry_count = tx_resp->failure_frame;
+		tx_status->queue_number = status & 0xff;
+		tx_status->queue_length = tx_resp->bt_kill_count;
+		tx_status->queue_length |= tx_resp->failure_rts;
+
+		tx_status->flags = iwl4965_is_tx_success(status)?
+			IEEE80211_TX_STATUS_ACK : 0;
+		tx_status->control.tx_rate =
+				iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+		/* FIXME: code repetition end */
+
+		IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+				    status & 0xff, tx_resp->failure_frame);
+		IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+				iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+		agg->wait_for_ba = 0;
+	} else {
+		/* Two or more frames were attempted; expect block-ack */
+		u64 bitmap = 0;
+		int start = agg->start_idx;
+
+		/* Construct bit-map of pending frames within Tx window */
+		for (i = 0; i < agg->frame_count; i++) {
+			u16 sc;
+			status = le32_to_cpu(frame_status[i]);
+			seq  = status >> 16;
+			idx = SEQ_TO_INDEX(seq);
+			txq_id = SEQ_TO_QUEUE(seq);
+
+			if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+				      AGG_TX_STATE_ABORT_MSK))
+				continue;
+
+			IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+					   agg->frame_count, txq_id, idx);
+
+			hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx);
+
+			sc = le16_to_cpu(hdr->seq_ctrl);
+			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+				IWL_ERROR("BUG_ON idx doesn't match seq control"
+					  " idx=%d, seq_idx=%d, seq=%d\n",
+					  idx, SEQ_TO_SN(sc),
+					  hdr->seq_ctrl);
+				return -1;
+			}
+
+			IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+					   i, idx, SEQ_TO_SN(sc));
+
+			sh = idx - start;
+			if (sh > 64) {
+				sh = (start - idx) + 0xff;
+				bitmap = bitmap << sh;
+				sh = 0;
+				start = idx;
+			} else if (sh < -64)
+				sh  = 0xff - (start - idx);
+			else if (sh < 0) {
+				sh = start - idx;
+				start = idx;
+				bitmap = bitmap << sh;
+				sh = 0;
+			}
+			bitmap |= (1 << sh);
+			IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+					   start, (u32)(bitmap & 0xFFFFFFFF));
+		}
+
+		agg->bitmap0 = bitmap & 0xFFFFFFFF;
+		agg->bitmap1 = bitmap >> 32;
+		agg->start_idx = start;
+		agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+		IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
+				   agg->frame_count, agg->start_idx,
+				   agg->bitmap0);
+
+		if (bitmap)
+			agg->wait_for_ba = 1;
+	}
+	return 0;
+}
+#endif
+#endif
+
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
+static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
+			    struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
+	struct ieee80211_tx_status *tx_status;
+	struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	u32  status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	int tid, sta_id;
+#endif
+#endif
+
+	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+			  "is out of range [0-%d] %d %d\n", txq_id,
+			  index, txq->q.n_bd, txq->q.write_ptr,
+			  txq->q.read_ptr);
+		return;
+	}
+
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	if (txq->sched_retry) {
+		const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
+		struct ieee80211_hdr *hdr =
+			iwl4965_tx_queue_get_hdr(priv, txq_id, index);
+		struct iwl4965_ht_agg *agg = NULL;
+		__le16 *qc = ieee80211_get_qos_ctrl(hdr);
+
+		if (qc == NULL) {
+			IWL_ERROR("BUG_ON qc is null!!!!\n");
+			return;
+		}
+
+		tid = le16_to_cpu(*qc) & 0xf;
+
+		sta_id = iwl4965_get_ra_sta_id(priv, hdr);
+		if (unlikely(sta_id == IWL_INVALID_STATION)) {
+			IWL_ERROR("Station not known for\n");
+			return;
+		}
+
+		agg = &priv->stations[sta_id].tid[tid].agg;
+
+		iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+		if ((tx_resp->frame_count == 1) &&
+		    !iwl4965_is_tx_success(status)) {
+			/* TODO: send BAR */
+		}
+
+		if ((txq->q.read_ptr != (scd_ssn & 0xff))) {
+			index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+					   "%d index %d\n", scd_ssn , index);
+			iwl4965_tx_queue_reclaim(priv, txq_id, index);
+		}
+	} else {
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+	tx_status = &(txq->txb[txq->q.read_ptr].status);
+
+	tx_status->retry_count = tx_resp->failure_frame;
+	tx_status->queue_number = status;
+	tx_status->queue_length = tx_resp->bt_kill_count;
+	tx_status->queue_length |= tx_resp->failure_rts;
+
+	tx_status->flags =
+	    iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+	tx_status->control.tx_rate =
+		iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+
+	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+		     "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status),
+		     status, le32_to_cpu(tx_resp->rate_n_flags),
+		     tx_resp->failure_frame);
+
+	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+	if (index != -1)
+		iwl4965_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	}
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl4965_rx_reply_alive(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_alive_resp *palive;
+	struct work_struct *pwork;
+
+	palive = &pkt->u.alive_frame;
+
+	IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+		IWL_DEBUG_INFO("Initialization Alive received.\n");
+		memcpy(&priv->card_alive_init,
+		       &pkt->u.alive_frame,
+		       sizeof(struct iwl4965_init_alive_resp));
+		pwork = &priv->init_alive_start;
+	} else {
+		IWL_DEBUG_INFO("Runtime Alive received.\n");
+		memcpy(&priv->card_alive, &pkt->u.alive_frame,
+		       sizeof(struct iwl4965_alive_resp));
+		pwork = &priv->alive_start;
+	}
+
+	/* We delay the ALIVE response by 5ms to
+	 * give the HW RF Kill time to activate... */
+	if (palive->is_valid == UCODE_VALID_OK)
+		queue_delayed_work(priv->workqueue, pwork,
+				   msecs_to_jiffies(5));
+	else
+		IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl4965_rx_reply_add_sta(struct iwl4965_priv *priv,
+				 struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+	return;
+}
+
+static void iwl4965_rx_reply_error(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+		"seq 0x%04X ser 0x%08X\n",
+		le32_to_cpu(pkt->u.err_resp.error_type),
+		get_cmd_string(pkt->u.err_resp.cmd_id),
+		pkt->u.err_resp.cmd_id,
+		le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+		le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl4965_rx_csa(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
+	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+	rxon->channel = csa->channel;
+	priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl4965_rx_spectrum_measure_notif(struct iwl4965_priv *priv,
+					  struct iwl4965_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+	if (!report->state) {
+		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+			  "Spectrum Measure Notification: Start\n");
+		return;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl4965_rx_pm_sleep_notif(struct iwl4965_priv *priv,
+				  struct iwl4965_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
+	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl4965_rx_pm_debug_statistics_notif(struct iwl4965_priv *priv,
+					     struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+			"notification for %s:\n",
+			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+	iwl4965_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl4965_bg_beacon_update(void *p)
+{
+	struct iwl4965_priv *priv = p;
+	struct sk_buff *beacon;
+
+	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+	if (!beacon) {
+		IWL_ERROR("update beacon failed\n");
+		return;
+	}
+
+	mutex_lock(&priv->mutex);
+	/* new beacon skb is allocated every time; dispose previous.*/
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = beacon;
+	mutex_unlock(&priv->mutex);
+
+	iwl4965_send_beacon_cmd(priv);
+}
+
+static void iwl4965_rx_beacon_notif(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
+	u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+		"tsf %d %d rate %d\n",
+		le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+		beacon->beacon_notify_hdr.failure_frame,
+		le32_to_cpu(beacon->ibss_mgr_status),
+		le32_to_cpu(beacon->high_tsf),
+		le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+		queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl4965_rx_reply_scan(struct iwl4965_priv *priv,
+			      struct iwl4965_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanreq_notification *notif =
+	    (struct iwl4965_scanreq_notification *)pkt->u.raw;
+
+	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl4965_rx_scan_start_notif(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanstart_notification *notif =
+	    (struct iwl4965_scanstart_notification *)pkt->u.raw;
+	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+	IWL_DEBUG_SCAN("Scan start: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       notif->tsf_high,
+		       notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv,
+				      struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanresults_notification *notif =
+	    (struct iwl4965_scanresults_notification *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan ch.res: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d "
+		       "elapsed=%lu usec (%dms since last)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       le32_to_cpu(notif->statistics[0]),
+		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->last_scan_jiffies, jiffies)));
+
+	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl4965_rx_scan_complete_notif(struct iwl4965_priv *priv,
+				       struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+		       scan_notif->scanned_channels,
+		       scan_notif->tsf_low,
+		       scan_notif->tsf_high, scan_notif->status);
+
+	/* The HW is no longer scanning */
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+
+	/* The scan completion notification came in, so kill that timer... */
+	cancel_delayed_work(&priv->scan_check);
+
+	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+		       (priv->scan_bands == 2) ? "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--;
+
+	/* If a request to abort was given, or the scan did not succeed
+	 * then we reset the scan state machine and terminate,
+	 * re-queuing another scan if one has been requested */
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_INFO("Aborted scan completed.\n");
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	} else {
+		/* If there are more bands on this scan pass reschedule */
+		if (priv->scan_bands > 0)
+			goto reschedule;
+	}
+
+	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
+	IWL_DEBUG_INFO("Setting scan to off\n");
+
+	clear_bit(STATUS_SCANNING, &priv->status);
+
+	IWL_DEBUG_INFO("Scan took %dms\n",
+		jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+	queue_work(priv->workqueue, &priv->scan_completed);
+
+	return;
+
+reschedule:
+	priv->scan_pass_start = jiffies;
+	queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+	unsigned long status = priv->status;
+
+	IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+		     RF_CARD_DISABLED)) {
+
+		iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
+			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+		if (!iwl4965_grab_nic_access(priv)) {
+			iwl4965_write_direct32(
+				priv, HBUS_TARG_MBX_C,
+				HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+			iwl4965_release_nic_access(priv);
+		}
+
+		if (!(flags & RXON_CARD_DISABLED)) {
+			iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+			if (!iwl4965_grab_nic_access(priv)) {
+				iwl4965_write_direct32(
+					priv, HBUS_TARG_MBX_C,
+					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+				iwl4965_release_nic_access(priv);
+			}
+		}
+
+		if (flags & RF_CARD_DISABLED) {
+			iwl4965_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);
+		}
+	}
+
+	if (flags & HW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+	if (flags & SW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+	if (!(flags & RXON_CARD_DISABLED))
+		iwl4965_scan_cancel(priv);
+
+	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+	    (test_bit(STATUS_RF_KILL_SW, &status) !=
+	     test_bit(STATUS_RF_KILL_SW, &priv->status)))
+		queue_work(priv->workqueue, &priv->rf_kill);
+	else
+		wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv)
+{
+	priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
+	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+	    iwl4965_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif;
+	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+	    iwl4965_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
+
+	/*
+	 * The same handler is used for both the REPLY to a discrete
+	 * statistics request from the host as well as for the periodic
+	 * statistics notifications (after received beacons) from the uCode.
+	 */
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
+
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif;
+	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+	    iwl4965_rx_scan_results_notif;
+	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+	    iwl4965_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
+
+	/* Set up hardware specific Rx handlers */
+	iwl4965_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
+{
+	struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	int huge = sequence & SEQ_HUGE_FRAME;
+	int cmd_index;
+	struct iwl4965_cmd *cmd;
+
+	/* If a Tx command is being handled and it isn't in the actual
+	 * command queue then there a command routing bug has been introduced
+	 * in the queue management code. */
+	if (txq_id != IWL_CMD_QUEUE_NUM)
+		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+			  txq_id, pkt->hdr.cmd);
+	BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+	cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+	/* Input error checking is done when commands are added to queue. */
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		cmd->meta.source->u.skb = rxb->skb;
+		rxb->skb = NULL;
+	} else if (cmd->meta.u.callback &&
+		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
+		rxb->skb = NULL;
+
+	iwl4965_tx_queue_reclaim(priv, txq_id, index);
+
+	if (!(cmd->meta.flags & CMD_ASYNC)) {
+		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
+	}
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by 4965.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the 4965.  The driver and 4965 manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl4965_rx_queue_alloc()   Allocates rx_free
+ * iwl4965_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl4965_rx_queue_restock
+ * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl4965_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl4965_rx()         Detach iwl4965_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl4965_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl4965_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q)
+{
+	u32 reg = 0;
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&q->lock, flags);
+
+	if (q->need_update == 0)
+		goto exit_unlock;
+
+	/* 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);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			iwl4965_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			goto exit_unlock;
+		}
+
+		rc = iwl4965_grab_nic_access(priv);
+		if (rc)
+			goto exit_unlock;
+
+		/* Device expects a multiple of 8 */
+		iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
+				     q->write & ~0x7);
+		iwl4965_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);
+
+
+	q->need_update = 0;
+
+ exit_unlock:
+	spin_unlock_irqrestore(&q->lock, flags);
+	return rc;
+}
+
+/**
+ * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv,
+					  dma_addr_t dma_addr)
+{
+	return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+
+/**
+ * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv)
+{
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl4965_rx_mem_buffer *rxb;
+	unsigned long flags;
+	int write, rc;
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	write = rxq->write & ~0x7;
+	while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		/* Get next free Rx buffer, remove from free list */
+		element = rxq->rx_free.next;
+		rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
+		list_del(element);
+
+		/* Point to Rx buffer via next RBD in circular buffer */
+		rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+		rxq->queue[rxq->write] = rxb;
+		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+		rxq->free_count--;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+	/* If the pre-allocated buffer pool is dropping low, schedule to
+	 * refill it */
+	if (rxq->free_count <= RX_LOW_WATERMARK)
+		queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+	/* If we've added more space for the firmware to place data, tell it.
+	 * Increment device's write pointer in multiples of 8. */
+	if ((write != (rxq->write & ~0x7))
+	    || (abs(rxq->write - rxq->read) > 7)) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		rxq->need_update = 1;
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		rc = iwl4965_rx_queue_update_write_ptr(priv, rxq);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl4965_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
+{
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl4965_rx_mem_buffer *rxb;
+	unsigned long flags;
+	spin_lock_irqsave(&rxq->lock, flags);
+	while (!list_empty(&rxq->rx_used)) {
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
+
+		/* Alloc a new receive buffer */
+		rxb->skb =
+		    alloc_skb(priv->hw_setting.rx_buf_size,
+				__GFP_NOWARN | GFP_ATOMIC);
+		if (!rxb->skb) {
+			if (net_ratelimit())
+				printk(KERN_CRIT DRV_NAME
+				       ": Can not allocate SKB buffers\n");
+			/* We don't reschedule replenish work here -- we will
+			 * call the restock method and if it still needs
+			 * more buffers it will schedule replenish */
+			break;
+		}
+		priv->alloc_rxb_skb++;
+		list_del(element);
+
+		/* 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);
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+*/
+static void __iwl4965_rx_replenish(void *data)
+{
+	struct iwl4965_priv *priv = data;
+
+	iwl4965_rx_allocate(priv);
+	iwl4965_rx_queue_restock(priv);
+}
+
+
+void iwl4965_rx_replenish(void *data)
+{
+	struct iwl4965_priv *priv = data;
+	unsigned long flags;
+
+	iwl4965_rx_allocate(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl4965_rx_queue_restock(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
+{
+	int i;
+	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 priv->hw_setting.rx_buf_size,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rxq->pool[i].skb);
+		}
+	}
+
+	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+			    rxq->dma_addr);
+	rxq->bd = NULL;
+}
+
+int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv)
+{
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+
+	spin_lock_init(&rxq->lock);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+
+	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
+	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+	if (!rxq->bd)
+		return -ENOMEM;
+
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	rxq->need_update = 0;
+	return 0;
+}
+
+void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
+{
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 priv->hw_setting.rx_buf_size,
+					 PCI_DMA_FROMDEVICE);
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb(rxq->pool[i].skb);
+			rxq->pool[i].skb = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/*	 0   1   2   3   4   5   6   7   8   9 */
+	 0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+	20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+	26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+	29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+	32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+	34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+	36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+	37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+	38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+	39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ *   (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl4965_calc_db_from_ratio(int sig_ratio)
+{
+	/* 1000:1 or higher just report as 60 dB */
+	if (sig_ratio >= 1000)
+		return 60;
+
+	/* 100:1 or higher, divide by 10 and use table,
+	 *   add 20 dB to make up for divide by 10 */
+	if (sig_ratio >= 100)
+		return (20 + (int)ratio2dB[sig_ratio/10]);
+
+	/* We shouldn't see this */
+	if (sig_ratio < 1)
+		return 0;
+
+	/* Use table for ratios 1:1 - 99:1 */
+	return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95)   /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ *   about formulas used below. */
+int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+	int sig_qual;
+	int degradation = PERFECT_RSSI - rssi_dbm;
+
+	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
+	 * as indicator; formula is (signal dbm - noise dbm).
+	 * SNR at or above 40 is a great signal (100%).
+	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+	 * Weakest usable signal is usually 10 - 15 dB SNR. */
+	if (noise_dbm) {
+		if (rssi_dbm - noise_dbm >= 40)
+			return 100;
+		else if (rssi_dbm < noise_dbm)
+			return 0;
+		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+	/* Else use just the signal level.
+	 * This formula is a least squares fit of data points collected and
+	 *   compared with a reference system that had a percentage (%) display
+	 *   for signal quality. */
+	} else
+		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+			    (15 * RSSI_RANGE + 62 * degradation)) /
+			   (RSSI_RANGE * RSSI_RANGE);
+
+	if (sig_qual > 100)
+		sig_qual = 100;
+	else if (sig_qual < 1)
+		sig_qual = 0;
+
+	return sig_qual;
+}
+
+/**
+ * iwl4965_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl4965_rx_handle(struct iwl4965_priv *priv)
+{
+	struct iwl4965_rx_mem_buffer *rxb;
+	struct iwl4965_rx_packet *pkt;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
+	u32 r, i;
+	int reclaim;
+	unsigned long flags;
+	u8 fill_rx = 0;
+	u32 count = 0;
+
+	/* uCode's read index (stored in shared DRAM) indicates the last Rx
+	 * buffer that the driver may process (last buffer filled by ucode). */
+	r = iwl4965_hw_get_rx_read(priv);
+	i = rxq->read;
+
+	/* Rx interrupt, but nothing sent from uCode */
+	if (i == r)
+		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+	if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
+
+	while (i != r) {
+		rxb = rxq->queue[i];
+
+		/* If an RXB doesn't have a Rx queue slot associated with it,
+		 * then a bug has been introduced in the queue refilling
+		 * routines -- catch it here */
+		BUG_ON(rxb == NULL);
+
+		rxq->queue[i] = NULL;
+
+		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+					    priv->hw_setting.rx_buf_size,
+					    PCI_DMA_FROMDEVICE);
+		pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+
+		/* Reclaim a command buffer only if this packet is a response
+		 *   to a (driver-originated) command.
+		 * If the packet (e.g. Rx frame) originated from uCode,
+		 *   there is no command buffer to reclaim.
+		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+		 *   but apparently a few don't get set; catch them here. */
+		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+			(pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+			(pkt->hdr.cmd != REPLY_4965_RX) &&
+			(pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+			(pkt->hdr.cmd != REPLY_TX);
+
+		/* Based on type of command response or notification,
+		 *   handle those that need handling via function in
+		 *   rx_handlers table.  See iwl4965_setup_rx_handlers() */
+		if (priv->rx_handlers[pkt->hdr.cmd]) {
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r = %d, i = %d, %s, 0x%02x\n", r, i,
+				get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+			priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+		} else {
+			/* No handling needed */
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r %d i %d No handler needed for %s, 0x%02x\n",
+				r, i, get_cmd_string(pkt->hdr.cmd),
+				pkt->hdr.cmd);
+		}
+
+		if (reclaim) {
+			/* Invoke any callbacks, transfer the skb to caller, and
+			 * fire off the (possibly) blocking iwl4965_send_cmd()
+			 * as we reclaim the driver command queue */
+			if (rxb && rxb->skb)
+				iwl4965_tx_cmd_complete(priv, rxb);
+			else
+				IWL_WARNING("Claim null rxb?\n");
+		}
+
+		/* For now we just don't re-use anything.  We can tweak this
+		 * later to try and re-use notification packets and SKBs that
+		 * fail to Rx correctly */
+		if (rxb->skb != NULL) {
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb_any(rxb->skb);
+			rxb->skb = NULL;
+		}
+
+		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+				 priv->hw_setting.rx_buf_size,
+				 PCI_DMA_FROMDEVICE);
+		spin_lock_irqsave(&rxq->lock, flags);
+		list_add_tail(&rxb->list, &priv->rxq.rx_used);
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		i = (i + 1) & RX_QUEUE_MASK;
+		/* If there are a lot of unused frames,
+		 * restock the Rx queue so ucode wont assert. */
+		if (fill_rx) {
+			count++;
+			if (count >= 8) {
+				priv->rxq.read = i;
+				__iwl4965_rx_replenish(priv);
+				count = 0;
+			}
+		}
+	}
+
+	/* Backtrack one entry */
+	priv->rxq.read = i;
+	iwl4965_rx_queue_restock(priv);
+}
+
+/**
+ * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
+ */
+static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
+				  struct iwl4965_tx_queue *txq)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int txq_id = txq->q.id;
+
+	if (txq->need_update == 0)
+		return rc;
+
+	/* if we're trying to save power */
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		/* 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);
+
+		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,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			return rc;
+		}
+
+		/* restore this queue's parameters in nic hardware. */
+		rc = iwl4965_grab_nic_access(priv);
+		if (rc)
+			return rc;
+		iwl4965_write_direct32(priv, HBUS_TARG_WRPTR,
+				     txq->q.write_ptr | (txq_id << 8));
+		iwl4965_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,
+			    txq->q.write_ptr | (txq_id << 8));
+
+	txq->need_update = 0;
+
+	return rc;
+}
+
+#ifdef CONFIG_IWL4965_DEBUG
+static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon)
+{
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_RADIO("RX CONFIG:\n");
+	iwl4965_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+			le32_to_cpu(rxon->filter_flags));
+	IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+			rxon->ofdm_basic_rates);
+	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+			print_mac(mac, rxon->node_addr));
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl4965_enable_interrupts(struct iwl4965_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);
+}
+
+static inline void iwl4965_disable_interrupts(struct iwl4965_priv *priv)
+{
+	clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl4965_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_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+	switch (i) {
+	case 1:
+		return "FAIL";
+	case 2:
+		return "BAD_PARAM";
+	case 3:
+		return "BAD_CHECKSUM";
+	case 4:
+		return "NMI_INTERRUPT";
+	case 5:
+		return "SYSASSERT";
+	case 6:
+		return "FATAL_ERROR";
+	}
+
+	return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv)
+{
+	u32 data2, line;
+	u32 desc, time, count, base, data1;
+	u32 blink1, blink2, ilink1, ilink2;
+	int rc;
+
+	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl4965_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);
+
+	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+		IWL_ERROR("Start IWL Error Log Dump:\n");
+		IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+			  priv->status, priv->config, 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));
+
+	IWL_ERROR("Desc               Time       "
+		  "data1      data2      line\n");
+	IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+		  desc_lookup(desc), desc, time, data1, data2, line);
+	IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
+	IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+		  ilink1, ilink2);
+
+	iwl4965_release_nic_access(priv);
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl4965_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
+ */
+static void iwl4965_print_event_log(struct iwl4965_priv *priv, u32 start_idx,
+				u32 num_events, u32 mode)
+{
+	u32 i;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 event_size;	/* 2 u32s, or 3 u32s if timestamp recorded */
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+
+	if (num_events == 0)
+		return;
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+	if (mode == 0)
+		event_size = 2 * sizeof(u32);
+	else
+		event_size = 3 * sizeof(u32);
+
+	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+	/* "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);
+		ptr += sizeof(u32);
+		time = iwl4965_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);
+			ptr += sizeof(u32);
+			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+		}
+	}
+}
+
+static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv)
+{
+	int rc;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 capacity;   /* event log capacity in # entries */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	u32 num_wraps;  /* # times uCode wrapped to top of log */
+	u32 next_entry; /* index of next entry to be written by uCode */
+	u32 size;       /* # entries that we'll print */
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl4965_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)));
+
+	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);
+		return;
+	}
+
+	IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+		  size, num_wraps);
+
+	/* if uCode has wrapped back to top of log, start at the oldest entry,
+	 * i.e the next one that uCode would fill. */
+	if (num_wraps)
+		iwl4965_print_event_log(priv, next_entry,
+				    capacity - next_entry, mode);
+
+	/* (then/else) start at top of log */
+	iwl4965_print_event_log(priv, 0, next_entry, mode);
+
+	iwl4965_release_nic_access(priv);
+}
+
+/**
+ * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl4965_irq_handle_error(struct iwl4965_priv *priv)
+{
+	/* Set the FW error flag -- cleared on iwl4965_down */
+	set_bit(STATUS_FW_ERROR, &priv->status);
+
+	/* Cancel currently queued command. */
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & IWL_DL_FW_ERRORS) {
+		iwl4965_dump_nic_error_log(priv);
+		iwl4965_dump_nic_event_log(priv);
+		iwl4965_print_rx_config_cmd(&priv->staging_rxon);
+	}
+#endif
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the INIT status bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+			  "Restarting adapter due to uCode error.\n");
+
+		if (iwl4965_is_associated(priv)) {
+			memcpy(&priv->recovery_rxon, &priv->active_rxon,
+			       sizeof(priv->recovery_rxon));
+			priv->error_recovering = 1;
+		}
+		queue_work(priv->workqueue, &priv->restart);
+	}
+}
+
+static void iwl4965_error_recovery(struct iwl4965_priv *priv)
+{
+	unsigned long flags;
+
+	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+	       sizeof(priv->staging_rxon));
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl4965_commit_rxon(priv);
+
+	iwl4965_rxon_add_station(priv, priv->bssid, 1);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+	priv->error_recovering = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
+{
+	u32 inta, handled = 0;
+	u32 inta_fh;
+	unsigned long flags;
+#ifdef CONFIG_IWL4965_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* 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);
+
+	/* 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);
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & IWL_DL_ISR) {
+		/* just for debug */
+		inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
+		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+			      inta, inta_mask, inta_fh);
+	}
+#endif
+
+	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+	 * atomic, make sure that inta covers all the interrupts that
+	 * we've discovered, even if FH interrupt came in just after
+	 * reading CSR_INT. */
+	if (inta_fh & CSR_FH_INT_RX_MASK)
+		inta |= CSR_INT_BIT_FH_RX;
+	if (inta_fh & CSR_FH_INT_TX_MASK)
+		inta |= CSR_INT_BIT_FH_TX;
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl4965_disable_interrupts(priv);
+
+		iwl4965_irq_handle_error(priv);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		return;
+	}
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & (IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+			IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE)
+			IWL_DEBUG_ISR("Alive interrupt\n");
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		int hw_rf_kill = 0;
+		if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+			hw_rf_kill = 1;
+
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+				"RF_KILL bit toggled to %s.\n",
+				hw_rf_kill ? "disable radio":"enable radio");
+
+		/* Queue restart only if RF_KILL switch was set to "kill"
+		 *   when we loaded driver, and is now set to "enable".
+		 * After we're Alive, RF_KILL gets handled by
+		 *   iwl4965_rx_card_state_notif() */
+		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) {
+			clear_bit(STATUS_RF_KILL_HW, &priv->status);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERROR("Microcode CT kill error detected.\n");
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
+			  inta);
+		iwl4965_irq_handle_error(priv);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR("Wakeup interrupt\n");
+		iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+		iwl4965_rx_handle(priv);
+		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+	}
+
+	if (inta & CSR_INT_BIT_FH_TX) {
+		IWL_DEBUG_ISR("Tx interrupt\n");
+		handled |= CSR_INT_BIT_FH_TX;
+	}
+
+	if (inta & ~handled)
+		IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+	if (inta & ~CSR_INI_SET_MASK) {
+		IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~CSR_INI_SET_MASK);
+		IWL_WARNING("   with FH_INT = 0x%08x\n", inta_fh);
+	}
+
+	/* Re-enable all interrupts */
+	iwl4965_enable_interrupts(priv);
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_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);
+		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+	}
+#endif
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl4965_isr(int irq, void *data, struct pt_regs *regs)
+{
+	struct iwl4965_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 inta_fh;
+	if (!priv)
+		return IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    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);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl4965_read32(priv, CSR_INT);
+	inta_fh = iwl4965_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,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta && !inta_fh) {
+		IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared. It might have already raised
+		 * an interrupt */
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		goto unplugged;
+	}
+
+	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+		      inta, inta_mask, inta_fh);
+
+	/* iwl4965_irq_tasklet() will service interrupts and re-enable them */
+	tasklet_schedule(&priv->irq_tasklet);
+
+ unplugged:
+	spin_unlock(&priv->lock);
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	iwl4965_enable_interrupts(priv);
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl4965_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl4965_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel.  We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware.  This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel.  There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl4965_eeprom_band_1[14] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl4965_eeprom_band_2[] = {	/* 4915-5080MHz */
+	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl4965_eeprom_band_3[] = {	/* 5170-5320MHz */
+	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl4965_eeprom_band_4[] = {	/* 5500-5700MHz */
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl4965_eeprom_band_5[] = {	/* 5725-5825MHz */
+	145, 149, 153, 157, 161, 165
+};
+
+static u8 iwl4965_eeprom_band_6[] = {       /* 2.4 FAT channel */
+	1, 2, 3, 4, 5, 6, 7
+};
+
+static u8 iwl4965_eeprom_band_7[] = {       /* 5.2 FAT channel */
+	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+static void iwl4965_init_band_reference(const struct iwl4965_priv *priv,
+				    int band,
+				    int *eeprom_ch_count,
+				    const struct iwl4965_eeprom_channel
+				    **eeprom_ch_info,
+				    const u8 **eeprom_ch_index)
+{
+	switch (band) {
+	case 1:		/* 2.4GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_1);
+		*eeprom_ch_info = priv->eeprom.band_1_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_1;
+		break;
+	case 2:		/* 4.9GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2);
+		*eeprom_ch_info = priv->eeprom.band_2_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_2;
+		break;
+	case 3:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_3);
+		*eeprom_ch_info = priv->eeprom.band_3_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_3;
+		break;
+	case 4:		/* 5.5GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4);
+		*eeprom_ch_info = priv->eeprom.band_4_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_4;
+		break;
+	case 5:		/* 5.7GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5);
+		*eeprom_ch_info = priv->eeprom.band_5_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_5;
+		break;
+	case 6:		/* 2.4GHz FAT channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6);
+		*eeprom_ch_info = priv->eeprom.band_24_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_6;
+		break;
+	case 7:		/* 5 GHz FAT channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7);
+		*eeprom_ch_info = priv->eeprom.band_52_channels;
+		*eeprom_ch_index = iwl4965_eeprom_band_7;
+		break;
+	default:
+		BUG();
+		return;
+	}
+}
+
+/**
+ * iwl4965_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
+const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv,
+						    int phymode, u16 channel)
+{
+	int i;
+
+	switch (phymode) {
+	case MODE_IEEE80211A:
+		for (i = 14; i < priv->channel_count; i++) {
+			if (priv->channel_info[i].channel == channel)
+				return &priv->channel_info[i];
+		}
+		break;
+
+	case MODE_IEEE80211B:
+	case MODE_IEEE80211G:
+		if (channel >= 1 && channel <= 14)
+			return &priv->channel_info[channel - 1];
+		break;
+
+	}
+
+	return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+			    ? # x " " : "")
+
+/**
+ * iwl4965_init_channel_map - Set up driver's info for all possible channels
+ */
+static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
+{
+	int eeprom_ch_count = 0;
+	const u8 *eeprom_ch_index = NULL;
+	const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL;
+	int band, ch;
+	struct iwl4965_channel_info *ch_info;
+
+	if (priv->channel_count) {
+		IWL_DEBUG_INFO("Channel map already initialized.\n");
+		return 0;
+	}
+
+	if (priv->eeprom.version < 0x2f) {
+		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+			    priv->eeprom.version);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+	priv->channel_count =
+	    ARRAY_SIZE(iwl4965_eeprom_band_1) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_2) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_3) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_4) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_5);
+
+	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+	priv->channel_info = kzalloc(sizeof(struct iwl4965_channel_info) *
+				     priv->channel_count, GFP_KERNEL);
+	if (!priv->channel_info) {
+		IWL_ERROR("Could not allocate channel_info\n");
+		priv->channel_count = 0;
+		return -ENOMEM;
+	}
+
+	ch_info = priv->channel_info;
+
+	/* Loop through the 5 EEPROM bands adding them in order to the
+	 * channel map we maintain (that contains additional information than
+	 * what just in the EEPROM) */
+	for (band = 1; band <= 5; band++) {
+
+		iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+			ch_info->channel = eeprom_ch_index[ch];
+			ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+			    MODE_IEEE80211A;
+
+			/* permanently store EEPROM's channel regulatory flags
+			 *   and max power in channel info database. */
+			ch_info->eeprom = eeprom_ch_info[ch];
+
+			/* Copy the run-time flags so they are there even on
+			 * invalid channels */
+			ch_info->flags = eeprom_ch_info[ch].flags;
+
+			if (!(is_channel_valid(ch_info))) {
+				IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+					       "No traffic\n",
+					       ch_info->channel,
+					       ch_info->flags,
+					       is_channel_a_band(ch_info) ?
+					       "5.2" : "2.4");
+				ch_info++;
+				continue;
+			}
+
+			/* Initialize regulatory-based run-time data */
+			ch_info->max_power_avg = ch_info->curr_txpow =
+			    eeprom_ch_info[ch].max_power_avg;
+			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+			ch_info->min_power = 0;
+
+			IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+				       " %ddBm): Ad-Hoc %ssupported\n",
+				       ch_info->channel,
+				       is_channel_a_band(ch_info) ?
+				       "5.2" : "2.4",
+				       CHECK_AND_PRINT(IBSS),
+				       CHECK_AND_PRINT(ACTIVE),
+				       CHECK_AND_PRINT(RADAR),
+				       CHECK_AND_PRINT(WIDE),
+				       CHECK_AND_PRINT(NARROW),
+				       CHECK_AND_PRINT(DFS),
+				       eeprom_ch_info[ch].flags,
+				       eeprom_ch_info[ch].max_power_avg,
+				       ((eeprom_ch_info[ch].
+					 flags & EEPROM_CHANNEL_IBSS)
+					&& !(eeprom_ch_info[ch].
+					     flags & EEPROM_CHANNEL_RADAR))
+				       ? "" : "not ");
+
+			/* Set the user_txpower_limit to the highest power
+			 * supported by any channel */
+			if (eeprom_ch_info[ch].max_power_avg >
+			    priv->user_txpower_limit)
+				priv->user_txpower_limit =
+				    eeprom_ch_info[ch].max_power_avg;
+
+			ch_info++;
+		}
+	}
+
+	/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
+	for (band = 6; band <= 7; band++) {
+		int phymode;
+		u8 fat_extension_chan;
+
+		iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
+		phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+
+			if ((band == 6) &&
+			    ((eeprom_ch_index[ch] == 5) ||
+			    (eeprom_ch_index[ch] == 6) ||
+			    (eeprom_ch_index[ch] == 7)))
+			       fat_extension_chan = HT_IE_EXT_CHANNEL_MAX;
+			else
+				fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
+
+			/* Set up driver's info for lower half */
+			iwl4965_set_fat_chan_info(priv, phymode,
+						  eeprom_ch_index[ch],
+						  &(eeprom_ch_info[ch]),
+						  fat_extension_chan);
+
+			/* Set up driver's info for upper half */
+			iwl4965_set_fat_chan_info(priv, phymode,
+						  (eeprom_ch_index[ch] + 4),
+						  &(eeprom_ch_info[ch]),
+						  HT_IE_EXT_CHANNEL_BELOW);
+		}
+	}
+
+	return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)	/* packets */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)	/* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)	/* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+
+static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode)
+{
+	if (phymode == MODE_IEEE80211A)
+		return IWL_ACTIVE_DWELL_TIME_52;
+	else
+		return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode)
+{
+	u16 active = iwl4965_get_active_dwell_time(priv, phymode);
+	u16 passive = (phymode != MODE_IEEE80211A) ?
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+	if (iwl4965_is_associated(priv)) {
+		/* If we're associated, we clamp the maximum passive
+		 * dwell time to be 98% of the beacon interval (minus
+		 * 2 * channel tune time) */
+		passive = priv->beacon_int;
+		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+			passive = IWL_PASSIVE_DWELL_BASE;
+		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+	}
+
+	if (passive <= active)
+		passive = active + 1;
+
+	return passive;
+}
+
+static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
+				     u8 is_active, u8 direct_mask,
+				     struct iwl4965_scan_channel *scan_ch)
+{
+	const struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode;
+	const struct iwl4965_channel_info *ch_info;
+	u16 passive_dwell = 0;
+	u16 active_dwell = 0;
+	int added, i;
+
+	hw_mode = iwl4965_get_hw_mode(priv, phymode);
+	if (!hw_mode)
+		return 0;
+
+	channels = hw_mode->channels;
+
+	active_dwell = iwl4965_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode);
+
+	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+		if (channels[i].chan ==
+		    le16_to_cpu(priv->active_rxon.channel)) {
+			if (iwl4965_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 = channels[i].chan;
+
+		ch_info = iwl4965_get_channel_info(priv, phymode,
+					 scan_ch->channel);
+		if (!is_channel_valid(ch_info)) {
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+				       scan_ch->channel);
+			continue;
+		}
+
+		if (!is_active || is_channel_passive(ch_info) ||
+		    !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+			scan_ch->type = 0;	/* passive */
+		else
+			scan_ch->type = 1;	/* active */
+
+		if (scan_ch->type & 1)
+			scan_ch->type |= (direct_mask << 1);
+
+		if (is_channel_narrow(ch_info))
+			scan_ch->type |= (1 << 7);
+
+		scan_ch->active_dwell = cpu_to_le16(active_dwell);
+		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+		/* Set txpower levels to defaults */
+		scan_ch->tpc.dsp_atten = 110;
+		/* scan_pwr_info->tpc.dsp_atten; */
+
+		/*scan_pwr_info->tpc.tx_gain; */
+		if (phymode == MODE_IEEE80211A)
+			scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else {
+			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+			 * power level:
+			 * scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 */
+		}
+
+		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+			       scan_ch->channel,
+			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+			       (scan_ch->type & 1) ?
+			       active_dwell : passive_dwell);
+
+		scan_ch++;
+		added++;
+	}
+
+	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+	return added;
+}
+
+static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv)
+{
+	int i, j;
+	for (i = 0; i < 3; i++) {
+		struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+		for (j = 0; j < hw_mode->num_channels; j++)
+			hw_mode->channels[j].flag = hw_mode->channels[j].val;
+	}
+}
+
+static void iwl4965_init_hw_rates(struct iwl4965_priv *priv,
+			      struct ieee80211_rate *rates)
+{
+	int i;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++) {
+		rates[i].rate = iwl4965_rates[i].ieee * 5;
+		rates[i].val = i; /* Rate scaling will work on indexes */
+		rates[i].val2 = i;
+		rates[i].flags = IEEE80211_RATE_SUPPORTED;
+		/* Only OFDM have the bits-per-symbol set */
+		if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+			rates[i].flags |= IEEE80211_RATE_OFDM;
+		else {
+			/*
+			 * If CCK 1M then set rate flag to CCK else CCK_2
+			 * which is CCK | PREAMBLE2
+			 */
+			rates[i].flags |= (iwl4965_rates[i].plcp == 10) ?
+				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+		}
+
+		/* Set up which ones are basic rates... */
+		if (IWL_BASIC_RATES_MASK & (1 << i))
+			rates[i].flags |= IEEE80211_RATE_BASIC;
+	}
+}
+
+/**
+ * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl4965_init_geos(struct iwl4965_priv *priv)
+{
+	struct iwl4965_channel_info *ch;
+	struct ieee80211_hw_mode *modes;
+	struct ieee80211_channel *channels;
+	struct ieee80211_channel *geo_ch;
+	struct ieee80211_rate *rates;
+	int i = 0;
+	enum {
+		A = 0,
+		B = 1,
+		G = 2,
+	};
+	int mode_count = 3;
+
+	if (priv->modes) {
+		IWL_DEBUG_INFO("Geography modes already initialized.\n");
+		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+		return 0;
+	}
+
+	modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+			GFP_KERNEL);
+	if (!modes)
+		return -ENOMEM;
+
+	channels = kzalloc(sizeof(struct ieee80211_channel) *
+			   priv->channel_count, GFP_KERNEL);
+	if (!channels) {
+		kfree(modes);
+		return -ENOMEM;
+	}
+
+	rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+			GFP_KERNEL);
+	if (!rates) {
+		kfree(modes);
+		kfree(channels);
+		return -ENOMEM;
+	}
+
+	/* 0 = 802.11a
+	 * 1 = 802.11b
+	 * 2 = 802.11g
+	 */
+
+	/* 5.2GHz channels start after the 2.4GHz channels */
+	modes[A].mode = MODE_IEEE80211A;
+	modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
+	modes[A].rates = rates;
+	modes[A].num_rates = 8;	/* just OFDM */
+	modes[A].rates = &rates[4];
+	modes[A].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+	iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A);
+#endif
+
+	modes[B].mode = MODE_IEEE80211B;
+	modes[B].channels = channels;
+	modes[B].rates = rates;
+	modes[B].num_rates = 4;	/* just CCK */
+	modes[B].num_channels = 0;
+
+	modes[G].mode = MODE_IEEE80211G;
+	modes[G].channels = channels;
+	modes[G].rates = rates;
+	modes[G].num_rates = 12;	/* OFDM & CCK */
+	modes[G].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+	iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G);
+#endif
+
+	priv->ieee_channels = channels;
+	priv->ieee_rates = rates;
+
+	iwl4965_init_hw_rates(priv, rates);
+
+	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+		ch = &priv->channel_info[i];
+
+		if (!is_channel_valid(ch)) {
+			IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+				    "skipping.\n",
+				    ch->channel, is_channel_a_band(ch) ?
+				    "5.2" : "2.4");
+			continue;
+		}
+
+		if (is_channel_a_band(ch)) {
+			geo_ch = &modes[A].channels[modes[A].num_channels++];
+		} else {
+			geo_ch = &modes[B].channels[modes[B].num_channels++];
+			modes[G].num_channels++;
+		}
+
+		geo_ch->freq = ieee80211chan2mhz(ch->channel);
+		geo_ch->chan = ch->channel;
+		geo_ch->power_level = ch->max_power_avg;
+		geo_ch->antenna_max = 0xff;
+
+		if (is_channel_valid(ch)) {
+			geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+			if (ch->flags & EEPROM_CHANNEL_IBSS)
+				geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+			if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+				geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+			if (ch->flags & EEPROM_CHANNEL_RADAR)
+				geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+			if (ch->max_power_avg > priv->max_channel_txpower_limit)
+				priv->max_channel_txpower_limit =
+				    ch->max_power_avg;
+		}
+
+		geo_ch->val = geo_ch->flag;
+	}
+
+	if ((modes[A].num_channels == 0) && priv->is_abg) {
+		printk(KERN_INFO DRV_NAME
+		       ": Incorrectly detected BG card as ABG.  Please send "
+		       "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+		       priv->pci_dev->device, priv->pci_dev->subsystem_device);
+		priv->is_abg = 0;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+	       modes[G].num_channels, modes[A].num_channels);
+
+	/*
+	 * NOTE:  We register these in preference of order -- the
+	 * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+	 * a phymode based on rates or AP capabilities but seems to
+	 * configure it purely on if the channel being configured
+	 * is supported by a mode -- and the first match is taken
+	 */
+
+	if (modes[G].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[G]);
+	if (modes[B].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[B]);
+	if (modes[A].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+	priv->modes = modes;
+	set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv)
+{
+	if (priv->ucode_code.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_code.len,
+				    priv->ucode_code.v_addr,
+				    priv->ucode_code.p_addr);
+		priv->ucode_code.v_addr = NULL;
+	}
+	if (priv->ucode_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data.len,
+				    priv->ucode_data.v_addr,
+				    priv->ucode_data.p_addr);
+		priv->ucode_data.v_addr = NULL;
+	}
+	if (priv->ucode_data_backup.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data_backup.len,
+				    priv->ucode_data_backup.v_addr,
+				    priv->ucode_data_backup.p_addr);
+		priv->ucode_data_backup.v_addr = NULL;
+	}
+	if (priv->ucode_init.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init.len,
+				    priv->ucode_init.v_addr,
+				    priv->ucode_init.p_addr);
+		priv->ucode_init.v_addr = NULL;
+	}
+	if (priv->ucode_init_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init_data.len,
+				    priv->ucode_init_data.v_addr,
+				    priv->ucode_init_data.p_addr);
+		priv->ucode_init_data.v_addr = NULL;
+	}
+	if (priv->ucode_boot.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_boot.len,
+				    priv->ucode_boot.v_addr,
+				    priv->ucode_boot.p_addr);
+		priv->ucode_boot.v_addr = NULL;
+	}
+}
+
+/**
+ * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image,
+				 u32 len)
+{
+	u32 val;
+	u32 save_len = len;
+	int rc = 0;
+	u32 errcnt;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl4965_grab_nic_access(priv);
+	if (rc)
+		return rc;
+
+	iwl4965_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);
+		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",
+				  save_len - len, val, le32_to_cpu(*image));
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 20)
+				break;
+		}
+	}
+
+	iwl4965_release_nic_access(priv);
+
+	if (!errcnt)
+		IWL_DEBUG_INFO
+		    ("ucode image in INSTRUCTION memory is good\n");
+
+	return rc;
+}
+
+
+/**
+ * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, u32 len)
+{
+	u32 val;
+	int rc = 0;
+	u32 errcnt = 0;
+	u32 i;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl4965_grab_nic_access(priv);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < len; i += 100, image += 100/sizeof(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,
+			i + RTC_INST_LOWER_BOUND);
+		val = _iwl4965_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 "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  i, val, *image);
+#endif
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 3)
+				break;
+		}
+	}
+
+	iwl4965_release_nic_access(priv);
+
+	return rc;
+}
+
+
+/**
+ * iwl4965_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl4965_verify_ucode(struct iwl4965_priv *priv)
+{
+	__le32 *image;
+	u32 len;
+	int rc = 0;
+
+	/* Try bootstrap */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try initialize */
+	image = (__le32 *)priv->ucode_init.v_addr;
+	len = priv->ucode_init.len;
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try runtime/protocol */
+	image = (__le32 *)priv->ucode_code.v_addr;
+	len = priv->ucode_code.len;
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+	/* Since nothing seems to match, show first several data entries in
+	 * instruction SRAM, so maybe visual inspection will give a clue.
+	 * Selection of bootstrap image (vs. other images) is arbitrary. */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl4965_verify_inst_full(priv, image, len);
+
+	return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl4965_verify_bsm(struct iwl4965_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	u32 reg;
+	u32 val;
+
+	IWL_DEBUG_INFO("Begin verify bsm\n");
+
+	/* verify BSM SRAM contents */
+	val = iwl4965_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);
+		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",
+				  BSM_SRAM_LOWER_BOUND,
+				  reg - BSM_SRAM_LOWER_BOUND, len,
+				  val, le32_to_cpu(*image));
+			return -EIO;
+		}
+	}
+
+	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+	return 0;
+}
+
+/**
+ * iwl4965_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL.  When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers.  Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image.  This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl4965_load_bsm(struct iwl4965_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	u32 inst_len;
+	u32 data_len;
+	int rc;
+	int i;
+	u32 done;
+	u32 reg_offset;
+
+	IWL_DEBUG_INFO("Begin load bsm\n");
+
+	/* make sure bootstrap program is no larger than BSM's SRAM size */
+	if (len > IWL_MAX_BSM_SIZE)
+		return -EINVAL;
+
+	/* Tell bootstrap uCode where to find the "Initialize" uCode
+	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
+	 * NOTE:  iwl4965_initialize_alive_start() will replace these values,
+	 *        after the "initialize" uCode has run, to point to
+	 *        runtime/protocol instructions and backup data cache. */
+	pinst = priv->ucode_init.p_addr >> 4;
+	pdata = priv->ucode_init_data.p_addr >> 4;
+	inst_len = priv->ucode_init.len;
+	data_len = priv->ucode_init_data.len;
+
+	rc = iwl4965_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);
+
+	/* 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,
+					  le32_to_cpu(*image));
+
+	rc = iwl4965_verify_bsm(priv);
+	if (rc) {
+		iwl4965_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,
+				 RTC_INST_LOWER_BOUND);
+	iwl4965_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,
+		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);
+		if (!(done & BSM_WR_CTRL_REG_BIT_START))
+			break;
+		udelay(10);
+	}
+	if (i < 100)
+		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+	else {
+		IWL_ERROR("BSM write did not complete!\n");
+		return -EIO;
+	}
+
+	/* 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,
+		BSM_WR_CTRL_REG_BIT_START_EN);
+
+	iwl4965_release_nic_access(priv);
+
+	return 0;
+}
+
+static void iwl4965_nic_start(struct iwl4965_priv *priv)
+{
+	/* Remove all resets to allow NIC to operate */
+	iwl4965_write32(priv, CSR_RESET, 0);
+}
+
+static int iwl4965_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
+{
+	desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
+	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
+}
+
+/**
+ * iwl4965_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl4965_read_ucode(struct iwl4965_priv *priv)
+{
+	struct iwl4965_ucode *ucode;
+	int ret;
+	const struct firmware *ucode_raw;
+	const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
+	u8 *src;
+	size_t len;
+	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+	/* Ask kernel firmware_class module to get the boot firmware off disk.
+	 * request_firmware() is synchronous, file is in memory on return. */
+	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (ret < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n",
+					name, ret);
+		goto error;
+	}
+
+	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+		       name, ucode_raw->size);
+
+	/* Make sure that we got at least our header! */
+	if (ucode_raw->size < sizeof(*ucode)) {
+		IWL_ERROR("File size way too small!\n");
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Data from ucode file:  header followed by uCode images */
+	ucode = (void *)ucode_raw->data;
+
+	ver = le32_to_cpu(ucode->ver);
+	inst_size = le32_to_cpu(ucode->inst_size);
+	data_size = le32_to_cpu(ucode->data_size);
+	init_size = le32_to_cpu(ucode->init_size);
+	init_data_size = le32_to_cpu(ucode->init_data_size);
+	boot_size = le32_to_cpu(ucode->boot_size);
+
+	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+		       inst_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+		       data_size);
+	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+		       init_size);
+	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+		       init_data_size);
+	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+		       boot_size);
+
+	/* Verify size of file vs. image size info in file's header */
+	if (ucode_raw->size < sizeof(*ucode) +
+		inst_size + data_size + init_size +
+		init_data_size + boot_size) {
+
+		IWL_DEBUG_INFO("uCode file size %d too small\n",
+			       (int)ucode_raw->size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Verify that uCode images will fit in card's SRAM */
+	if (inst_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
+			       inst_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	if (data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
+				data_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (init_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init instr len %d too large to fit in\n",
+		      init_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (init_data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init data len %d too large to fit in\n",
+		      init_data_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+	if (boot_size > IWL_MAX_BSM_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode boot instr len %d too large to fit in\n",
+		      boot_size);
+		ret = -EINVAL;
+		goto err_release;
+	}
+
+	/* Allocate ucode buffers for card's bus-master loading ... */
+
+	/* Runtime instructions and 2 copies of data:
+	 * 1) unmodified from disk
+	 * 2) backup cache for save/restore during power-downs */
+	priv->ucode_code.len = inst_size;
+	iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
+
+	priv->ucode_data.len = data_size;
+	iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
+
+	priv->ucode_data_backup.len = data_size;
+	iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+
+	/* Initialization instructions and data */
+	if (init_size && init_data_size) {
+		priv->ucode_init.len = init_size;
+		iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+		priv->ucode_init_data.len = init_data_size;
+		iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+
+		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+			goto err_pci_alloc;
+	}
+
+	/* Bootstrap (instructions only, no data) */
+	if (boot_size) {
+		priv->ucode_boot.len = boot_size;
+		iwl4965_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
+
+		if (!priv->ucode_boot.v_addr)
+			goto err_pci_alloc;
+	}
+
+	/* Copy images into buffers for card's bus-master reads ... */
+
+	/* Runtime instructions (first block of data in file) */
+	src = &ucode->data[0];
+	len = priv->ucode_code.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len);
+	memcpy(priv->ucode_code.v_addr, src, len);
+	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+	/* Runtime data (2nd block)
+	 * NOTE:  Copy into backup buffer will be done in iwl4965_up()  */
+	src = &ucode->data[inst_size];
+	len = priv->ucode_data.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
+	memcpy(priv->ucode_data.v_addr, src, len);
+	memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+	/* Initialization instructions (3rd block) */
+	if (init_size) {
+		src = &ucode->data[inst_size + data_size];
+		len = priv->ucode_init.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+				len);
+		memcpy(priv->ucode_init.v_addr, src, len);
+	}
+
+	/* Initialization data (4th block) */
+	if (init_data_size) {
+		src = &ucode->data[inst_size + data_size + init_size];
+		len = priv->ucode_init_data.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
+			       len);
+		memcpy(priv->ucode_init_data.v_addr, src, len);
+	}
+
+	/* Bootstrap instructions (5th block) */
+	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+	len = priv->ucode_boot.len;
+	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
+	memcpy(priv->ucode_boot.v_addr, src, len);
+
+	/* We have our copies now, allow OS release its copies */
+	release_firmware(ucode_raw);
+	return 0;
+
+ err_pci_alloc:
+	IWL_ERROR("failed to allocate pci memory\n");
+	ret = -ENOMEM;
+	iwl4965_dealloc_ucode_pci(priv);
+
+ err_release:
+	release_firmware(ucode_raw);
+
+ error:
+	return ret;
+}
+
+
+/**
+ * iwl4965_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv)
+{
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	int rc = 0;
+	unsigned long flags;
+
+	/* bits 35:4 for 4965 */
+	pinst = priv->ucode_code.p_addr >> 4;
+	pdata = priv->ucode_data_backup.p_addr >> 4;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl4965_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,
+				 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,
+				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+	iwl4965_release_nic_access(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+	return rc;
+}
+
+/**
+ * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ *   (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl4965_init_alive_start(struct iwl4965_priv *priv)
+{
+	/* Check alive response for "valid" sign from uCode */
+	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Initialize Alive failed.\n");
+		goto restart;
+	}
+
+	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "initialize" alive if code weren't properly loaded.  */
+	if (iwl4965_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+		goto restart;
+	}
+
+	/* Calculate temperature */
+	priv->temperature = iwl4965_get_temperature(priv);
+
+	/* Send pointers to protocol/runtime uCode image ... init code will
+	 * load and launch runtime uCode, which will send us another "Alive"
+	 * notification. */
+	IWL_DEBUG_INFO("Initialization Alive received.\n");
+	if (iwl4965_set_ucode_ptrs(priv)) {
+		/* Runtime instruction load won't happen;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+		goto restart;
+	}
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl4965_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl4965_init_alive_start()).
+ */
+static void iwl4965_alive_start(struct iwl4965_priv *priv)
+{
+	int rc = 0;
+
+	IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+	if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Alive failed.\n");
+		goto restart;
+	}
+
+	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "runtime" alive if code weren't properly loaded.  */
+	if (iwl4965_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+		goto restart;
+	}
+
+	iwl4965_clear_stations_table(priv);
+
+	rc = iwl4965_alive_notify(priv);
+	if (rc) {
+		IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
+			    rc);
+		goto restart;
+	}
+
+	/* After the ALIVE response, we can send host commands to 4965 uCode */
+	set_bit(STATUS_ALIVE, &priv->status);
+
+	/* Clear out the uCode error bit if it is set */
+	clear_bit(STATUS_FW_ERROR, &priv->status);
+
+	rc = iwl4965_init_channel_map(priv);
+	if (rc) {
+		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+		return;
+	}
+
+	iwl4965_init_geos(priv);
+
+	if (iwl4965_is_rfkill(priv))
+		return;
+
+	if (!priv->mac80211_registered) {
+		/* Unlock so any user space entry points can call back into
+		 * the driver without a deadlock... */
+		mutex_unlock(&priv->mutex);
+		iwl4965_rate_control_register(priv->hw);
+		rc = ieee80211_register_hw(priv->hw);
+		priv->hw->conf.beacon_int = 100;
+		mutex_lock(&priv->mutex);
+
+		if (rc) {
+			iwl4965_rate_control_unregister(priv->hw);
+			IWL_ERROR("Failed to register network "
+				  "device (error %d)\n", rc);
+			return;
+		}
+
+		priv->mac80211_registered = 1;
+
+		iwl4965_reset_channel_flag(priv);
+	} else
+		ieee80211_start_queues(priv->hw);
+
+	priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+	if (iwl4965_is_associated(priv)) {
+		struct iwl4965_rxon_cmd *active_rxon =
+				(struct iwl4965_rxon_cmd *)(&priv->active_rxon);
+
+		memcpy(&priv->staging_rxon, &priv->active_rxon,
+		       sizeof(priv->staging_rxon));
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	} else {
+		/* Initialize our rx_config data */
+		iwl4965_connection_init_rx_config(priv);
+		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	}
+
+	/* Configure Bluetooth device coexistence support */
+	iwl4965_send_bt_config(priv);
+
+	/* Configure the adapter for unassociated operation */
+	iwl4965_commit_rxon(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");
+
+	if (priv->error_recovering)
+		iwl4965_error_recovery(priv);
+
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv);
+
+static void __iwl4965_down(struct iwl4965_priv *priv)
+{
+	unsigned long flags;
+	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	struct ieee80211_conf *conf = NULL;
+
+	IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	if (!exit_pending)
+		set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	iwl4965_clear_stations_table(priv);
+
+	/* Unblock any waiting calls */
+	wake_up_interruptible_all(&priv->wait_command_queue);
+
+	iwl4965_cancel_deferred_work(priv);
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		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);
+
+	/* tell the device to stop sending interrupts */
+	iwl4965_disable_interrupts(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	/* If we have not previously called iwl4965_init() then
+	 * clear all bits but the RF Kill and SUSPEND bits and return */
+	if (!iwl4965_is_init(priv)) {
+		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+					STATUS_RF_KILL_HW |
+			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+					STATUS_IN_SUSPEND;
+		goto exit;
+	}
+
+	/* ...otherwise clear out all the status bits but the RF Kill and
+	 * SUSPEND bits and continue taking the NIC down. */
+	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+				STATUS_RF_KILL_HW |
+			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+				STATUS_RF_KILL_SW |
+			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+				STATUS_IN_SUSPEND |
+			test_bit(STATUS_FW_ERROR, &priv->status) <<
+				STATUS_FW_ERROR;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+			 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl4965_hw_txq_ctx_stop(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,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl4965_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);
+	iwl4965_hw_nic_reset(priv);
+
+ exit:
+	memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp));
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+	priv->ibss_beacon = NULL;
+
+	/* clear out any free frames */
+	iwl4965_clear_free_frames(priv);
+}
+
+static void iwl4965_down(struct iwl4965_priv *priv)
+{
+	mutex_lock(&priv->mutex);
+	__iwl4965_down(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl4965_up(struct iwl4965_priv *priv)
+{
+	DECLARE_MAC_BUF(mac);
+	int rc, i;
+	u32 hw_rf_kill = 0;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_WARNING("Exit pending; will not bring the NIC up\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("Radio disabled by SW RF kill (module "
+			    "parameter)\n");
+		return 0;
+	}
+
+	iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	rc = iwl4965_hw_nic_init(priv);
+	if (rc) {
+		IWL_ERROR("Unable to int nic\n");
+		return rc;
+	}
+
+	/* 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_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl4965_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);
+
+	/* Copy original ucode data image from disk into backup cache.
+	 * This will be used to initialize the on-board processor's
+	 * data SRAM for a clean start when the runtime program first loads. */
+	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+			priv->ucode_data.len);
+
+	/* If platform's RF_KILL switch is set to KILL,
+	 * wait for BIT_INT_RF_KILL interrupt before loading uCode
+	 * and getting things started */
+	if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+		hw_rf_kill = 1;
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
+		IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+		return 0;
+	}
+
+	for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+		iwl4965_clear_stations_table(priv);
+
+		/* load bootstrap state machine,
+		 * load bootstrap program into processor's memory,
+		 * prepare to load the "initialize" uCode */
+		rc = iwl4965_load_bsm(priv);
+
+		if (rc) {
+			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+			continue;
+		}
+
+		/* start card; "initialize" will load runtime ucode */
+		iwl4965_nic_start(priv);
+
+		/* MAC Address location in EEPROM is same for 3945/4965 */
+		get_eeprom_mac(priv, priv->mac_addr);
+		IWL_DEBUG_INFO("MAC address: %s\n",
+			       print_mac(mac, priv->mac_addr));
+
+		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+		return 0;
+	}
+
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl4965_down(priv);
+
+	/* tried to restart and config the device for as long as our
+	 * patience could withstand */
+	IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+	return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl4965_bg_init_alive_start(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl4965_init_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_alive_start(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl4965_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_rf_kill(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl4965_is_rfkill(priv)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+			  "HW and/or SW RF Kill no longer active, restarting "
+			  "device\n");
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	} else {
+
+		if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+			IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+					  "disabled by SW switch\n");
+		else
+			IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+				    "Kill switch must be turned off for "
+				    "wireless networking to work.\n");
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl4965_bg_scan_check(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	if (test_bit(STATUS_SCANNING, &priv->status) ||
+	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+			  "Scan completion watchdog resetting adapter (%dms)\n",
+			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			iwl4965_send_scan_abort(priv);
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_request_scan(void *p)
+{
+	struct iwl4965_priv *priv = p;
+	struct iwl4965_host_cmd cmd = {
+		.id = REPLY_SCAN_CMD,
+		.len = sizeof(struct iwl4965_scan_cmd),
+		.meta.flags = CMD_SIZE_HUGE,
+	};
+	int rc = 0;
+	struct iwl4965_scan_cmd *scan;
+	struct ieee80211_conf *conf = NULL;
+	u8 direct_mask;
+	int phymode;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl4965_is_ready(priv)) {
+		IWL_WARNING("request scan called when driver not ready.\n");
+		goto done;
+	}
+
+	/* Make sure the scan wasn't cancelled before this queued work
+	 * was given the chance to run... */
+	if (!test_bit(STATUS_SCANNING, &priv->status))
+		goto done;
+
+	/* This should never be called or scheduled if there is currently
+	 * a scan active in the hardware. */
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+			       "Ignoring second request.\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+		goto done;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+		goto done;
+	}
+
+	if (iwl4965_is_rfkill(priv)) {
+		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+		goto done;
+	}
+
+	if (!test_bit(STATUS_READY, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
+		goto done;
+	}
+
+	if (!priv->scan_bands) {
+		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+		goto done;
+	}
+
+	if (!priv->scan) {
+		priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) +
+				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+		if (!priv->scan) {
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+	scan = priv->scan;
+	memset(scan, 0, sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+	if (iwl4965_is_associated(priv)) {
+		u16 interval = 0;
+		u32 extra;
+		u32 suspend_time = 100;
+		u32 scan_suspend_time = 100;
+		unsigned long flags;
+
+		IWL_DEBUG_INFO("Scanning while associated...\n");
+
+		spin_lock_irqsave(&priv->lock, flags);
+		interval = priv->beacon_int;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		scan->suspend_time = 0;
+		scan->max_out_time = cpu_to_le32(200 * 1024);
+		if (!interval)
+			interval = suspend_time;
+
+		extra = (suspend_time / interval) << 22;
+		scan_suspend_time = (extra |
+		    ((suspend_time % interval) * 1024));
+		scan->suspend_time = cpu_to_le32(scan_suspend_time);
+		IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+			       scan_suspend_time, interval);
+	}
+
+	/* We should add the ability for user to lock to PASSIVE ONLY */
+	if (priv->one_direct_scan) {
+		IWL_DEBUG_SCAN
+		    ("Kicking off one direct scan for '%s'\n",
+		     iwl4965_escape_essid(priv->direct_ssid,
+				      priv->direct_ssid_len));
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->direct_ssid_len;
+		memcpy(scan->direct_scan[0].ssid,
+		       priv->direct_ssid, priv->direct_ssid_len);
+		direct_mask = 1;
+	} else if (!iwl4965_is_associated(priv) && 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
+		direct_mask = 0;
+
+	/* We don't build a direct scan probe request; the uCode will do
+	 * that based on the direct_mask added to each channel entry */
+	scan->tx_cmd.len = cpu_to_le16(
+		iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+			IWL_MAX_SCAN_SIZE - sizeof(scan), 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.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	/* flags + rate selection */
+
+	scan->tx_cmd.tx_flags |= cpu_to_le32(0x200);
+
+	switch (priv->scan_bands) {
+	case 2:
+		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,
+				RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
+
+		scan->good_CRC_th = 0;
+		phymode = MODE_IEEE80211G;
+		break;
+
+	case 1:
+		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;
+		phymode = MODE_IEEE80211A;
+		break;
+
+	default:
+		IWL_WARNING("Invalid scan band count\n");
+		goto done;
+	}
+
+	/* select Rx chains */
+
+	/* Force use of chains B and C (0x6) for scan Rx.
+	 * Avoid A (0x1) because of its off-channel reception on A-band.
+	 * MIMO is not used here, but value is required to make uCode happy. */
+	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
+			cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
+			(0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
+			(0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
+
+	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));
+	else
+		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+	scan->channel_count =
+		iwl4965_get_channels_for_scan(
+			priv, phymode, 1, /* active */
+			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);
+	cmd.data = scan;
+	scan->len = cpu_to_le16(cmd.len);
+
+	set_bit(STATUS_SCAN_HW, &priv->status);
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
+	if (rc)
+		goto done;
+
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IWL_SCAN_CHECK_WATCHDOG);
+
+	mutex_unlock(&priv->mutex);
+	return;
+
+ done:
+	/* inform mac80211 scan aborted */
+	queue_work(priv->workqueue, &priv->scan_completed);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_up(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	__iwl4965_up(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_restart(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	iwl4965_down(priv);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl4965_bg_rx_replenish(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl4965_rx_replenish(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
+static void iwl4965_bg_post_associate(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	int rc = 0;
+	struct ieee80211_conf *conf = NULL;
+	DECLARE_MAC_BUF(mac);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+		return;
+	}
+
+	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+			priv->assoc_id,
+			print_mac(mac, priv->active_rxon.bssid_addr));
+
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!priv->interface_id || !priv->is_open) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+	iwl4965_scan_cancel_timeout(priv, 200);
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl4965_commit_rxon(priv);
+
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
+	iwl4965_setup_rxon_timing(priv);
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+			      sizeof(priv->rxon_timing), &priv->rxon_timing);
+	if (rc)
+		IWL_WARNING("REPLY_RXON_TIMING failed - "
+			    "Attempting to continue.\n");
+
+	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+#ifdef CONFIG_IWL4965_HT
+	if (priv->current_ht_config.is_ht)
+		iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
+#endif /* CONFIG_IWL4965_HT*/
+	iwl4965_set_rxon_chain(priv);
+	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+	IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+			priv->assoc_id, priv->beacon_int);
+
+	if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+	}
+
+	iwl4965_commit_rxon(priv);
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_STA:
+		iwl4965_rate_scale_init(priv->hw, IWL_AP_ID);
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+
+		/* clear out the station table */
+		iwl4965_clear_stations_table(priv);
+
+		iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
+		iwl4965_rxon_add_station(priv, priv->bssid, 0);
+		iwl4965_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl4965_send_beacon_cmd(priv);
+
+		break;
+
+	default:
+		IWL_ERROR("%s Should not be called in %d mode\n",
+				__FUNCTION__, priv->iw_mode);
+		break;
+	}
+
+	iwl4965_sequence_reset(priv);
+
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	/* Enable Rx differential gain and sensitivity calibrations */
+	iwl4965_chain_noise_reset(priv);
+	priv->start_calib = 1;
+#endif /* CONFIG_IWL4965_SENSITIVITY */
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		priv->assoc_station_added = 1;
+
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_activate_qos(priv, 0);
+#endif /* CONFIG_IWL4965_QOS */
+	/* we have just associated, don't start scan too early */
+	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl4965_bg_abort_scan(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	if (!iwl4965_is_ready(priv))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_SCAN_ABORTING, &priv->status);
+	iwl4965_send_scan_abort(priv);
+
+	mutex_unlock(&priv->mutex);
+}
+
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+static void iwl4965_bg_scan_completed(void *p)
+{
+	struct iwl4965_priv *priv = p;
+
+	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (priv->cache_conf)
+		iwl4965_mac_config(priv->hw, priv->cache_conf);
+
+	ieee80211_scan_completed(priv->hw);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	mutex_lock(&priv->mutex);
+	iwl4965_hw_reg_send_txpower(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl4965_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	/* we should be verifying the device is ready to be opened */
+	mutex_lock(&priv->mutex);
+
+	priv->is_open = 1;
+
+	if (!iwl4965_is_rfkill(priv))
+		ieee80211_start_queues(priv->hw);
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static void iwl4965_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+
+	mutex_lock(&priv->mutex);
+	/* stop mac, cancel any scan request and clear
+	 * RXON_FILTER_ASSOC_MSK BIT
+	 */
+	priv->is_open = 0;
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	iwl4965_scan_cancel_timeout(priv, 100);
+	cancel_delayed_work(&priv->post_associate);
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl4965_commit_rxon(priv);
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct ieee80211_tx_control *ctl)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		IWL_DEBUG_MAC80211("leave - monitor\n");
+		return -1;
+	}
+
+	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+		     ctl->tx_rate);
+
+	if (iwl4965_tx_skb(priv, skb, ctl))
+		dev_kfree_skb_any(skb);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+
+	if (priv->interface_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->interface_id = conf->if_id;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+
+	if (conf->mac_addr) {
+		IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
+		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+	}
+	iwl4965_set_mode(priv, conf->type);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/**
+ * iwl4965_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	const struct iwl4965_channel_info *ch_info;
+	unsigned long flags;
+	int ret = 0;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+	if (!iwl4965_is_ready(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+	 * what is exposed through include/ declarations */
+	if (unlikely(!iwl4965_param_disable_hw_scan &&
+		     test_bit(STATUS_SCANNING, &priv->status))) {
+
+		if (unlikely(priv->cache_conf))
+			IWL_DEBUG_MAC80211("leave - still scanning\n");
+		else {
+			/* Cache the configuration now so that we can
+			 * replay it after the hardware scan is finished. */
+			priv->cache_conf = kmalloc(sizeof(*conf), GFP_KERNEL);
+			if (priv->cache_conf) {
+				memcpy(priv->cache_conf, conf, sizeof(*conf));
+				IWL_DEBUG_MAC80211("leave - scanning\n");
+			} else {
+				IWL_DEBUG_MAC80211("leave - no memory\n");
+				ret = -ENOMEM;
+			}
+		}
+		mutex_unlock(&priv->mutex);
+		return ret;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel);
+	if (!is_channel_valid(ch_info)) {
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+			       conf->channel, conf->phymode);
+		IWL_DEBUG_MAC80211("leave - invalid channel\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		ret = -EINVAL;
+		goto out;
+	}
+
+#ifdef CONFIG_IWL4965_HT
+	/* if we are switching fron ht to 2.4 clear flags
+	 * from any ht related info since 2.4 does not
+	 * support ht */
+	if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel)
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	    && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
+#endif
+	)
+		priv->staging_rxon.flags = 0;
+#endif /* CONFIG_IWL4965_HT */
+
+	iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+	iwl4965_set_flags_for_phymode(priv, conf->phymode);
+
+	/* The list of supported rates and rate mask can be different
+	 * for each phymode; since the phymode may have changed, reset
+	 * the rate mask to what mac80211 lists */
+	iwl4965_set_rate(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+		iwl4965_hw_channel_switch(priv, conf->channel);
+		goto out;
+	}
+#endif
+
+	iwl4965_radio_kill_sw(priv, !conf->radio_enabled);
+
+	if (!conf->radio_enabled) {
+		IWL_DEBUG_MAC80211("leave - radio disabled\n");
+		goto out;
+	}
+
+	if (iwl4965_is_rfkill(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF kill\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	iwl4965_set_rate(priv);
+
+	if (memcmp(&priv->active_rxon,
+		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
+		iwl4965_commit_rxon(priv);
+	else
+		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out:
+	if (priv->cache_conf) {
+		kfree(priv->cache_conf);
+		priv->cache_conf = NULL;
+	}
+	mutex_unlock(&priv->mutex);
+	return ret;
+}
+
+static void iwl4965_config_ap(struct iwl4965_priv *priv)
+{
+	int rc = 0;
+
+	if (priv->status & STATUS_EXIT_PENDING)
+		return;
+
+	/* The following should be done only at AP bring up */
+	if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+		/* RXON - unassoc (to set timing command) */
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+
+		/* RXON Timing */
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
+		iwl4965_setup_rxon_timing(priv);
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+				sizeof(priv->rxon_timing), &priv->rxon_timing);
+		if (rc)
+			IWL_WARNING("REPLY_RXON_TIMING failed - "
+					"Attempting to continue.\n");
+
+		iwl4965_set_rxon_chain(priv);
+
+		/* FIXME: what should be the assoc_id for AP? */
+		priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+			priv->staging_rxon.flags |=
+				RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &=
+				~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+			if (priv->assoc_capability &
+				WLAN_CAPABILITY_SHORT_SLOT_TIME)
+				priv->staging_rxon.flags |=
+					RXON_FLG_SHORT_SLOT_MSK;
+			else
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+
+			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+		}
+		/* restore RXON assoc */
+		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+#ifdef CONFIG_IWL4965_QOS
+		iwl4965_activate_qos(priv, 1);
+#endif
+		iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
+	}
+	iwl4965_send_beacon_cmd(priv);
+
+	/* FIXME - we need to add code here to detect a totally new
+	 * configuration, reset the AP, unassoc, rxon timing, assoc,
+	 * clear sta table, add BCAST sta... */
+}
+
+static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
+	int rc;
+
+	if (conf == NULL)
+		return -EIO;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!conf->beacon || !conf->ssid_len)) {
+		IWL_DEBUG_MAC80211
+		    ("Leaving in AP mode because HostAPD is not ready.\n");
+		return 0;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+	if (conf->bssid)
+		IWL_DEBUG_MAC80211("bssid: %s\n",
+				   print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->interface_id != if_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (!conf->bssid) {
+			conf->bssid = priv->mac_addr;
+			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+					   print_mac(mac, conf->bssid));
+		}
+		if (priv->ibss_beacon)
+			dev_kfree_skb(priv->ibss_beacon);
+
+		priv->ibss_beacon = conf->beacon;
+	}
+
+	if (iwl4965_is_rfkill(priv))
+		goto done;
+
+	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+	    !is_multicast_ether_addr(conf->bssid)) {
+		/* If there is currently a HW scan going on in the background
+		 * then we need to cancel it else the RXON below will fail. */
+		if (iwl4965_scan_cancel_timeout(priv, 100)) {
+			IWL_WARNING("Aborted scan still in progress "
+				    "after 100ms\n");
+			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+			mutex_unlock(&priv->mutex);
+			return -EAGAIN;
+		}
+		memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+		/* TODO: Audit driver for usage of these members and see
+		 * if mac80211 deprecates them (priv->bssid looks like it
+		 * shouldn't be there, but I haven't scanned the IBSS code
+		 * to verify) - jpk */
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl4965_config_ap(priv);
+		else {
+			rc = iwl4965_commit_rxon(priv);
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+				iwl4965_rxon_add_station(
+					priv, priv->active_rxon.bssid_addr, 1);
+		}
+
+	} else {
+		iwl4965_scan_cancel_timeout(priv, 100);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+	}
+
+ done:
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!conf->ssid_len)
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+	else
+		memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+	priv->essid_len = conf->ssid_len;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl4965_configure_filter(struct ieee80211_hw *hw,
+				 unsigned int changed_flags,
+				 unsigned int *total_flags,
+				 int mc_count, struct dev_addr_list *mc_list)
+{
+	/*
+	 * XXX: dummy
+	 * see also iwl4965_connection_init_rx_config
+	 */
+	*total_flags = 0;
+}
+
+static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+
+	if (iwl4965_is_ready_rf(priv)) {
+		iwl4965_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+	}
+	if (priv->interface_id == conf->if_id) {
+		priv->interface_id = 0;
+		memset(priv->bssid, 0, ETH_ALEN);
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+		priv->essid_len = 0;
+	}
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+static void iwl4965_mac_erp_ie_changed(struct ieee80211_hw *hw,
+		u8 changes, int cts_protection, int preamble)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	if (changes & IEEE80211_ERP_CHANGE_PREAMBLE) {
+		if (preamble == WLAN_ERP_PREAMBLE_SHORT)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	}
+
+	if (changes & IEEE80211_ERP_CHANGE_PROTECTION) {
+		if (cts_protection && (priv->phymode != MODE_IEEE80211A))
+			priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+	}
+
+	if (iwl4965_is_associated(priv))
+		iwl4965_send_rxon_assoc(priv);
+}
+
+static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		rc = -EIO;
+		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+		goto out_unlock;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
+		rc = -EIO;
+		IWL_ERROR("ERROR: APs don't scan\n");
+		goto out_unlock;
+	}
+
+	/* we don't schedule scan within next_scan_jiffies period */
+	if (priv->next_scan_jiffies &&
+			time_after(priv->next_scan_jiffies, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	/* if we just finished scan ask for delay */
+	if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
+				IWL_DELAY_NEXT_SCAN, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	if (len) {
+		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
+			       iwl4965_escape_essid(ssid, len), (int)len);
+
+		priv->one_direct_scan = 1;
+		priv->direct_ssid_len = (u8)
+		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+	} else
+		priv->one_direct_scan = 0;
+
+	rc = iwl4965_scan_initiate(priv);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   const u8 *local_addr, const u8 *addr,
+			   struct ieee80211_key_conf *key)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	int rc = 0;
+	u8 sta_id;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl4965_param_hwcrypto) {
+		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (is_zero_ether_addr(addr))
+		/* only support pairwise keys */
+		return -EOPNOTSUPP;
+
+	sta_id = iwl4965_hw_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+				   print_mac(mac, addr));
+		return -EINVAL;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	iwl4965_scan_cancel_timeout(priv, 100);
+
+	switch (cmd) {
+	case  SET_KEY:
+		rc = iwl4965_update_sta_key_info(priv, key, sta_id);
+		if (!rc) {
+			iwl4965_set_rxon_hwcrypto(priv, 1);
+			iwl4965_commit_rxon(priv);
+			key->hw_key_idx = sta_id;
+			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		}
+		break;
+	case DISABLE_KEY:
+		rc = iwl4965_clear_sta_key_info(priv, sta_id);
+		if (!rc) {
+			iwl4965_set_rxon_hwcrypto(priv, 0);
+			iwl4965_commit_rxon(priv);
+			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl4965_priv *priv = hw->priv;
+#ifdef CONFIG_IWL4965_QOS
+	unsigned long flags;
+	int q;
+#endif /* CONFIG_IWL4965_QOS */
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	if (queue >= AC_NUM) {
+		IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+		return 0;
+	}
+
+#ifdef CONFIG_IWL4965_QOS
+	if (!priv->qos_data.qos_enable) {
+		priv->qos_data.qos_active = 0;
+		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+		return 0;
+	}
+	q = AC_NUM - 1 - queue;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+	priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+	priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+	priv->qos_data.def_qos_parm.ac[q].edca_txop =
+			cpu_to_le16((params->burst_time * 100));
+
+	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+	priv->qos_data.qos_active = 1;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		iwl4965_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl4965_is_associated(priv))
+		iwl4965_activate_qos(priv, 0);
+
+	mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWL4965_QOS */
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	int i, avail;
+	struct iwl4965_tx_queue *txq;
+	struct iwl4965_queue *q;
+	unsigned long flags;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (i = 0; i < AC_NUM; i++) {
+		txq = &priv->txq[i];
+		q = &txq->q;
+		avail = iwl4965_queue_space(q);
+
+		stats->data[i].len = q->n_window - avail;
+		stats->data[i].limit = q->n_window - q->high_mark;
+		stats->data[i].count = q->n_window;
+
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
+			     struct ieee80211_low_level_stats *stats)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWL4965_HT
+	spin_lock_irqsave(&priv->lock, flags);
+	memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
+	spin_unlock_irqrestore(&priv->lock, flags);
+#ifdef CONFIG_IWL4965_HT_AGG
+/*	if (priv->lq_mngr.agg_ctrl.granted_ba)
+		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
+
+	memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control));
+	priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
+	priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
+	priv->lq_mngr.agg_ctrl.auto_agg = 1;
+
+	if (priv->lq_mngr.agg_ctrl.auto_agg)
+		priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_reset_qos(priv);
+#endif
+
+	cancel_delayed_work(&priv->post_associate);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = 0;
+	priv->assoc_capability = 0;
+	priv->call_post_assoc_from_beacon = 0;
+	priv->assoc_station_added = 0;
+
+	/* new association get rid of ibss beacon skb */
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = NULL;
+
+	priv->beacon_int = priv->hw->conf.beacon_int;
+	priv->timestamp1 = 0;
+	priv->timestamp0 = 0;
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		priv->beacon_int = 0;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	/* we are restarting association process
+	 * clear RXON_FILTER_ASSOC_MSK bit
+	 */
+	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+		iwl4965_scan_cancel_timeout(priv, 100);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+	}
+
+	/* Per mac80211.h: This is only used in IBSS mode... */
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+
+		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	priv->only_active_channel = 0;
+
+	iwl4965_set_rate(priv);
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+				 struct ieee80211_tx_control *control)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = skb;
+
+	priv->assoc_id = 0;
+
+	IWL_DEBUG_MAC80211("leave\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_reset_qos(priv);
+#endif
+
+	queue_work(priv->workqueue, &priv->post_associate);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_IWL4965_HT
+
+static void iwl4965_ht_info_fill(struct ieee80211_conf *conf,
+				 struct iwl4965_priv *priv)
+{
+	struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+	struct ieee80211_ht_info *ht_conf = &conf->ht_conf;
+	struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf;
+
+	IWL_DEBUG_MAC80211("enter: \n");
+
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) {
+		iwl_conf->is_ht = 0;
+		return;
+	}
+
+	iwl_conf->is_ht = 1;
+	priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+		iwl_conf->sgf |= 0x1;
+	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+		iwl_conf->sgf |= 0x2;
+
+	iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+	iwl_conf->max_amsdu_size =
+		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+	iwl_conf->supported_chan_width =
+		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+	iwl_conf->tx_mimo_ps_mode =
+		(u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+	iwl_conf->control_channel = ht_bss_conf->primary_channel;
+	iwl_conf->extension_chan_offset =
+		ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+	iwl_conf->tx_chan_width =
+		!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+	iwl_conf->ht_protection =
+		ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+	iwl_conf->non_GF_STA_present =
+		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+	IWL_DEBUG_MAC80211("control channel %d\n",
+		iwl_conf->control_channel);
+	IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
+			       struct ieee80211_conf *conf)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter: \n");
+
+	iwl4965_ht_info_fill(conf, priv);
+	iwl4965_set_rxon_chain(priv);
+
+	if (priv && priv->assoc_id &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->lock, flags);
+		if (priv->beacon_int)
+			queue_work(priv->workqueue, &priv->post_associate.work);
+		else
+			priv->call_post_assoc_from_beacon = 1;
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+
+	IWL_DEBUG_MAC80211("leave:\n");
+	return 0;
+}
+
+static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
+			struct ieee80211_ht_cap *ht_cap,
+			u8 use_current_config)
+{
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_hw_mode *mode = conf->mode;
+
+	if (use_current_config) {
+		ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap);
+		memcpy(ht_cap->supp_mcs_set,
+				conf->ht_conf.supp_mcs_set, 16);
+	} else {
+		ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap);
+		memcpy(ht_cap->supp_mcs_set,
+				mode->ht_info.supp_mcs_set, 16);
+	}
+	ht_cap->ampdu_params_info =
+		(mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+		((mode->ht_info.ampdu_density << 2) &
+					IEEE80211_HT_CAP_AMPDU_DENSITY);
+}
+
+#endif /*CONFIG_IWL4965_HT*/
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWL4965_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+	return sprintf(buf, "0x%08X\n", iwl4965_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+				 const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 0);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in hex or decimal form.\n", buf);
+	else
+		iwl4965_debug_level = val;
+
+	return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+		   show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWL4965_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 iwl4965_priv *priv = (struct iwl4965_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 iwl4965_priv *priv = (struct iwl4965_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)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+
+	if (!iwl4965_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", iwl4965_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct iwl4965_priv *priv = d->driver_data;
+	return iwl4965_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 10);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in decimal form.\n", buf);
+	else
+		iwl4965_hw_reg_set_txpower(priv, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	u32 flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+		/* Cancel any currently running scans... */
+		if (iwl4965_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+				       flags);
+			priv->staging_rxon.flags = cpu_to_le32(flags);
+			iwl4965_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+		/* Cancel any currently running scans... */
+		if (iwl4965_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+				       "0x%04X\n", filter_flags);
+			priv->staging_rxon.filter_flags =
+				cpu_to_le32(filter_flags);
+			iwl4965_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+		   store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		       (priv->phymode << 8) |
+			le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+			  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u16 tune = simple_strtoul(p, &p, 0);
+	u8 phymode = (tune >> 8) & 0xff;
+	u16 channel = tune & 0xff;
+
+	IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+	mutex_lock(&priv->mutex);
+	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+	    (priv->phymode != phymode)) {
+		const struct iwl4965_channel_info *ch_info;
+
+		ch_info = iwl4965_get_channel_info(priv, phymode, channel);
+		if (!ch_info) {
+			IWL_WARNING("Requested invalid phymode/channel "
+				    "combination: %d %d\n", phymode, channel);
+			mutex_unlock(&priv->mutex);
+			return -EINVAL;
+		}
+
+		/* Cancel any currently running scans... */
+		if (iwl4965_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing phymode and "
+				       "rxon.channel = %d %d\n",
+				       phymode, channel);
+
+			iwl4965_set_rxon_channel(priv, phymode, channel);
+			iwl4965_set_flags_for_phymode(priv, phymode);
+
+			iwl4965_set_rate(priv);
+			iwl4965_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_spectrum_notification measure_report;
+	u32 size = sizeof(measure_report), len = 0, ofs = 0;
+	u8 *data = (u8 *) & measure_report;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!(priv->measurement_status & MEASUREMENT_READY)) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return 0;
+	}
+	memcpy(&measure_report, &priv->measure_report, size);
+	priv->measurement_status = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	struct ieee80211_measurement_params params = {
+		.channel = le16_to_cpu(priv->active_rxon.channel),
+		.start_time = cpu_to_le64(priv->last_tsf),
+		.duration = cpu_to_le16(1),
+	};
+	u8 type = IWL_MEASURE_BASIC;
+	u8 buffer[32];
+	u8 channel;
+
+	if (count) {
+		char *p = buffer;
+		strncpy(buffer, buf, min(sizeof(buffer), count));
+		channel = simple_strtoul(p, NULL, 0);
+		if (channel)
+			params.channel = channel;
+
+		p = buffer;
+		while (*p && *p != ' ')
+			p++;
+		if (*p)
+			type = simple_strtoul(p + 1, NULL, 0);
+	}
+
+	IWL_DEBUG_INFO("Invoking measurement of type %d on "
+		       "channel %d (for '%s')\n", type, params.channel, buf);
+	iwl4965_get_measurement(priv, &params, type);
+
+	return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+		   show_measurement, store_measurement);
+#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */
+
+static ssize_t store_retry_rate(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+
+	priv->retry_rate = simple_strtoul(buf, NULL, 0);
+	if (priv->retry_rate <= 0)
+		priv->retry_rate = 1;
+
+	return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+		   store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	int rc;
+	int mode;
+
+	mode = simple_strtoul(buf, NULL, 0);
+	mutex_lock(&priv->mutex);
+
+	if (!iwl4965_is_ready(priv)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+		mode = IWL_POWER_AC;
+	else
+		mode |= IWL_POWER_ENABLED;
+
+	if (mode != priv->power_mode) {
+		rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		if (rc) {
+			IWL_DEBUG_MAC80211("failed setting power mode.\n");
+			goto out;
+		}
+		priv->power_mode = mode;
+	}
+
+	rc = count;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+	350000,
+	250000,
+	75000,
+	37000,
+	25000,
+};
+static const s32 period_duration[] = {
+	400000,
+	700000,
+	1000000,
+	1000000,
+	1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	int level = IWL_POWER_LEVEL(priv->power_mode);
+	char *p = buf;
+
+	p += sprintf(p, "%d ", level);
+	switch (level) {
+	case IWL_POWER_MODE_CAM:
+	case IWL_POWER_AC:
+		p += sprintf(p, "(AC)");
+		break;
+	case IWL_POWER_BATTERY:
+		p += sprintf(p, "(BATTERY)");
+		break;
+	default:
+		p += sprintf(p,
+			     "(Timeout %dms, Period %dms)",
+			     timeout_duration[level - 1] / 1000,
+			     period_duration[level - 1] / 1000);
+	}
+
+	if (!(priv->power_mode & IWL_POWER_ENABLED))
+		p += sprintf(p, " OFF\n");
+	else
+		p += sprintf(p, " \n");
+
+	return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+		   store_power_level);
+
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	int len = 0, i;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode = NULL;
+	int count = 0;
+
+	if (!iwl4965_is_ready(priv))
+		return -EAGAIN;
+
+	hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G);
+	if (!hw_mode)
+		hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	}
+
+	len +=
+	    sprintf(&buf[len],
+		    "Displaying %d channels in 2.4GHz band "
+		    "(802.11bg):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	} else {
+		channels = NULL;
+		count = 0;
+	}
+
+	len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+		       "(802.11a):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl4965_notif_statistics);
+	u32 len = 0, ofs = 0;
+	u8 *data = (u8 *) & priv->statistics;
+	int rc = 0;
+
+	if (!iwl4965_is_alive(priv))
+		return -EAGAIN;
+
+	mutex_lock(&priv->mutex);
+	rc = iwl4965_send_statistics_request(priv);
+	mutex_unlock(&priv->mutex);
+
+	if (rc) {
+		len = sprintf(buf,
+			      "Error sending statistics request: 0x%08X\n", rc);
+		return len;
+	}
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+
+	if (!iwl4965_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int ant;
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+
+	if (count == 0)
+		return 0;
+
+	if (sscanf(buf, "%1i", &ant) != 1) {
+		IWL_DEBUG_INFO("not in hex or decimal form.\n");
+		return count;
+	}
+
+	if ((ant >= 0) && (ant <= 2)) {
+		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+		priv->antenna = (enum iwl4965_antenna)ant;
+	} else
+		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+	return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+			   struct device_attribute *attr, char *buf)
+{
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	if (!iwl4965_is_alive(priv))
+		return -EAGAIN;
+	return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl4965_dump_nic_error_log((struct iwl4965_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl4965_dump_nic_event_log((struct iwl4965_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl4965_setup_deferred_work(struct iwl4965_priv *priv)
+{
+	priv->workqueue = create_workqueue(DRV_NAME);
+
+	init_waitqueue_head(&priv->wait_command_queue);
+
+	INIT_WORK(&priv->up, iwl4965_bg_up, priv);
+	INIT_WORK(&priv->restart, iwl4965_bg_restart, priv);
+	INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish, priv);
+	INIT_WORK(&priv->scan_completed, iwl4965_bg_scan_completed, priv);
+	INIT_WORK(&priv->request_scan, iwl4965_bg_request_scan, priv);
+	INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan, priv);
+	INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill, priv);
+	INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update, priv);
+	INIT_WORK(&priv->post_associate, iwl4965_bg_post_associate, priv);
+	INIT_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start, priv);
+	INIT_WORK(&priv->alive_start, iwl4965_bg_alive_start, priv);
+	INIT_WORK(&priv->scan_check, iwl4965_bg_scan_check, priv);
+
+	iwl4965_hw_setup_deferred_work(priv);
+
+	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+		     iwl4965_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv)
+{
+	iwl4965_hw_cancel_deferred_work(priv);
+
+#if 0 /* Not in RHEL5...(and probably wrong upstream...) */
+	cancel_delayed_work_sync(&priv->init_alive_start);
+#else
+	cancel_delayed_work(&priv->init_alive_start);
+	/* Make sure he has completed, since he can schedule other work */
+	flush_workqueue(priv->workqueue);
+#endif
+	cancel_delayed_work(&priv->scan_check);
+	cancel_delayed_work(&priv->alive_start);
+	cancel_delayed_work(&priv->post_associate);
+#if 0 /* Not in RHEL5... */
+	cancel_work_sync(&priv->beacon_update);
+#else
+	flush_workqueue(priv->workqueue);
+#endif
+}
+
+static struct attribute *iwl4965_sysfs_entries[] = {
+	&dev_attr_antenna.attr,
+	&dev_attr_channels.attr,
+	&dev_attr_dump_errors.attr,
+	&dev_attr_dump_events.attr,
+	&dev_attr_flags.attr,
+	&dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+	&dev_attr_measurement.attr,
+#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,
+	&dev_attr_temperature.attr,
+	&dev_attr_tune.attr,
+	&dev_attr_tx_power.attr,
+
+	NULL
+};
+
+static struct attribute_group iwl4965_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = iwl4965_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl4965_hw_ops = {
+	.tx = iwl4965_mac_tx,
+	.start = iwl4965_mac_start,
+	.stop = iwl4965_mac_stop,
+	.add_interface = iwl4965_mac_add_interface,
+	.remove_interface = iwl4965_mac_remove_interface,
+	.config = iwl4965_mac_config,
+	.config_interface = iwl4965_mac_config_interface,
+	.configure_filter = iwl4965_configure_filter,
+	.set_key = iwl4965_mac_set_key,
+	.get_stats = iwl4965_mac_get_stats,
+	.get_tx_stats = iwl4965_mac_get_tx_stats,
+	.conf_tx = iwl4965_mac_conf_tx,
+	.get_tsf = iwl4965_mac_get_tsf,
+	.reset_tsf = iwl4965_mac_reset_tsf,
+	.beacon_update = iwl4965_mac_beacon_update,
+	.erp_ie_changed = iwl4965_mac_erp_ie_changed,
+#ifdef CONFIG_IWL4965_HT
+	.conf_ht = iwl4965_mac_conf_ht,
+#ifdef CONFIG_IWL4965_HT_AGG
+	.ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
+	.ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
+	.ht_rx_agg_start = iwl4965_mac_ht_rx_agg_start,
+	.ht_rx_agg_stop = iwl4965_mac_ht_rx_agg_stop,
+#endif  /* CONFIG_IWL4965_HT_AGG */
+#endif  /* CONFIG_IWL4965_HT */
+	.hw_scan = iwl4965_mac_hw_scan
+};
+
+static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = 0;
+	struct iwl4965_priv *priv;
+	struct ieee80211_hw *hw;
+	int i;
+
+	/* Disabling hardware scan means that mac80211 will perform scans
+	 * "the hard way", rather than using device's scan. */
+	if (iwl4965_param_disable_hw_scan) {
+		IWL_DEBUG_INFO("Disabling hw_scan\n");
+		iwl4965_hw_ops.hw_scan = NULL;
+	}
+
+	if ((iwl4965_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl4965_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	hw = ieee80211_alloc_hw(sizeof(struct iwl4965_priv), &iwl4965_hw_ops);
+	if (hw == NULL) {
+		IWL_ERROR("Can not allocate network device\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+
+	hw->rate_control_algorithm = "iwl-4965-rs";
+
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	priv = hw->priv;
+	priv->hw = hw;
+
+	priv->pci_dev = pdev;
+	priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna;
+#ifdef CONFIG_IWL4965_DEBUG
+	iwl4965_debug_level = iwl4965_param_debug;
+	atomic_set(&priv->restrict_refcnt, 0);
+#endif
+	priv->retry_rate = 1;
+
+	priv->ibss_beacon = NULL;
+
+	/* Tell mac80211 and its clients (e.g. Wireless Extensions)
+	 *   the range of signal quality values that we'll provide.
+	 * Negative values for level/noise indicate that we'll provide dBm.
+	 * For WE, at least, non-0 values here *enable* display of values
+	 *   in app (iwconfig). */
+	hw->max_rssi = -20;	/* signal level, negative indicates dBm */
+	hw->max_noise = -20;	/* noise level, negative indicates dBm */
+	hw->max_signal = 100;	/* link quality indication (%) */
+
+	/* Tell mac80211 our Tx characteristics */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+	/* Default value; 4 EDCA QOS priorities */
+	hw->queues = 4;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	/* Enhanced value; more queues, to support 11n aggregation */
+	hw->queues = 16;
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+	spin_lock_init(&priv->lq_mngr.lock);
+
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+
+	mutex_init(&priv->mutex);
+	if (pci_enable_device(pdev)) {
+		err = -ENODEV;
+		goto out_ieee80211_free_hw;
+	}
+
+	pci_set_master(pdev);
+
+	/* Clear the driver's (not device's) station table */
+	iwl4965_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->phymode = -1;
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err) {
+		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+		goto out_pci_disable_device;
+	}
+
+	pci_set_drvdata(pdev, priv);
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err)
+		goto out_pci_disable_device;
+
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	priv->hw_base = pci_iomap(pdev, 0, 0);
+	if (!priv->hw_base) {
+		err = -ENODEV;
+		goto out_pci_release_regions;
+	}
+
+	IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+			(unsigned long long) pci_resource_len(pdev, 0));
+	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+	/* Initialize module parameter values here */
+
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl4965_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
+	}
+
+	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+	priv->ps_mode = 0;
+	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+	priv->valid_antenna = 0x7;	/* assume all 3 connected */
+	priv->ps_mode = IWL_MIMO_PS_NONE;
+
+	/* Choose which receivers/antennas to use */
+	iwl4965_set_rxon_chain(priv);
+
+	printk(KERN_INFO DRV_NAME
+	       ": Detected Intel Wireless WiFi Link 4965AGN\n");
+
+	/* Device-specific setup */
+	if (iwl4965_hw_set_hw_setting(priv)) {
+		IWL_ERROR("failed to set hw settings\n");
+		mutex_unlock(&priv->mutex);
+		goto out_iounmap;
+	}
+
+#ifdef CONFIG_IWL4965_QOS
+	if (iwl4965_param_qos_enable)
+		priv->qos_data.qos_enable = 1;
+
+	iwl4965_reset_qos(priv);
+
+	priv->qos_data.qos_active = 0;
+	priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWL4965_QOS */
+
+	iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl4965_setup_deferred_work(priv);
+	iwl4965_setup_rx_handlers(priv);
+
+	priv->rates_mask = IWL_RATES_MASK;
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IWL_POWER_AC;
+	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+	iwl4965_disable_interrupts(priv);
+
+	pci_enable_msi(pdev);
+
+	err = request_irq(pdev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv);
+	if (err) {
+		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+		goto out_disable_msi;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+	if (err) {
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		mutex_unlock(&priv->mutex);
+		goto out_release_irq;
+	}
+
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
+	err = iwl4965_read_ucode(priv);
+	if (err) {
+		IWL_ERROR("Could not read microcode: %d\n", err);
+		mutex_unlock(&priv->mutex);
+		goto out_pci_alloc;
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_INFO("Queueing UP work.\n");
+
+	queue_work(priv->workqueue, &priv->up);
+
+	return 0;
+
+ out_pci_alloc:
+	iwl4965_dealloc_ucode_pci(priv);
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+
+ out_release_irq:
+	free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+	pci_disable_msi(pdev);
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+	iwl4965_unset_hw_setting(priv);
+
+ out_iounmap:
+	pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+	pci_release_regions(pdev);
+ out_pci_disable_device:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+	ieee80211_free_hw(priv->hw);
+ out:
+	return err;
+}
+
+static void iwl4965_pci_remove(struct pci_dev *pdev)
+{
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
+	struct list_head *p, *q;
+	int i;
+
+	if (!priv)
+		return;
+
+	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+	mutex_lock(&priv->mutex);
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl4965_down(priv);
+	mutex_unlock(&priv->mutex);
+
+	/* 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]) {
+			list_del(p);
+			kfree(list_entry(p, struct iwl4965_ibss_seq, list));
+		}
+	}
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+
+	iwl4965_dealloc_ucode_pci(priv);
+
+	if (priv->rxq.bd)
+		iwl4965_rx_queue_free(priv, &priv->rxq);
+	iwl4965_hw_txq_ctx_free(priv);
+
+	iwl4965_unset_hw_setting(priv);
+	iwl4965_clear_stations_table(priv);
+
+	if (priv->mac80211_registered) {
+		ieee80211_unregister_hw(priv->hw);
+		iwl4965_rate_control_unregister(priv->hw);
+	}
+
+	/*netif_stop_queue(dev); */
+	flush_workqueue(priv->workqueue);
+
+	/* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes
+	 * priv->workqueue... so we can't take down the workqueue
+	 * until now... */
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	free_irq(pdev->irq, priv);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, priv->hw_base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(priv->channel_info);
+
+	kfree(priv->ieee_channels);
+	kfree(priv->ieee_rates);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+	/* Take down the device; powers it off, etc. */
+	__iwl4965_down(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl4965_resume(struct iwl4965_priv *priv)
+{
+	unsigned long flags;
+
+	/* The following it a temporary work around due to the
+	 * suspend / resume not fully initializing the NIC correctly.
+	 * Without all of the following, resume will not attempt to take
+	 * down the NIC (it shouldn't really need to) and will just try
+	 * and bring the NIC back up.  However that fails during the
+	 * ucode verification process.  This then causes iwl4965_down to be
+	 * called *after* iwl4965_hw_nic_init() has succeeded -- which
+	 * then lets the next init sequence succeed.  So, we've
+	 * replicated all of that NIC init code here... */
+
+	iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	iwl4965_hw_nic_init(priv);
+
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+	iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+	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);
+
+	/* tell the device to stop sending interrupts */
+	iwl4965_disable_interrupts(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl4965_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	if (!iwl4965_grab_nic_access(priv)) {
+		iwl4965_write_prph(priv, APMG_CLK_DIS_REG,
+				APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl4965_release_nic_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl4965_hw_nic_reset(priv);
+
+	/* Bring the device back up */
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl4965_pci_resume(struct pci_dev *pdev)
+{
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
+	int err;
+
+	printk(KERN_INFO "Coming out of suspend...\n");
+
+	mutex_lock(&priv->mutex);
+
+	pci_set_power_state(pdev, PCI_D0);
+	err = pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	/*
+	 * Suspend/Resume resets the PCI configuration space, so we have to
+	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+	 * from interfering with C3 CPU state. pci_restore_state won't help
+	 * here since it only restores the first 64 bytes pci config header.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	iwl4965_resume(priv);
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl4965_driver = {
+	.name = DRV_NAME,
+	.id_table = iwl4965_hw_card_ids,
+	.probe = iwl4965_pci_probe,
+	.remove = __devexit_p(iwl4965_pci_remove),
+#ifdef CONFIG_PM
+	.suspend = iwl4965_pci_suspend,
+	.resume = iwl4965_pci_resume,
+#endif
+};
+
+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 = pci_register_driver(&iwl4965_driver);
+	if (ret) {
+		IWL_ERROR("Unable to initialize PCI module\n");
+		return ret;
+	}
+#ifdef CONFIG_IWL4965_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;
+	}
+#endif
+
+	return ret;
+}
+
+static void __exit iwl4965_exit(void)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
+#endif
+	pci_unregister_driver(&iwl4965_driver);
+}
+
+module_param_named(antenna, iwl4965_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl4965_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl4965_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+		 "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl4965_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl4965_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl4965_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
+
+module_exit(iwl4965_exit);
+module_init(iwl4965_init);
diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h
index 0d45312..87606dd 100644
--- a/drivers/net/wireless/iwlwifi/iwlwifi.h
+++ b/drivers/net/wireless/iwlwifi/iwlwifi.h
@@ -31,20 +31,31 @@
 #define __iwlwifi_h__
 
 #include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
 #include <net/ieee80211_radiotap.h>
 
+#include "iwl-compat.h"
+
 struct iwl_priv;
 
 /* Hardware specific file defines the PCI IDs table for that hardware module */
 extern struct pci_device_id iwl_hw_card_ids[];
 
 #if IWL == 3945
+
 #define DRV_NAME	"iwl3945"
+#include "iwl-hw.h"
+#include "iwl-3945-hw.h"
+
 #elif IWL == 4965
+
 #define DRV_NAME        "iwl4965"
+#include "iwl-hw.h"
+#include "iwl-4965-hw.h"
+
 #endif
 
-#include "iwl-hw.h"
+#include "iwl-prph.h"
 
 /*
  * Driver implementation data structures, constants, inline
@@ -58,16 +69,28 @@ extern struct pci_device_id iwl_hw_card_ids[];
 
 #include "iwl-debug.h"
 
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
 
 /* Module parameters accessible from iwl-*.c */
-extern int param_disable_hw_scan;
-extern int param_debug;
-extern int param_mode;
-extern int param_disable;
-extern int param_antenna;
-extern int param_hwcrypto;
-extern int param_qos_enable;
-
+extern int iwl_param_disable_hw_scan;
+extern int iwl_param_debug;
+extern int iwl_param_mode;
+extern int iwl_param_disable;
+extern int iwl_param_antenna;
+extern int iwl_param_hwcrypto;
+extern int iwl_param_qos_enable;
+extern int iwl_param_queues_num;
 
 enum iwl_antenna {
 	IWL_ANTENNA_DIVERSITY,
@@ -103,7 +126,7 @@ struct iwl_rt_rx_hdr {
 	__le64 rt_tsf;		/* TSF */
 	u8 rt_flags;		/* radiotap packet flags */
 	u8 rt_rate;		/* rate in 500kb/s */
-	__le16 rt_channel;	/* channel in mHz */
+	__le16 rt_channelMHz;	/* channel in MHz */
 	__le16 rt_chbitmask;	/* channel bitfield */
 	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
 	s8 rt_dbmnoise;
@@ -133,7 +156,6 @@ struct iwl_queue {
 	dma_addr_t dma_addr;   /* physical addr for BD's */
 	int n_window;	       /* safe queue window */
 	u32 id;
-	u32 element_size;
 	int low_mark;	       /* low watermark, resume queue if free
 				* space more than this */
 	int high_mark;         /* high watermark, stop queue if free
@@ -156,7 +178,7 @@ struct iwl_tx_info {
  */
 struct iwl_tx_queue {
 	struct iwl_queue q;
-	u8 *bd;
+	struct iwl_tfd_frame *bd;
 	struct iwl_cmd *cmd;
 	dma_addr_t dma_addr_cmd;
 	struct iwl_tx_info *txb;
@@ -173,14 +195,16 @@ struct iwl_tx_queue {
 #include "iwl-4965-rs.h"
 #endif
 
-#define IWL_TX_QUEUE_AC0	0
-#define IWL_TX_QUEUE_AC1	1
-#define IWL_TX_QUEUE_AC2	2
-#define IWL_TX_QUEUE_AC3	3
-#define IWL_TX_QUEUE_HCCA_1	5
-#define IWL_TX_QUEUE_HCCA_2	6
-#define IWL_TX_QUEUE_NONE	7
-#define IWL_MAX_NUM_QUEUES   16
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
 
 /* Power management (not Tx power) structures */
 
@@ -229,9 +253,10 @@ struct iwl_frame {
 #define SEQ_TO_INDEX(x) (x & 0xff)
 #define INDEX_TO_SEQ(x) (x & 0xff)
 #define SEQ_HUGE_FRAME  (0x4000)
-#define SEQ_RX_FRAME    (0x8000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
 #define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4 ) & IEEE80211_SCTL_SEQ)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
 
 enum {
 	/* CMD_SIZE_NORMAL = 0, */
@@ -240,31 +265,23 @@ enum {
 	CMD_ASYNC = (1 << 1),
 	/* CMD_NO_SKB = 0, */
 	CMD_WANT_SKB = (1 << 2),
-	/* CMD_LOCK = 0, */
-	CMD_NO_LOCK = (1 << 4),
 };
 
 struct iwl_cmd;
 struct iwl_priv;
 
-#define CMD_VAR_MAGIC 0xA987
-
 struct iwl_cmd_meta {
 	struct iwl_cmd_meta *source;
 	union {
 		struct sk_buff *skb;
-		int (*callback)(struct iwl_priv * priv,
-				struct iwl_cmd * cmd, struct sk_buff * skb);
+		int (*callback)(struct iwl_priv *priv,
+				struct iwl_cmd *cmd, struct sk_buff *skb);
 	} __attribute__ ((packed)) u;
 
-	u16 len;
-
 	/* The CMD_SIZE_HUGE flag bit indicates that the command
 	 * structure is stored at the end of the shared queue memory. */
-	u8 flags;
+	u32 flags;
 
-	u8 token;
-	u16 magic;
 } __attribute__ ((packed));
 
 struct iwl_cmd {
@@ -282,10 +299,8 @@ struct iwl_cmd {
 		struct iwl_powertable_cmd powertable;
 		struct iwl_qosparam_cmd qosparam;
 		struct iwl_tx_cmd tx;
-		struct iwl_key_cmd key;
 		struct iwl_tx_beacon_cmd tx_beacon;
 		struct iwl_rxon_assoc_cmd rxon_assoc;
-		struct iwl_rate_scaling_cmd rate_scale;
 		u8 *indirect;
 		u8 payload[360];
 	} __attribute__ ((packed)) cmd;
@@ -304,12 +319,8 @@ struct iwl_host_cmd {
 /*
  * RX related structures and functions
  */
-
-#if IWL == 3945
-#define RX_SPACE_HIGH_MARK	52
-#else
-#define RX_SPACE_HIGH_MARK	210
-#endif
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
 
 #define SUP_RATE_11A_MAX_NUM_CHANNELS  8
 #define SUP_RATE_11B_MAX_NUM_CHANNELS  4
@@ -328,7 +339,7 @@ struct iwl_host_cmd {
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
 struct iwl_rx_queue {
-	void *bd;
+	__le32 *bd;
 	dma_addr_t dma_addr;
 	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
 	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
@@ -352,51 +363,54 @@ struct iwl_rx_queue {
 #define MAX_B_CHANNELS  14
 #define MIN_B_CHANNELS  1
 
-#define STATUS_HCMD_ACTIVE      (1<<0)	/* host command in progress */
-
-#define STATUS_INT_ENABLED      (1<<1)
-#define STATUS_RF_KILL_HW       (1<<2)
-#define STATUS_RF_KILL_SW       (1<<3)
-#define STATUS_RF_KILL_MASK     (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-
-#define STATUS_INIT             (1<<4)
-#define STATUS_ALIVE            (1<<5)
-#define STATUS_READY            (1<<6)
-#define STATUS_TEMPERATURE      (1<<7)
-#define STATUS_GEO_CONFIGURED   (1<<8)
-#define STATUS_EXIT_PENDING     (1<<9)
-#define STATUS_IN_SUSPEND       (1<<10)
-#define STATUS_STATISTICS       (1<<11)
-
-#define STATUS_AUTH             (1<<13)
-
-#define STATUS_DISASSOCIATING   (1<<15)
-
-#define STATUS_ROAMING           (1<<16)
-#define STATUS_SCANNING          (1<<17)
-#define STATUS_SCAN_ABORTING     (1<<19)
-#define STATUS_SCAN_PENDING      (1<<20)
-#define STATUS_SCAN_HW           (1<<21)
-
-#define STATUS_POWER_PMI        (1<<24)
-#define STATUS_RESTRICTED       (1<<26)
-#define STATUS_FW_ERROR         (1<<27)
-
-#define STATUS_TX_MEASURE       (1<<28)
-
-/*todoG need to support adding adhoc station MAX_STATION should be 25 */
-#define IWL_INVALID_STATION     (0xff)
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
 
 #define MAX_TID_COUNT        9
 
 #define IWL_INVALID_RATE     0xFF
 #define IWL_INVALID_VALUE    -1
+
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_ht_agg {
+	u16 txq_id;
+	u16 frame_count;
+	u16 wait_for_ba;
+	u16 start_idx;
+	u32 bitmap0;
+	u32 bitmap1;
+	u32 rate_n_flags;
+};
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+
 struct iwl_tid_data {
 	u16 seq_number;
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
 #ifdef CONFIG_IWLWIFI_HT_AGG
-	s8 txq_id;
-	u8 ht_agg_active;
-#endif				/* CONFIG_IWLWIFI_HT_AGG */
+	struct iwl_ht_agg agg;
+#endif	/* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
 };
 
 struct iwl_hw_key {
@@ -423,10 +437,10 @@ struct sta_ht_info {
 	u8 is_ht;
 	u16 rx_mimo_ps_mode;
 	u16 tx_mimo_ps_mode;
+	u16 control_channel;
 	u8 max_amsdu_size;
 	u8 ampdu_factor;
 	u8 mpdu_density;
-	u8 control_chan;
 	u8 operating_mode;
 	u8 supported_chan_width;
 	u8 extension_chan_offset;
@@ -438,12 +452,44 @@ struct sta_ht_info {
 };
 #endif				/*CONFIG_IWLWIFI_HT */
 
+#ifdef CONFIG_IWLWIFI_QOS
+
+union iwl_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS sturctures */
+struct iwl_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl_qos_capabity qos_cap;
+	struct iwl_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWLWIFI_QOS */
+
 #define STA_PS_STATUS_WAKE             0
 #define STA_PS_STATUS_SLEEP            1
 
 struct iwl_station_entry {
 	struct iwl_addsta_cmd sta;
 	struct iwl_tid_data tid[MAX_TID_COUNT];
+#if IWL == 3945
 	union {
 		struct {
 			u8 rate;
@@ -451,6 +497,7 @@ struct iwl_station_entry {
 		} s;
 		u16 rate_n_flags;
 	} current_rate;
+#endif
 	u8 used;
 	u8 ps_status;
 	struct iwl_hw_key keyinfo;
@@ -466,15 +513,15 @@ struct fw_image_desc {
 /* uCode file layout */
 struct iwl_ucode {
 	__le32 ver;		/* major/minor/subminor */
-	__le32 inst_size;		/* bytes of runtime instructions */
-	__le32 data_size;		/* bytes of runtime data */
-	__le32 init_size;		/* bytes of initialization instructions */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
 	__le32 init_data_size;	/* bytes of initialization data */
-	__le32 boot_size;		/* bytes of bootstrap instructions */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
 	u8 data[0];		/* data in same order as "size" elements */
 };
 
-#define IWL_IBSS_MAC_HASH_SIZE 31
+#define IWL_IBSS_MAC_HASH_SIZE 32
 
 struct iwl_ibss_seq {
 	u8 mac[ETH_ALEN];
@@ -485,35 +532,31 @@ struct iwl_ibss_seq {
 };
 
 struct iwl_driver_hw_info {
-	u16 max_queue_number;
+	u16 max_txq_num;
 	u16 ac_queue_count;
 	u32 rx_buffer_size;
 	u16 tx_cmd_len;
 	u16 max_rxq_size;
 	u16 max_rxq_log;
 	u32 cck_flag;
+	u8  max_stations;
+	u8  bcast_sta_id;
 	void *shared_virt;
 	dma_addr_t shared_phys;
 };
 
 
-#define STA_FLG_RTS_MIMO_PROT_POS	(17)
-#define STA_FLG_RTS_MIMO_PROT_MSK	(1 << STA_FLG_RTS_MIMO_PROT_POS)
-#define STA_FLG_AGG_MPDU_8US_POS	(18)
-#define STA_FLG_AGG_MPDU_8US_MSK	(1 << STA_FLG_AGG_MPDU_8US_POS)
+#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
 #define STA_FLG_MAX_AGG_SIZE_POS	(19)
-#define STA_FLG_MAX_AGG_SIZE_MSK	(3 << STA_FLG_MAX_AGG_SIZE_POS)
-#define STA_FLG_FAT_EN_POS		(21)
-#define STA_FLG_FAT_EN_MSK		(1 << STA_FLG_FAT_EN_POS)
-#define STA_FLG_MIMO_DIS_POS		(22)
-#define STA_FLG_MIMO_DIS_MSK		(1 << STA_FLG_MIMO_DIS_POS)
+#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
 #define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK	(7 << STA_FLG_AGG_MPDU_DENSITY_POS)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
 #define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
 #define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
 
-#include "iwl-3945.h"
-#include "iwl-4965.h"
 
 #include "iwl-priv.h"
 
@@ -532,7 +575,7 @@ struct iwl_driver_hw_info {
 
 /******************************************************************************
  *
- * Functions implemented in base.c which are forward declared here
+ * Functions implemented in iwl-base.c which are forward declared here
  * for use by iwl-*.c
  *
  *****************************************************************************/
@@ -540,7 +583,7 @@ struct iwl_addsta_cmd;
 extern int iwl_send_add_station(struct iwl_priv *priv,
 				struct iwl_addsta_cmd *sta, u8 flags);
 extern const char *iwl_get_tx_fail_reason(u32 status);
-extern u8 iwl_add_station(struct iwl_priv *priv, const u8 * bssid,
+extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid,
 			  int is_ap, u8 flags);
 extern int iwl_is_network_packet(struct iwl_priv *priv,
 				 struct ieee80211_hdr *header);
@@ -574,26 +617,31 @@ extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm);
 extern int iwl_tx_queue_init(struct iwl_priv *priv,
 			     struct iwl_tx_queue *txq, int count, u32 id);
 extern int iwl_rx_queue_restock(struct iwl_priv *priv);
-extern void iwl_rx_replenish(void *data, u8 do_lock);
+extern void iwl_rx_replenish(void *data);
 extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
 			    const void *data);
+extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv,
+		struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
+		struct iwl_host_cmd *cmd);
 extern int __must_check iwl_send_cmd(struct iwl_priv *priv,
-				     struct iwl_host_cmd *cmd);
-extern int iwl_fill_beacon_frame(struct iwl_priv *priv,
-				 struct ieee80211_hdr *hdr, const u8 * dest,
-				 int left);
+		struct iwl_host_cmd *cmd);
+extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
 extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
 					 struct iwl_rx_queue *q);
 extern int iwl_send_statistics_request(struct iwl_priv *priv);
 extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
 				   u32 decrypt_res,
 				   struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
 
 extern const u8 BROADCAST_ADDR[ETH_ALEN];
 
 /*
- * Currently used by ipw-3945-rs... look at restructuring so that it doesn't
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
  * call this... todo... fix that.
 */
 extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
@@ -601,25 +649,23 @@ extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
 
 static inline int iwl_is_associated(struct iwl_priv *priv)
 {
-	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ?
-		1 : 0;
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
 }
-extern void iwl_down(struct iwl_priv *priv);
 
 /******************************************************************************
  *
- * Functions implemented in iwl-*.c which are forward declared here
- * for use by base.c
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
  *
  * NOTE:  The implementation of these functions are hardware specific
- * which is why they are in the hardware specific files (vs. base.c)
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
  *
  * Naming convention --
  * iwl_         <-- Its part of iwlwifi (should be changed to iwl_)
  * iwl_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
  * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
  * iwl_bg_      <-- Called from work queue context
- * d_           <-- mac80211 callback
+ * iwl_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
 extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv);
@@ -633,17 +679,14 @@ extern int iwl_hw_nic_stop_master(struct iwl_priv *priv);
 extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
 extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv);
 extern int iwl_hw_nic_reset(struct iwl_priv *priv);
-extern int iwl_hw_tx_queue_attach_buffer_to_tfd(
-	struct iwl_priv *priv, void *tfd, dma_addr_t addr, u16 len);
-extern int iwl_hw_tx_queue_free_tfd(struct iwl_priv *priv,
-				    struct iwl_tx_queue *txq);
+extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 extern int iwl_hw_get_temperature(struct iwl_priv *priv);
-extern int iwl_tx_queue_free_tfd(struct iwl_priv *priv,
-				 struct iwl_tx_queue *txq);
 extern int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 				struct iwl_tx_queue *txq);
-extern int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-				 struct iwl_frame *frame, u16 rate);
+extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+				 struct iwl_frame *frame, u8 rate);
 extern int iwl_hw_get_rx_read(struct iwl_priv *priv);
 extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 				     struct iwl_cmd *cmd,
@@ -665,7 +708,8 @@ extern int iwl4965_get_temperature(const struct iwl_priv *priv);
  * not yet been merged into a single common layer for managing the
  * station tables.
  */
-extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 * bssid);
-
+extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
 
+extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel);
+extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 #endif
diff --git a/include/net/mac80211_compat.h b/include/net/mac80211_compat.h
index bd6ee09..6231b27 100644
--- a/include/net/mac80211_compat.h
+++ b/include/net/mac80211_compat.h
@@ -3,11 +3,6 @@
 
 #define BIT(nr)			(1UL << (nr))
 
-enum {
-	false	= 0,
-	true	= 1
-};
-
 /*
  *      We tag multicasts with these structures.
  */