Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100
index 3ab4037..f3fcaa4 100644
--- a/Documentation/networking/README.ipw2100
+++ b/Documentation/networking/README.ipw2100
@@ -3,18 +3,18 @@
 
 Intel(R) PRO/Wireless 2100 Network Connection
 
-Copyright (C) 2003-2005, Intel Corporation
+Copyright (C) 2003-2006, Intel Corporation
 
 README.ipw2100
 
-Version: 1.1.3
-Date   : October 17, 2005
+Version: git-1.1.5
+Date   : January 25, 2006
 
 Index
 -----------------------------------------------
 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
 1. Introduction
-2. Release 1.1.3 Current Features
+2. Release git-1.1.5 Current Features
 3. Command Line Parameters
 4. Sysfs Helper Files
 5. Radio Kill Switch
@@ -89,7 +89,7 @@
 for the driver project.
 
 
-2. Release 1.1.3 Current Supported Features
+2. Release git-1.1.5 Current Supported Features
 -----------------------------------------------
 - Managed (BSS) and Ad-Hoc (IBSS)
 - WEP (shared key and open)
@@ -270,7 +270,7 @@
 9. License
 -----------------------------------------------
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License (version 2) as 
diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200
index c6492d3..acb30c5 100644
--- a/Documentation/networking/README.ipw2200
+++ b/Documentation/networking/README.ipw2200
@@ -10,7 +10,7 @@
 PRO/Wireless 2915ABG Driver for Linux will be used to reference the
 unified driver.
 
-Copyright (C) 2004-2005, Intel Corporation
+Copyright (C) 2004-2006, Intel Corporation
 
 README.ipw2200
 
@@ -26,9 +26,11 @@
 1.2. Module parameters
 1.3. Wireless Extension Private Methods
 1.4. Sysfs Helper Files
+1.5. Supported channels
 2.   Ad-Hoc Networking
 3.   Interacting with Wireless Tools
 3.1. iwconfig mode
+3.2. iwconfig sens
 4.   About the Version Numbers
 5.   Firmware installation
 6.   Support
@@ -314,6 +316,35 @@
 	running ifconfig and is therefore disabled by default.
 
 
+1.5. Supported channels
+-----------------------------------------------
+
+Upon loading the Intel(R) PRO/Wireless 2915ABG Driver for Linux, a
+message stating the detected geography code and the number of 802.11
+channels supported by the card will be displayed in the log.
+
+The geography code corresponds to a regulatory domain as shown in the
+table below.
+
+					  Supported channels
+Code	Geography			802.11bg	802.11a
+
+---	Restricted			11 	 	 0
+ZZF	Custom US/Canada		11	 	 8
+ZZD	Rest of World			13	 	 0
+ZZA	Custom USA & Europe & High	11		13
+ZZB	Custom NA & Europe    		11		13
+ZZC	Custom Japan			11	 	 4
+ZZM	Custom 				11	 	 0
+ZZE	Europe				13		19
+ZZJ	Custom Japan			14	 	 4
+ZZR	Rest of World			14	 	 0
+ZZH	High Band			13	 	 4
+ZZG	Custom Europe			13	 	 4
+ZZK	Europe 				13		24
+ZZL	Europe				11		13
+
+
 2.   Ad-Hoc Networking
 -----------------------------------------------
 
@@ -353,6 +384,15 @@
 are reset to the value used when the module was loaded.  This includes
 channels, rates, ESSID, etc.
 
+3.2 iwconfig sens
+-----------------------------------------------
+
+The 'iwconfig ethX sens XX' command will not set the signal sensitivity
+threshold, as described in iwconfig documentation, but rather the number
+of consecutive missed beacons that will trigger handover, i.e. roaming
+to another access point. At the same time, it will set the disassociation
+threshold to 3 times the given value.
+
 
 4.   About the Version Numbers
 -----------------------------------------------
@@ -408,7 +448,7 @@
 7.  License
 -----------------------------------------------
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
 
   This program is free software; you can redistribute it and/or modify it 
   under the terms of the GNU General Public License version 2 as 
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index eb79198..72335c8 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 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
@@ -167,12 +167,12 @@
 
 #include "ipw2100.h"
 
-#define IPW2100_VERSION "git-1.1.4"
+#define IPW2100_VERSION "git-1.2.2"
 
 #define DRV_NAME	"ipw2100"
 #define DRV_VERSION	IPW2100_VERSION
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2005 Intel Corporation"
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
@@ -1418,7 +1418,7 @@
 	if (priv->status & STATUS_ENABLED)
 		return 0;
 
-	down(&priv->adapter_sem);
+	mutex_lock(&priv->adapter_mutex);
 
 	if (rf_kill_active(priv)) {
 		IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
@@ -1444,7 +1444,7 @@
 	}
 
       fail_up:
-	up(&priv->adapter_sem);
+	mutex_unlock(&priv->adapter_mutex);
 	return err;
 }
 
@@ -1576,7 +1576,7 @@
 		cancel_delayed_work(&priv->hang_check);
 	}
 
-	down(&priv->adapter_sem);
+	mutex_lock(&priv->adapter_mutex);
 
 	err = ipw2100_hw_send_command(priv, &cmd);
 	if (err) {
@@ -1595,7 +1595,7 @@
 	IPW_DEBUG_INFO("TODO: implement scan state machine\n");
 
       fail_up:
-	up(&priv->adapter_sem);
+	mutex_unlock(&priv->adapter_mutex);
 	return err;
 }
 
@@ -1888,7 +1888,7 @@
 	priv->status |= STATUS_RESET_PENDING;
 	spin_unlock_irqrestore(&priv->low_lock, flags);
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	/* stop timed checks so that they don't interfere with reset */
 	priv->stop_hang_check = 1;
 	cancel_delayed_work(&priv->hang_check);
@@ -1898,7 +1898,7 @@
 		wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
 
 	ipw2100_up(priv, 0);
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
 }
 
@@ -2390,15 +2390,6 @@
 		IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
 		return;
 	}
-#ifdef CONFIG_IPW2100_MONITOR
-	if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR &&
-		     priv->config & CFG_CRC_CHECK &&
-		     status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
-		IPW_DEBUG_RX("CRC error in packet.  Dropping.\n");
-		priv->ieee->stats.rx_errors++;
-		return;
-	}
-#endif
 
 	if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
 		     !(priv->status & STATUS_ASSOCIATED))) {
@@ -2446,6 +2437,89 @@
 	priv->rx_queue.drv[i].host_addr = packet->dma_addr;
 }
 
+#ifdef CONFIG_IPW2100_MONITOR
+
+static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
+		   struct ieee80211_rx_stats *stats)
+{
+	struct ipw2100_status *status = &priv->status_queue.drv[i];
+	struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
+
+	/* Magic struct that slots into the radiotap header -- no reason
+	 * to build this manually element by element, we can write it much
+	 * more efficiently than we can parse it. ORDER MATTERS HERE */
+	struct ipw_rt_hdr {
+		struct ieee80211_radiotap_header rt_hdr;
+		s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
+	} *ipw_rt;
+
+	IPW_DEBUG_RX("Handler...\n");
+
+	if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
+				sizeof(struct ipw_rt_hdr))) {
+		IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
+			       "  Dropping.\n",
+			       priv->net_dev->name,
+			       status->frame_size,
+			       skb_tailroom(packet->skb));
+		priv->ieee->stats.rx_errors++;
+		return;
+	}
+
+	if (unlikely(!netif_running(priv->net_dev))) {
+		priv->ieee->stats.rx_errors++;
+		priv->wstats.discard.misc++;
+		IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+		return;
+	}
+
+	if (unlikely(priv->config & CFG_CRC_CHECK &&
+		     status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
+		IPW_DEBUG_RX("CRC error in packet.  Dropping.\n");
+		priv->ieee->stats.rx_errors++;
+		return;
+	}
+
+	pci_unmap_single(priv->pci_dev, packet->dma_addr,
+			 sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
+	memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
+		packet->skb->data, status->frame_size);
+
+	ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
+
+	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
+	ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total hdr+data */
+
+	ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL;
+
+	ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
+
+	skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
+
+	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
+		priv->ieee->stats.rx_errors++;
+
+		/* ieee80211_rx failed, so it didn't free the SKB */
+		dev_kfree_skb_any(packet->skb);
+		packet->skb = NULL;
+	}
+
+	/* We need to allocate a new SKB and attach it to the RDB. */
+	if (unlikely(ipw2100_alloc_skb(priv, packet))) {
+		IPW_DEBUG_WARNING(
+			"%s: Unable to allocate SKB onto RBD ring - disabling "
+			"adapter.\n", priv->net_dev->name);
+		/* TODO: schedule adapter shutdown */
+		IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
+	}
+
+	/* Update the RDB entry */
+	priv->rx_queue.drv[i].host_addr = packet->dma_addr;
+}
+
+#endif
+
 static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
 {
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2577,7 +2651,7 @@
 		case P8023_DATA_VAL:
 #ifdef CONFIG_IPW2100_MONITOR
 			if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
-				isr_rx(priv, i, &stats);
+				isr_rx_monitor(priv, i, &stats);
 				break;
 			}
 #endif
@@ -3882,7 +3956,7 @@
 #ifdef CONFIG_IPW2100_MONITOR
 	case IW_MODE_MONITOR:
 		priv->last_mode = priv->ieee->iw_mode;
-		priv->net_dev->type = ARPHRD_IEEE80211;
+		priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
 		break;
 #endif				/* CONFIG_IPW2100_MONITOR */
 	}
@@ -4138,7 +4212,7 @@
 	IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO  %s\n",
 			  disable_radio ? "OFF" : "ON");
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 
 	if (disable_radio) {
 		priv->status |= STATUS_RF_KILL_SW;
@@ -4156,7 +4230,7 @@
 			schedule_reset(priv);
 	}
 
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return 1;
 }
 
@@ -5460,7 +5534,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int i, force_update = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED))
 		goto done;
 
@@ -5533,7 +5607,7 @@
 	if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
 		ipw2100_configure_security(priv, 0);
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 }
 
 static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
@@ -5657,7 +5731,7 @@
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 
 	priv->config |= CFG_CUSTOM_MAC;
 	memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
@@ -5667,12 +5741,12 @@
 		goto done;
 
 	priv->reset_backoff = 0;
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	ipw2100_reset_adapter(priv);
 	return 0;
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -6015,8 +6089,8 @@
 	strcpy(priv->nick, "ipw2100");
 
 	spin_lock_init(&priv->low_lock);
-	sema_init(&priv->action_sem, 1);
-	sema_init(&priv->adapter_sem, 1);
+	mutex_init(&priv->action_mutex);
+	mutex_init(&priv->adapter_mutex);
 
 	init_waitqueue_head(&priv->wait_command_queue);
 
@@ -6181,7 +6255,7 @@
 	 * member to call a function that then just turns and calls ipw2100_up.
 	 * net_dev->init is called after name allocation but before the
 	 * notifier chain is called */
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_WARNING DRV_NAME
@@ -6217,12 +6291,12 @@
 
 	priv->status |= STATUS_INITIALIZED;
 
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
 	return 0;
 
       fail_unlock:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
       fail:
 	if (dev) {
@@ -6262,7 +6336,7 @@
 	struct net_device *dev;
 
 	if (priv) {
-		down(&priv->action_sem);
+		mutex_lock(&priv->action_mutex);
 
 		priv->status &= ~STATUS_INITIALIZED;
 
@@ -6277,9 +6351,9 @@
 		/* Take down the hardware */
 		ipw2100_down(priv);
 
-		/* Release the semaphore so that the network subsystem can
+		/* Release the mutex so that the network subsystem can
 		 * complete any needed calls into the driver... */
-		up(&priv->action_sem);
+		mutex_unlock(&priv->action_mutex);
 
 		/* Unregister the device first - this results in close()
 		 * being called if the device is open.  If we free storage
@@ -6318,7 +6392,7 @@
 
 	IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (priv->status & STATUS_INITIALIZED) {
 		/* Take down the device; powers it off, etc. */
 		ipw2100_down(priv);
@@ -6331,7 +6405,7 @@
 	pci_disable_device(pci_dev);
 	pci_set_power_state(pci_dev, PCI_D3hot);
 
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
 	return 0;
 }
@@ -6345,7 +6419,7 @@
 	if (IPW2100_PM_DISABLED)
 		return 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 
 	IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
 
@@ -6371,7 +6445,7 @@
 	if (!(priv->status & STATUS_RF_KILL_SW))
 		ipw2100_up(priv, 0);
 
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
 	return 0;
 }
@@ -6535,7 +6609,7 @@
 	if (priv->ieee->iw_mode == IW_MODE_INFRA)
 		return -EOPNOTSUPP;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -6566,7 +6640,7 @@
 	}
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -6607,7 +6681,7 @@
 	if (wrqu->mode == priv->ieee->iw_mode)
 		return 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -6630,7 +6704,7 @@
 	}
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -6812,7 +6886,7 @@
 	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
 		return -EINVAL;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -6841,7 +6915,7 @@
 		     wrqu->ap_addr.sa_data[5] & 0xff);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -6877,7 +6951,7 @@
 	int length = 0;
 	int err = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -6914,7 +6988,7 @@
 	err = ipw2100_set_essid(priv, essid, length, 0);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -6995,7 +7069,7 @@
 	u32 rate;
 	int err = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7022,7 +7096,7 @@
 
 	IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7042,7 +7116,7 @@
 		return 0;
 	}
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7074,7 +7148,7 @@
 	IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7089,7 +7163,7 @@
 	if (wrqu->rts.fixed == 0)
 		return -EINVAL;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7109,7 +7183,7 @@
 
 	IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7160,7 +7234,7 @@
 		value = wrqu->txpower.value;
 	}
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7171,7 +7245,7 @@
 	IPW_DEBUG_WX("SET TX Power -> %d \n", value);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7263,7 +7337,7 @@
 	if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
 		return 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7290,7 +7364,7 @@
 	IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7333,7 +7407,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7348,7 +7422,7 @@
 	}
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7398,7 +7472,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7431,7 +7505,7 @@
 	IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 
 }
@@ -7735,7 +7809,7 @@
 	int enable = (parms[0] > 0);
 	int err = 0;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7753,7 +7827,7 @@
 			err = ipw2100_switch_mode(priv, priv->last_mode);
 	}
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7776,7 +7850,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err = 0, mode = *(int *)extra;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7788,7 +7862,7 @@
 	if (priv->power_mode != mode)
 		err = ipw2100_set_power_mode(priv, mode);
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7840,7 +7914,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err, mode = *(int *)extra;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7858,7 +7932,7 @@
 	err = ipw2100_system_config(priv, 0);
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -7888,7 +7962,7 @@
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	int err, mode = *(int *)extra;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 	if (!(priv->status & STATUS_INITIALIZED)) {
 		err = -EIO;
 		goto done;
@@ -7905,7 +7979,7 @@
 	err = 0;
 
       done:
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 	return err;
 }
 
@@ -8210,11 +8284,11 @@
 	if (priv->status & STATUS_STOPPING)
 		return;
 
-	down(&priv->action_sem);
+	mutex_lock(&priv->action_mutex);
 
 	IPW_DEBUG_WX("enter\n");
 
-	up(&priv->action_sem);
+	mutex_unlock(&priv->action_mutex);
 
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 
@@ -8237,7 +8311,7 @@
 
 	if (!(priv->status & STATUS_ASSOCIATED)) {
 		IPW_DEBUG_WX("Configuring ESSID\n");
-		down(&priv->action_sem);
+		mutex_lock(&priv->action_mutex);
 		/* This is a disassociation event, so kick the firmware to
 		 * look for another AP */
 		if (priv->config & CFG_STATIC_ESSID)
@@ -8245,7 +8319,7 @@
 					  0);
 		else
 			ipw2100_set_essid(priv, NULL, 0, 0);
-		up(&priv->action_sem);
+		mutex_unlock(&priv->action_mutex);
 	}
 
 	wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
index 5136091..55b7227 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2100.h
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 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
@@ -41,7 +41,12 @@
 
 #include <net/ieee80211.h>
 
+#ifdef CONFIG_IPW2100_MONITOR
+#include <net/ieee80211_radiotap.h>
+#endif
+
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 struct ipw2100_priv;
 struct ipw2100_tx_packet;
@@ -590,8 +595,8 @@
 	int inta_other;
 
 	spinlock_t low_lock;
-	struct semaphore action_sem;
-	struct semaphore adapter_sem;
+	struct mutex action_mutex;
+	struct mutex adapter_mutex;
 
 	wait_queue_head_t wait_command_queue;
 };
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index ed37141..9dce522 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
 
   802.11 status code portion of this file from ethereal-0.10.6:
     Copyright 2000, Axis Communications AB
@@ -33,9 +33,9 @@
 #include "ipw2200.h"
 #include <linux/version.h>
 
-#define IPW2200_VERSION "git-1.0.10"
+#define IPW2200_VERSION "git-1.1.1"
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT	"Copyright(c) 2003-2005 Intel Corporation"
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
 
 #define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
@@ -153,12 +153,6 @@
 static void ipw_set_hwcrypto_keys(struct ipw_priv *);
 static void ipw_send_wep_keys(struct ipw_priv *, int);
 
-static int ipw_is_valid_channel(struct ieee80211_device *, u8);
-static int ipw_channel_to_index(struct ieee80211_device *, u8);
-static u8 ipw_freq_to_channel(struct ieee80211_device *, u32);
-static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *);
-static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *);
-
 static int snprint_line(char *buf, size_t count,
 			const u8 * data, u32 len, u32 ofs)
 {
@@ -1654,7 +1648,7 @@
 			break;
 		}
 
-		if (ipw_is_valid_channel(priv->ieee, channel))
+		if (ieee80211_is_valid_channel(priv->ieee, channel))
 			priv->speed_scan[pos++] = channel;
 		else
 			IPW_WARNING("Skipping invalid channel request: %d\n",
@@ -1802,9 +1796,9 @@
 	}
 
 	if (inta & IPW_INTA_BIT_FATAL_ERROR) {
-		IPW_ERROR("Firmware error detected.  Restarting.\n");
+		IPW_WARNING("Firmware error detected.  Restarting.\n");
 		if (priv->error) {
-			IPW_ERROR("Sysfs 'error' log already exists.\n");
+			IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
 #ifdef CONFIG_IPW2200_DEBUG
 			if (ipw_debug_level & IPW_DL_FW_ERRORS) {
 				struct ipw_fw_error *error =
@@ -1817,10 +1811,10 @@
 		} else {
 			priv->error = ipw_alloc_error_log(priv);
 			if (priv->error)
-				IPW_ERROR("Sysfs 'error' log captured.\n");
+				IPW_DEBUG_FW("Sysfs 'error' log captured.\n");
 			else
-				IPW_ERROR("Error allocating sysfs 'error' "
-					  "log.\n");
+				IPW_DEBUG_FW("Error allocating sysfs 'error' "
+					     "log.\n");
 #ifdef CONFIG_IPW2200_DEBUG
 			if (ipw_debug_level & IPW_DL_FW_ERRORS)
 				ipw_dump_error_log(priv, priv->error);
@@ -2222,7 +2216,7 @@
 
 static int ipw_set_tx_power(struct ipw_priv *priv)
 {
-	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
 	struct ipw_tx_power tx_power;
 	s8 max_power;
 	int i;
@@ -2835,33 +2829,11 @@
 	mdelay(5);
 }
 
-struct fw_header {
-	u32 version;
-	u32 mode;
-};
-
 struct fw_chunk {
 	u32 address;
 	u32 length;
 };
 
-#define IPW_FW_MAJOR_VERSION 2
-#define IPW_FW_MINOR_VERSION 4
-
-#define IPW_FW_MINOR(x) ((x & 0xff) >> 8)
-#define IPW_FW_MAJOR(x) (x & 0xff)
-
-#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION)
-
-#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \
-"." __stringify(IPW_FW_MINOR_VERSION) "-"
-
-#if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0
-#define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw"
-#else
-#define IPW_FW_NAME(x) "ipw2200_" x ".fw"
-#endif
-
 static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 {
 	int rc = 0, i, addr;
@@ -3130,33 +3102,47 @@
 	return rc;
 }
 
+
+struct ipw_fw {
+	u32 ver;
+	u32 boot_size;
+	u32 ucode_size;
+	u32 fw_size;
+	u8 data[0];
+};
+
 static int ipw_get_fw(struct ipw_priv *priv,
-		      const struct firmware **fw, const char *name)
+		      const struct firmware **raw, const char *name)
 {
-	struct fw_header *header;
+	struct ipw_fw *fw;
 	int rc;
 
 	/* ask firmware_class module to get the boot firmware off disk */
-	rc = request_firmware(fw, name, &priv->pci_dev->dev);
+	rc = request_firmware(raw, name, &priv->pci_dev->dev);
 	if (rc < 0) {
-		IPW_ERROR("%s load failed: Reason %d\n", name, rc);
+		IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc);
 		return rc;
 	}
 
-	header = (struct fw_header *)(*fw)->data;
-	if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) {
-		IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n",
-			  name,
-			  IPW_FW_MAJOR(le32_to_cpu(header->version)),
-			  IPW_FW_MAJOR_VERSION);
+	if ((*raw)->size < sizeof(*fw)) {
+		IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size);
 		return -EINVAL;
 	}
 
-	IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n",
+	fw = (void *)(*raw)->data;
+
+	if ((*raw)->size < sizeof(*fw) +
+	    fw->boot_size + fw->ucode_size + fw->fw_size) {
+		IPW_ERROR("%s is too small or corrupt (%zd)\n",
+			  name, (*raw)->size);
+		return -EINVAL;
+	}
+
+	IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n",
 		       name,
-		       IPW_FW_MAJOR(le32_to_cpu(header->version)),
-		       IPW_FW_MINOR(le32_to_cpu(header->version)),
-		       (*fw)->size - sizeof(struct fw_header));
+		       le32_to_cpu(fw->ver) >> 16,
+		       le32_to_cpu(fw->ver) & 0xff,
+		       (*raw)->size - sizeof(*fw));
 	return 0;
 }
 
@@ -3196,17 +3182,13 @@
 
 #ifdef CONFIG_PM
 static int fw_loaded = 0;
-static const struct firmware *bootfw = NULL;
-static const struct firmware *firmware = NULL;
-static const struct firmware *ucode = NULL;
+static const struct firmware *raw = NULL;
 
 static void free_firmware(void)
 {
 	if (fw_loaded) {
-		release_firmware(bootfw);
-		release_firmware(ucode);
-		release_firmware(firmware);
-		bootfw = ucode = firmware = NULL;
+		release_firmware(raw);
+		raw = NULL;
 		fw_loaded = 0;
 	}
 }
@@ -3217,33 +3199,47 @@
 static int ipw_load(struct ipw_priv *priv)
 {
 #ifndef CONFIG_PM
-	const struct firmware *bootfw = NULL;
-	const struct firmware *firmware = NULL;
-	const struct firmware *ucode = NULL;
+	const struct firmware *raw = NULL;
 #endif
-	char *ucode_name;
-	char *fw_name;
+	struct ipw_fw *fw;
+	u8 *boot_img, *ucode_img, *fw_img;
+	u8 *name = NULL;
 	int rc = 0, retries = 3;
 
 	switch (priv->ieee->iw_mode) {
 	case IW_MODE_ADHOC:
-		ucode_name = IPW_FW_NAME("ibss_ucode");
-		fw_name = IPW_FW_NAME("ibss");
+		name = "ipw2200-ibss.fw";
 		break;
 #ifdef CONFIG_IPW2200_MONITOR
 	case IW_MODE_MONITOR:
-		ucode_name = IPW_FW_NAME("sniffer_ucode");
-		fw_name = IPW_FW_NAME("sniffer");
+		name = "ipw2200-sniffer.fw";
 		break;
 #endif
 	case IW_MODE_INFRA:
-		ucode_name = IPW_FW_NAME("bss_ucode");
-		fw_name = IPW_FW_NAME("bss");
+		name = "ipw2200-bss.fw";
 		break;
-	default:
-		rc = -EINVAL;
 	}
 
+	if (!name) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+#ifdef CONFIG_PM
+	if (!fw_loaded) {
+#endif
+		rc = ipw_get_fw(priv, &raw, name);
+		if (rc < 0)
+			goto error;
+#ifdef CONFIG_PM
+	}
+#endif
+
+	fw = (void *)raw->data;
+	boot_img = &fw->data[0];
+	ucode_img = &fw->data[fw->boot_size];
+	fw_img = &fw->data[fw->boot_size + fw->ucode_size];
+
 	if (rc < 0)
 		goto error;
 
@@ -3275,18 +3271,8 @@
 	ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
 			IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
 
-#ifdef CONFIG_PM
-	if (!fw_loaded) {
-#endif
-		rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot"));
-		if (rc < 0)
-			goto error;
-#ifdef CONFIG_PM
-	}
-#endif
 	/* DMA the initial boot firmware into the device */
-	rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
-			       bootfw->size - sizeof(struct fw_header));
+	rc = ipw_load_firmware(priv, boot_img, fw->boot_size);
 	if (rc < 0) {
 		IPW_ERROR("Unable to load boot firmware: %d\n", rc);
 		goto error;
@@ -3307,19 +3293,8 @@
 	/* ack fw init done interrupt */
 	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
 
-#ifdef CONFIG_PM
-	if (!fw_loaded) {
-#endif
-		rc = ipw_get_fw(priv, &ucode, ucode_name);
-		if (rc < 0)
-			goto error;
-#ifdef CONFIG_PM
-	}
-#endif
-
 	/* DMA the ucode into the device */
-	rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
-			    ucode->size - sizeof(struct fw_header));
+	rc = ipw_load_ucode(priv, ucode_img, fw->ucode_size);
 	if (rc < 0) {
 		IPW_ERROR("Unable to load ucode: %d\n", rc);
 		goto error;
@@ -3328,20 +3303,8 @@
 	/* stop nic */
 	ipw_stop_nic(priv);
 
-#ifdef CONFIG_PM
-	if (!fw_loaded) {
-#endif
-		rc = ipw_get_fw(priv, &firmware, fw_name);
-		if (rc < 0)
-			goto error;
-#ifdef CONFIG_PM
-	}
-#endif
-
 	/* DMA bss firmware into the device */
-	rc = ipw_load_firmware(priv, firmware->data +
-			       sizeof(struct fw_header),
-			       firmware->size - sizeof(struct fw_header));
+	rc = ipw_load_firmware(priv, fw_img, fw->fw_size);
 	if (rc < 0) {
 		IPW_ERROR("Unable to load firmware: %d\n", rc);
 		goto error;
@@ -3406,9 +3369,7 @@
 	ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
 
 #ifndef CONFIG_PM
-	release_firmware(bootfw);
-	release_firmware(ucode);
-	release_firmware(firmware);
+	release_firmware(raw);
 #endif
 	return 0;
 
@@ -3418,15 +3379,11 @@
 		priv->rxq = NULL;
 	}
 	ipw_tx_queue_free(priv);
-	if (bootfw)
-		release_firmware(bootfw);
-	if (ucode)
-		release_firmware(ucode);
-	if (firmware)
-		release_firmware(firmware);
+	if (raw)
+		release_firmware(raw);
 #ifdef CONFIG_PM
 	fw_loaded = 0;
-	bootfw = ucode = firmware = NULL;
+	raw = NULL;
 #endif
 
 	return rc;
@@ -4547,10 +4504,9 @@
 
 			if (notif->size == sizeof(*x)) {
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-					  "link deterioration: '%s' " MAC_FMT
-					  " \n", escape_essid(priv->essid,
-							      priv->essid_len),
-					  MAC_ARG(priv->bssid));
+					"link deterioration: type %d, cnt %d\n",
+					x->silence_notification_type,
+					x->silence_count);
 				memcpy(&priv->last_link_deterioration, x,
 				       sizeof(*x));
 			} else {
@@ -5533,15 +5489,6 @@
 		return 0;
 	}
 
-	if (priv->ieee->wpa_enabled &&
-	    network->wpa_ie_len == 0 && network->rsn_ie_len == 0) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
-				"because of WPA capability mismatch.\n",
-				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
-		return 0;
-	}
-
 	if ((priv->config & CFG_STATIC_BSSID) &&
 	    memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
@@ -5562,7 +5509,7 @@
 	}
 
 	/* Filter out invalid channel in current GEO */
-	if (!ipw_is_valid_channel(priv->ieee, network->channel)) {
+	if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
 		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
 				"because of invalid channel in current GEO\n",
 				escape_essid(network->ssid, network->ssid_len),
@@ -5607,7 +5554,7 @@
 static void ipw_adhoc_create(struct ipw_priv *priv,
 			     struct ieee80211_network *network)
 {
-	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
 	int i;
 
 	/*
@@ -5622,10 +5569,10 @@
 	 * FW fatal error.
 	 *
 	 */
-	switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+	switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
 	case IEEE80211_52GHZ_BAND:
 		network->mode = IEEE_A;
-		i = ipw_channel_to_index(priv->ieee, priv->channel);
+		i = ieee80211_channel_to_index(priv->ieee, priv->channel);
 		if (i == -1)
 			BUG();
 		if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
@@ -5639,7 +5586,7 @@
 			network->mode = IEEE_G;
 		else
 			network->mode = IEEE_B;
-		i = ipw_channel_to_index(priv->ieee, priv->channel);
+		i = ieee80211_channel_to_index(priv->ieee, priv->channel);
 		if (i == -1)
 			BUG();
 		if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
@@ -5963,7 +5910,7 @@
 	const struct ieee80211_geo *geo;
 	int i;
 
-	geo = ipw_get_geo(priv->ieee);
+	geo = ieee80211_get_geo(priv->ieee);
 
 	if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
 		int start = channel_index;
@@ -6023,7 +5970,7 @@
 				channel_index++;
 				scan->channels_list[channel_index] = channel;
 				index =
-				    ipw_channel_to_index(priv->ieee, channel);
+				    ieee80211_channel_to_index(priv->ieee, channel);
 				ipw_set_scan_type(scan, channel_index,
 						  geo->bg[index].
 						  flags &
@@ -6105,7 +6052,7 @@
 		u8 channel;
 		u8 band = 0;
 
-		switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+		switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
 		case IEEE80211_52GHZ_BAND:
 			band = (u8) (IPW_A_MODE << 6) | 1;
 			channel = priv->channel;
@@ -6568,7 +6515,7 @@
 * get the modulation type of the current network or
 * the card current mode
 */
-u8 ipw_qos_current_mode(struct ipw_priv * priv)
+static u8 ipw_qos_current_mode(struct ipw_priv * priv)
 {
 	u8 mode = 0;
 
@@ -7815,12 +7762,10 @@
 
 	while (i != r) {
 		rxb = priv->rxq->queue[i];
-#ifdef CONFIG_IPW2200_DEBUG
 		if (unlikely(rxb == NULL)) {
 			printk(KERN_CRIT "Queue not allocated!\n");
 			break;
 		}
-#endif
 		priv->rxq->queue[i] = NULL;
 
 		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
@@ -7839,7 +7784,8 @@
 					    le16_to_cpu(pkt->u.frame.rssi_dbm) -
 					    IPW_RSSI_TO_DBM,
 					.signal =
-					    le16_to_cpu(pkt->u.frame.signal),
+					    le16_to_cpu(pkt->u.frame.rssi_dbm) -
+					    IPW_RSSI_TO_DBM + 0x100,
 					.noise =
 					    le16_to_cpu(pkt->u.frame.noise),
 					.rate = pkt->u.frame.rate,
@@ -7903,7 +7849,8 @@
 					     le16_to_cpu(pkt->u.frame.length));
 
 				if (le16_to_cpu(pkt->u.frame.length) <
-				    frame_hdr_len(header)) {
+				    ieee80211_get_hdrlen(le16_to_cpu(
+						    header->frame_ctl))) {
 					IPW_DEBUG_DROP
 					    ("Received packet is too small. "
 					     "Dropping.\n");
@@ -7993,7 +7940,14 @@
 #define	DEFAULT_SHORT_RETRY_LIMIT 7U
 #define	DEFAULT_LONG_RETRY_LIMIT  4U
 
-static int ipw_sw_reset(struct ipw_priv *priv, int init)
+/**
+ * ipw_sw_reset
+ * @option: options to control different reset behaviour
+ * 	    0 = reset everything except the 'disable' module_param
+ * 	    1 = reset everything and print out driver info (for probe only)
+ * 	    2 = reset everything
+ */
+static int ipw_sw_reset(struct ipw_priv *priv, int option)
 {
 	int band, modulation;
 	int old_mode = priv->ieee->iw_mode;
@@ -8020,7 +7974,7 @@
 	priv->essid_len = 0;
 	memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
 
-	if (disable) {
+	if (disable && option) {
 		priv->status |= STATUS_RF_KILL_SW;
 		IPW_DEBUG_INFO("Radio disabled.\n");
 	}
@@ -8072,7 +8026,7 @@
 
 	if ((priv->pci_dev->device == 0x4223) ||
 	    (priv->pci_dev->device == 0x4224)) {
-		if (init)
+		if (option == 1)
 			printk(KERN_INFO DRV_NAME
 			       ": Detected Intel PRO/Wireless 2915ABG Network "
 			       "Connection\n");
@@ -8083,7 +8037,7 @@
 		priv->adapter = IPW_2915ABG;
 		priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
 	} else {
-		if (init)
+		if (option == 1)
 			printk(KERN_INFO DRV_NAME
 			       ": Detected Intel PRO/Wireless 2200BG Network "
 			       "Connection\n");
@@ -8200,7 +8154,7 @@
 			   union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
-	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
 	struct iw_freq *fwrq = &wrqu->freq;
 	int ret = 0, i;
 	u8 channel, flags;
@@ -8215,17 +8169,17 @@
 	}
 	/* if setting by freq convert to channel */
 	if (fwrq->e == 1) {
-		channel = ipw_freq_to_channel(priv->ieee, fwrq->m);
+		channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m);
 		if (channel == 0)
 			return -EINVAL;
 	} else
 		channel = fwrq->m;
 
-	if (!(band = ipw_is_valid_channel(priv->ieee, channel)))
+	if (!(band = ieee80211_is_valid_channel(priv->ieee, channel)))
 		return -EINVAL;
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
-		i = ipw_channel_to_index(priv->ieee, channel);
+		i = ieee80211_channel_to_index(priv->ieee, channel);
 		if (i == -1)
 			return -EINVAL;
 
@@ -8353,7 +8307,7 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct iw_range *range = (struct iw_range *)extra;
-	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
 	int i = 0, j;
 
 	wrqu->data.length = sizeof(*range);
@@ -8365,7 +8319,7 @@
 	range->max_qual.qual = 100;
 	/* TODO: Find real max RSSI and stick here */
 	range->max_qual.level = 0;
-	range->max_qual.noise = priv->ieee->worst_rssi + 0x100;
+	range->max_qual.noise = 0;
 	range->max_qual.updated = 7;	/* Updated all three */
 
 	range->avg_qual.qual = 70;
@@ -8395,20 +8349,28 @@
 
 	i = 0;
 	if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
-		for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES;
-		     i++, j++) {
+		for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) {
+			if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
+			    (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY))
+				continue;
+
 			range->freq[i].i = geo->bg[j].channel;
 			range->freq[i].m = geo->bg[j].freq * 100000;
 			range->freq[i].e = 1;
+			i++;
 		}
 	}
 
 	if (priv->ieee->mode & IEEE_A) {
-		for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES;
-		     i++, j++) {
+		for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) {
+			if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
+			    (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY))
+				continue;
+
 			range->freq[i].i = geo->a[j].channel;
 			range->freq[i].m = geo->a[j].freq * 100000;
 			range->freq[i].e = 1;
+			i++;
 		}
 	}
 
@@ -8609,6 +8571,52 @@
 	return 0;
 }
 
+static int ipw_wx_set_sens(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	int err = 0;
+
+	IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value);
+	IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value);
+	mutex_lock(&priv->mutex);
+
+	if (wrqu->sens.fixed == 0)
+	{
+		priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
+		priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
+		goto out;
+	}
+	if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) ||
+	    (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	priv->roaming_threshold = wrqu->sens.value;
+	priv->disassociate_threshold = 3*wrqu->sens.value;
+      out:
+	mutex_unlock(&priv->mutex);
+	return err;
+}
+
+static int ipw_wx_get_sens(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct ipw_priv *priv = ieee80211_priv(dev);
+	mutex_lock(&priv->mutex);
+	wrqu->sens.fixed = 1;
+	wrqu->sens.value = priv->roaming_threshold;
+	mutex_unlock(&priv->mutex);
+
+	IPW_DEBUG_WX("GET roaming threshold -> %s %d \n",
+		     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
+
+	return 0;
+}
+
 static int ipw_wx_set_rate(struct net_device *dev,
 			   struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
@@ -9395,7 +9403,7 @@
 
 	mutex_lock(&priv->mutex);
 
-	ret = ipw_sw_reset(priv, 0);
+	ret = ipw_sw_reset(priv, 2);
 	if (!ret) {
 		free_firmware();
 		ipw_adapter_restart(priv);
@@ -9430,6 +9438,8 @@
 	IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
 	IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
 	IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
+	IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens,
+	IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens,
 	IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
 	IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
 	IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
@@ -9575,7 +9585,7 @@
 	wstats->qual.level = average_value(&priv->average_rssi);
 	wstats->qual.noise = average_value(&priv->average_noise);
 	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
-	    IW_QUAL_NOISE_UPDATED;
+	    IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM;
 
 	wstats->miss.beacon = average_value(&priv->average_missed_beacons);
 	wstats->discard.retries = priv->last_tx_failures;
@@ -9601,12 +9611,13 @@
 	sys_config->disable_unicast_decryption = 1;
 	sys_config->exclude_multicast_unencrypted = 0;
 	sys_config->disable_multicast_decryption = 1;
-	sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH;
+	sys_config->antenna_diversity = CFG_SYS_ANTENNA_SLOW_DIV;
 	sys_config->pass_crc_to_host = 0;	/* TODO: See if 1 gives us FCS */
 	sys_config->dot11g_auto_detection = 0;
 	sys_config->enable_cts_to_self = 0;
 	sys_config->bt_coexist_collision_thr = 0;
 	sys_config->pass_noise_stats_to_host = 1;	//1 -- fix for 256
+	sys_config->silence_threshold = 0x1e;
 }
 
 static int ipw_net_open(struct net_device *dev)
@@ -9654,11 +9665,6 @@
 	u16 remaining_bytes;
 	int fc;
 
-	/* If there isn't room in the queue, we return busy and let the
-	 * network stack requeue the packet for us */
-	if (ipw_queue_space(q) < q->high_mark)
-		return NETDEV_TX_BUSY;
-
 	switch (priv->ieee->iw_mode) {
 	case IW_MODE_ADHOC:
 		hdr_len = IEEE80211_3ADDR_LEN;
@@ -9824,6 +9830,9 @@
 	q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
 	ipw_write32(priv, q->reg_w, q->first_empty);
 
+	if (ipw_queue_space(q) < q->high_mark)
+		netif_stop_queue(priv->net_dev);
+
 	return NETDEV_TX_OK;
 
       drop:
@@ -9963,9 +9972,8 @@
 		return -EINVAL;
 	mutex_lock(&p->mutex);
 	memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
-	for (i = IPW_EEPROM_DATA;
-	     i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++)
-		ipw_write8(p, i, p->eeprom[i]);
+	for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
+		ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]);
 	mutex_unlock(&p->mutex);
 	return 0;
 }
@@ -10370,6 +10378,9 @@
  * not intended for resale of the above mentioned Intel adapters has
  * not been tested.
  *
+ * Remember to update the table in README.ipw2200 when changing this
+ * table.
+ *
  */
 static const struct ieee80211_geo ipw_geos[] = {
 	{			/* Restricted */
@@ -10617,96 +10628,6 @@
 	 }
 };
 
-/* GEO code borrowed from ieee80211_geo.c */
-static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
-{
-	int i;
-
-	/* Driver needs to initialize the geography map before using
-	 * these helper functions */
-	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
-
-	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
-		for (i = 0; i < ieee->geo.bg_channels; i++)
-			/* NOTE: If G mode is currently supported but
-			 * this is a B only channel, we don't see it
-			 * as valid. */
-			if ((ieee->geo.bg[i].channel == channel) &&
-			    (!(ieee->mode & IEEE_G) ||
-			     !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
-				return IEEE80211_24GHZ_BAND;
-
-	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
-		for (i = 0; i < ieee->geo.a_channels; i++)
-			if (ieee->geo.a[i].channel == channel)
-				return IEEE80211_52GHZ_BAND;
-
-	return 0;
-}
-
-static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel)
-{
-	int i;
-
-	/* Driver needs to initialize the geography map before using
-	 * these helper functions */
-	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
-
-	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
-		for (i = 0; i < ieee->geo.bg_channels; i++)
-			if (ieee->geo.bg[i].channel == channel)
-				return i;
-
-	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
-		for (i = 0; i < ieee->geo.a_channels; i++)
-			if (ieee->geo.a[i].channel == channel)
-				return i;
-
-	return -1;
-}
-
-static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq)
-{
-	int i;
-
-	/* Driver needs to initialize the geography map before using
-	 * these helper functions */
-	BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
-
-	freq /= 100000;
-
-	if (ieee->freq_band & IEEE80211_24GHZ_BAND)
-		for (i = 0; i < ieee->geo.bg_channels; i++)
-			if (ieee->geo.bg[i].freq == freq)
-				return ieee->geo.bg[i].channel;
-
-	if (ieee->freq_band & IEEE80211_52GHZ_BAND)
-		for (i = 0; i < ieee->geo.a_channels; i++)
-			if (ieee->geo.a[i].freq == freq)
-				return ieee->geo.a[i].channel;
-
-	return 0;
-}
-
-static int ipw_set_geo(struct ieee80211_device *ieee,
-		       const struct ieee80211_geo *geo)
-{
-	memcpy(ieee->geo.name, geo->name, 3);
-	ieee->geo.name[3] = '\0';
-	ieee->geo.bg_channels = geo->bg_channels;
-	ieee->geo.a_channels = geo->a_channels;
-	memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
-	       sizeof(struct ieee80211_channel));
-	memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
-	       sizeof(struct ieee80211_channel));
-	return 0;
-}
-
-static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee)
-{
-	return &ieee->geo;
-}
-
 #define MAX_HW_RESTARTS 5
 static int ipw_up(struct ipw_priv *priv)
 {
@@ -10753,14 +10674,11 @@
 				    priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
 			j = 0;
 		}
-		if (ipw_set_geo(priv->ieee, &ipw_geos[j])) {
+		if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) {
 			IPW_WARNING("Could not set geography.");
 			return 0;
 		}
 
-		IPW_DEBUG_INFO("Geography %03d [%s] detected.\n",
-			       j, priv->ieee->geo.name);
-
 		if (priv->status & STATUS_RF_KILL_SW) {
 			IPW_WARNING("Radio disabled by module parameter.\n");
 			return 0;
@@ -11081,6 +10999,12 @@
 		IPW_ERROR("failed to register network device\n");
 		goto out_remove_sysfs;
 	}
+
+	printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg "
+	       "channels, %d 802.11a channels)\n",
+	       priv->ieee->geo.name, priv->ieee->geo.bg_channels,
+	       priv->ieee->geo.a_channels);
+
 	return 0;
 
       out_remove_sysfs:
@@ -11271,8 +11195,10 @@
 module_param(led, int, 0444);
 MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
 
+#ifdef CONFIG_IPW2200_DEBUG
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
+#endif
 
 module_param(channel, int, 0444);
 MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 5405ba1..4b98049 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1,6 +1,6 @@
 /******************************************************************************
 
-  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+  Copyright(c) 2003 - 2006 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
@@ -246,8 +246,10 @@
 #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED       31
 
 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING         1
-#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT           24
+#define IPW_MB_ROAMING_THRESHOLD_MIN                    1
 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT                8
+#define IPW_MB_ROAMING_THRESHOLD_MAX                    30
+#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT           3*IPW_MB_ROAMING_THRESHOLD_DEFAULT
 #define IPW_REAL_RATE_RX_PACKET_THRESHOLD               300
 
 #define MACADRR_BYTE_LEN                     6
@@ -618,13 +620,16 @@
 	u8 reserved;
 } __attribute__ ((packed));
 
+#define SILENCE_OVER_THRESH (1)
+#define SILENCE_UNDER_THRESH (2)
+
 struct notif_link_deterioration {
 	struct ipw_cmd_stats stats;
 	u8 rate;
 	u8 modulation;
 	struct rate_histogram histogram;
-	u8 reserved1;
-	u16 reserved2;
+	u8 silence_notification_type;	/* SILENCE_OVER/UNDER_THRESH */
+	u16 silence_count;
 } __attribute__ ((packed));
 
 struct notif_association {
@@ -782,7 +787,7 @@
 	u8 enable_cts_to_self;
 	u8 enable_multicast_filtering;
 	u8 bt_coexist_collision_thr;
-	u8 reserved2;
+	u8 silence_threshold;
 	u8 accept_all_mgmt_bcpr;
 	u8 accept_all_mgtm_frames;
 	u8 pass_noise_stats_to_host;
@@ -1892,6 +1897,7 @@
 #define CFG_SYS_ANTENNA_BOTH            0x00	/* NIC selects best antenna */
 #define CFG_SYS_ANTENNA_A               0x01	/* force antenna A */
 #define CFG_SYS_ANTENNA_B               0x03	/* force antenna B */
+#define CFG_SYS_ANTENNA_SLOW_DIV        0x02	/* consider background noise */
 
 /*
  * The definitions below were lifted off the ipw2100 driver, which only
@@ -1907,27 +1913,4 @@
 
 #define IPW_MAX_CONFIG_RETRIES 10
 
-static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr)
-{
-	u32 retval;
-	u16 fc;
-
-	retval = sizeof(struct ieee80211_hdr_3addr);
-	fc = le16_to_cpu(hdr->frame_ctl);
-
-	/*
-	 * Function     ToDS    FromDS
-	 * IBSS         0       0
-	 * To AP        1       0
-	 * From AP      0       1
-	 * WDS (bridge) 1       1
-	 *
-	 * Only WDS frames use Address4 among them. --YZ
-	 */
-	if (!(fc & IEEE80211_FCTL_TODS) || !(fc & IEEE80211_FCTL_FROMDS))
-		retval -= ETH_ALEN;
-
-	return retval;
-}
-
 #endif				/* __ipw2200_h__ */
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 785d5a1..a7f2a64 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -1345,7 +1345,19 @@
 	ieee80211_network_reset(dst);
 	dst->ibss_dfs = src->ibss_dfs;
 
-	memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
+	/* We only update the statistics if they were created by receiving
+	 * the network information on the actual channel the network is on.
+	 * 
+	 * This keeps beacons received on neighbor channels from bringing
+	 * down the signal level of an AP. */
+	if (dst->channel == src->stats.received_channel)
+		memcpy(&dst->stats, &src->stats,
+		       sizeof(struct ieee80211_rx_stats));
+	else
+		IEEE80211_DEBUG_SCAN("Network " MAC_FMT " info received "
+			"off channel (%d vs. %d)\n", MAC_ARG(src->bssid),
+			dst->channel, src->stats.received_channel);
+
 	dst->capability = src->capability;
 	memcpy(dst->rates, src->rates, src->rates_len);
 	dst->rates_len = src->rates_len;