All of lore.kernel.org
 help / color / mirror / Atom feed
* Please pull 'upstream-fixes' branch of wireless-2.6
@ 2007-03-16 21:31 John W. Linville
  2007-03-16 21:34 ` Please pull 'upstream' " John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-03-16 21:31 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless

The following changes since commit db98e0b434a6265c451ffe94ec0a29b8d0aaf587:
  Linus Torvalds (1):
        Linux 2.6.21-rc4

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream-fixes

Larry Finger (1):
      bcm43xx: MANUALWLAN fixes

Michal Schmidt (1):
      airo: Fix an error path memory leak

 drivers/net/wireless/airo.c                  |    4 +++-
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c |   14 +++++++-------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a8c2bfe..2ada76a 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2852,7 +2852,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	if (rc) {
 		airo_print_err(dev->name, "register interrupt %d failed, rc %d",
 				irq, rc);
-		goto err_out_unlink;
+		goto err_out_nets;
 	}
 	if (!is_pcmcia) {
 		if (!request_region( dev->base_addr, 64, dev->name )) {
@@ -2935,6 +2935,8 @@ err_out_res:
 	        release_region( dev->base_addr, 64 );
 err_out_irq:
 	free_irq(dev->irq, dev);
+err_out_nets:
+	airo_networks_free(ai);
 err_out_unlink:
 	del_airo_dev(dev);
 err_out_thr:
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 32beb91..ee1e7a2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -882,10 +882,10 @@ static void _stack_save(u32 *_stackptr, size_t *stackidx,
 {
 	u32 *stackptr = &(_stackptr[*stackidx]);
 
-	assert((offset & 0xF000) == 0x0000);
-	assert((id & 0xF0) == 0x00);
+	assert((offset & 0xE000) == 0x0000);
+	assert((id & 0xF8) == 0x00);
 	*stackptr = offset;
-	*stackptr |= ((u32)id) << 12;
+	*stackptr |= ((u32)id) << 13;
 	*stackptr |= ((u32)value) << 16;
 	(*stackidx)++;
 	assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
@@ -896,12 +896,12 @@ static u16 _stack_restore(u32 *stackptr,
 {
 	size_t i;
 
-	assert((offset & 0xF000) == 0x0000);
-	assert((id & 0xF0) == 0x00);
+	assert((offset & 0xE000) == 0x0000);
+	assert((id & 0xF8) == 0x00);
 	for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
-		if ((*stackptr & 0x00000FFF) != offset)
+		if ((*stackptr & 0x00001FFF) != offset)
 			continue;
-		if (((*stackptr & 0x0000F000) >> 12) != id)
+		if (((*stackptr & 0x00007000) >> 13) != id)
 			continue;
 		return ((*stackptr & 0xFFFF0000) >> 16);
 	}
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-03-16 21:31 Please pull 'upstream-fixes' branch of wireless-2.6 John W. Linville
@ 2007-03-16 21:34 ` John W. Linville
  2007-03-23  5:55   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-03-16 21:34 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless

The following changes since commit 0e39a919461842a38e406702fe0e94c6138ddfef
  John W. Linville (1):
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (4):
      zd1211rw: Use compare_ether_addr()
      zd1211rw: Reject AL2230S devices
      zd1211rw: Add AL2230S RF support
      zd1211rw: More device IDs

Larry Finger (2):
      bcm43xx: MANUALWLAN fixes
      bcm43xx:Eliminate some 'G Mode Enable' magic numbers

Michal Schmidt (3):
      airo: Fix an error path memory leak
      airo: Don't check for NULL before kfree()
      airo: Make /sys/bus/pci/drivers/airo/{,un}bind work

 drivers/net/wireless/airo.c                  |   74 ++++++++++-------------
 drivers/net/wireless/bcm43xx/bcm43xx.h       |    3 +
 drivers/net/wireless/bcm43xx/bcm43xx_main.c  |    4 +-
 drivers/net/wireless/bcm43xx/bcm43xx_phy.c   |    8 +-
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c |   14 ++--
 drivers/net/wireless/zd1211rw/zd_chip.c      |    6 +-
 drivers/net/wireless/zd1211rw/zd_chip.h      |    2 +-
 drivers/net/wireless/zd1211rw/zd_mac.c       |   10 ++--
 drivers/net/wireless/zd1211rw/zd_rf.c        |    2 +-
 drivers/net/wireless/zd1211rw/zd_rf.h        |    2 +-
 drivers/net/wireless/zd1211rw/zd_rf_al2230.c |   83 ++++++++++++++++++++++---
 drivers/net/wireless/zd1211rw/zd_usb.c       |    3 +
 12 files changed, 136 insertions(+), 75 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a8c2bfe..254f285 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1145,6 +1145,7 @@ static void airo_networks_free(struct airo_info *ai);
 struct airo_info {
 	struct net_device_stats	stats;
 	struct net_device             *dev;
+	struct list_head              dev_list;
 	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
 	   use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
@@ -2360,6 +2361,21 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu)
 	return 0;
 }
 
+static LIST_HEAD(airo_devices);
+
+static void add_airo_dev(struct airo_info *ai)
+{
+	/* Upper layers already keep track of PCI devices,
+	 * so we only need to remember our non-PCI cards. */
+	if (!ai->pci)
+		list_add_tail(&ai->dev_list, &airo_devices);
+}
+
+static void del_airo_dev(struct airo_info *ai)
+{
+	if (!ai->pci)
+		list_del(&ai->dev_list);
+}
 
 static int airo_close(struct net_device *dev) {
 	struct airo_info *ai = dev->priv;
@@ -2381,8 +2397,6 @@ static int airo_close(struct net_device *dev) {
 	return 0;
 }
 
-static void del_airo_dev( struct net_device *dev );
-
 void stop_airo_card( struct net_device *dev, int freeres )
 {
 	struct airo_info *ai = dev->priv;
@@ -2434,14 +2448,12 @@ void stop_airo_card( struct net_device *dev, int freeres )
 		}
         }
 	crypto_free_cipher(ai->tfm);
-	del_airo_dev( dev );
+	del_airo_dev(ai);
 	free_netdev( dev );
 }
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int add_airo_dev( struct net_device *dev );
-
 static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
@@ -2740,8 +2752,6 @@ static int airo_networks_allocate(struct airo_info *ai)
 
 static void airo_networks_free(struct airo_info *ai)
 {
-	if (!ai->networks)
-		return;
 	kfree(ai->networks);
 	ai->networks = NULL;
 }
@@ -2816,12 +2826,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	if (IS_ERR(ai->airo_thread_task))
 		goto err_out_free;
 	ai->tfm = NULL;
-	rc = add_airo_dev( dev );
-	if (rc)
-		goto err_out_thr;
+	add_airo_dev(ai);
 
 	if (airo_networks_allocate (ai))
-		goto err_out_unlink;
+		goto err_out_thr;
 	airo_networks_initialize (ai);
 
 	/* The Airo-specific entries in the device structure. */
@@ -2852,7 +2860,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	if (rc) {
 		airo_print_err(dev->name, "register interrupt %d failed, rc %d",
 				irq, rc);
-		goto err_out_unlink;
+		goto err_out_nets;
 	}
 	if (!is_pcmcia) {
 		if (!request_region( dev->base_addr, 64, dev->name )) {
@@ -2935,9 +2943,10 @@ err_out_res:
 	        release_region( dev->base_addr, 64 );
 err_out_irq:
 	free_irq(dev->irq, dev);
-err_out_unlink:
-	del_airo_dev(dev);
+err_out_nets:
+	airo_networks_free(ai);
 err_out_thr:
+	del_airo_dev(ai);
 	set_bit(JOB_DIE, &ai->jobs);
 	kthread_stop(ai->airo_thread_task);
 err_out_free:
@@ -5536,11 +5545,6 @@ static int proc_close( struct inode *inode, struct file *file )
 	return 0;
 }
 
-static struct net_device_list {
-	struct net_device *dev;
-	struct net_device_list *next;
-} *airo_devices;
-
 /* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
@@ -5583,26 +5587,6 @@ static void timer_func( struct net_device *dev ) {
 	apriv->expires = RUN_AT(HZ*3);
 }
 
-static int add_airo_dev( struct net_device *dev ) {
-	struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
-	if ( !node )
-		return -ENOMEM;
-
-	node->dev = dev;
-	node->next = airo_devices;
-	airo_devices = node;
-
-	return 0;
-}
-
-static void del_airo_dev( struct net_device *dev ) {
-	struct net_device_list **p = &airo_devices;
-	while( *p && ( (*p)->dev != dev ) )
-		p = &(*p)->next;
-	if ( *p && (*p)->dev == dev )
-		*p = (*p)->next;
-}
-
 #ifdef CONFIG_PCI
 static int __devinit airo_pci_probe(struct pci_dev *pdev,
 				    const struct pci_device_id *pent)
@@ -5626,6 +5610,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
 
 static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	airo_print_info(dev->name, "Unregistering...");
+	stop_airo_card(dev, 1);
 }
 
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5751,9 +5739,11 @@ static int __init airo_init_module( void )
 
 static void __exit airo_cleanup_module( void )
 {
-	while( airo_devices ) {
-		airo_print_info(airo_devices->dev->name, "Unregistering...\n");
-		stop_airo_card( airo_devices->dev, 1 );
+	struct airo_info *ai;
+	while(!list_empty(&airo_devices)) {
+		ai = list_entry(airo_devices.next, struct airo_info, dev_list);
+		airo_print_info(ai->dev->name, "Unregistering...");
+		stop_airo_card(ai->dev, 1);
 	}
 #ifdef CONFIG_PCI
 	pci_unregister_driver(&airo_driver);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 95ff175..f8483c1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -277,11 +277,14 @@
 #define BCM43xx_SBTMSTATELOW_REJECT		0x02
 #define BCM43xx_SBTMSTATELOW_CLOCK		0x10000
 #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK	0x20000
+#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE	0x20000000
 
 /* sbtmstatehigh state flags */
 #define BCM43xx_SBTMSTATEHIGH_SERROR		0x00000001
 #define BCM43xx_SBTMSTATEHIGH_BUSY		0x00000004
 #define BCM43xx_SBTMSTATEHIGH_TIMEOUT		0x00000020
+#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL	0x00010000
+#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL	0x00020000
 #define BCM43xx_SBTMSTATEHIGH_COREFLAGS		0x1FFF0000
 #define BCM43xx_SBTMSTATEHIGH_DMA64BIT		0x10000000
 #define BCM43xx_SBTMSTATEHIGH_GATEDCLK		0x20000000
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 80cb88e..282f98f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1389,7 +1389,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
 				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
 	} else {
 		if (connect_phy)
-			flags |= 0x20000000;
+			flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_phy_connect(bcm, connect_phy);
 		bcm43xx_core_enable(bcm, flags);
 		bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3586,7 +3586,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
 		u32 sbtmstatelow;
 
 		sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		sbtmstatelow |= 0x20000000;
+		sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
 	}
 	err = wireless_core_up(bcm, 1);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index cae8925..8a99790 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
 
 	flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
 	if (connect) {
-		if (!(flags & 0x00010000))
+		if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
 			return -ENODEV;
 		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		flags |= (0x800 << 18);
+		flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
 	} else {
-		if (!(flags & 0x00020000))
+		if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
 			return -ENODEV;
 		flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
-		flags &= ~(0x800 << 18);
+		flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
 	}
 out:
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 32beb91..ee1e7a2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -882,10 +882,10 @@ static void _stack_save(u32 *_stackptr, size_t *stackidx,
 {
 	u32 *stackptr = &(_stackptr[*stackidx]);
 
-	assert((offset & 0xF000) == 0x0000);
-	assert((id & 0xF0) == 0x00);
+	assert((offset & 0xE000) == 0x0000);
+	assert((id & 0xF8) == 0x00);
 	*stackptr = offset;
-	*stackptr |= ((u32)id) << 12;
+	*stackptr |= ((u32)id) << 13;
 	*stackptr |= ((u32)value) << 16;
 	(*stackidx)++;
 	assert(*stackidx < BCM43xx_INTERFSTACK_SIZE);
@@ -896,12 +896,12 @@ static u16 _stack_restore(u32 *stackptr,
 {
 	size_t i;
 
-	assert((offset & 0xF000) == 0x0000);
-	assert((id & 0xF0) == 0x00);
+	assert((offset & 0xE000) == 0x0000);
+	assert((id & 0xF8) == 0x00);
 	for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) {
-		if ((*stackptr & 0x00000FFF) != offset)
+		if ((*stackptr & 0x00001FFF) != offset)
 			continue;
-		if (((*stackptr & 0x0000F000) >> 12) != id)
+		if (((*stackptr & 0x00007000) >> 13) != id)
 			continue;
 		return ((*stackptr & 0xFFFF0000) >> 16);
 	}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index f97288d..f6861da 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
 	i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
 	i += scnprintf(buffer+i, size-i, " ");
 	i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
-	i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+	i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
 		chip->patch_cck_gain ? 'g' : '-',
 		chip->patch_cr157 ? '7' : '-',
 		chip->patch_6m_band_edge ? '6' : '-',
-		chip->new_phy_layout ? 'N' : '-');
+		chip->new_phy_layout ? 'N' : '-',
+		chip->al2230s_bit ? 'S' : '-');
 	return i;
 }
 
@@ -337,6 +338,7 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
 	chip->patch_cr157 = (value >> 13) & 0x1;
 	chip->patch_6m_band_edge = (value >> 21) & 0x1;
 	chip->new_phy_layout = (value >> 31) & 0x1;
+	chip->al2230s_bit = (value >> 7) & 0x1;
 	chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
 	chip->supports_tx_led = 1;
 	if (value & (1 << 24)) { /* LED scenario */
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index b07569e..ae39c22 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -711,7 +711,7 @@ struct zd_chip {
 	u16 link_led;
 	unsigned int pa_type:4,
 		patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
-		new_phy_layout:1,
+		new_phy_layout:1, al2230s_bit:1,
 		is_zd1211b:1, supports_tx_led:1;
 };
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 4c5f78e..19172f5 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -974,14 +974,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
 	switch (ieee->iw_mode) {
 	case IW_MODE_ADHOC:
 		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
-		    memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+		    compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
 			return 0;
 		break;
 	case IW_MODE_AUTO:
 	case IW_MODE_INFRA:
 		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
 		    IEEE80211_FCTL_FROMDS ||
-		    memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+		    compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
 			return 0;
 		break;
 	default:
@@ -989,9 +989,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
 		return 0;
 	}
 
-	return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+	return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
 	       (is_multicast_ether_addr(hdr->addr1) &&
-		memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+		compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
 	       (netdev->flags & IFF_PROMISC);
 }
 
@@ -1047,7 +1047,7 @@ static void update_qual_rssi(struct zd_mac *mac,
 	hdr = (struct ieee80211_hdr_3addr *)buffer;
 	if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
 		return;
-	if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+	if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
 		return;
 
 	spin_lock_irqsave(&mac->lock, flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index f50cff3..e6d604b 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -34,7 +34,7 @@ static const char *rfs[] = {
 	[AL2210_RF]	= "AL2210_RF",
 	[MAXIM_NEW_RF]	= "MAXIM_NEW_RF",
 	[UW2453_RF]	= "UW2453_RF",
-	[AL2230S_RF]	= "AL2230S_RF",
+	[UNKNOWN_A_RF]	= "UNKNOWN_A_RF",
 	[RALINK_RF]	= "RALINK_RF",
 	[INTERSIL_RF]	= "INTERSIL_RF",
 	[RF2959_RF]	= "RF2959_RF",
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index a57732e..ee8ac3a 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -26,7 +26,7 @@
 #define AL2210_RF			0x7
 #define MAXIM_NEW_RF			0x8
 #define UW2453_RF			0x9
-#define AL2230S_RF			0xa
+#define UNKNOWN_A_RF			0xa
 #define RALINK_RF			0xb
 #define INTERSIL_RF			0xc
 #define RF2959_RF			0xd
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 25323a1..85a9ad2 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
 	{ CR240, 0x57 }, { CR9,   0xe0 },
 };
 
+static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
+	{ CR47,   0x1e }, /* MARK_002 */
+	{ CR106,  0x22 },
+	{ CR107,  0x2a }, /* MARK_002 */
+	{ CR109,  0x13 }, /* MARK_002 */
+	{ CR118,  0xf8 }, /* MARK_002 */
+	{ CR119,  0x12 }, { CR122,  0xe0 },
+	{ CR128,  0x10 }, /* MARK_001 from 0xe->0x10 */
+	{ CR129,  0x0e }, /* MARK_001 from 0xd->0x0e */
+	{ CR130,  0x10 }, /* MARK_001 from 0xb->0x0d */
+};
+
 static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
 {
 	int r;
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 	int r;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	static const struct zd_ioreq16 ioreqs[] = {
+	static const struct zd_ioreq16 ioreqs_init[] = {
 		{ CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
 		{ CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
 		{ CR44,   0x33 }, { CR106,  0x2a }, { CR107, 0x1a },
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 		{ CR119,  0x10 }, { CR120,  0x4f }, { CR121, 0x77 },
 		{ CR122,  0xe0 }, { CR137,  0x88 }, { CR252, 0xff },
 		{ CR253,  0xff },
+	};
 
-		/* These following happen separately in the vendor driver */
-		{ },
-
+	static const struct zd_ioreq16 ioreqs_pll[] = {
 		/* shdnb(PLL_ON)=0 */
 		{ CR251,  0x2f },
 		/* shdnb(PLL_ON)=1 */
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 		{ CR138,  0x28 }, { CR203,  0x06 },
 	};
 
-	static const u32 rv[] = {
+	static const u32 rv1[] = {
 		/* Channel 1 */
 		0x03f790,
 		0x033331,
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 		0x0b3331,
 		0x03b812,
 		0x00fff3,
+	};
+
+	static const u32 rv2[] = {
 		0x000da4,
 		0x0f4dc5, /* fix freq shift, 0x04edc5 */
 		0x0805b6,
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 		0x0bdffc,
 		0x00000d,
 		0x00500f,
+	};
 
-		/* These writes happen separately in the vendor driver */
+	static const u32 rv3[] = {
 		0x00d00f,
 		0x004c0f,
 		0x00540f,
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
 		0x00500f,
 	};
 
-	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init));
+	if (r)
+		return r;
+
+	if (chip->al2230s_bit) {
+		r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+			ARRAY_SIZE(ioreqs_init_al2230s));
+		if (r)
+			return r;
+	}
+
+	r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+	if (r)
+		return r;
+
+	/* improve band edge for AL2230S */
+	if (chip->al2230s_bit)
+		r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
+	else
+		r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
 	if (r)
 		return r;
 
-	r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+	r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+	if (r)
+		return r;
+
+	r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll));
+	if (r)
+		return r;
+
+	r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
 	if (r)
 		return r;
 
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
 		0x481dc0,
 		0xcfff00,
 		0x25a000,
+	};
 
+	static const u32 rv2[] = {
 		/* To improve AL2230 yield, improve phase noise, 4713 */
 		0x25a000,
 		0xa3b2f0,
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
 		{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
 	};
 
-	static const u32 rv2[] = {
+	static const u32 rv3[] = {
 		/* To improve AL2230 yield, 4713 */
 		0xf01b00,
 		0xf01e00,
@@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
 	r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
 	if (r)
 		return r;
+
+	if (chip->al2230s_bit) {
+		r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+			ARRAY_SIZE(ioreqs_init_al2230s));
+		if (r)
+			return r;
+	}
+
 	r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
 	if (r)
 		return r;
 	r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
 	if (r)
 		return r;
-	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+
+	if (chip->al2230s_bit)
+		r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
+	else
+		r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
 	if (r)
 		return r;
+
 	r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
 	if (r)
 		return r;
+	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+	if (r)
+		return r;
+	r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3));
+	if (r)
+		return r;
 	r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
 	if (r)
 		return r;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 5e67106..145ad61 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -62,6 +62,9 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-03-16 21:34 ` Please pull 'upstream' " John W. Linville
@ 2007-03-23  5:55   ` Jeff Garzik
  2007-03-23 12:02     ` Dan Williams
  0 siblings, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2007-03-23  5:55 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

John W. Linville wrote:
> The following changes since commit 0e39a919461842a38e406702fe0e94c6138ddfef
>   John W. Linville (1):
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

pulled this and upstream-fixes.  libertas had a merge conflict that I 
would prefer you sort out.

You should merge libertas branch into upstream anyway

	Jeff




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-03-23  5:55   ` Jeff Garzik
@ 2007-03-23 12:02     ` Dan Williams
  0 siblings, 0 replies; 108+ messages in thread
From: Dan Williams @ 2007-03-23 12:02 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: John W. Linville, linux-wireless

On Fri, 2007-03-23 at 01:55 -0400, Jeff Garzik wrote:
> John W. Linville wrote:
> > The following changes since commit 0e39a919461842a38e406702fe0e94c6138ddfef
> >   John W. Linville (1):
> >         Merge branch 'upstream-fixes' into upstream
> > 
> > are found in the git repository at:
> > 
> >   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> pulled this and upstream-fixes.  libertas had a merge conflict that I 
> would prefer you sort out.
> 
> You should merge libertas branch into upstream anyway

Could you elaborate a bit?  We definitely need to get that fixed.

Dan



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-05-29 18:31 ` Please pull 'upstream' " John W. Linville
@ 2007-05-30 14:03   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-05-30 14:03 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, netdev

John W. Linville wrote:
> The following changes since commit d7ea3be56adc95b17351221fd95e78115f3b01f4:
>   Brandon Craig Rhodes (1):
>         hostap: Allocate enough tailroom for TKIP
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Akinobu Mita (1):
>       softmac: use list_for_each_entry
> 
> Daniel Drake (4):
>       zd1211rw: Add ID for ZyXEL G-200v2
>       zd1211rw: Extend RF layer
>       zd1211rw: Add UW2453 RF support
>       zd1211rw: Make CCK gain patching conditional on RF type
> 
> Jouni Malinen (1):
>       hostap: Remove driver version number
> 
> Larry Finger (1):
>       bcm43xx: Fix deviation from specifications in set_baseband_attenuation
> 
> Matthias Kaehlcke (1):
>       hostap: Use list_for_each_entry
> 
> Pavel Roskin (1):
>       hostap: Suppress broadcast if no stations are associated
> 
>  drivers/net/wireless/bcm43xx/bcm43xx_phy.c      |    2 +-
>  drivers/net/wireless/hostap/hostap_ap.c         |   34 +-
>  drivers/net/wireless/hostap/hostap_config.h     |    2 -
>  drivers/net/wireless/hostap/hostap_cs.c         |    4 -
>  drivers/net/wireless/hostap/hostap_ioctl.c      |    2 -
>  drivers/net/wireless/hostap/hostap_main.c       |    1 -
>  drivers/net/wireless/hostap/hostap_pci.c        |    5 -
>  drivers/net/wireless/hostap/hostap_plx.c        |    5 -
>  drivers/net/wireless/zd1211rw/Makefile          |    2 +-
>  drivers/net/wireless/zd1211rw/zd_chip.c         |    5 +-
>  drivers/net/wireless/zd1211rw/zd_chip.h         |    3 +
>  drivers/net/wireless/zd1211rw/zd_rf.c           |   21 +-
>  drivers/net/wireless/zd1211rw/zd_rf.h           |   28 ++
>  drivers/net/wireless/zd1211rw/zd_rf_al2230.c    |    1 +
>  drivers/net/wireless/zd1211rw/zd_rf_al7230b.c   |    1 +
>  drivers/net/wireless/zd1211rw/zd_rf_uw2453.c    |  534 +++++++++++++++++++++++
>  drivers/net/wireless/zd1211rw/zd_usb.c          |    1 +
>  net/ieee80211/softmac/ieee80211softmac_module.c |   32 +-
>  18 files changed, 611 insertions(+), 72 deletions(-)
>  create mode 100644 drivers/net/wireless/zd1211rw/zd_rf_uw2453.c

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-05-29 18:30 Please pull 'upstream-fixes' " John W. Linville
@ 2007-05-29 18:31 ` John W. Linville
  2007-05-30 14:03   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-05-29 18:31 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless, netdev

The following changes since commit d7ea3be56adc95b17351221fd95e78115f3b01f4:
  Brandon Craig Rhodes (1):
        hostap: Allocate enough tailroom for TKIP

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Akinobu Mita (1):
      softmac: use list_for_each_entry

Daniel Drake (4):
      zd1211rw: Add ID for ZyXEL G-200v2
      zd1211rw: Extend RF layer
      zd1211rw: Add UW2453 RF support
      zd1211rw: Make CCK gain patching conditional on RF type

Jouni Malinen (1):
      hostap: Remove driver version number

Larry Finger (1):
      bcm43xx: Fix deviation from specifications in set_baseband_attenuation

Matthias Kaehlcke (1):
      hostap: Use list_for_each_entry

Pavel Roskin (1):
      hostap: Suppress broadcast if no stations are associated

 drivers/net/wireless/bcm43xx/bcm43xx_phy.c      |    2 +-
 drivers/net/wireless/hostap/hostap_ap.c         |   34 +-
 drivers/net/wireless/hostap/hostap_config.h     |    2 -
 drivers/net/wireless/hostap/hostap_cs.c         |    4 -
 drivers/net/wireless/hostap/hostap_ioctl.c      |    2 -
 drivers/net/wireless/hostap/hostap_main.c       |    1 -
 drivers/net/wireless/hostap/hostap_pci.c        |    5 -
 drivers/net/wireless/hostap/hostap_plx.c        |    5 -
 drivers/net/wireless/zd1211rw/Makefile          |    2 +-
 drivers/net/wireless/zd1211rw/zd_chip.c         |    5 +-
 drivers/net/wireless/zd1211rw/zd_chip.h         |    3 +
 drivers/net/wireless/zd1211rw/zd_rf.c           |   21 +-
 drivers/net/wireless/zd1211rw/zd_rf.h           |   28 ++
 drivers/net/wireless/zd1211rw/zd_rf_al2230.c    |    1 +
 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c   |    1 +
 drivers/net/wireless/zd1211rw/zd_rf_uw2453.c    |  534 +++++++++++++++++++++++
 drivers/net/wireless/zd1211rw/zd_usb.c          |    1 +
 net/ieee80211/softmac/ieee80211softmac_module.c |   32 +-
 18 files changed, 611 insertions(+), 72 deletions(-)
 create mode 100644 drivers/net/wireless/zd1211rw/zd_rf_uw2453.c

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b37f1e3..d779199 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1638,7 +1638,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
 		return;
 	}
 
-	if (phy->analog > 1) {
+	if (phy->analog == 1) {
 		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
 		value |= (baseband_attenuation << 2) & 0x003C;
 	} else {
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 5b3abd5..9090052 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -326,7 +326,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
 	char *p = page;
 	struct ap_data *ap = (struct ap_data *) data;
 	char *policy_txt;
-	struct list_head *ptr;
 	struct mac_entry *entry;
 
 	if (off != 0) {
@@ -352,14 +351,12 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
 	p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
 	p += sprintf(p, "MAC list:\n");
 	spin_lock_bh(&ap->mac_restrictions.lock);
-	for (ptr = ap->mac_restrictions.mac_list.next;
-	     ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {
+	list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) {
 		if (p - page > PAGE_SIZE - 80) {
 			p += sprintf(p, "All entries did not fit one page.\n");
 			break;
 		}
 
-		entry = list_entry(ptr, struct mac_entry, list);
 		p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
 	}
 	spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -413,7 +410,6 @@ int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
 static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
 			       u8 *mac)
 {
-	struct list_head *ptr;
 	struct mac_entry *entry;
 	int found = 0;
 
@@ -421,10 +417,7 @@ static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
 		return 0;
 
 	spin_lock_bh(&mac_restrictions->lock);
-	for (ptr = mac_restrictions->mac_list.next;
-	     ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
-		entry = list_entry(ptr, struct mac_entry, list);
-
+	list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
 		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
 			found = 1;
 			break;
@@ -519,7 +512,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
 {
 	char *p = page;
 	struct ap_data *ap = (struct ap_data *) data;
-	struct list_head *ptr;
+	struct sta_info *sta;
 	int i;
 
 	if (off > PROC_LIMIT) {
@@ -529,9 +522,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
 
 	p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
 	spin_lock_bh(&ap->sta_table_lock);
-	for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
-		struct sta_info *sta = (struct sta_info *) ptr;
-
+	list_for_each_entry(sta, &ap->sta_list, list) {
 		if (!sta->ap)
 			continue;
 
@@ -861,7 +852,7 @@ void hostap_init_ap_proc(local_info_t *local)
 
 void hostap_free_data(struct ap_data *ap)
 {
-	struct list_head *n, *ptr;
+	struct sta_info *n, *sta;
 
 	if (ap == NULL || !ap->initialized) {
 		printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
@@ -875,8 +866,7 @@ void hostap_free_data(struct ap_data *ap)
 	ap->crypt = ap->crypt_priv = NULL;
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 
-	list_for_each_safe(ptr, n, &ap->sta_list) {
-		struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+	list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
 		ap_sta_hash_del(ap, sta);
 		list_del(&sta->list);
 		if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
@@ -2704,6 +2694,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
 
 	if (hdr->addr1[0] & 0x01) {
 		/* broadcast/multicast frame - no AP related processing */
+		if (local->ap->num_sta <= 0)
+			ret = AP_TX_DROP;
 		goto out;
 	}
 
@@ -3198,15 +3190,14 @@ int hostap_update_rx_stats(struct ap_data *ap,
 
 void hostap_update_rates(local_info_t *local)
 {
-	struct list_head *ptr;
+	struct sta_info *sta;
 	struct ap_data *ap = local->ap;
 
 	if (!ap)
 		return;
 
 	spin_lock_bh(&ap->sta_table_lock);
-	for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
-		struct sta_info *sta = (struct sta_info *) ptr;
+	list_for_each_entry(sta, &ap->sta_list, list) {
 		prism2_check_tx_rates(sta);
 	}
 	spin_unlock_bh(&ap->sta_table_lock);
@@ -3242,11 +3233,10 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
 void hostap_add_wds_links(local_info_t *local)
 {
 	struct ap_data *ap = local->ap;
-	struct list_head *ptr;
+	struct sta_info *sta;
 
 	spin_lock_bh(&ap->sta_table_lock);
-	list_for_each(ptr, &ap->sta_list) {
-		struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+	list_for_each_entry(sta, &ap->sta_list, list) {
 		if (sta->ap)
 			hostap_wds_link_oper(local, sta->addr, WDS_ADD);
 	}
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h
index c090a5a..30acd39 100644
--- a/drivers/net/wireless/hostap/hostap_config.h
+++ b/drivers/net/wireless/hostap/hostap_config.h
@@ -1,8 +1,6 @@
 #ifndef HOSTAP_CONFIG_H
 #define HOSTAP_CONFIG_H
 
-#define PRISM2_VERSION "0.4.4-kernel"
-
 /* In the previous versions of Host AP driver, support for user space version
  * of IEEE 802.11 management (hostapd) used to be disabled in the default
  * configuration. From now on, support for hostapd is always included and it is
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index ee1532b..30e723f 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static dev_info_t dev_info = "hostap_cs";
 
 MODULE_AUTHOR("Jouni Malinen");
@@ -30,7 +29,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
 		   "cards (PC Card).");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 static int ignore_cis_vcc;
@@ -910,14 +908,12 @@ static struct pcmcia_driver hostap_driver = {
 
 static int __init init_prism2_pccard(void)
 {
-	printk(KERN_INFO "%s: %s\n", dev_info, version);
 	return pcmcia_register_driver(&hostap_driver);
 }
 
 static void __exit exit_prism2_pccard(void)
 {
 	pcmcia_unregister_driver(&hostap_driver);
-	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index cdea7f7..8c71077 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -3893,8 +3893,6 @@ static void prism2_get_drvinfo(struct net_device *dev,
 	local = iface->local;
 
 	strncpy(info->driver, "hostap", sizeof(info->driver) - 1);
-	strncpy(info->version, PRISM2_VERSION,
-		sizeof(info->version) - 1);
 	snprintf(info->fw_version, sizeof(info->fw_version) - 1,
 		 "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
 		 (local->sta_fw_ver >> 8) & 0xff,
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 4743426..446de51 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -37,7 +37,6 @@
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Host AP common routines");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 #define TX_TIMEOUT (2 * HZ)
 
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index db4899e..0cd48d1 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_pci";
 
 
@@ -29,7 +28,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
 		   "PCI cards.");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 /* struct local_info::hw_priv */
@@ -462,8 +460,6 @@ static struct pci_driver prism2_pci_drv_id = {
 
 static int __init init_prism2_pci(void)
 {
-	printk(KERN_INFO "%s: %s\n", dev_info, version);
-
 	return pci_register_driver(&prism2_pci_drv_id);
 }
 
@@ -471,7 +467,6 @@ static int __init init_prism2_pci(void)
 static void __exit exit_prism2_pci(void)
 {
 	pci_unregister_driver(&prism2_pci_drv_id);
-	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index f0fd5ec..0183df7 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,6 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_plx";
 
 
@@ -32,7 +31,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
 		   "cards (PLX).");
 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
 
 
 static int ignore_cis;
@@ -623,8 +621,6 @@ static struct pci_driver prism2_plx_drv_id = {
 
 static int __init init_prism2_plx(void)
 {
-	printk(KERN_INFO "%s: %s\n", dev_info, version);
-
 	return pci_register_driver(&prism2_plx_drv_id);
 }
 
@@ -632,7 +628,6 @@ static int __init init_prism2_plx(void)
 static void __exit exit_prism2_plx(void)
 {
 	pci_unregister_driver(&prism2_plx_drv_id);
-	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
 
 
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 6603ad5..4d50590 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 zd1211rw-objs := zd_chip.o zd_ieee80211.o \
 		zd_mac.o zd_netdev.o \
 		zd_rf_al2230.o zd_rf_rf2959.o \
-		zd_rf_al7230b.o \
+		zd_rf_al7230b.o zd_rf_uw2453.o \
 		zd_rf.o zd_usb.o zd_util.o
 
 ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 95b4a2a..5b624bf 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -1253,6 +1253,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
 {
 	int r;
 
+	if (!zd_rf_should_update_pwr_int(&chip->rf))
+		return 0;
+
 	r = update_pwr_int(chip, channel);
 	if (r)
 		return r;
@@ -1283,7 +1286,7 @@ static int patch_cck_gain(struct zd_chip *chip)
 	int r;
 	u32 value;
 
-	if (!chip->patch_cck_gain)
+	if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf))
 		return 0;
 
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index ce0a5f6..79d0288 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -608,6 +608,9 @@ enum {
 #define CR_ZD1211B_TXOP			CTL_REG(0x0b20)
 #define CR_ZD1211B_RETRY_MAX		CTL_REG(0x0b28)
 
+/* Used to detect PLL lock */
+#define UW2453_INTR_REG			((zd_addr_t)0x85c1)
+
 #define CWIN_SIZE			0x007f043f
 
 
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index 549c23b..7407409 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -52,34 +52,38 @@ const char *zd_rf_name(u8 type)
 void zd_rf_init(struct zd_rf *rf)
 {
 	memset(rf, 0, sizeof(*rf));
+
+	/* default to update channel integration, as almost all RF's do want
+	 * this */
+	rf->update_channel_int = 1;
 }
 
 void zd_rf_clear(struct zd_rf *rf)
 {
+	if (rf->clear)
+		rf->clear(rf);
 	ZD_MEMCLEAR(rf, sizeof(*rf));
 }
 
 int zd_rf_init_hw(struct zd_rf *rf, u8 type)
 {
-	int r, t;
+	int r = 0;
+	int t;
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	switch (type) {
 	case RF2959_RF:
 		r = zd_rf_init_rf2959(rf);
-		if (r)
-			return r;
 		break;
 	case AL2230_RF:
 		r = zd_rf_init_al2230(rf);
-		if (r)
-			return r;
 		break;
 	case AL7230B_RF:
 		r = zd_rf_init_al7230b(rf);
-		if (r)
-			return r;
+		break;
+	case UW2453_RF:
+		r = zd_rf_init_uw2453(rf);
 		break;
 	default:
 		dev_err(zd_chip_dev(chip),
@@ -88,6 +92,9 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
 		return -ENODEV;
 	}
 
+	if (r)
+		return r;
+
 	rf->type = type;
 
 	r = zd_chip_lock_phy_regs(chip);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index aa9cc10..c6dfd82 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -48,12 +48,26 @@ struct zd_rf {
 
 	u8 channel;
 
+	/* whether channel integration and calibration should be updated
+	 * defaults to 1 (yes) */
+	u8 update_channel_int:1;
+
+	/* whether CR47 should be patched from the EEPROM, if the appropriate
+	 * flag is set in the POD. The vendor driver suggests that this should
+	 * be done for all RF's, but a bug in their code prevents but their
+	 * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */
+	u8 patch_cck_gain:1;
+
+	/* private RF driver data */
+	void *priv;
+
 	/* RF-specific functions */
 	int (*init_hw)(struct zd_rf *rf);
 	int (*set_channel)(struct zd_rf *rf, u8 channel);
 	int (*switch_radio_on)(struct zd_rf *rf);
 	int (*switch_radio_off)(struct zd_rf *rf);
 	int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
+	void (*clear)(struct zd_rf *rf);
 };
 
 const char *zd_rf_name(u8 type);
@@ -71,10 +85,24 @@ int zd_switch_radio_off(struct zd_rf *rf);
 int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
 int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
 
+static inline int zd_rf_should_update_pwr_int(struct zd_rf *rf)
+{
+	return rf->update_channel_int;
+}
+
+static inline int zd_rf_should_patch_cck_gain(struct zd_rf *rf)
+{
+	return rf->patch_cck_gain;
+}
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
 /* Functions for individual RF chips */
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
 int zd_rf_init_al2230(struct zd_rf *rf);
 int zd_rf_init_al7230b(struct zd_rf *rf);
+int zd_rf_init_uw2453(struct zd_rf *rf);
 
 #endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 511392a..e7a4ecf 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -432,5 +432,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 		rf->switch_radio_on = zd1211_al2230_switch_radio_on;
 	}
 	rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+	rf->patch_cck_gain = 1;
 	return 0;
 }
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index 5e5e9dd..f4e8b6a 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -483,6 +483,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf)
 		rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
 		rf->set_channel = zd1211_al7230b_set_channel;
 		rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+		rf->patch_cck_gain = 1;
 	}
 
 	rf->switch_radio_off = al7230b_switch_radio_off;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
new file mode 100644
index 0000000..414e40d
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -0,0 +1,534 @@
+/* zd_rf_uw2453.c: Functions for the UW2453 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+/* This RF programming code is based upon the code found in v2.16.0.0 of the
+ * ZyDAS vendor driver. Unlike other RF's, Ubec publish full technical specs
+ * for this RF on their website, so we're able to understand more than
+ * usual as to what is going on. Thumbs up for Ubec for doing that. */
+
+/* The 3-wire serial interface provides access to 8 write-only registers.
+ * The data format is a 4 bit register address followed by a 20 bit value. */
+#define UW2453_REGWRITE(reg, val) ((((reg) & 0xf) << 20) | ((val) & 0xfffff))
+
+/* For channel tuning, we have to configure registers 1 (synthesizer), 2 (synth
+ * fractional divide ratio) and 3 (VCO config).
+ *
+ * We configure the RF to produce an interrupt when the PLL is locked onto
+ * the configured frequency. During initialization, we run through a variety
+ * of different VCO configurations on channel 1 until we detect a PLL lock.
+ * When this happens, we remember which VCO configuration produced the lock
+ * and use it later. Actually, we use the configuration *after* the one that
+ * produced the lock, which seems odd, but it works.
+ *
+ * If we do not see a PLL lock on any standard VCO config, we fall back on an
+ * autocal configuration, which has a fixed (as opposed to per-channel) VCO
+ * config and different synth values from the standard set (divide ratio
+ * is still shared with the standard set). */
+
+/* The per-channel synth values for all standard VCO configurations. These get
+ * written to register 1. */
+static const u8 uw2453_std_synth[] = {
+	RF_CHANNEL( 1) = 0x47,
+	RF_CHANNEL( 2) = 0x47,
+	RF_CHANNEL( 3) = 0x67,
+	RF_CHANNEL( 4) = 0x67,
+	RF_CHANNEL( 5) = 0x67,
+	RF_CHANNEL( 6) = 0x67,
+	RF_CHANNEL( 7) = 0x57,
+	RF_CHANNEL( 8) = 0x57,
+	RF_CHANNEL( 9) = 0x57,
+	RF_CHANNEL(10) = 0x57,
+	RF_CHANNEL(11) = 0x77,
+	RF_CHANNEL(12) = 0x77,
+	RF_CHANNEL(13) = 0x77,
+	RF_CHANNEL(14) = 0x4f,
+};
+
+/* This table stores the synthesizer fractional divide ratio for *all* VCO
+ * configurations (both standard and autocal). These get written to register 2.
+ */
+static const u16 uw2453_synth_divide[] = {
+	RF_CHANNEL( 1) = 0x999,
+	RF_CHANNEL( 2) = 0x99b,
+	RF_CHANNEL( 3) = 0x998,
+	RF_CHANNEL( 4) = 0x99a,
+	RF_CHANNEL( 5) = 0x999,
+	RF_CHANNEL( 6) = 0x99b,
+	RF_CHANNEL( 7) = 0x998,
+	RF_CHANNEL( 8) = 0x99a,
+	RF_CHANNEL( 9) = 0x999,
+	RF_CHANNEL(10) = 0x99b,
+	RF_CHANNEL(11) = 0x998,
+	RF_CHANNEL(12) = 0x99a,
+	RF_CHANNEL(13) = 0x999,
+	RF_CHANNEL(14) = 0xccc,
+};
+
+/* Here is the data for all the standard VCO configurations. We shrink our
+ * table a little by observing that both channels in a consecutive pair share
+ * the same value. We also observe that the high 4 bits ([0:3] in the specs)
+ * are all 'Reserved' and are always set to 0x4 - we chop them off in the data
+ * below. */
+#define CHAN_TO_PAIRIDX(a) ((a - 1) / 2)
+#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)]
+static const u16 uw2453_std_vco_cfg[][7] = {
+	{ /* table 1 */
+		RF_CHANPAIR( 1,  2) = 0x664d,
+		RF_CHANPAIR( 3,  4) = 0x604d,
+		RF_CHANPAIR( 5,  6) = 0x6675,
+		RF_CHANPAIR( 7,  8) = 0x6475,
+		RF_CHANPAIR( 9, 10) = 0x6655,
+		RF_CHANPAIR(11, 12) = 0x6455,
+		RF_CHANPAIR(13, 14) = 0x6665,
+	},
+	{ /* table 2 */
+		RF_CHANPAIR( 1,  2) = 0x666d,
+		RF_CHANPAIR( 3,  4) = 0x606d,
+		RF_CHANPAIR( 5,  6) = 0x664d,
+		RF_CHANPAIR( 7,  8) = 0x644d,
+		RF_CHANPAIR( 9, 10) = 0x6675,
+		RF_CHANPAIR(11, 12) = 0x6475,
+		RF_CHANPAIR(13, 14) = 0x6655,
+	},
+	{ /* table 3 */
+		RF_CHANPAIR( 1,  2) = 0x665d,
+		RF_CHANPAIR( 3,  4) = 0x605d,
+		RF_CHANPAIR( 5,  6) = 0x666d,
+		RF_CHANPAIR( 7,  8) = 0x646d,
+		RF_CHANPAIR( 9, 10) = 0x664d,
+		RF_CHANPAIR(11, 12) = 0x644d,
+		RF_CHANPAIR(13, 14) = 0x6675,
+	},
+	{ /* table 4 */
+		RF_CHANPAIR( 1,  2) = 0x667d,
+		RF_CHANPAIR( 3,  4) = 0x607d,
+		RF_CHANPAIR( 5,  6) = 0x665d,
+		RF_CHANPAIR( 7,  8) = 0x645d,
+		RF_CHANPAIR( 9, 10) = 0x666d,
+		RF_CHANPAIR(11, 12) = 0x646d,
+		RF_CHANPAIR(13, 14) = 0x664d,
+	},
+	{ /* table 5 */
+		RF_CHANPAIR( 1,  2) = 0x6643,
+		RF_CHANPAIR( 3,  4) = 0x6043,
+		RF_CHANPAIR( 5,  6) = 0x667d,
+		RF_CHANPAIR( 7,  8) = 0x647d,
+		RF_CHANPAIR( 9, 10) = 0x665d,
+		RF_CHANPAIR(11, 12) = 0x645d,
+		RF_CHANPAIR(13, 14) = 0x666d,
+	},
+	{ /* table 6 */
+		RF_CHANPAIR( 1,  2) = 0x6663,
+		RF_CHANPAIR( 3,  4) = 0x6063,
+		RF_CHANPAIR( 5,  6) = 0x6643,
+		RF_CHANPAIR( 7,  8) = 0x6443,
+		RF_CHANPAIR( 9, 10) = 0x667d,
+		RF_CHANPAIR(11, 12) = 0x647d,
+		RF_CHANPAIR(13, 14) = 0x665d,
+	},
+	{ /* table 7 */
+		RF_CHANPAIR( 1,  2) = 0x6653,
+		RF_CHANPAIR( 3,  4) = 0x6053,
+		RF_CHANPAIR( 5,  6) = 0x6663,
+		RF_CHANPAIR( 7,  8) = 0x6463,
+		RF_CHANPAIR( 9, 10) = 0x6643,
+		RF_CHANPAIR(11, 12) = 0x6443,
+		RF_CHANPAIR(13, 14) = 0x667d,
+	},
+	{ /* table 8 */
+		RF_CHANPAIR( 1,  2) = 0x6673,
+		RF_CHANPAIR( 3,  4) = 0x6073,
+		RF_CHANPAIR( 5,  6) = 0x6653,
+		RF_CHANPAIR( 7,  8) = 0x6453,
+		RF_CHANPAIR( 9, 10) = 0x6663,
+		RF_CHANPAIR(11, 12) = 0x6463,
+		RF_CHANPAIR(13, 14) = 0x6643,
+	},
+	{ /* table 9 */
+		RF_CHANPAIR( 1,  2) = 0x664b,
+		RF_CHANPAIR( 3,  4) = 0x604b,
+		RF_CHANPAIR( 5,  6) = 0x6673,
+		RF_CHANPAIR( 7,  8) = 0x6473,
+		RF_CHANPAIR( 9, 10) = 0x6653,
+		RF_CHANPAIR(11, 12) = 0x6453,
+		RF_CHANPAIR(13, 14) = 0x6663,
+	},
+	{ /* table 10 */
+		RF_CHANPAIR( 1,  2) = 0x666b,
+		RF_CHANPAIR( 3,  4) = 0x606b,
+		RF_CHANPAIR( 5,  6) = 0x664b,
+		RF_CHANPAIR( 7,  8) = 0x644b,
+		RF_CHANPAIR( 9, 10) = 0x6673,
+		RF_CHANPAIR(11, 12) = 0x6473,
+		RF_CHANPAIR(13, 14) = 0x6653,
+	},
+	{ /* table 11 */
+		RF_CHANPAIR( 1,  2) = 0x665b,
+		RF_CHANPAIR( 3,  4) = 0x605b,
+		RF_CHANPAIR( 5,  6) = 0x666b,
+		RF_CHANPAIR( 7,  8) = 0x646b,
+		RF_CHANPAIR( 9, 10) = 0x664b,
+		RF_CHANPAIR(11, 12) = 0x644b,
+		RF_CHANPAIR(13, 14) = 0x6673,
+	},
+
+};
+
+/* The per-channel synth values for autocal. These get written to register 1. */
+static const u16 uw2453_autocal_synth[] = {
+	RF_CHANNEL( 1) = 0x6847,
+	RF_CHANNEL( 2) = 0x6847,
+	RF_CHANNEL( 3) = 0x6867,
+	RF_CHANNEL( 4) = 0x6867,
+	RF_CHANNEL( 5) = 0x6867,
+	RF_CHANNEL( 6) = 0x6867,
+	RF_CHANNEL( 7) = 0x6857,
+	RF_CHANNEL( 8) = 0x6857,
+	RF_CHANNEL( 9) = 0x6857,
+	RF_CHANNEL(10) = 0x6857,
+	RF_CHANNEL(11) = 0x6877,
+	RF_CHANNEL(12) = 0x6877,
+	RF_CHANNEL(13) = 0x6877,
+	RF_CHANNEL(14) = 0x684f,
+};
+
+/* The VCO configuration for autocal (all channels) */
+static const u16 UW2453_AUTOCAL_VCO_CFG = 0x6662;
+
+/* TX gain settings. The array index corresponds to the TX power integration
+ * values found in the EEPROM. The values get written to register 7. */
+static u32 uw2453_txgain[] = {
+	[0x00] = 0x0e313,
+	[0x01] = 0x0fb13,
+	[0x02] = 0x0e093,
+	[0x03] = 0x0f893,
+	[0x04] = 0x0ea93,
+	[0x05] = 0x1f093,
+	[0x06] = 0x1f493,
+	[0x07] = 0x1f693,
+	[0x08] = 0x1f393,
+	[0x09] = 0x1f35b,
+	[0x0a] = 0x1e6db,
+	[0x0b] = 0x1ff3f,
+	[0x0c] = 0x1ffff,
+	[0x0d] = 0x361d7,
+	[0x0e] = 0x37fbf,
+	[0x0f] = 0x3ff8b,
+	[0x10] = 0x3ff33,
+	[0x11] = 0x3fb3f,
+	[0x12] = 0x3ffff,
+};
+
+/* RF-specific structure */
+struct uw2453_priv {
+	/* index into synth/VCO config tables where PLL lock was found
+	 * -1 means autocal */
+	int config;
+};
+
+#define UW2453_PRIV(rf) ((struct uw2453_priv *) (rf)->priv)
+
+static int uw2453_synth_set_channel(struct zd_chip *chip, int channel,
+	bool autocal)
+{
+	int r;
+	int idx = channel - 1;
+	u32 val;
+
+	if (autocal)
+		val = UW2453_REGWRITE(1, uw2453_autocal_synth[idx]);
+	else
+		val = UW2453_REGWRITE(1, uw2453_std_synth[idx]);
+
+	r = zd_rfwrite_locked(chip, val, RF_RV_BITS);
+	if (r)
+		return r;
+
+	return zd_rfwrite_locked(chip,
+		UW2453_REGWRITE(2, uw2453_synth_divide[idx]), RF_RV_BITS);
+}
+
+static int uw2453_write_vco_cfg(struct zd_chip *chip, u16 value)
+{
+	/* vendor driver always sets these upper bits even though the specs say
+	 * they are reserved */
+	u32 val = 0x40000 | value;
+	return zd_rfwrite_locked(chip, UW2453_REGWRITE(3, val), RF_RV_BITS);
+}
+
+static int uw2453_init_mode(struct zd_chip *chip)
+{
+	static const u32 rv[] = {
+		UW2453_REGWRITE(0, 0x25f98), /* enter IDLE mode */
+		UW2453_REGWRITE(0, 0x25f9a), /* enter CAL_VCO mode */
+		UW2453_REGWRITE(0, 0x25f94), /* enter RX/TX mode */
+		UW2453_REGWRITE(0, 0x27fd4), /* power down RSSI circuit */
+	};
+
+	return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int uw2453_set_tx_gain_level(struct zd_chip *chip, int channel)
+{
+	u8 int_value = chip->pwr_int_values[channel - 1];
+
+	if (int_value >= ARRAY_SIZE(uw2453_txgain)) {
+		dev_dbg_f(zd_chip_dev(chip), "can't configure TX gain for "
+			  "int value %x on channel %d\n", int_value, channel);
+		return 0;
+	}
+
+	return zd_rfwrite_locked(chip,
+		UW2453_REGWRITE(7, uw2453_txgain[int_value]), RF_RV_BITS);
+}
+
+static int uw2453_init_hw(struct zd_rf *rf)
+{
+	int i, r;
+	int found_config = -1;
+	u16 intr_status;
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR10,  0x89 }, { CR15,  0x20 },
+		{ CR17,  0x28 }, /* 6112 no change */
+		{ CR23,  0x38 }, { CR24,  0x20 }, { CR26,  0x93 },
+		{ CR27,  0x15 }, { CR28,  0x3e }, { CR29,  0x00 },
+		{ CR33,  0x28 }, { CR34,  0x30 },
+		{ CR35,  0x43 }, /* 6112 3e->43 */
+		{ CR41,  0x24 }, { CR44,  0x32 },
+		{ CR46,  0x92 }, /* 6112 96->92 */
+		{ CR47,  0x1e },
+		{ CR48,  0x04 }, /* 5602 Roger */
+		{ CR49,  0xfa }, { CR79,  0x58 }, { CR80,  0x30 },
+		{ CR81,  0x30 }, { CR87,  0x0a }, { CR89,  0x04 },
+		{ CR91,  0x00 }, { CR92,  0x0a }, { CR98,  0x8d },
+		{ CR99,  0x28 }, { CR100, 0x02 },
+		{ CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
+		{ CR102, 0x27 },
+		{ CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */
+		{ CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
+		{ CR109, 0x13 },
+		{ CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
+		{ CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 },
+		{ CR114, 0x23 }, /* 6221 27->23 */
+		{ CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
+		{ CR116, 0x24 }, /* 6220 1c->24 */
+		{ CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
+		{ CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
+		{ CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
+		{ CR120, 0x4f },
+		{ CR121, 0x1f }, /* 6220 4f->1f */
+		{ CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad },
+		{ CR126, 0x6c }, { CR127, 0x03 },
+		{ CR128, 0x14 }, /* 6302 12->11 */
+		{ CR129, 0x12 }, /* 6301 10->0f */
+		{ CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 },
+		{ CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff },
+		{ CR253, 0xff },
+	};
+
+	static const u32 rv[] = {
+		UW2453_REGWRITE(4, 0x2b),    /* configure reciever gain */
+		UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */
+		UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */
+		UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */
+
+		/* enter CAL_FIL mode, TX gain set by registers, RX gain set by pins,
+		 * RSSI circuit powered down, reduced RSSI range */
+		UW2453_REGWRITE(0, 0x25f9c), /* 5d01 cal_fil */
+
+		/* synthesizer configuration for channel 1 */
+		UW2453_REGWRITE(1, 0x47),
+		UW2453_REGWRITE(2, 0x999),
+
+		/* disable manual VCO band selection */
+		UW2453_REGWRITE(3, 0x7602),
+
+		/* enable manual VCO band selection, configure current level */
+		UW2453_REGWRITE(3, 0x46063),
+	};
+
+	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	if (r)
+		return r;
+
+	r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+	if (r)
+		return r;
+
+	r = uw2453_init_mode(chip);
+	if (r)
+		return r;
+
+	/* Try all standard VCO configuration settings on channel 1 */
+	for (i = 0; i < ARRAY_SIZE(uw2453_std_vco_cfg) - 1; i++) {
+		/* Configure synthesizer for channel 1 */
+		r = uw2453_synth_set_channel(chip, 1, false);
+		if (r)
+			return r;
+
+		/* Write VCO config */
+		r = uw2453_write_vco_cfg(chip, uw2453_std_vco_cfg[i][0]);
+		if (r)
+			return r;
+
+		/* ack interrupt event */
+		r = zd_iowrite16_locked(chip, 0x0f, UW2453_INTR_REG);
+		if (r)
+			return r;
+
+		/* check interrupt status */
+		r = zd_ioread16_locked(chip, &intr_status, UW2453_INTR_REG);
+		if (r)
+			return r;
+
+		if (!intr_status & 0xf) {
+			dev_dbg_f(zd_chip_dev(chip),
+				"PLL locked on configuration %d\n", i);
+			found_config = i;
+			break;
+		}
+	}
+
+	if (found_config == -1) {
+		/* autocal */
+		dev_dbg_f(zd_chip_dev(chip),
+			"PLL did not lock, using autocal\n");
+
+		r = uw2453_synth_set_channel(chip, 1, true);
+		if (r)
+			return r;
+
+		r = uw2453_write_vco_cfg(chip, UW2453_AUTOCAL_VCO_CFG);
+		if (r)
+			return r;
+	}
+
+	/* To match the vendor driver behaviour, we use the configuration after
+	 * the one that produced a lock. */
+	UW2453_PRIV(rf)->config = found_config + 1;
+
+	return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
+{
+	int r;
+	u16 vco_cfg;
+	int config = UW2453_PRIV(rf)->config;
+	bool autocal = (config == -1);
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+	};
+
+	r = uw2453_synth_set_channel(chip, channel, autocal);
+	if (r)
+		return r;
+
+	if (autocal)
+		vco_cfg = UW2453_AUTOCAL_VCO_CFG;
+	else
+		vco_cfg = uw2453_std_vco_cfg[config][CHAN_TO_PAIRIDX(channel)];
+
+	r = uw2453_write_vco_cfg(chip, vco_cfg);
+	if (r)
+		return r;
+
+	r = uw2453_init_mode(chip);
+	if (r)
+		return r;
+
+	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	if (r)
+		return r;
+
+	r = uw2453_set_tx_gain_level(chip, channel);
+	if (r)
+		return r;
+
+	return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_switch_radio_on(struct zd_rf *rf)
+{
+	int r;
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+	struct zd_ioreq16 ioreqs[] = {
+		{ CR11,  0x00 }, { CR251, 0x3f },
+	};
+
+	/* enter RXTX mode */
+	r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f94), RF_RV_BITS);
+	if (r)
+		return r;
+
+	if (chip->is_zd1211b)
+		ioreqs[1].value = 0x7f;
+
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int uw2453_switch_radio_off(struct zd_rf *rf)
+{
+	int r;
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR11,  0x04 }, { CR251, 0x2f },
+	};
+
+	/* enter IDLE mode */
+	/* FIXME: shouldn't we go to SLEEP? sent email to zydas */
+	r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f90), RF_RV_BITS);
+	if (r)
+		return r;
+
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static void uw2453_clear(struct zd_rf *rf)
+{
+	kfree(rf->priv);
+}
+
+int zd_rf_init_uw2453(struct zd_rf *rf)
+{
+	rf->init_hw = uw2453_init_hw;
+	rf->set_channel = uw2453_set_channel;
+	rf->switch_radio_on = uw2453_switch_radio_on;
+	rf->switch_radio_off = uw2453_switch_radio_off;
+	rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+	rf->clear = uw2453_clear;
+	/* we have our own TX integration code */
+	rf->update_channel_int = 0;
+
+	rf->priv = kmalloc(sizeof(struct uw2453_priv), GFP_KERNEL);
+	if (rf->priv == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 8459549..740a219 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -54,6 +54,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index c308756..6398e6e 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -456,18 +456,13 @@ void
 ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
 	struct ieee80211softmac_network *add_net)
 {
-	struct list_head *list_ptr;
-	struct ieee80211softmac_network *softmac_net = NULL;
+	struct ieee80211softmac_network *softmac_net;
 
-	list_for_each(list_ptr, &mac->network_list) {
-		softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+	list_for_each_entry(softmac_net, &mac->network_list, list) {
 		if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
-			break;
-		else
-			softmac_net = NULL;
+			return;
 	}
-	if(softmac_net == NULL)
-		list_add(&(add_net->list), &mac->network_list);
+	list_add(&(add_net->list), &mac->network_list);
 }
 
 /* Add a network to the list, with locking */
@@ -506,16 +501,13 @@ struct ieee80211softmac_network *
 ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
 	u8 *bssid)
 {
-	struct list_head *list_ptr;
-	struct ieee80211softmac_network *softmac_net = NULL;
-	list_for_each(list_ptr, &mac->network_list) {
-		softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+	struct ieee80211softmac_network *softmac_net;
+
+	list_for_each_entry(softmac_net, &mac->network_list, list) {
 		if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
-			break;
-		else
-			softmac_net = NULL;
+			return softmac_net;
 	}
-	return softmac_net;
+	return NULL;
 }
 
 /* Get a network from the list by BSSID with locking */
@@ -537,11 +529,9 @@ struct ieee80211softmac_network *
 ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
 	struct ieee80211softmac_essid *essid)
 {
-	struct list_head *list_ptr;
-	struct ieee80211softmac_network *softmac_net = NULL;
+	struct ieee80211softmac_network *softmac_net;
 
-	list_for_each(list_ptr, &mac->network_list) {
-		softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+	list_for_each_entry(softmac_net, &mac->network_list, list) {
 		if (softmac_net->essid.len == essid->len &&
 			!memcmp(softmac_net->essid.data, essid->data, essid->len))
 			return softmac_net;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-05-08 17:39 John W. Linville
@ 2007-05-09 22:54 ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-05-09 22:54 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev, linux-wireless

John W. Linville wrote:
> The following changes since commit 5b94f675f57e4ff16c8fda09088d7480a84dcd91:
>   Linus Torvalds (1):
>         Merge master.kernel.org:/.../davem/sparc-2.6
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL
> 
>  drivers/net/wireless/bcm43xx/bcm43xx.h      |   18 +-----
>  drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |    4 -
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c |   81 ---------------------------
>  drivers/net/wireless/bcm43xx/bcm43xx_main.h |   19 ------
>  drivers/net/wireless/zd1211rw/zd_usb.c      |    4 +
>  include/net/ieee80211.h                     |    2 +
>  net/ieee80211/ieee80211_geo.c               |   16 +++++
>  net/ieee80211/ieee80211_wx.c                |    8 ++-
>  8 files changed, 31 insertions(+), 121 deletions(-)

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2007-05-08 17:39 John W. Linville
  2007-05-09 22:54 ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-05-08 17:39 UTC (permalink / raw)
  To: jeff; +Cc: netdev, linux-wireless

The following changes since commit 5b94f675f57e4ff16c8fda09088d7480a84dcd91:
  Linus Torvalds (1):
        Merge master.kernel.org:/.../davem/sparc-2.6

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Add ID for ZyXEL AG-225H v2

Larry Finger (3):
      ieee80211: add ieee80211_channel_to_freq
      ieee80211: include frequency in scan results
      bcm43xx: Remove dead configuration variable CONFIG_947XX

Matthew Davidson (1):
      zd1211rw: Add ID for Sitecom WL-117

Ulrich Kunitz (1):
      zd1211rw: Added new USB id for Planex GW-US54ZGL

 drivers/net/wireless/bcm43xx/bcm43xx.h      |   18 +-----
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |    4 -
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |   81 ---------------------------
 drivers/net/wireless/bcm43xx/bcm43xx_main.h |   19 ------
 drivers/net/wireless/zd1211rw/zd_usb.c      |    4 +
 include/net/ieee80211.h                     |    2 +
 net/ieee80211/ieee80211_geo.c               |   16 +++++
 net/ieee80211/ieee80211_wx.c                |    8 ++-
 8 files changed, 31 insertions(+), 121 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index f8483c1..10e07e8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -658,12 +658,6 @@ struct bcm43xx_pio {
 
 #define BCM43xx_MAX_80211_CORES		2
 
-#ifdef CONFIG_BCM947XX
-#define core_offset(bcm) (bcm)->current_core_offset
-#else
-#define core_offset(bcm) 0
-#endif
-
 /* Generic information about a core. */
 struct bcm43xx_coreinfo {
 	u8 available:1,
@@ -789,10 +783,6 @@ struct bcm43xx_private {
 
 	/* The currently active core. */
 	struct bcm43xx_coreinfo *current_core;
-#ifdef CONFIG_BCM947XX
-	/** current core memory offset */
-	u32 current_core_offset;
-#endif
 	struct bcm43xx_coreinfo *active_80211_core;
 	/* coreinfo structs for all possible cores follow.
 	 * Note that a core might not exist.
@@ -943,25 +933,25 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
 static inline
 u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread16(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
 {
-	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite16(value, bcm->mmio_addr + offset);
 }
 
 static inline
 u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread32(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
 {
-	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite32(value, bcm->mmio_addr + offset);
 }
 
 static inline
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index e3d2e61..1f7731f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -660,10 +660,6 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
 	if (dma64)
 		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
-#endif
 
 	ring->bcm = bcm;
 	ring->nr_slots = nr_slots;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 5e96bca..ef6b253 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -61,10 +61,6 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_BCM947XX
-extern char *nvram_get(char *name);
-#endif
-
 #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
@@ -142,10 +138,6 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple fi
 	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 43XG 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#ifdef CONFIG_BCM947XX
-	/* SB bus on BCM947xx */
-	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#endif
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
@@ -786,9 +778,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 {
 	u16 value;
 	u16 *sprom;
-#ifdef CONFIG_BCM947XX
-	char *c;
-#endif
 
 	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
 			GFP_KERNEL);
@@ -796,28 +785,7 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 		printk(KERN_ERR PFX "sprom_extract OOM\n");
 		return -ENOMEM;
 	}
-#ifdef CONFIG_BCM947XX
-	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
-	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
-
-	if ((c = nvram_get("il0macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
-
-	if ((c = nvram_get("et1macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
-
-	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
-	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
-	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
-
-	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
-	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
-	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
-
-	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
-#else
 	bcm43xx_sprom_read(bcm, sprom);
-#endif
 
 	/* boardflags2 */
 	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
@@ -1225,12 +1193,6 @@ static int _switch_core(struct bcm43xx_private *bcm, int core)
 			goto error;
 		udelay(10);
 	}
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		bcm->current_core_offset = 0x1000 * core;
-	else
-		bcm->current_core_offset = 0;
-#endif
 
 	return 0;
 error:
@@ -1387,19 +1349,6 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
 
 	if ((bcm43xx_core_enabled(bcm)) &&
 	    !bcm43xx_using_pio(bcm)) {
-//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
-#if 0
-#ifndef CONFIG_BCM947XX
-		/* reset all used DMA controllers. */
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		if (bcm->current_core->rev < 5)
-			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-#endif
-#endif
 	}
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -2140,32 +2089,11 @@ out:
 	return err;
 }
 
-#ifdef CONFIG_BCM947XX
-static struct pci_device_id bcm43xx_47xx_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-	{ 0 }
-};
-#endif
-
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
 	int err;
 
 	bcm->irq = bcm->pci_dev->irq;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0) {
-		struct pci_dev *d;
-		struct pci_device_id *id;
-		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
-			d = pci_get_device(id->vendor, id->device, NULL);
-			if (d != NULL) {
-				bcm->irq = d->irq;
-				pci_dev_put(d);
-				break;
-			}
-		}
-	}
-#endif
 	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
 			  IRQF_SHARED, KBUILD_MODNAME, bcm);
 	if (err)
@@ -2645,10 +2573,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
 			chip_id_16 = 0x4610;
 		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
 			chip_id_16 = 0x4710;
-#ifdef CONFIG_BCM947XX
-		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
-			chip_id_16 = 0x4309;
-#endif
 		else {
 			printk(KERN_ERR PFX "Could not determine Chip ID\n");
 			return -ENODEV;
@@ -4144,11 +4068,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
 	struct bcm43xx_private *bcm;
 	int err;
 
-#ifdef CONFIG_BCM947XX
-	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
-		return -ENODEV;
-#endif
-
 #ifdef DEBUG_SINGLE_DEVICE_ONLY
 	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
 		return -ENODEV;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index f763571..c8f3c53 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -33,25 +33,6 @@
 
 #include "bcm43xx.h"
 
-#ifdef CONFIG_BCM947XX
-#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-
-static inline void e_aton(char *str, char *dest)
-{
-	int i = 0;
-	u16 *d = (u16 *) dest;
-
-	for (;;) {
-		dest[i++] = (char) simple_strtoul(str, NULL, 16);
-		str += 2;
-		if (!*str++ || i == 6)
-			break;
-	}
-	for (i = 0; i < 3; i++)
-		d[i] = cpu_to_be16(d[i]);
-}
-#endif
-
 #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
 /* Magic helper macro to pad structures. Ignore those above. It's magic. */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index e04cffc..8459549 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -40,6 +40,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
@@ -67,8 +68,11 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
 	{}
 };
 
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d56b292..bbd85cd 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1291,6 +1291,8 @@ extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
 extern const struct ieee80211_channel *ieee80211_get_channel(struct
 							     ieee80211_device
 							     *ieee, u8 channel);
+extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
+				      u8 channel);
 
 /* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
index 305a09d..960ad13 100644
--- a/net/ieee80211/ieee80211_geo.c
+++ b/net/ieee80211/ieee80211_geo.c
@@ -94,6 +94,21 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
 	return -1;
 }
 
+u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+{
+	const struct ieee80211_channel * ch;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+		return 0;
+
+	ch = ieee80211_get_channel(ieee, channel);
+	if (!ch->channel)
+		return 0;
+	return ch->freq;
+}
+
 u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
 {
 	int i;
@@ -174,6 +189,7 @@ EXPORT_SYMBOL(ieee80211_get_channel);
 EXPORT_SYMBOL(ieee80211_get_channel_flags);
 EXPORT_SYMBOL(ieee80211_is_valid_channel);
 EXPORT_SYMBOL(ieee80211_freq_to_channel);
+EXPORT_SYMBOL(ieee80211_channel_to_freq);
 EXPORT_SYMBOL(ieee80211_channel_to_index);
 EXPORT_SYMBOL(ieee80211_set_geo);
 EXPORT_SYMBOL(ieee80211_get_geo);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index cee5e13..523a137 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -89,15 +89,17 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
 	}
 
-	/* Add frequency/channel */
+	/* Add channel and frequency */
 	iwe.cmd = SIOCGIWFREQ;
-/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
-	iwe.u.freq.e = 3; */
 	iwe.u.freq.m = network->channel;
 	iwe.u.freq.e = 0;
 	iwe.u.freq.i = 0;
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
 
+	iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+	iwe.u.freq.e = 6;
+	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	if (network->capability & WLAN_CAPABILITY_PRIVACY)
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-08 17:38   ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-08 17:38 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless, netdev

This request is withdrawn.  New request to follow.

On Mon, May 07, 2007 at 01:51:21PM -0400, John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes
> 
> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL

-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-08 17:38   ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-08 17:38 UTC (permalink / raw)
  To: jeff-o2qLIJkoznsdnm+yROfE0A
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA

This request is withdrawn.  New request to follow.

On Mon, May 07, 2007 at 01:51:21PM -0400, John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes
> 
> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL

-- 
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-08  8:49     ` Johannes Berg
  0 siblings, 0 replies; 108+ messages in thread
From: Johannes Berg @ 2007-05-08  8:49 UTC (permalink / raw)
  To: Dan Williams; +Cc: John W. Linville, jeff, linux-wireless, netdev

[-- Attachment #1: Type: text/plain, Size: 310 bytes --]

On Mon, 2007-05-07 at 17:15 -0400, Dan Williams wrote:

> So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
> are in for 2.6.22?  Or is that for 2.6.23?

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2a5e1c0eb9efe26eed1dd072fe08de5797a7efd5

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-08  8:49     ` Johannes Berg
  0 siblings, 0 replies; 108+ messages in thread
From: Johannes Berg @ 2007-05-08  8:49 UTC (permalink / raw)
  To: Dan Williams
  Cc: John W. Linville, jeff-o2qLIJkoznsdnm+yROfE0A,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 310 bytes --]

On Mon, 2007-05-07 at 17:15 -0400, Dan Williams wrote:

> So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
> are in for 2.6.22?  Or is that for 2.6.23?

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2a5e1c0eb9efe26eed1dd072fe08de5797a7efd5

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-05-07 23:09   ` Jeff Garzik
  (?)
  (?)
@ 2007-05-07 23:38   ` John W. Linville
  -1 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-07 23:38 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: linux-wireless, netdev

On Mon, May 07, 2007 at 07:09:20PM -0400, Jeff Garzik wrote:
> John W. Linville wrote:

> >Ivo van Doorn (1):
> >      Add 93cx6 eeprom library

> >Michael Wu (1):
> >      Add rtl8187 wireless driver

I presume these are the two parts you question.  (Just checking...)

> The normal development process is:
> 
> * commit new code to your repository
> * that goes into -mm for public testing and review
> * merge window opens
> * the code that has seen public testing and review goes upstream
> 
> The general idea is everything you want in 2.6.22 should be prepared and 
> in -mm BEFORE 2.6.21 is released, and the 2.6.22 merge window opens.
> 
> It's quite normal for fixes and minor changes to trickle in after the 
> push that follows the merge window opening.  But new drivers that have 
> not been through this process do not fall under "fixes and minor changes."
 
I agree whole-heartedly.

The whole mac80211 driver package (including rtl8187) has been in -mm
(and rawhide) for most of the 2.6.21 development cycle.  The rtl8187
driver in particular has been relatively stable for the past couple
of months ("3 files changed, 13 insertions(+), 4 deletions(-)" since
7 March 2007), and it seems to work well.

> I also did not see any response to my "better as a single file driver" 
> suggestion.

Yes, I see that now.  Do you consider this a merge requirement?

My main concern pre-merge would be accidentally destabilizing the code
while stitching the files together.  Other than that, the suggestion
seems worthwhile.  However, I think Michael plans to expand the driver
to support rtl8180 and rtl8185.  This may factor into why he chose
to organize the code the way he has.

> So, I'll pull if you remove the two late additions.

Any chance that you find the comments above persuasive? :-)

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 23:30     ` Michael Wu
  0 siblings, 0 replies; 108+ messages in thread
From: Michael Wu @ 2007-05-07 23:30 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: John W. Linville, linux-wireless, netdev

[-- Attachment #1: Type: text/plain, Size: 255 bytes --]

On Monday 07 May 2007 19:09, Jeff Garzik wrote:
> The general idea is everything you want in 2.6.22 should be prepared and
> in -mm BEFORE 2.6.21 is released, and the 2.6.22 merge window opens.
>
rtl8187 has been in -mm since 2.6.21-rc2-mm1.

-Michael Wu

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 23:30     ` Michael Wu
  0 siblings, 0 replies; 108+ messages in thread
From: Michael Wu @ 2007-05-07 23:30 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: John W. Linville, linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 255 bytes --]

On Monday 07 May 2007 19:09, Jeff Garzik wrote:
> The general idea is everything you want in 2.6.22 should be prepared and
> in -mm BEFORE 2.6.21 is released, and the 2.6.22 merge window opens.
>
rtl8187 has been in -mm since 2.6.21-rc2-mm1.

-Michael Wu

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 23:09   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-05-07 23:09 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless, netdev

John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes
> 
> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL


The normal development process is:

* commit new code to your repository
* that goes into -mm for public testing and review
* merge window opens
* the code that has seen public testing and review goes upstream

The general idea is everything you want in 2.6.22 should be prepared and 
in -mm BEFORE 2.6.21 is released, and the 2.6.22 merge window opens.

It's quite normal for fixes and minor changes to trickle in after the 
push that follows the merge window opening.  But new drivers that have 
not been through this process do not fall under "fixes and minor changes."

I also did not see any response to my "better as a single file driver" 
suggestion.

So, I'll pull if you remove the two late additions.

	Jeff



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 23:09   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-05-07 23:09 UTC (permalink / raw)
  To: John W. Linville
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA

John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes
> 
> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL


The normal development process is:

* commit new code to your repository
* that goes into -mm for public testing and review
* merge window opens
* the code that has seen public testing and review goes upstream

The general idea is everything you want in 2.6.22 should be prepared and 
in -mm BEFORE 2.6.21 is released, and the 2.6.22 merge window opens.

It's quite normal for fixes and minor changes to trickle in after the 
push that follows the merge window opening.  But new drivers that have 
not been through this process do not fall under "fixes and minor changes."

I also did not see any response to my "better as a single file driver" 
suggestion.

So, I'll pull if you remove the two late additions.

	Jeff

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 22:51     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-07 22:51 UTC (permalink / raw)
  To: Dan Williams; +Cc: jeff, linux-wireless, netdev

On Mon, May 07, 2007 at 05:15:50PM -0400, Dan Williams wrote:
> On Mon, 2007-05-07 at 13:51 -0400, John W. Linville wrote:

> > John W. Linville (1):
> >       libertas: fix for wireless Kconfig changes
> 
> So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
> are in for 2.6.22?  Or is that for 2.6.23?

My hope/intent is for Jeff to pull and pass this along in time for 2.6.22.

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 22:51     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-07 22:51 UTC (permalink / raw)
  To: Dan Williams
  Cc: jeff-o2qLIJkoznsdnm+yROfE0A,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, May 07, 2007 at 05:15:50PM -0400, Dan Williams wrote:
> On Mon, 2007-05-07 at 13:51 -0400, John W. Linville wrote:

> > John W. Linville (1):
> >       libertas: fix for wireless Kconfig changes
> 
> So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
> are in for 2.6.22?  Or is that for 2.6.23?

My hope/intent is for Jeff to pull and pass this along in time for 2.6.22.

John
-- 
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 21:15   ` Dan Williams
  0 siblings, 0 replies; 108+ messages in thread
From: Dan Williams @ 2007-05-07 21:15 UTC (permalink / raw)
  To: John W. Linville; +Cc: jeff, linux-wireless, netdev

On Mon, 2007-05-07 at 13:51 -0400, John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes

So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
are in for 2.6.22?  Or is that for 2.6.23?

Dan

> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL
> 
>  MAINTAINERS                                    |   10 +
>  drivers/misc/Kconfig                           |    6 +
>  drivers/misc/Makefile                          |    1 +
>  drivers/misc/eeprom_93cx6.c                    |  347 +++++++++++
>  drivers/net/wireless/Kconfig                   |    4 +-
>  drivers/net/wireless/Makefile                  |    3 +
>  drivers/net/wireless/bcm43xx/bcm43xx.h         |   18 +-
>  drivers/net/wireless/bcm43xx/bcm43xx_dma.c     |    4 -
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   81 ---
>  drivers/net/wireless/bcm43xx/bcm43xx_main.h    |   19 -
>  drivers/net/wireless/rtl818x/Kconfig           |   16 +
>  drivers/net/wireless/rtl818x/Makefile          |    2 +
>  drivers/net/wireless/rtl818x/rtl8187.h         |  125 ++++
>  drivers/net/wireless/rtl818x/rtl8187_dev.c     |  730 +++++++++++++++++++++++
>  drivers/net/wireless/rtl818x/rtl8187_rtl8225.c |  744 ++++++++++++++++++++++++
>  drivers/net/wireless/rtl818x/rtl8187_rtl8225.h |   30 +
>  drivers/net/wireless/rtl818x/rtl818x.h         |  212 +++++++
>  drivers/net/wireless/zd1211rw/zd_usb.c         |    4 +
>  include/linux/eeprom_93cx6.h                   |   77 +++
>  include/net/ieee80211.h                        |    2 +
>  net/ieee80211/ieee80211_geo.c                  |   16 +
>  net/ieee80211/ieee80211_wx.c                   |    8 +-
>  net/mac80211/ieee80211_sta.c                   |    2 +-
>  23 files changed, 2338 insertions(+), 123 deletions(-)
>  create mode 100644 drivers/misc/eeprom_93cx6.c
>  create mode 100644 drivers/net/wireless/rtl818x/Kconfig
>  create mode 100644 drivers/net/wireless/rtl818x/Makefile
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187.h
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_dev.c
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
>  create mode 100644 drivers/net/wireless/rtl818x/rtl818x.h
>  create mode 100644 include/linux/eeprom_93cx6.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0492dd8..c72774f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2935,6 +2935,16 @@ S:	Maintained
>  RISCOM8 DRIVER
>  S:	Orphan
>  
> +RTL818X WIRELESS DRIVER
> +P:	Michael Wu
> +M:	flamingice@sourmilk.net
> +P:	Andrea Merello
> +M:	andreamrl@tiscali.it
> +L:	linux-wireless@vger.kernel.org
> +W:	http://linuxwireless.org/
> +T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
> +S:	Maintained
> +
>  S3 SAVAGE FRAMEBUFFER DRIVER
>  P:	Antonino Daplas
>  M:	adaplas@gmail.com
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index a3c525b..607a180 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -178,4 +178,10 @@ config THINKPAD_ACPI_BAY
>  
>  	  If you are not sure, say Y here.
>  
> +config EEPROM_93CX6
> +	tristate "EEPROM 93CX6 support"
> +	---help---
> +	  This is a driver for the EEPROM chipsets 93c46 and 93c66.
> +	  The driver supports both read as well as write commands.
> +
>  endmenu
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index e325164..42b34a9 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
>  obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
>  obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
>  obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
> +obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
> diff --git a/drivers/misc/eeprom_93cx6.c b/drivers/misc/eeprom_93cx6.c
> new file mode 100644
> index 0000000..a948ddc
> --- /dev/null
> +++ b/drivers/misc/eeprom_93cx6.c
> @@ -0,0 +1,347 @@
> +/*
> +	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
> +	<http://rt2x00.serialmonkey.com>
> +
> +	This program is free software; you can redistribute it and/or modify
> +	it under the terms of the GNU General Public License as published by
> +	the Free Software Foundation; either version 2 of the License, or
> +	(at your option) any later version.
> +
> +	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.,
> +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +/*
> +	Module: eeprom_93cx6
> +	Abstract: EEPROM reader routines for 93cx6 chipsets.
> +	Supported chipsets: 93c46 & 93c66.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/version.h>
> +#include <linux/delay.h>
> +#include <linux/eeprom_93cx6.h>
> +
> +MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
> +MODULE_VERSION("1.0");
> +MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
> +MODULE_LICENSE("GPL");
> +
> +static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
> +{
> +	eeprom->reg_data_clock = 1;
> +	eeprom->register_write(eeprom);
> +	udelay(1);
> +}
> +
> +static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
> +{
> +	eeprom->reg_data_clock = 0;
> +	eeprom->register_write(eeprom);
> +	udelay(1);
> +}
> +
> +static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Clear all flags, and enable chip select.
> +	 */
> +	eeprom->register_read(eeprom);
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +	eeprom->reg_data_clock = 0;
> +	eeprom->reg_chip_select = 1;
> +	eeprom->register_write(eeprom);
> +
> +	/*
> +	 * kick a pulse.
> +	 */
> +	eeprom_93cx6_pulse_high(eeprom);
> +	eeprom_93cx6_pulse_low(eeprom);
> +}
> +
> +static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Clear chip_select and data_in flags.
> +	 */
> +	eeprom->register_read(eeprom);
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_chip_select = 0;
> +	eeprom->register_write(eeprom);
> +
> +	/*
> +	 * kick a pulse.
> +	 */
> +	eeprom_93cx6_pulse_high(eeprom);
> +	eeprom_93cx6_pulse_low(eeprom);
> +}
> +
> +static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
> +	const u16 data, const u16 count)
> +{
> +	unsigned int i;
> +
> +	eeprom->register_read(eeprom);
> +
> +	/*
> +	 * Clear data flags.
> +	 */
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +
> +	/*
> +	 * Start writing all bits.
> +	 */
> +	for (i = count; i > 0; i--) {
> +		/*
> +		 * Check if this bit needs to be set.
> +		 */
> +		eeprom->reg_data_in = !!(data & (1 << (i - 1)));
> +
> +		/*
> +		 * Write the bit to the eeprom register.
> +		 */
> +		eeprom->register_write(eeprom);
> +
> +		/*
> +		 * Kick a pulse.
> +		 */
> +		eeprom_93cx6_pulse_high(eeprom);
> +		eeprom_93cx6_pulse_low(eeprom);
> +	}
> +
> +	eeprom->reg_data_in = 0;
> +	eeprom->register_write(eeprom);
> +}
> +
> +static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
> +	u16 *data, const u16 count)
> +{
> +	unsigned int i;
> +	u16 buf = 0;
> +
> +	eeprom->register_read(eeprom);
> +
> +	/*
> +	 * Clear data flags.
> +	 */
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +
> +	/*
> +	 * Start reading all bits.
> +	 */
> +	for (i = count; i > 0; i--) {
> +		eeprom_93cx6_pulse_high(eeprom);
> +
> +		eeprom->register_read(eeprom);
> +
> +		/*
> +		 * Clear data_in flag.
> +		 */
> +		eeprom->reg_data_in = 0;
> +
> +		/*
> +		 * Read if the bit has been set.
> +		 */
> +		if (eeprom->reg_data_out)
> +			buf |= (1 << (i - 1));
> +
> +		eeprom_93cx6_pulse_low(eeprom);
> +	}
> +
> +	*data = buf;
> +}
> +
> +static void eeprom_93cx6_ewen(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWEN_OPCODE, 5);
> +	eeprom_93cx6_write_bits(eeprom, 0, 6);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +
> +static void eeprom_93cx6_ewds(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWDS_OPCODE, 5);
> +	eeprom_93cx6_write_bits(eeprom, 0, 6);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +
> +/**
> + * eeprom_93cx6_read - Read multiple words from eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start reading
> + * @data: target pointer where the information will have to be stored
> + *
> + * This function will read the eeprom data as host-endian word
> + * into the given data pointer.
> + */
> +void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
> +	u16 *data)
> +{
> +	u16 command;
> +
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
> +	eeprom_93cx6_write_bits(eeprom, command,
> +		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
> +
> +	/*
> +	 * Read the requested 16 bits.
> +	 */
> +	eeprom_93cx6_read_bits(eeprom, data, 16);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
> +
> +/**
> + * eeprom_93cx6_multiread - Read multiple words from eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start reading
> + * @data: target pointer where the information will have to be stored
> + * @words: Number of words that should be read.
> + *
> + * This function will read all requested words from the eeprom,
> + * this is done by calling eeprom_93cx6_read() multiple times.
> + * But with the additional change that while the eeprom_93cx6_read
> + * will return host ordered bytes, this method will return little
> + * endian words.
> + */
> +void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
> +	__le16 *data, const u16 words)
> +{
> +	unsigned int i;
> +	u16 tmp;
> +
> +	for (i = 0; i < words; i++) {
> +		tmp = 0;
> +		eeprom_93cx6_read(eeprom, word + i, &tmp);
> +		data[i] = cpu_to_le16(tmp);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
> +
> +/**
> + * eeprom_93cx6_write - Write multiple words to the eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start writing
> + * @data: Data that will be written
> + *
> + * This function will write the eeprom data as host-endian word
> + * from the given data pointer.
> + */
> +void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, const u8 word,
> +	u16 data)
> +{
> +	u16 command;
> +
> +	/*
> +	 * select the ewen opcode.
> +	 */
> +	eeprom_93cx6_ewen(eeprom);
> +
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the write opcode and the word to be read.
> +	 */
> +	command = (PCI_EEPROM_WRITE_OPCODE << eeprom->width) | word;
> +	eeprom_93cx6_write_bits(eeprom, command,
> +		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
> +
> +	/*
> +	 * Write the requested 16 bits.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, data, 16);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +
> +	/*
> +	 * Take a short break.
> +	 */
> +	msleep(10000);
> +
> +	/*
> +	 * select the ewen opcode.
> +	 */
> +	eeprom_93cx6_ewds(eeprom);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_write);
> +
> +
> +/**
> + * eeprom_93cx6_multiwrite - Write multiple words to the eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start writing
> + * @data: Pointer where the information will be read from
> + * @words: Number of words that should be written.
> + *
> + * This function will write all requested words to the eeprom,
> + * this is done by calling eeprom_93cx6_write() multiple times.
> + * This method accepts little endian data, so it will first be
> + * converted into host endian.
> + */
> +void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom, const u8 word,
> +	__le16 *data, const u16 words)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < words; i++)
> +		eeprom_93cx6_write(eeprom, word + i, le16_to_cpu(data[i]));
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_multiwrite);
> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
> index 0184614..6ff5a8a 100644
> --- a/drivers/net/wireless/Kconfig
> +++ b/drivers/net/wireless/Kconfig
> @@ -267,7 +267,7 @@ config IPW2200_DEBUG
>  
>  config LIBERTAS_USB
>  	tristate "Marvell Libertas 8388 802.11a/b/g cards"
> -	depends on NET_RADIO && USB
> +	depends on USB && WLAN_80211
>  	select FW_LOADER
>  	---help---
>  	  A driver for Marvell Libertas 8388 USB devices.
> @@ -542,4 +542,6 @@ source "drivers/net/wireless/hostap/Kconfig"
>  source "drivers/net/wireless/bcm43xx/Kconfig"
>  source "drivers/net/wireless/zd1211rw/Kconfig"
>  
> +source "drivers/net/wireless/rtl818x/Kconfig"
> +
>  endmenu
> diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
> index d212460..198c992 100644
> --- a/drivers/net/wireless/Makefile
> +++ b/drivers/net/wireless/Makefile
> @@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
>  
>  obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
>  obj-$(CONFIG_LIBERTAS_USB)     += libertas/
> +
> +# Drivers using mac80211 stack (net/mac80211)
> +obj-$(CONFIG_RTL818X)		+= rtl818x/
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
> index f8483c1..10e07e8 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx.h
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
> @@ -658,12 +658,6 @@ struct bcm43xx_pio {
>  
>  #define BCM43xx_MAX_80211_CORES		2
>  
> -#ifdef CONFIG_BCM947XX
> -#define core_offset(bcm) (bcm)->current_core_offset
> -#else
> -#define core_offset(bcm) 0
> -#endif
> -
>  /* Generic information about a core. */
>  struct bcm43xx_coreinfo {
>  	u8 available:1,
> @@ -789,10 +783,6 @@ struct bcm43xx_private {
>  
>  	/* The currently active core. */
>  	struct bcm43xx_coreinfo *current_core;
> -#ifdef CONFIG_BCM947XX
> -	/** current core memory offset */
> -	u32 current_core_offset;
> -#endif
>  	struct bcm43xx_coreinfo *active_80211_core;
>  	/* coreinfo structs for all possible cores follow.
>  	 * Note that a core might not exist.
> @@ -943,25 +933,25 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
>  static inline
>  u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
>  {
> -	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
> +	return ioread16(bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
>  {
> -	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
> +	iowrite16(value, bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
>  {
> -	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
> +	return ioread32(bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
>  {
> -	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
> +	iowrite32(value, bcm->mmio_addr + offset);
>  }
>  
>  static inline
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> index e3d2e61..1f7731f 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> @@ -660,10 +660,6 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
>  	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
>  	if (dma64)
>  		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0)
> -		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
> -#endif
>  
>  	ring->bcm = bcm;
>  	ring->nr_slots = nr_slots;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> index 5e96bca..ef6b253 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> @@ -61,10 +61,6 @@ MODULE_AUTHOR("Stefano Brivio");
>  MODULE_AUTHOR("Michael Buesch");
>  MODULE_LICENSE("GPL");
>  
> -#ifdef CONFIG_BCM947XX
> -extern char *nvram_get(char *name);
> -#endif
> -
>  #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
>  static int modparam_pio;
>  module_param_named(pio, modparam_pio, int, 0444);
> @@ -142,10 +138,6 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple fi
>  	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
>  	/* Broadcom 43XG 802.11b/g */
>  	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
> -#ifdef CONFIG_BCM947XX
> -	/* SB bus on BCM947xx */
> -	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
> -#endif
>  	{ 0 },
>  };
>  MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
> @@ -786,9 +778,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
>  {
>  	u16 value;
>  	u16 *sprom;
> -#ifdef CONFIG_BCM947XX
> -	char *c;
> -#endif
>  
>  	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
>  			GFP_KERNEL);
> @@ -796,28 +785,7 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
>  		printk(KERN_ERR PFX "sprom_extract OOM\n");
>  		return -ENOMEM;
>  	}
> -#ifdef CONFIG_BCM947XX
> -	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
> -	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
> -
> -	if ((c = nvram_get("il0macaddr")) != NULL)
> -		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
> -
> -	if ((c = nvram_get("et1macaddr")) != NULL)
> -		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
> -
> -	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
> -	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
> -	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
> -
> -	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
> -	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
> -	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
> -
> -	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
> -#else
>  	bcm43xx_sprom_read(bcm, sprom);
> -#endif
>  
>  	/* boardflags2 */
>  	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
> @@ -1225,12 +1193,6 @@ static int _switch_core(struct bcm43xx_private *bcm, int core)
>  			goto error;
>  		udelay(10);
>  	}
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0)
> -		bcm->current_core_offset = 0x1000 * core;
> -	else
> -		bcm->current_core_offset = 0;
> -#endif
>  
>  	return 0;
>  error:
> @@ -1387,19 +1349,6 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
>  
>  	if ((bcm43xx_core_enabled(bcm)) &&
>  	    !bcm43xx_using_pio(bcm)) {
> -//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
> -#if 0
> -#ifndef CONFIG_BCM947XX
> -		/* reset all used DMA controllers. */
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
> -		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
> -		if (bcm->current_core->rev < 5)
> -			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
> -#endif
> -#endif
>  	}
>  	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
>  		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> @@ -2140,32 +2089,11 @@ out:
>  	return err;
>  }
>  
> -#ifdef CONFIG_BCM947XX
> -static struct pci_device_id bcm43xx_47xx_ids[] = {
> -	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
> -	{ 0 }
> -};
> -#endif
> -
>  static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
>  {
>  	int err;
>  
>  	bcm->irq = bcm->pci_dev->irq;
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0) {
> -		struct pci_dev *d;
> -		struct pci_device_id *id;
> -		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
> -			d = pci_get_device(id->vendor, id->device, NULL);
> -			if (d != NULL) {
> -				bcm->irq = d->irq;
> -				pci_dev_put(d);
> -				break;
> -			}
> -		}
> -	}
> -#endif
>  	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
>  			  IRQF_SHARED, KBUILD_MODNAME, bcm);
>  	if (err)
> @@ -2645,10 +2573,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
>  			chip_id_16 = 0x4610;
>  		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
>  			chip_id_16 = 0x4710;
> -#ifdef CONFIG_BCM947XX
> -		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
> -			chip_id_16 = 0x4309;
> -#endif
>  		else {
>  			printk(KERN_ERR PFX "Could not determine Chip ID\n");
>  			return -ENODEV;
> @@ -4144,11 +4068,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
>  	struct bcm43xx_private *bcm;
>  	int err;
>  
> -#ifdef CONFIG_BCM947XX
> -	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
> -		return -ENODEV;
> -#endif
> -
>  #ifdef DEBUG_SINGLE_DEVICE_ONLY
>  	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
>  		return -ENODEV;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> index f763571..c8f3c53 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> @@ -33,25 +33,6 @@
>  
>  #include "bcm43xx.h"
>  
> -#ifdef CONFIG_BCM947XX
> -#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
> -
> -static inline void e_aton(char *str, char *dest)
> -{
> -	int i = 0;
> -	u16 *d = (u16 *) dest;
> -
> -	for (;;) {
> -		dest[i++] = (char) simple_strtoul(str, NULL, 16);
> -		str += 2;
> -		if (!*str++ || i == 6)
> -			break;
> -	}
> -	for (i = 0; i < 3; i++)
> -		d[i] = cpu_to_be16(d[i]);
> -}
> -#endif
> -
>  #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
>  #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
>  /* Magic helper macro to pad structures. Ignore those above. It's magic. */
> diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
> new file mode 100644
> index 0000000..e2c27f8
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/Kconfig
> @@ -0,0 +1,16 @@
> +config RTL818X
> +	bool
> +	default n
> +
> +config RTL8187
> +	tristate "Realtek 8187 USB support"
> +	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
> +	select RTL818X
> +	select EEPROM_93CX6
> +	---help---
> +	  This is a driver for RTL8187 based cards.
> +	  These are USB based chips found in cards such as:
> +
> +	  Netgear WG111v2
> +
> +	  Thanks to Realtek for their support!
> diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
> new file mode 100644
> index 0000000..fe5dd6f
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/Makefile
> @@ -0,0 +1,2 @@
> +rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
> +obj-$(CONFIG_RTL8187)	+= rtl8187.o
> diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
> new file mode 100644
> index 0000000..bd0b6f9
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187.h
> @@ -0,0 +1,125 @@
> +#ifndef RTL8187_H
> +#define RTL8187_H
> +
> +#include "rtl818x.h"
> +
> +#define RTL8187_REQT_READ	0xC0
> +#define RTL8187_REQT_WRITE	0x40
> +#define RTL8187_REQ_GET_REG	0x05
> +#define RTL8187_REQ_SET_REG	0x05
> +
> +#define RTL8187_MAX_RX		0x9C4
> +
> +struct rtl8187_rx_info {
> +	struct urb *urb;
> +	struct ieee80211_hw *dev;
> +};
> +
> +struct rtl8187_rx_hdr {
> +	__le16 len;
> +	__le16 rate;
> +	u8 noise;
> +	u8 signal;
> +	u8 agc;
> +	u8 reserved;
> +	__le64 mac_time;
> +} __attribute__((packed));
> +
> +struct rtl8187_tx_info {
> +	struct ieee80211_tx_control *control;
> +	struct urb *urb;
> +	struct ieee80211_hw *dev;
> +};
> +
> +struct rtl8187_tx_hdr {
> +	__le32 flags;
> +#define RTL8187_TX_FLAG_NO_ENCRYPT	(1 << 15)
> +#define RTL8187_TX_FLAG_MORE_FRAG	(1 << 17)
> +#define RTL8187_TX_FLAG_CTS		(1 << 18)
> +#define RTL8187_TX_FLAG_RTS		(1 << 23)
> +	__le16 rts_duration;
> +	__le16 len;
> +	__le32 retry;
> +} __attribute__((packed));
> +
> +struct rtl8187_priv {
> +	/* common between rtl818x drivers */
> +	struct rtl818x_csr *map;
> +	void (*rf_init)(struct ieee80211_hw *);
> +	int mode;
> +
> +	/* rtl8187 specific */
> +	struct ieee80211_channel channels[14];
> +	struct ieee80211_rate rates[12];
> +	struct ieee80211_hw_mode modes[2];
> +	struct usb_device *udev;
> +	u8 *hwaddr;
> +	u16 txpwr_base;
> +	u8 asic_rev;
> +	struct sk_buff_head rx_queue;
> +};
> +
> +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
> +
> +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
> +{
> +	u8 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return val;
> +}
> +
> +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
> +{
> +	__le16 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return le16_to_cpu(val);
> +}
> +
> +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
> +{
> +	__le32 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return le32_to_cpu(val);
> +}
> +
> +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
> +				    u8 *addr, u8 val)
> +{
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +}
> +
> +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
> +				     __le16 *addr, u16 val)
> +{
> +	__le16 buf = cpu_to_le16(val);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
> +}
> +
> +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
> +				     __le32 *addr, u32 val)
> +{
> +	__le32 buf = cpu_to_le32(val);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
> +}
> +
> +#endif /* RTL8187_H */
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
> new file mode 100644
> index 0000000..8f9e781
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
> @@ -0,0 +1,730 @@
> +
> +/*
> + * Linux device driver for RTL8187
> + *
> + * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
> + *
> + * Based on the r8187 driver, which is:
> + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
> + *
> + * Thanks to Realtek for their support!
> + *
> + * 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
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/usb.h>
> +#include <linux/delay.h>
> +#include <linux/etherdevice.h>
> +#include <linux/eeprom_93cx6.h>
> +#include <net/mac80211.h>
> +
> +#include "rtl8187.h"
> +#include "rtl8187_rtl8225.h"
> +
> +MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
> +MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
> +MODULE_DESCRIPTION("RTL8187 USB wireless driver");
> +MODULE_LICENSE("GPL");
> +
> +static struct usb_device_id rtl8187_table[] __devinitdata = {
> +	/* Realtek */
> +	{USB_DEVICE(0x0bda, 0x8187)},
> +	/* Netgear */
> +	{USB_DEVICE(0x0846, 0x6100)},
> +	{USB_DEVICE(0x0846, 0x6a00)},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(usb, rtl8187_table);
> +
> +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	data <<= 8;
> +	data |= addr | 0x80;
> +
> +	rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
> +
> +	mdelay(1);
> +}
> +
> +static void rtl8187_tx_cb(struct urb *urb)
> +{
> +	struct ieee80211_tx_status status = { {0} };
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
> +
> +	usb_free_urb(info->urb);
> +	if (info->control)
> +		memcpy(&status.control, info->control, sizeof(status.control));
> +	kfree(info->control);
> +	skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
> +	status.flags |= IEEE80211_TX_STATUS_ACK;
> +	ieee80211_tx_status_irqsafe(info->dev, skb, &status);
> +}
> +
> +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
> +		      struct ieee80211_tx_control *control)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_tx_hdr *hdr;
> +	struct rtl8187_tx_info *info;
> +	struct urb *urb;
> +	u32 tmp;
> +
> +	urb = usb_alloc_urb(0, GFP_ATOMIC);
> +	if (!urb) {
> +		kfree_skb(skb);
> +		return 0;
> +	}
> +
> +	hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
> +	tmp = skb->len - sizeof(*hdr);
> +	tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
> +	tmp |= control->rts_cts_rate << 19;
> +	tmp |= control->tx_rate << 24;
> +	if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
> +		tmp |= RTL8187_TX_FLAG_MORE_FRAG;
> +	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
> +		tmp |= RTL8187_TX_FLAG_RTS;
> +		hdr->rts_duration =
> +			ieee80211_rts_duration(dev, skb->len, control);
> +	}
> +	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
> +		tmp |= RTL8187_TX_FLAG_CTS;
> +	hdr->flags = cpu_to_le32(tmp);
> +	hdr->len = 0;
> +	tmp = control->retry_limit << 8;
> +	hdr->retry = cpu_to_le32(tmp);
> +
> +	info = (struct rtl8187_tx_info *)skb->cb;
> +	info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
> +	info->urb = urb;
> +	info->dev = dev;
> +	usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
> +			  hdr, skb->len, rtl8187_tx_cb, skb);
> +	usb_submit_urb(urb, GFP_ATOMIC);
> +
> +	return 0;
> +}
> +
> +static void rtl8187_rx_cb(struct urb *urb)
> +{
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
> +	struct ieee80211_hw *dev = info->dev;
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_rx_hdr *hdr;
> +	struct ieee80211_rx_status rx_status = { 0 };
> +	int rate, signal;
> +
> +	if (unlikely(urb->status)) {
> +		info->urb = NULL;
> +		usb_free_urb(urb);
> +		return;
> +	}
> +
> +	skb_unlink(skb, &priv->rx_queue);
> +	skb_put(skb, urb->actual_length);
> +	hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
> +	skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
> +
> +	signal = hdr->agc >> 1;
> +	rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
> +	if (rate > 3) {	/* OFDM rate */
> +		if (signal > 90)
> +			signal = 90;
> +		else if (signal < 25)
> +			signal = 25;
> +		signal = 90 - signal;
> +	} else {	/* CCK rate */
> +		if (signal > 95)
> +			signal = 95;
> +		else if (signal < 30)
> +			signal = 30;
> +		signal = 95 - signal;
> +	}
> +
> +	rx_status.antenna = (hdr->signal >> 7) & 1;
> +	rx_status.signal = 64 - min(hdr->noise, (u8)64);
> +	rx_status.ssi = signal;
> +	rx_status.rate = rate;
> +	rx_status.freq = dev->conf.freq;
> +	rx_status.channel = dev->conf.channel;
> +	rx_status.phymode = dev->conf.phymode;
> +	rx_status.mactime = le64_to_cpu(hdr->mac_time);
> +	ieee80211_rx_irqsafe(dev, skb, &rx_status);
> +
> +	skb = dev_alloc_skb(RTL8187_MAX_RX);
> +	if (unlikely(!skb)) {
> +		usb_free_urb(urb);
> +		/* TODO check rx queue length and refill *somewhere* */
> +		return;
> +	}
> +
> +	info = (struct rtl8187_rx_info *)skb->cb;
> +	info->urb = urb;
> +	info->dev = dev;
> +	urb->transfer_buffer = skb_tail_pointer(skb);
> +	urb->context = skb;
> +	skb_queue_tail(&priv->rx_queue, skb);
> +
> +	usb_submit_urb(urb, GFP_ATOMIC);
> +}
> +
> +static int rtl8187_init_urbs(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct urb *entry;
> +	struct sk_buff *skb;
> +	struct rtl8187_rx_info *info;
> +
> +	while (skb_queue_len(&priv->rx_queue) < 8) {
> +		skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
> +		if (!skb)
> +			break;
> +		entry = usb_alloc_urb(0, GFP_KERNEL);
> +		if (!entry) {
> +			kfree_skb(skb);
> +			break;
> +		}
> +		usb_fill_bulk_urb(entry, priv->udev,
> +				  usb_rcvbulkpipe(priv->udev, 1),
> +				  skb_tail_pointer(skb),
> +				  RTL8187_MAX_RX, rtl8187_rx_cb, skb);
> +		info = (struct rtl8187_rx_info *)skb->cb;
> +		info->urb = entry;
> +		info->dev = dev;
> +		skb_queue_tail(&priv->rx_queue, skb);
> +		usb_submit_urb(entry, GFP_KERNEL);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rtl8187_init_hw(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg;
> +	int i;
> +
> +	/* reset */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
> +
> +	mdelay(200);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
> +	mdelay(200);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg &= (1 << 1);
> +	reg |= RTL818X_CMD_RESET;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	i = 10;
> +	do {
> +		mdelay(2);
> +		if (!(rtl818x_ioread8(priv, &priv->map->CMD) &
> +		      RTL818X_CMD_RESET))
> +			break;
> +	} while (--i);
> +
> +	if (!i) {
> +		printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* reload registers from eeprom */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
> +
> +	i = 10;
> +	do {
> +		mdelay(4);
> +		if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) &
> +		      RTL818X_EEPROM_CMD_CONFIG))
> +			break;
> +	} while (--i);
> +
> +	if (!i) {
> +		printk(KERN_ERR "%s: eeprom reset timeout!\n",
> +		       wiphy_name(dev->wiphy));
> +		return -ETIMEDOUT;
> +	}
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	/* setup card */
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
> +
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
> +	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
> +
> +	rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
> +	reg &= 0x3F;
> +	reg |= 0x80;
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
> +	rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
> +	rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
> +
> +	// TODO: set RESP_RATE and BRSR properly
> +	rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
> +
> +	/* host_usb_init */
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
> +	reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
> +	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80);
> +	mdelay(100);
> +
> +	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
> +	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
> +	mdelay(100);
> +
> +	priv->rf_init(dev);
> +
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
> +	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
> +	rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
> +	rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
> +	rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
> +
> +	return 0;
> +}
> +
> +static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
> +{
> +	u32 reg;
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
> +	/* Enable TX loopback on MAC level to avoid TX during channel
> +	 * changes, as this has be seen to causes problems and the
> +	 * card will stop work until next reset
> +	 */
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
> +			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
> +	mdelay(10);
> +	rtl8225_rf_set_channel(dev, channel);
> +	mdelay(10);
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
> +}
> +
> +static int rtl8187_open(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u32 reg;
> +	int ret;
> +
> +	ret = rtl8187_init_hw(dev);
> +	if (ret)
> +		return ret;
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
> +
> +	rtl8187_init_urbs(dev);
> +
> +	reg = RTL818X_RX_CONF_ONLYERLPKT |
> +	      RTL818X_RX_CONF_RX_AUTORESETPHY |
> +	      RTL818X_RX_CONF_BSSID |
> +	      RTL818X_RX_CONF_MGMT |
> +	      RTL818X_RX_CONF_CTRL |
> +	      RTL818X_RX_CONF_DATA |
> +	      (7 << 13 /* RX FIFO threshold NONE */) |
> +	      (7 << 10 /* MAX RX DMA */) |
> +	      RTL818X_RX_CONF_BROADCAST |
> +	      RTL818X_RX_CONF_MULTICAST |
> +	      RTL818X_RX_CONF_NICMAC;
> +	if (priv->mode == IEEE80211_IF_TYPE_MNTR)
> +		reg |= RTL818X_RX_CONF_MONITOR;
> +
> +	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
> +	reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
> +	reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
> +	rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
> +	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
> +	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
> +	reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
> +	rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
> +
> +	reg  = RTL818X_TX_CONF_CW_MIN |
> +	       (7 << 21 /* MAX TX DMA */) |
> +	       RTL818X_TX_CONF_NO_ICV;
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg |= RTL818X_CMD_TX_ENABLE;
> +	reg |= RTL818X_CMD_RX_ENABLE;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	return 0;
> +}
> +
> +static int rtl8187_stop(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_rx_info *info;
> +	struct sk_buff *skb;
> +	u32 reg;
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg &= ~RTL818X_CMD_TX_ENABLE;
> +	reg &= ~RTL818X_CMD_RX_ENABLE;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	rtl8225_rf_stop(dev);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	while ((skb = skb_dequeue(&priv->rx_queue))) {
> +		info = (struct rtl8187_rx_info *)skb->cb;
> +		if (!info->urb)
> +			continue;
> +
> +		usb_kill_urb(info->urb);
> +		kfree_skb(skb);
> +	}
> +	return 0;
> +}
> +
> +static int rtl8187_add_interface(struct ieee80211_hw *dev,
> +				 struct ieee80211_if_init_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
> +	if (priv->mode != IEEE80211_IF_TYPE_MGMT)
> +		return -1;
> +
> +	switch (conf->type) {
> +	case IEEE80211_IF_TYPE_STA:
> +	case IEEE80211_IF_TYPE_MNTR:
> +		priv->mode = conf->type;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	priv->hwaddr = conf->mac_addr;
> +
> +	return 0;
> +}
> +
> +static void rtl8187_remove_interface(struct ieee80211_hw *dev,
> +				     struct ieee80211_if_init_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	priv->mode = IEEE80211_IF_TYPE_MGMT;
> +}
> +
> +static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	rtl8187_set_channel(dev, conf->channel);
> +
> +	rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
> +
> +	if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
> +		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
> +	else
> +		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
> +
> +	switch (conf->phymode) {
> +	case MODE_IEEE80211B:
> +		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
> +		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
> +		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
> +		break;
> +	case MODE_IEEE80211G:
> +		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
> +		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
> +		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
> +		break;
> +	default:
> +		BUG();
> +		break;
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
> +	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
> +	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
> +	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
> +	return 0;
> +}
> +
> +static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
> +				    struct ieee80211_if_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
> +
> +	if (is_valid_ether_addr(conf->bssid))
> +		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
> +	else
> +		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
> +
> +	return 0;
> +}
> +
> +static const struct ieee80211_ops rtl8187_ops = {
> +	.tx			= rtl8187_tx,
> +	.open			= rtl8187_open,
> +	.stop			= rtl8187_stop,
> +	.add_interface		= rtl8187_add_interface,
> +	.remove_interface	= rtl8187_remove_interface,
> +	.config			= rtl8187_config,
> +	.config_interface	= rtl8187_config_interface,
> +};
> +
> +static void rtl8187_register_read(struct eeprom_93cx6 *eeprom)
> +{
> +	struct ieee80211_hw *dev = eeprom->data;
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
> +
> +	eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
> +	eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
> +	eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
> +	eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
> +}
> +
> +static void rtl8187_register_write(struct eeprom_93cx6 *eeprom)
> +{
> +	struct ieee80211_hw *dev = eeprom->data;
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg = RTL818X_EEPROM_CMD_PROGRAM;
> +
> +	if (eeprom->reg_data_in)
> +		reg |= RTL818X_EEPROM_CMD_WRITE;
> +	if (eeprom->reg_data_out)
> +		reg |= RTL818X_EEPROM_CMD_READ;
> +	if (eeprom->reg_data_clock)
> +		reg |= RTL818X_EEPROM_CMD_CK;
> +	if (eeprom->reg_chip_select)
> +		reg |= RTL818X_EEPROM_CMD_CS;
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
> +	udelay(10);
> +}
> +
> +static int __devinit rtl8187_probe(struct usb_interface *intf,
> +				   const struct usb_device_id *id)
> +{
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	struct ieee80211_hw *dev;
> +	struct rtl8187_priv *priv;
> +	struct eeprom_93cx6 eeprom;
> +	struct ieee80211_channel *channel;
> +	u16 txpwr, reg;
> +	int err, i;
> +
> +	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
> +	if (!dev) {
> +		printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	priv = dev->priv;
> +
> +	SET_IEEE80211_DEV(dev, &intf->dev);
> +	usb_set_intfdata(intf, dev);
> +	priv->udev = udev;
> +
> +	usb_get_dev(udev);
> +
> +	skb_queue_head_init(&priv->rx_queue);
> +	memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
> +	memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
> +	priv->map = (struct rtl818x_csr *)0xFF00;
> +	priv->modes[0].mode = MODE_IEEE80211G;
> +	priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
> +	priv->modes[0].rates = priv->rates;
> +	priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
> +	priv->modes[0].channels = priv->channels;
> +	priv->modes[1].mode = MODE_IEEE80211B;
> +	priv->modes[1].num_rates = 4;
> +	priv->modes[1].rates = priv->rates;
> +	priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
> +	priv->modes[1].channels = priv->channels;
> +	priv->mode = IEEE80211_IF_TYPE_MGMT;
> +	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
> +		     IEEE80211_HW_RX_INCLUDES_FCS |
> +		     IEEE80211_HW_WEP_INCLUDE_IV |
> +		     IEEE80211_HW_DATA_NULLFUNC_ACK;
> +	dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
> +	dev->queues = 1;
> +	dev->max_rssi = 65;
> +	dev->max_signal = 64;
> +
> +	for (i = 0; i < 2; i++)
> +		if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
> +			goto err_free_dev;
> +
> +	eeprom.data = dev;
> +	eeprom.register_read = rtl8187_register_read;
> +	eeprom.register_write = rtl8187_register_write;
> +	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
> +		eeprom.width = PCI_EEPROM_WIDTH_93C66;
> +	else
> +		eeprom.width = PCI_EEPROM_WIDTH_93C46;
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	udelay(10);
> +
> +	eeprom_93cx6_multiread(&eeprom, 0x7,
> +			       (__le16 __force *)dev->wiphy->perm_addr, 3);
> +	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
> +		printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly generated MAC address\n");
> +		random_ether_addr(dev->wiphy->perm_addr);
> +	}
> +
> +	channel = priv->channels;
> +	for (i = 0; i < 3; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x16 + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +	for (i = 0; i < 2; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x3D + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +	for (i = 0; i < 2; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x1B + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +
> +	eeprom_93cx6_read(&eeprom, 0x05, &priv->txpwr_base);
> +
> +	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
> +	/* 0 means asic B-cut, we should use SW 3 wire
> +	 * bit-by-bit banging for radio. 1 means we can use
> +	 * USB specific request to write radio registers */
> +	priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write(dev, 0, 0x1B7);
> +
> +	if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
> +		priv->rf_init = rtl8225_rf_init;
> +	else
> +		priv->rf_init = rtl8225z2_rf_init;
> +
> +	rtl8225_write(dev, 0, 0x0B7);
> +
> +	err = ieee80211_register_hw(dev);
> +	if (err) {
> +		printk(KERN_ERR "rtl8187: Cannot register device\n");
> +		goto err_free_dev;
> +	}
> +
> +	printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
> +	       wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
> +	       priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
> +	       "rtl8225" : "rtl8225z2");
> +
> +	return 0;
> +
> + err_free_dev:
> +	ieee80211_free_hw(dev);
> +	usb_set_intfdata(intf, NULL);
> +	usb_put_dev(udev);
> +	return err;
> +}
> +
> +static void __devexit rtl8187_disconnect(struct usb_interface *intf)
> +{
> +	struct ieee80211_hw *dev = usb_get_intfdata(intf);
> +	struct rtl8187_priv *priv;
> +
> +	if (!dev)
> +		return;
> +
> +	ieee80211_unregister_hw(dev);
> +
> +	priv = dev->priv;
> +	usb_put_dev(interface_to_usbdev(intf));
> +	ieee80211_free_hw(dev);
> +}
> +
> +static struct usb_driver rtl8187_driver = {
> +	.name		= KBUILD_MODNAME,
> +	.id_table	= rtl8187_table,
> +	.probe		= rtl8187_probe,
> +	.disconnect	= rtl8187_disconnect,
> +};
> +
> +static int __init rtl8187_init(void)
> +{
> +	return usb_register(&rtl8187_driver);
> +}
> +
> +static void __exit rtl8187_exit(void)
> +{
> +	usb_deregister(&rtl8187_driver);
> +}
> +
> +module_init(rtl8187_init);
> +module_exit(rtl8187_exit);
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
> new file mode 100644
> index 0000000..a89f023
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
> @@ -0,0 +1,744 @@
> +
> +/*
> + * Radio tuning for RTL8225 on RTL8187
> + *
> + * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
> + *
> + * Based on the r8187 driver, which is:
> + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
> + *
> + * Thanks to Realtek for their support!
> + *
> + * 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
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/usb.h>
> +#include <net/mac80211.h>
> +
> +#include "rtl8187.h"
> +#include "rtl8187_rtl8225.h"
> +
> +static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg84, reg82;
> +	u32 bangdata;
> +	int i;
> +
> +	bangdata = (data << 4) | (addr & 0xf);
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
> +
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(10);
> +
> +	for (i = 15; i >= 0; i--) {
> +		u16 reg = reg80 | (bangdata & (1 << i)) >> i;
> +
> +		if (i & 1)
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
> +
> +		if (!(i & 1))
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	mdelay(2);
> +}
> +
> +static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg82, reg84;
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +
> +	reg80 &= ~(0x3 << 2);
> +	reg84 &= ~0xF;
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(10);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			addr, 0x8225, &data, sizeof(data), HZ / 2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	mdelay(2);
> +}
> +
> +void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	if (priv->asic_rev)
> +		rtl8225_write_8051(dev, addr, data);
> +	else
> +		rtl8225_write_bitbang(dev, addr, data);
> +}
> +
> +u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg82, reg84, out;
> +	int i;
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +
> +	reg80 &= ~0xF;
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(4);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(5);
> +
> +	for (i = 4; i >= 0; i--) {
> +		u16 reg = reg80 | ((addr >> i) & 1);
> +
> +		if (!(i & 1)) {
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +			udelay(1);
> +		}
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg | (1 << 1));
> +		udelay(2);
> +
> +		if (i & 1) {
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +			udelay(1);
> +		}
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3) | (1 << 1));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3));
> +	udelay(2);
> +
> +	out = 0;
> +	for (i = 11; i >= 0; i--) {
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3));
> +		udelay(1);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +
> +		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
> +			out |= 1 << i;
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3));
> +		udelay(2);
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3) | (1 << 2));
> +	udelay(2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
> +
> +	return out;
> +}
> +
> +static const u16 rtl8225bcd_rxgain[] = {
> +	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
> +	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
> +	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
> +	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
> +	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
> +	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
> +	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
> +	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
> +	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
> +	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
> +	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
> +	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
> +};
> +
> +static const u8 rtl8225_agc[] = {
> +	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
> +	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
> +	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
> +	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
> +	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
> +	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
> +	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
> +	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
> +	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
> +	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
> +	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
> +	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
> +	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
> +};
> +
> +static const u8 rtl8225_gain[] = {
> +	0x23, 0x88, 0x7c, 0xa5,	/* -82dBm */
> +	0x23, 0x88, 0x7c, 0xb5,	/* -82dBm */
> +	0x23, 0x88, 0x7c, 0xc5,	/* -82dBm */
> +	0x33, 0x80, 0x79, 0xc5,	/* -78dBm */
> +	0x43, 0x78, 0x76, 0xc5,	/* -74dBm */
> +	0x53, 0x60, 0x73, 0xc5,	/* -70dBm */
> +	0x63, 0x58, 0x70, 0xc5,	/* -66dBm */
> +};
> +
> +static const u8 rtl8225_threshold[] = {
> +	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
> +};
> +
> +static const u8 rtl8225_tx_gain_cck_ofdm[] = {
> +	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
> +};
> +
> +static const u8 rtl8225_tx_power_cck[] = {
> +	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
> +	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
> +	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
> +	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
> +	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
> +	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
> +};
> +
> +static const u8 rtl8225_tx_power_cck_ch14[] = {
> +	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
> +	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
> +	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
> +	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
> +	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
> +	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +static const u8 rtl8225_tx_power_ofdm[] = {
> +	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
> +};
> +
> +static const u32 rtl8225_chan[] = {
> +	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
> +	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
> +};
> +
> +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 cck_power, ofdm_power;
> +	const u8 *tmp;
> +	u32 reg;
> +	int i;
> +
> +	cck_power = priv->channels[channel - 1].val & 0xF;
> +	ofdm_power = priv->channels[channel - 1].val >> 4;
> +
> +	cck_power = min(cck_power, (u8)11);
> +	ofdm_power = min(ofdm_power, (u8)35);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
> +			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
> +
> +	if (channel == 14)
> +		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
> +	else
> +		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
> +
> +	for (i = 0; i < 8; i++)
> +		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
> +
> +	mdelay(1); // FIXME: optional?
> +
> +	/* anaparam2 on */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write_phy_ofdm(dev, 2, 0x42);
> +	rtl8225_write_phy_ofdm(dev, 6, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 8, 0x00);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
> +			 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
> +
> +	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
> +
> +	rtl8225_write_phy_ofdm(dev, 5, *tmp);
> +	rtl8225_write_phy_ofdm(dev, 7, *tmp);
> +
> +	mdelay(1);
> +}
> +
> +void rtl8225_rf_init(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	rtl8225_write(dev, 0x0, 0x067); mdelay(1);
> +	rtl8225_write(dev, 0x1, 0xFE0); mdelay(1);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
> +	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
> +	rtl8225_write(dev, 0x4, 0x486); mdelay(1);
> +	rtl8225_write(dev, 0x5, 0xBC0); mdelay(1);
> +	rtl8225_write(dev, 0x6, 0xAE6); mdelay(1);
> +	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
> +	rtl8225_write(dev, 0x8, 0x01F); mdelay(1);
> +	rtl8225_write(dev, 0x9, 0x334); mdelay(1);
> +	rtl8225_write(dev, 0xA, 0xFD4); mdelay(1);
> +	rtl8225_write(dev, 0xB, 0x391); mdelay(1);
> +	rtl8225_write(dev, 0xC, 0x050); mdelay(1);
> +	rtl8225_write(dev, 0xD, 0x6DB); mdelay(1);
> +	rtl8225_write(dev, 0xE, 0x029); mdelay(1);
> +	rtl8225_write(dev, 0xF, 0x914); mdelay(100);
> +
> +	rtl8225_write(dev, 0x2, 0xC4D); mdelay(200);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(200);
> +
> +	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
> +		rtl8225_write(dev, 0x02, 0x0c4d);
> +		mdelay(200);
> +		rtl8225_write(dev, 0x02, 0x044d);
> +		mdelay(100);
> +		if (!(rtl8225_read(dev, 6) & (1 << 7)))
> +			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
> +			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
> +	}
> +
> +	rtl8225_write(dev, 0x0, 0x127);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
> +		rtl8225_write(dev, 0x1, i + 1);
> +		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
> +	}
> +
> +	rtl8225_write(dev, 0x0, 0x027);
> +	rtl8225_write(dev, 0x0, 0x22F);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
> +		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
> +		mdelay(1);
> +		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
> +		mdelay(1);
> +	}
> +
> +	mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
> +
> +	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
> +	rtl8225_write_phy_cck(dev, 0x19, 0x00);
> +	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
> +	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
> +	rtl8225_write_phy_cck(dev, 0x40, 0x86);
> +	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x44, 0x1f); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x45, 0x1e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x46, 0x1a); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x47, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x48, 0x10); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x49, 0x0a); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4a, 0x05); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4b, 0x02); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
> +
> +	rtl8225_rf_set_tx_power(dev, 1);
> +
> +	/* RX antenna default to A */
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
> +	mdelay(1);
> +	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
> +
> +	/* set sensitivity */
> +	rtl8225_write(dev, 0x0c, 0x50);
> +	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
> +	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
> +}
> +
> +static const u8 rtl8225z2_tx_power_cck_ch14[] = {
> +	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +static const u8 rtl8225z2_tx_power_cck[] = {
> +	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
> +};
> +
> +static const u8 rtl8225z2_tx_power_ofdm[] = {
> +	0x42, 0x00, 0x40, 0x00, 0x40
> +};
> +
> +static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
> +	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
> +	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
> +	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
> +	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
> +	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
> +	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
> +};
> +
> +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 cck_power, ofdm_power;
> +	const u8 *tmp;
> +	u32 reg;
> +	int i;
> +
> +	cck_power = priv->channels[channel - 1].val & 0xF;
> +	ofdm_power = priv->channels[channel - 1].val >> 4;
> +
> +	cck_power = min(cck_power, (u8)15);
> +	cck_power += priv->txpwr_base & 0xF;
> +	cck_power = min(cck_power, (u8)35);
> +
> +	ofdm_power = min(ofdm_power, (u8)15);
> +	ofdm_power += priv->txpwr_base >> 4;
> +	ofdm_power = min(ofdm_power, (u8)35);
> +
> +	if (channel == 14)
> +		tmp = rtl8225z2_tx_power_cck_ch14;
> +	else
> +		tmp = rtl8225z2_tx_power_cck;
> +
> +	for (i = 0; i < 8; i++)
> +		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
> +			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
> +	mdelay(1);
> +
> +	/* anaparam2 on */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write_phy_ofdm(dev, 2, 0x42);
> +	rtl8225_write_phy_ofdm(dev, 5, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 6, 0x40);
> +	rtl8225_write_phy_ofdm(dev, 7, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 8, 0x40);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
> +			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
> +	mdelay(1);
> +}
> +
> +static const u16 rtl8225z2_rxgain[] = {
> +	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
> +	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
> +	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
> +	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
> +	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
> +	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
> +	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
> +	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
> +	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
> +	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
> +	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
> +	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
> +};
> +
> +static const u8 rtl8225z2_gain_bg[] = {
> +	0x23, 0x15, 0xa5, /* -82-1dBm */
> +	0x23, 0x15, 0xb5, /* -82-2dBm */
> +	0x23, 0x15, 0xc5, /* -82-3dBm */
> +	0x33, 0x15, 0xc5, /* -78dBm */
> +	0x43, 0x15, 0xc5, /* -74dBm */
> +	0x53, 0x15, 0xc5, /* -70dBm */
> +	0x63, 0x15, 0xc5  /* -66dBm */
> +};
> +
> +void rtl8225z2_rf_init(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	rtl8225_write(dev, 0x0, 0x2BF); mdelay(1);
> +	rtl8225_write(dev, 0x1, 0xEE0); mdelay(1);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
> +	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
> +	rtl8225_write(dev, 0x4, 0x8C3); mdelay(1);
> +	rtl8225_write(dev, 0x5, 0xC72); mdelay(1);
> +	rtl8225_write(dev, 0x6, 0x0E6); mdelay(1);
> +	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
> +	rtl8225_write(dev, 0x8, 0x03F); mdelay(1);
> +	rtl8225_write(dev, 0x9, 0x335); mdelay(1);
> +	rtl8225_write(dev, 0xa, 0x9D4); mdelay(1);
> +	rtl8225_write(dev, 0xb, 0x7BB); mdelay(1);
> +	rtl8225_write(dev, 0xc, 0x850); mdelay(1);
> +	rtl8225_write(dev, 0xd, 0xCDF); mdelay(1);
> +	rtl8225_write(dev, 0xe, 0x02B); mdelay(1);
> +	rtl8225_write(dev, 0xf, 0x114); mdelay(100);
> +
> +	rtl8225_write(dev, 0x0, 0x1B7);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
> +		rtl8225_write(dev, 0x1, i + 1);
> +		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
> +	}
> +
> +	rtl8225_write(dev, 0x3, 0x080);
> +	rtl8225_write(dev, 0x5, 0x004);
> +	rtl8225_write(dev, 0x0, 0x0B7);
> +	rtl8225_write(dev, 0x2, 0xc4D);
> +
> +	mdelay(200);
> +	rtl8225_write(dev, 0x2, 0x44D);
> +	mdelay(100);
> +
> +	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
> +		rtl8225_write(dev, 0x02, 0x0C4D);
> +		mdelay(200);
> +		rtl8225_write(dev, 0x02, 0x044D);
> +		mdelay(100);
> +		if (!(rtl8225_read(dev, 6) & (1 << 7)))
> +			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
> +			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
> +	}
> +
> +	mdelay(200);
> +
> +	rtl8225_write(dev, 0x0, 0x2BF);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
> +		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
> +		mdelay(1);
> +		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
> +		mdelay(1);
> +	}
> +
> +	mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
> +	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x11, 0x07); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x17); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); mdelay(1); //FIXME: not needed?
> +	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x25, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
> +
> +	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
> +	rtl8225_write_phy_cck(dev, 0x19, 0x00);
> +	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
> +	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
> +	rtl8225_write_phy_cck(dev, 0x40, 0x86);
> +	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x44, 0x36); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x45, 0x35); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x46, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x47, 0x25); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x48, 0x1c); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x49, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4a, 0x09); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4b, 0x04); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); mdelay(1);
> +
> +	rtl8225z2_rf_set_tx_power(dev, 1);
> +
> +	/* RX antenna default to A */
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
> +	mdelay(1);
> +	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
> +}
> +
> +void rtl8225_rf_stop(struct ieee80211_hw *dev)
> +{
> +	u8 reg;
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	rtl8225_write(dev, 0x4, 0x1f); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +}
> +
> +void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	if (priv->rf_init == rtl8225_rf_init)
> +		rtl8225_rf_set_tx_power(dev, channel);
> +	else
> +		rtl8225z2_rf_set_tx_power(dev, channel);
> +
> +	rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
> +	mdelay(10);
> +}
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
> new file mode 100644
> index 0000000..ed28118
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
> @@ -0,0 +1,30 @@
> +#ifndef RTL8187_RTL8225_H
> +#define RTL8187_RTL8225_H
> +
> +#define RTL8225_ANAPARAM_ON	0xa0000a59
> +#define RTL8225_ANAPARAM2_ON	0x860c7312
> +#define RTL8225_ANAPARAM_OFF	0xa00beb59
> +#define RTL8225_ANAPARAM2_OFF	0x840dec11
> +
> +void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
> +u16  rtl8225_read(struct ieee80211_hw *, u8 addr);
> +
> +void rtl8225_rf_init(struct ieee80211_hw *);
> +void rtl8225z2_rf_init(struct ieee80211_hw *);
> +void rtl8225_rf_stop(struct ieee80211_hw *);
> +void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
> +
> +
> +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
> +					  u8 addr, u32 data)
> +{
> +	rtl8187_write_phy(dev, addr, data);
> +}
> +
> +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
> +					 u8 addr, u32 data)
> +{
> +	rtl8187_write_phy(dev, addr, data | 0x10000);
> +}
> +
> +#endif /* RTL8187_RTL8225_H */
> diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
> new file mode 100644
> index 0000000..e4ee946
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl818x.h
> @@ -0,0 +1,212 @@
> +#ifndef RTL818X_H
> +#define RTL818X_H
> +
> +struct rtl818x_csr {
> +	u8	MAC[6];
> +	u8	reserved_0[2];
> +	__le32	MAR[2];
> +	u8	RX_FIFO_COUNT;
> +	u8	reserved_1;
> +	u8	TX_FIFO_COUNT;
> +	u8	BQREQ;
> +	u8	reserved_2[4];
> +	__le32	TSFT[2];
> +	__le32	TLPDA;
> +	__le32	TNPDA;
> +	__le32	THPDA;
> +	__le16	BRSR;
> +	u8	BSSID[6];
> +	u8	RESP_RATE;
> +	u8	EIFS;
> +	u8	reserved_3[1];
> +	u8	CMD;
> +#define RTL818X_CMD_TX_ENABLE		(1 << 2)
> +#define RTL818X_CMD_RX_ENABLE		(1 << 3)
> +#define RTL818X_CMD_RESET		(1 << 4)
> +	u8	reserved_4[4];
> +	__le16	INT_MASK;
> +	__le16	INT_STATUS;
> +#define RTL818X_INT_RX_OK		(1 <<  0)
> +#define RTL818X_INT_RX_ERR		(1 <<  1)
> +#define RTL818X_INT_TXL_OK		(1 <<  2)
> +#define RTL818X_INT_TXL_ERR		(1 <<  3)
> +#define RTL818X_INT_RX_DU		(1 <<  4)
> +#define RTL818X_INT_RX_FO		(1 <<  5)
> +#define RTL818X_INT_TXN_OK		(1 <<  6)
> +#define RTL818X_INT_TXN_ERR		(1 <<  7)
> +#define RTL818X_INT_TXH_OK		(1 <<  8)
> +#define RTL818X_INT_TXH_ERR		(1 <<  9)
> +#define RTL818X_INT_TXB_OK		(1 << 10)
> +#define RTL818X_INT_TXB_ERR		(1 << 11)
> +#define RTL818X_INT_ATIM		(1 << 12)
> +#define RTL818X_INT_BEACON		(1 << 13)
> +#define RTL818X_INT_TIME_OUT		(1 << 14)
> +#define RTL818X_INT_TX_FO		(1 << 15)
> +	__le32	TX_CONF;
> +#define RTL818X_TX_CONF_LOOPBACK_MAC	(1 << 17)
> +#define RTL818X_TX_CONF_NO_ICV		(1 << 19)
> +#define RTL818X_TX_CONF_DISCW		(1 << 20)
> +#define RTL818X_TX_CONF_R8180_ABCD	(2 << 25)
> +#define RTL818X_TX_CONF_R8180_F		(3 << 25)
> +#define RTL818X_TX_CONF_R8185_ABC	(4 << 25)
> +#define RTL818X_TX_CONF_R8185_D		(5 << 25)
> +#define RTL818X_TX_CONF_HWVER_MASK	(7 << 25)
> +#define RTL818X_TX_CONF_CW_MIN		(1 << 31)
> +	__le32	RX_CONF;
> +#define RTL818X_RX_CONF_MONITOR		(1 <<  0)
> +#define RTL818X_RX_CONF_NICMAC		(1 <<  1)
> +#define RTL818X_RX_CONF_MULTICAST	(1 <<  2)
> +#define RTL818X_RX_CONF_BROADCAST	(1 <<  3)
> +#define RTL818X_RX_CONF_DATA		(1 << 18)
> +#define RTL818X_RX_CONF_CTRL		(1 << 19)
> +#define RTL818X_RX_CONF_MGMT		(1 << 20)
> +#define RTL818X_RX_CONF_BSSID		(1 << 23)
> +#define RTL818X_RX_CONF_RX_AUTORESETPHY	(1 << 28)
> +#define RTL818X_RX_CONF_ONLYERLPKT	(1 << 31)
> +	__le32	INT_TIMEOUT;
> +	__le32	TBDA;
> +	u8	EEPROM_CMD;
> +#define RTL818X_EEPROM_CMD_READ		(1 << 0)
> +#define RTL818X_EEPROM_CMD_WRITE	(1 << 1)
> +#define RTL818X_EEPROM_CMD_CK		(1 << 2)
> +#define RTL818X_EEPROM_CMD_CS		(1 << 3)
> +#define RTL818X_EEPROM_CMD_NORMAL	(0 << 6)
> +#define RTL818X_EEPROM_CMD_LOAD		(1 << 6)
> +#define RTL818X_EEPROM_CMD_PROGRAM	(2 << 6)
> +#define RTL818X_EEPROM_CMD_CONFIG	(3 << 6)
> +	u8	CONFIG0;
> +	u8	CONFIG1;
> +	u8	CONFIG2;
> +	__le32	ANAPARAM;
> +	u8	MSR;
> +#define RTL818X_MSR_NO_LINK		(0 << 2)
> +#define RTL818X_MSR_ADHOC		(1 << 2)
> +#define RTL818X_MSR_INFRA		(2 << 2)
> +	u8	CONFIG3;
> +#define RTL818X_CONFIG3_ANAPARAM_WRITE	(1 << 6)
> +	u8	CONFIG4;
> +#define RTL818X_CONFIG4_POWEROFF	(1 << 6)
> +#define RTL818X_CONFIG4_VCOOFF		(1 << 7)
> +	u8	TESTR;
> +	u8	reserved_9[2];
> +	__le16	PGSELECT;
> +	__le32	ANAPARAM2;
> +	u8	reserved_10[12];
> +	__le16	BEACON_INTERVAL;
> +	__le16	ATIM_WND;
> +	__le16	BEACON_INTERVAL_TIME;
> +	__le16	ATIMTR_INTERVAL;
> +	u8	reserved_11[4];
> +	u8	PHY[4];
> +	__le16	RFPinsOutput;
> +	__le16	RFPinsEnable;
> +	__le16	RFPinsSelect;
> +	__le16	RFPinsInput;
> +	__le32	RF_PARA;
> +	__le32	RF_TIMING;
> +	u8	GP_ENABLE;
> +	u8	GPIO;
> +	u8	reserved_12[10];
> +	u8	TX_AGC_CTL;
> +#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT		(1 << 0)
> +#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT	(1 << 1)
> +#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT			(1 << 2)
> +	u8	TX_GAIN_CCK;
> +	u8	TX_GAIN_OFDM;
> +	u8	TX_ANTENNA;
> +	u8	reserved_13[16];
> +	u8	WPA_CONF;
> +	u8	reserved_14[3];
> +	u8	SIFS;
> +	u8	DIFS;
> +	u8	SLOT;
> +	u8	reserved_15[5];
> +	u8	CW_CONF;
> +#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT	(1 << 0)
> +#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT	(1 << 1)
> +	u8	CW_VAL;
> +	u8	RATE_FALLBACK;
> +	u8	reserved_16[25];
> +	u8	CONFIG5;
> +	u8	TX_DMA_POLLING;
> +	u8	reserved_17[2];
> +	__le16	CWR;
> +	u8	RETRY_CTR;
> +	u8	reserved_18[5];
> +	__le32	RDSAR;
> +	u8	reserved_19[18];
> +	u16	TALLY_CNT;
> +	u8	TALLY_SEL;
> +} __attribute__((packed));
> +
> +static const struct ieee80211_rate rtl818x_rates[] = {
> +	{ .rate = 10,
> +	  .val = 0,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 20,
> +	  .val = 1,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 55,
> +	  .val = 2,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 110,
> +	  .val = 3,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 60,
> +	  .val = 4,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 90,
> +	  .val = 5,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 120,
> +	  .val = 6,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 180,
> +	  .val = 7,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 240,
> +	  .val = 8,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 360,
> +	  .val = 9,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 480,
> +	  .val = 10,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 540,
> +	  .val = 11,
> +	  .flags = IEEE80211_RATE_OFDM },
> +};
> +
> +static const struct ieee80211_channel rtl818x_channels[] = {
> +	{ .chan = 1,
> +	  .freq = 2412},
> +	{ .chan = 2,
> +	  .freq = 2417},
> +	{ .chan = 3,
> +	  .freq = 2422},
> +	{ .chan = 4,
> +	  .freq = 2427},
> +	{ .chan = 5,
> +	  .freq = 2432},
> +	{ .chan = 6,
> +	  .freq = 2437},
> +	{ .chan = 7,
> +	  .freq = 2442},
> +	{ .chan = 8,
> +	  .freq = 2447},
> +	{ .chan = 9,
> +	  .freq = 2452},
> +	{ .chan = 10,
> +	  .freq = 2457},
> +	{ .chan = 11,
> +	  .freq = 2462},
> +	{ .chan = 12,
> +	  .freq = 2467},
> +	{ .chan = 13,
> +	  .freq = 2472},
> +	{ .chan = 14,
> +	  .freq = 2484}
> +};
> +
> +#endif /* RTL818X_H */
> diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
> index e04cffc..8459549 100644
> --- a/drivers/net/wireless/zd1211rw/zd_usb.c
> +++ b/drivers/net/wireless/zd1211rw/zd_usb.c
> @@ -40,6 +40,7 @@ static struct usb_device_id usb_ids[] = {
>  	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
> +	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
> @@ -67,8 +68,11 @@ static struct usb_device_id usb_ids[] = {
>  	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
>  	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
>  	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
> +	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
> +	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
>  	/* "Driverless" devices that need ejecting */
>  	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
> +	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
>  	{}
>  };
>  
> diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
> new file mode 100644
> index 0000000..4b9be59
> --- /dev/null
> +++ b/include/linux/eeprom_93cx6.h
> @@ -0,0 +1,77 @@
> +/*
> +	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
> +	<http://rt2x00.serialmonkey.com>
> +
> +	This program is free software; you can redistribute it and/or modify
> +	it under the terms of the GNU General Public License as published by
> +	the Free Software Foundation; either version 2 of the License, or
> +	(at your option) any later version.
> +
> +	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.,
> +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +/*
> +	Module: eeprom_93cx6
> +	Abstract: EEPROM reader datastructures for 93cx6 chipsets.
> +	Supported chipsets: 93c46 & 93c66.
> + */
> +
> +/*
> + * EEPROM operation defines.
> + */
> +#define PCI_EEPROM_WIDTH_93C46	6
> +#define PCI_EEPROM_WIDTH_93C66	8
> +#define PCI_EEPROM_WIDTH_OPCODE	3
> +#define PCI_EEPROM_WRITE_OPCODE	0x05
> +#define PCI_EEPROM_READ_OPCODE	0x06
> +#define PCI_EEPROM_EWDS_OPCODE	0x10
> +#define PCI_EEPROM_EWEN_OPCODE	0x13
> +
> +/**
> + * struct eeprom_93cx6 - control structure for setting the commands
> + * for reading the eeprom data.
> + * @data: private pointer for the driver.
> + * @register_read(struct eeprom_93cx6 *eeprom): handler to
> + * read the eeprom register, this function should set all reg_* fields.
> + * @register_write(struct eeprom_93cx6 *eeprom): handler to
> + * write to the eeprom register by using all reg_* fields.
> + * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines
> + * @reg_data_in: register field to indicate data input
> + * @reg_data_out: register field to indicate data output
> + * @reg_data_clock: register field to set the data clock
> + * @reg_chip_select: register field to set the chip select
> + *
> + * This structure is used for the communication between the driver
> + * and the eeprom_93cx6 handlers for reading the eeprom.
> + */
> +struct eeprom_93cx6 {
> +	void *data;
> +
> +	void (*register_read)(struct eeprom_93cx6 *eeprom);
> +	void (*register_write)(struct eeprom_93cx6 *eeprom);
> +
> +	int width;
> +
> +	char reg_data_in;
> +	char reg_data_out;
> +	char reg_data_clock;
> +	char reg_chip_select;
> +};
> +
> +extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
> +	const u8 word, u16 *data);
> +extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
> +	const u8 word, __le16 *data, const u16 words);
> +
> +extern void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom,
> +	const u8 word, u16 data);
> +extern void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom,
> +	const u8 word, __le16 *data, const u16 words);
> diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
> index d56b292..bbd85cd 100644
> --- a/include/net/ieee80211.h
> +++ b/include/net/ieee80211.h
> @@ -1291,6 +1291,8 @@ extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
>  extern const struct ieee80211_channel *ieee80211_get_channel(struct
>  							     ieee80211_device
>  							     *ieee, u8 channel);
> +extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
> +				      u8 channel);
>  
>  /* ieee80211_wx.c */
>  extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
> diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
> index 305a09d..960ad13 100644
> --- a/net/ieee80211/ieee80211_geo.c
> +++ b/net/ieee80211/ieee80211_geo.c
> @@ -94,6 +94,21 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
>  	return -1;
>  }
>  
> +u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
> +{
> +	const struct ieee80211_channel * ch;
> +
> +	/* Driver needs to initialize the geography map before using
> +	 * these helper functions */
> +	if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
> +		return 0;
> +
> +	ch = ieee80211_get_channel(ieee, channel);
> +	if (!ch->channel)
> +		return 0;
> +	return ch->freq;
> +}
> +
>  u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
>  {
>  	int i;
> @@ -174,6 +189,7 @@ EXPORT_SYMBOL(ieee80211_get_channel);
>  EXPORT_SYMBOL(ieee80211_get_channel_flags);
>  EXPORT_SYMBOL(ieee80211_is_valid_channel);
>  EXPORT_SYMBOL(ieee80211_freq_to_channel);
> +EXPORT_SYMBOL(ieee80211_channel_to_freq);
>  EXPORT_SYMBOL(ieee80211_channel_to_index);
>  EXPORT_SYMBOL(ieee80211_set_geo);
>  EXPORT_SYMBOL(ieee80211_get_geo);
> diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
> index cee5e13..523a137 100644
> --- a/net/ieee80211/ieee80211_wx.c
> +++ b/net/ieee80211/ieee80211_wx.c
> @@ -89,15 +89,17 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
>  		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
>  	}
>  
> -	/* Add frequency/channel */
> +	/* Add channel and frequency */
>  	iwe.cmd = SIOCGIWFREQ;
> -/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
> -	iwe.u.freq.e = 3; */
>  	iwe.u.freq.m = network->channel;
>  	iwe.u.freq.e = 0;
>  	iwe.u.freq.i = 0;
>  	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
>  
> +	iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
> +	iwe.u.freq.e = 6;
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
> +
>  	/* Add encryption capability */
>  	iwe.cmd = SIOCGIWENCODE;
>  	if (network->capability & WLAN_CAPABILITY_PRIVACY)
> diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
> index 822917d..3e07e9d 100644
> --- a/net/mac80211/ieee80211_sta.c
> +++ b/net/mac80211/ieee80211_sta.c
> @@ -17,6 +17,7 @@
>   * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
>   *    SSID)
>   */
> +#include <linux/delay.h>
>  #include <linux/if_ether.h>
>  #include <linux/skbuff.h>
>  #include <linux/netdevice.h>
> @@ -27,7 +28,6 @@
>  #include <linux/rtnetlink.h>
>  #include <net/iw_handler.h>
>  #include <asm/types.h>
> -#include <asm/delay.h>
>  
>  #include <net/mac80211.h>
>  #include "ieee80211_i.h"


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 21:15   ` Dan Williams
  0 siblings, 0 replies; 108+ messages in thread
From: Dan Williams @ 2007-05-07 21:15 UTC (permalink / raw)
  To: John W. Linville
  Cc: jeff-o2qLIJkoznsdnm+yROfE0A,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

On Mon, 2007-05-07 at 13:51 -0400, John W. Linville wrote:
> The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
>   Linus Torvalds (1):
>         Merge git://git.kernel.org/.../sam/kbuild
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Add ID for ZyXEL AG-225H v2
> 
> Geert Uytterhoeven (1):
>       mac80211: include <linux/delay.h> instead of <asm/delay.h>
> 
> Ivo van Doorn (1):
>       Add 93cx6 eeprom library
> 
> John W. Linville (1):
>       libertas: fix for wireless Kconfig changes

So the kconfig changes with s/NET_RADIO/NET_80211 (or whatever it was)
are in for 2.6.22?  Or is that for 2.6.23?

Dan

> Larry Finger (3):
>       ieee80211: add ieee80211_channel_to_freq
>       ieee80211: include frequency in scan results
>       bcm43xx: Remove dead configuration variable CONFIG_947XX
> 
> Matthew Davidson (1):
>       zd1211rw: Add ID for Sitecom WL-117
> 
> Michael Wu (1):
>       Add rtl8187 wireless driver
> 
> Ulrich Kunitz (1):
>       zd1211rw: Added new USB id for Planex GW-US54ZGL
> 
>  MAINTAINERS                                    |   10 +
>  drivers/misc/Kconfig                           |    6 +
>  drivers/misc/Makefile                          |    1 +
>  drivers/misc/eeprom_93cx6.c                    |  347 +++++++++++
>  drivers/net/wireless/Kconfig                   |    4 +-
>  drivers/net/wireless/Makefile                  |    3 +
>  drivers/net/wireless/bcm43xx/bcm43xx.h         |   18 +-
>  drivers/net/wireless/bcm43xx/bcm43xx_dma.c     |    4 -
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   81 ---
>  drivers/net/wireless/bcm43xx/bcm43xx_main.h    |   19 -
>  drivers/net/wireless/rtl818x/Kconfig           |   16 +
>  drivers/net/wireless/rtl818x/Makefile          |    2 +
>  drivers/net/wireless/rtl818x/rtl8187.h         |  125 ++++
>  drivers/net/wireless/rtl818x/rtl8187_dev.c     |  730 +++++++++++++++++++++++
>  drivers/net/wireless/rtl818x/rtl8187_rtl8225.c |  744 ++++++++++++++++++++++++
>  drivers/net/wireless/rtl818x/rtl8187_rtl8225.h |   30 +
>  drivers/net/wireless/rtl818x/rtl818x.h         |  212 +++++++
>  drivers/net/wireless/zd1211rw/zd_usb.c         |    4 +
>  include/linux/eeprom_93cx6.h                   |   77 +++
>  include/net/ieee80211.h                        |    2 +
>  net/ieee80211/ieee80211_geo.c                  |   16 +
>  net/ieee80211/ieee80211_wx.c                   |    8 +-
>  net/mac80211/ieee80211_sta.c                   |    2 +-
>  23 files changed, 2338 insertions(+), 123 deletions(-)
>  create mode 100644 drivers/misc/eeprom_93cx6.c
>  create mode 100644 drivers/net/wireless/rtl818x/Kconfig
>  create mode 100644 drivers/net/wireless/rtl818x/Makefile
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187.h
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_dev.c
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
>  create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
>  create mode 100644 drivers/net/wireless/rtl818x/rtl818x.h
>  create mode 100644 include/linux/eeprom_93cx6.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0492dd8..c72774f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2935,6 +2935,16 @@ S:	Maintained
>  RISCOM8 DRIVER
>  S:	Orphan
>  
> +RTL818X WIRELESS DRIVER
> +P:	Michael Wu
> +M:	flamingice-R9e9/4HEdknk1uMJSBkQmQ@public.gmane.org
> +P:	Andrea Merello
> +M:	andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org
> +L:	linux-wireless-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> +W:	http://linuxwireless.org/
> +T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
> +S:	Maintained
> +
>  S3 SAVAGE FRAMEBUFFER DRIVER
>  P:	Antonino Daplas
>  M:	adaplas-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index a3c525b..607a180 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -178,4 +178,10 @@ config THINKPAD_ACPI_BAY
>  
>  	  If you are not sure, say Y here.
>  
> +config EEPROM_93CX6
> +	tristate "EEPROM 93CX6 support"
> +	---help---
> +	  This is a driver for the EEPROM chipsets 93c46 and 93c66.
> +	  The driver supports both read as well as write commands.
> +
>  endmenu
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index e325164..42b34a9 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
>  obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
>  obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
>  obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
> +obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
> diff --git a/drivers/misc/eeprom_93cx6.c b/drivers/misc/eeprom_93cx6.c
> new file mode 100644
> index 0000000..a948ddc
> --- /dev/null
> +++ b/drivers/misc/eeprom_93cx6.c
> @@ -0,0 +1,347 @@
> +/*
> +	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
> +	<http://rt2x00.serialmonkey.com>
> +
> +	This program is free software; you can redistribute it and/or modify
> +	it under the terms of the GNU General Public License as published by
> +	the Free Software Foundation; either version 2 of the License, or
> +	(at your option) any later version.
> +
> +	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.,
> +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +/*
> +	Module: eeprom_93cx6
> +	Abstract: EEPROM reader routines for 93cx6 chipsets.
> +	Supported chipsets: 93c46 & 93c66.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/version.h>
> +#include <linux/delay.h>
> +#include <linux/eeprom_93cx6.h>
> +
> +MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
> +MODULE_VERSION("1.0");
> +MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
> +MODULE_LICENSE("GPL");
> +
> +static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
> +{
> +	eeprom->reg_data_clock = 1;
> +	eeprom->register_write(eeprom);
> +	udelay(1);
> +}
> +
> +static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
> +{
> +	eeprom->reg_data_clock = 0;
> +	eeprom->register_write(eeprom);
> +	udelay(1);
> +}
> +
> +static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Clear all flags, and enable chip select.
> +	 */
> +	eeprom->register_read(eeprom);
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +	eeprom->reg_data_clock = 0;
> +	eeprom->reg_chip_select = 1;
> +	eeprom->register_write(eeprom);
> +
> +	/*
> +	 * kick a pulse.
> +	 */
> +	eeprom_93cx6_pulse_high(eeprom);
> +	eeprom_93cx6_pulse_low(eeprom);
> +}
> +
> +static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Clear chip_select and data_in flags.
> +	 */
> +	eeprom->register_read(eeprom);
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_chip_select = 0;
> +	eeprom->register_write(eeprom);
> +
> +	/*
> +	 * kick a pulse.
> +	 */
> +	eeprom_93cx6_pulse_high(eeprom);
> +	eeprom_93cx6_pulse_low(eeprom);
> +}
> +
> +static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
> +	const u16 data, const u16 count)
> +{
> +	unsigned int i;
> +
> +	eeprom->register_read(eeprom);
> +
> +	/*
> +	 * Clear data flags.
> +	 */
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +
> +	/*
> +	 * Start writing all bits.
> +	 */
> +	for (i = count; i > 0; i--) {
> +		/*
> +		 * Check if this bit needs to be set.
> +		 */
> +		eeprom->reg_data_in = !!(data & (1 << (i - 1)));
> +
> +		/*
> +		 * Write the bit to the eeprom register.
> +		 */
> +		eeprom->register_write(eeprom);
> +
> +		/*
> +		 * Kick a pulse.
> +		 */
> +		eeprom_93cx6_pulse_high(eeprom);
> +		eeprom_93cx6_pulse_low(eeprom);
> +	}
> +
> +	eeprom->reg_data_in = 0;
> +	eeprom->register_write(eeprom);
> +}
> +
> +static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
> +	u16 *data, const u16 count)
> +{
> +	unsigned int i;
> +	u16 buf = 0;
> +
> +	eeprom->register_read(eeprom);
> +
> +	/*
> +	 * Clear data flags.
> +	 */
> +	eeprom->reg_data_in = 0;
> +	eeprom->reg_data_out = 0;
> +
> +	/*
> +	 * Start reading all bits.
> +	 */
> +	for (i = count; i > 0; i--) {
> +		eeprom_93cx6_pulse_high(eeprom);
> +
> +		eeprom->register_read(eeprom);
> +
> +		/*
> +		 * Clear data_in flag.
> +		 */
> +		eeprom->reg_data_in = 0;
> +
> +		/*
> +		 * Read if the bit has been set.
> +		 */
> +		if (eeprom->reg_data_out)
> +			buf |= (1 << (i - 1));
> +
> +		eeprom_93cx6_pulse_low(eeprom);
> +	}
> +
> +	*data = buf;
> +}
> +
> +static void eeprom_93cx6_ewen(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWEN_OPCODE, 5);
> +	eeprom_93cx6_write_bits(eeprom, 0, 6);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +
> +static void eeprom_93cx6_ewds(struct eeprom_93cx6 *eeprom)
> +{
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWDS_OPCODE, 5);
> +	eeprom_93cx6_write_bits(eeprom, 0, 6);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +
> +/**
> + * eeprom_93cx6_read - Read multiple words from eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start reading
> + * @data: target pointer where the information will have to be stored
> + *
> + * This function will read the eeprom data as host-endian word
> + * into the given data pointer.
> + */
> +void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
> +	u16 *data)
> +{
> +	u16 command;
> +
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the read opcode and the word to be read.
> +	 */
> +	command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
> +	eeprom_93cx6_write_bits(eeprom, command,
> +		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
> +
> +	/*
> +	 * Read the requested 16 bits.
> +	 */
> +	eeprom_93cx6_read_bits(eeprom, data, 16);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
> +
> +/**
> + * eeprom_93cx6_multiread - Read multiple words from eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start reading
> + * @data: target pointer where the information will have to be stored
> + * @words: Number of words that should be read.
> + *
> + * This function will read all requested words from the eeprom,
> + * this is done by calling eeprom_93cx6_read() multiple times.
> + * But with the additional change that while the eeprom_93cx6_read
> + * will return host ordered bytes, this method will return little
> + * endian words.
> + */
> +void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
> +	__le16 *data, const u16 words)
> +{
> +	unsigned int i;
> +	u16 tmp;
> +
> +	for (i = 0; i < words; i++) {
> +		tmp = 0;
> +		eeprom_93cx6_read(eeprom, word + i, &tmp);
> +		data[i] = cpu_to_le16(tmp);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
> +
> +/**
> + * eeprom_93cx6_write - Write multiple words to the eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start writing
> + * @data: Data that will be written
> + *
> + * This function will write the eeprom data as host-endian word
> + * from the given data pointer.
> + */
> +void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, const u8 word,
> +	u16 data)
> +{
> +	u16 command;
> +
> +	/*
> +	 * select the ewen opcode.
> +	 */
> +	eeprom_93cx6_ewen(eeprom);
> +
> +	/*
> +	 * Initialize the eeprom register
> +	 */
> +	eeprom_93cx6_startup(eeprom);
> +
> +	/*
> +	 * Select the write opcode and the word to be read.
> +	 */
> +	command = (PCI_EEPROM_WRITE_OPCODE << eeprom->width) | word;
> +	eeprom_93cx6_write_bits(eeprom, command,
> +		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
> +
> +	/*
> +	 * Write the requested 16 bits.
> +	 */
> +	eeprom_93cx6_write_bits(eeprom, data, 16);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +
> +	/*
> +	 * Take a short break.
> +	 */
> +	msleep(10000);
> +
> +	/*
> +	 * select the ewen opcode.
> +	 */
> +	eeprom_93cx6_ewds(eeprom);
> +
> +	/*
> +	 * Cleanup eeprom register.
> +	 */
> +	eeprom_93cx6_cleanup(eeprom);
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_write);
> +
> +
> +/**
> + * eeprom_93cx6_multiwrite - Write multiple words to the eeprom
> + * @eeprom: Pointer to eeprom structure
> + * @word: Word index from where we should start writing
> + * @data: Pointer where the information will be read from
> + * @words: Number of words that should be written.
> + *
> + * This function will write all requested words to the eeprom,
> + * this is done by calling eeprom_93cx6_write() multiple times.
> + * This method accepts little endian data, so it will first be
> + * converted into host endian.
> + */
> +void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom, const u8 word,
> +	__le16 *data, const u16 words)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < words; i++)
> +		eeprom_93cx6_write(eeprom, word + i, le16_to_cpu(data[i]));
> +}
> +EXPORT_SYMBOL_GPL(eeprom_93cx6_multiwrite);
> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
> index 0184614..6ff5a8a 100644
> --- a/drivers/net/wireless/Kconfig
> +++ b/drivers/net/wireless/Kconfig
> @@ -267,7 +267,7 @@ config IPW2200_DEBUG
>  
>  config LIBERTAS_USB
>  	tristate "Marvell Libertas 8388 802.11a/b/g cards"
> -	depends on NET_RADIO && USB
> +	depends on USB && WLAN_80211
>  	select FW_LOADER
>  	---help---
>  	  A driver for Marvell Libertas 8388 USB devices.
> @@ -542,4 +542,6 @@ source "drivers/net/wireless/hostap/Kconfig"
>  source "drivers/net/wireless/bcm43xx/Kconfig"
>  source "drivers/net/wireless/zd1211rw/Kconfig"
>  
> +source "drivers/net/wireless/rtl818x/Kconfig"
> +
>  endmenu
> diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
> index d212460..198c992 100644
> --- a/drivers/net/wireless/Makefile
> +++ b/drivers/net/wireless/Makefile
> @@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
>  
>  obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
>  obj-$(CONFIG_LIBERTAS_USB)     += libertas/
> +
> +# Drivers using mac80211 stack (net/mac80211)
> +obj-$(CONFIG_RTL818X)		+= rtl818x/
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
> index f8483c1..10e07e8 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx.h
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
> @@ -658,12 +658,6 @@ struct bcm43xx_pio {
>  
>  #define BCM43xx_MAX_80211_CORES		2
>  
> -#ifdef CONFIG_BCM947XX
> -#define core_offset(bcm) (bcm)->current_core_offset
> -#else
> -#define core_offset(bcm) 0
> -#endif
> -
>  /* Generic information about a core. */
>  struct bcm43xx_coreinfo {
>  	u8 available:1,
> @@ -789,10 +783,6 @@ struct bcm43xx_private {
>  
>  	/* The currently active core. */
>  	struct bcm43xx_coreinfo *current_core;
> -#ifdef CONFIG_BCM947XX
> -	/** current core memory offset */
> -	u32 current_core_offset;
> -#endif
>  	struct bcm43xx_coreinfo *active_80211_core;
>  	/* coreinfo structs for all possible cores follow.
>  	 * Note that a core might not exist.
> @@ -943,25 +933,25 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
>  static inline
>  u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
>  {
> -	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
> +	return ioread16(bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
>  {
> -	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
> +	iowrite16(value, bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
>  {
> -	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
> +	return ioread32(bcm->mmio_addr + offset);
>  }
>  
>  static inline
>  void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
>  {
> -	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
> +	iowrite32(value, bcm->mmio_addr + offset);
>  }
>  
>  static inline
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> index e3d2e61..1f7731f 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
> @@ -660,10 +660,6 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
>  	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
>  	if (dma64)
>  		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0)
> -		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
> -#endif
>  
>  	ring->bcm = bcm;
>  	ring->nr_slots = nr_slots;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> index 5e96bca..ef6b253 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> @@ -61,10 +61,6 @@ MODULE_AUTHOR("Stefano Brivio");
>  MODULE_AUTHOR("Michael Buesch");
>  MODULE_LICENSE("GPL");
>  
> -#ifdef CONFIG_BCM947XX
> -extern char *nvram_get(char *name);
> -#endif
> -
>  #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
>  static int modparam_pio;
>  module_param_named(pio, modparam_pio, int, 0444);
> @@ -142,10 +138,6 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple fi
>  	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
>  	/* Broadcom 43XG 802.11b/g */
>  	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
> -#ifdef CONFIG_BCM947XX
> -	/* SB bus on BCM947xx */
> -	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
> -#endif
>  	{ 0 },
>  };
>  MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
> @@ -786,9 +778,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
>  {
>  	u16 value;
>  	u16 *sprom;
> -#ifdef CONFIG_BCM947XX
> -	char *c;
> -#endif
>  
>  	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
>  			GFP_KERNEL);
> @@ -796,28 +785,7 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
>  		printk(KERN_ERR PFX "sprom_extract OOM\n");
>  		return -ENOMEM;
>  	}
> -#ifdef CONFIG_BCM947XX
> -	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
> -	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
> -
> -	if ((c = nvram_get("il0macaddr")) != NULL)
> -		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
> -
> -	if ((c = nvram_get("et1macaddr")) != NULL)
> -		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
> -
> -	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
> -	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
> -	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
> -
> -	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
> -	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
> -	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
> -
> -	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
> -#else
>  	bcm43xx_sprom_read(bcm, sprom);
> -#endif
>  
>  	/* boardflags2 */
>  	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
> @@ -1225,12 +1193,6 @@ static int _switch_core(struct bcm43xx_private *bcm, int core)
>  			goto error;
>  		udelay(10);
>  	}
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0)
> -		bcm->current_core_offset = 0x1000 * core;
> -	else
> -		bcm->current_core_offset = 0;
> -#endif
>  
>  	return 0;
>  error:
> @@ -1387,19 +1349,6 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
>  
>  	if ((bcm43xx_core_enabled(bcm)) &&
>  	    !bcm43xx_using_pio(bcm)) {
> -//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
> -#if 0
> -#ifndef CONFIG_BCM947XX
> -		/* reset all used DMA controllers. */
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
> -		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
> -		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
> -		if (bcm->current_core->rev < 5)
> -			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
> -#endif
> -#endif
>  	}
>  	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
>  		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> @@ -2140,32 +2089,11 @@ out:
>  	return err;
>  }
>  
> -#ifdef CONFIG_BCM947XX
> -static struct pci_device_id bcm43xx_47xx_ids[] = {
> -	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
> -	{ 0 }
> -};
> -#endif
> -
>  static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
>  {
>  	int err;
>  
>  	bcm->irq = bcm->pci_dev->irq;
> -#ifdef CONFIG_BCM947XX
> -	if (bcm->pci_dev->bus->number == 0) {
> -		struct pci_dev *d;
> -		struct pci_device_id *id;
> -		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
> -			d = pci_get_device(id->vendor, id->device, NULL);
> -			if (d != NULL) {
> -				bcm->irq = d->irq;
> -				pci_dev_put(d);
> -				break;
> -			}
> -		}
> -	}
> -#endif
>  	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
>  			  IRQF_SHARED, KBUILD_MODNAME, bcm);
>  	if (err)
> @@ -2645,10 +2573,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
>  			chip_id_16 = 0x4610;
>  		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
>  			chip_id_16 = 0x4710;
> -#ifdef CONFIG_BCM947XX
> -		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
> -			chip_id_16 = 0x4309;
> -#endif
>  		else {
>  			printk(KERN_ERR PFX "Could not determine Chip ID\n");
>  			return -ENODEV;
> @@ -4144,11 +4068,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
>  	struct bcm43xx_private *bcm;
>  	int err;
>  
> -#ifdef CONFIG_BCM947XX
> -	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
> -		return -ENODEV;
> -#endif
> -
>  #ifdef DEBUG_SINGLE_DEVICE_ONLY
>  	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
>  		return -ENODEV;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> index f763571..c8f3c53 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
> @@ -33,25 +33,6 @@
>  
>  #include "bcm43xx.h"
>  
> -#ifdef CONFIG_BCM947XX
> -#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
> -
> -static inline void e_aton(char *str, char *dest)
> -{
> -	int i = 0;
> -	u16 *d = (u16 *) dest;
> -
> -	for (;;) {
> -		dest[i++] = (char) simple_strtoul(str, NULL, 16);
> -		str += 2;
> -		if (!*str++ || i == 6)
> -			break;
> -	}
> -	for (i = 0; i < 3; i++)
> -		d[i] = cpu_to_be16(d[i]);
> -}
> -#endif
> -
>  #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
>  #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
>  /* Magic helper macro to pad structures. Ignore those above. It's magic. */
> diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
> new file mode 100644
> index 0000000..e2c27f8
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/Kconfig
> @@ -0,0 +1,16 @@
> +config RTL818X
> +	bool
> +	default n
> +
> +config RTL8187
> +	tristate "Realtek 8187 USB support"
> +	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
> +	select RTL818X
> +	select EEPROM_93CX6
> +	---help---
> +	  This is a driver for RTL8187 based cards.
> +	  These are USB based chips found in cards such as:
> +
> +	  Netgear WG111v2
> +
> +	  Thanks to Realtek for their support!
> diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
> new file mode 100644
> index 0000000..fe5dd6f
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/Makefile
> @@ -0,0 +1,2 @@
> +rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
> +obj-$(CONFIG_RTL8187)	+= rtl8187.o
> diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
> new file mode 100644
> index 0000000..bd0b6f9
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187.h
> @@ -0,0 +1,125 @@
> +#ifndef RTL8187_H
> +#define RTL8187_H
> +
> +#include "rtl818x.h"
> +
> +#define RTL8187_REQT_READ	0xC0
> +#define RTL8187_REQT_WRITE	0x40
> +#define RTL8187_REQ_GET_REG	0x05
> +#define RTL8187_REQ_SET_REG	0x05
> +
> +#define RTL8187_MAX_RX		0x9C4
> +
> +struct rtl8187_rx_info {
> +	struct urb *urb;
> +	struct ieee80211_hw *dev;
> +};
> +
> +struct rtl8187_rx_hdr {
> +	__le16 len;
> +	__le16 rate;
> +	u8 noise;
> +	u8 signal;
> +	u8 agc;
> +	u8 reserved;
> +	__le64 mac_time;
> +} __attribute__((packed));
> +
> +struct rtl8187_tx_info {
> +	struct ieee80211_tx_control *control;
> +	struct urb *urb;
> +	struct ieee80211_hw *dev;
> +};
> +
> +struct rtl8187_tx_hdr {
> +	__le32 flags;
> +#define RTL8187_TX_FLAG_NO_ENCRYPT	(1 << 15)
> +#define RTL8187_TX_FLAG_MORE_FRAG	(1 << 17)
> +#define RTL8187_TX_FLAG_CTS		(1 << 18)
> +#define RTL8187_TX_FLAG_RTS		(1 << 23)
> +	__le16 rts_duration;
> +	__le16 len;
> +	__le32 retry;
> +} __attribute__((packed));
> +
> +struct rtl8187_priv {
> +	/* common between rtl818x drivers */
> +	struct rtl818x_csr *map;
> +	void (*rf_init)(struct ieee80211_hw *);
> +	int mode;
> +
> +	/* rtl8187 specific */
> +	struct ieee80211_channel channels[14];
> +	struct ieee80211_rate rates[12];
> +	struct ieee80211_hw_mode modes[2];
> +	struct usb_device *udev;
> +	u8 *hwaddr;
> +	u16 txpwr_base;
> +	u8 asic_rev;
> +	struct sk_buff_head rx_queue;
> +};
> +
> +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
> +
> +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
> +{
> +	u8 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return val;
> +}
> +
> +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
> +{
> +	__le16 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return le16_to_cpu(val);
> +}
> +
> +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
> +{
> +	__le32 val;
> +
> +	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +
> +	return le32_to_cpu(val);
> +}
> +
> +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
> +				    u8 *addr, u8 val)
> +{
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
> +}
> +
> +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
> +				     __le16 *addr, u16 val)
> +{
> +	__le16 buf = cpu_to_le16(val);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
> +}
> +
> +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
> +				     __le32 *addr, u32 val)
> +{
> +	__le32 buf = cpu_to_le32(val);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
> +}
> +
> +#endif /* RTL8187_H */
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
> new file mode 100644
> index 0000000..8f9e781
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
> @@ -0,0 +1,730 @@
> +
> +/*
> + * Linux device driver for RTL8187
> + *
> + * Copyright 2007 Michael Wu <flamingice-R9e9/4HEdknk1uMJSBkQmQ@public.gmane.org>
> + * Copyright 2007 Andrea Merello <andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org>
> + *
> + * Based on the r8187 driver, which is:
> + * Copyright 2005 Andrea Merello <andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org>, et al.
> + *
> + * Thanks to Realtek for their support!
> + *
> + * 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
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/usb.h>
> +#include <linux/delay.h>
> +#include <linux/etherdevice.h>
> +#include <linux/eeprom_93cx6.h>
> +#include <net/mac80211.h>
> +
> +#include "rtl8187.h"
> +#include "rtl8187_rtl8225.h"
> +
> +MODULE_AUTHOR("Michael Wu <flamingice-R9e9/4HEdknk1uMJSBkQmQ@public.gmane.org>");
> +MODULE_AUTHOR("Andrea Merello <andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org>");
> +MODULE_DESCRIPTION("RTL8187 USB wireless driver");
> +MODULE_LICENSE("GPL");
> +
> +static struct usb_device_id rtl8187_table[] __devinitdata = {
> +	/* Realtek */
> +	{USB_DEVICE(0x0bda, 0x8187)},
> +	/* Netgear */
> +	{USB_DEVICE(0x0846, 0x6100)},
> +	{USB_DEVICE(0x0846, 0x6a00)},
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(usb, rtl8187_table);
> +
> +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	data <<= 8;
> +	data |= addr | 0x80;
> +
> +	rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
> +	rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
> +
> +	mdelay(1);
> +}
> +
> +static void rtl8187_tx_cb(struct urb *urb)
> +{
> +	struct ieee80211_tx_status status = { {0} };
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
> +
> +	usb_free_urb(info->urb);
> +	if (info->control)
> +		memcpy(&status.control, info->control, sizeof(status.control));
> +	kfree(info->control);
> +	skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
> +	status.flags |= IEEE80211_TX_STATUS_ACK;
> +	ieee80211_tx_status_irqsafe(info->dev, skb, &status);
> +}
> +
> +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
> +		      struct ieee80211_tx_control *control)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_tx_hdr *hdr;
> +	struct rtl8187_tx_info *info;
> +	struct urb *urb;
> +	u32 tmp;
> +
> +	urb = usb_alloc_urb(0, GFP_ATOMIC);
> +	if (!urb) {
> +		kfree_skb(skb);
> +		return 0;
> +	}
> +
> +	hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
> +	tmp = skb->len - sizeof(*hdr);
> +	tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
> +	tmp |= control->rts_cts_rate << 19;
> +	tmp |= control->tx_rate << 24;
> +	if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
> +		tmp |= RTL8187_TX_FLAG_MORE_FRAG;
> +	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
> +		tmp |= RTL8187_TX_FLAG_RTS;
> +		hdr->rts_duration =
> +			ieee80211_rts_duration(dev, skb->len, control);
> +	}
> +	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
> +		tmp |= RTL8187_TX_FLAG_CTS;
> +	hdr->flags = cpu_to_le32(tmp);
> +	hdr->len = 0;
> +	tmp = control->retry_limit << 8;
> +	hdr->retry = cpu_to_le32(tmp);
> +
> +	info = (struct rtl8187_tx_info *)skb->cb;
> +	info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
> +	info->urb = urb;
> +	info->dev = dev;
> +	usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
> +			  hdr, skb->len, rtl8187_tx_cb, skb);
> +	usb_submit_urb(urb, GFP_ATOMIC);
> +
> +	return 0;
> +}
> +
> +static void rtl8187_rx_cb(struct urb *urb)
> +{
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
> +	struct ieee80211_hw *dev = info->dev;
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_rx_hdr *hdr;
> +	struct ieee80211_rx_status rx_status = { 0 };
> +	int rate, signal;
> +
> +	if (unlikely(urb->status)) {
> +		info->urb = NULL;
> +		usb_free_urb(urb);
> +		return;
> +	}
> +
> +	skb_unlink(skb, &priv->rx_queue);
> +	skb_put(skb, urb->actual_length);
> +	hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
> +	skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
> +
> +	signal = hdr->agc >> 1;
> +	rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
> +	if (rate > 3) {	/* OFDM rate */
> +		if (signal > 90)
> +			signal = 90;
> +		else if (signal < 25)
> +			signal = 25;
> +		signal = 90 - signal;
> +	} else {	/* CCK rate */
> +		if (signal > 95)
> +			signal = 95;
> +		else if (signal < 30)
> +			signal = 30;
> +		signal = 95 - signal;
> +	}
> +
> +	rx_status.antenna = (hdr->signal >> 7) & 1;
> +	rx_status.signal = 64 - min(hdr->noise, (u8)64);
> +	rx_status.ssi = signal;
> +	rx_status.rate = rate;
> +	rx_status.freq = dev->conf.freq;
> +	rx_status.channel = dev->conf.channel;
> +	rx_status.phymode = dev->conf.phymode;
> +	rx_status.mactime = le64_to_cpu(hdr->mac_time);
> +	ieee80211_rx_irqsafe(dev, skb, &rx_status);
> +
> +	skb = dev_alloc_skb(RTL8187_MAX_RX);
> +	if (unlikely(!skb)) {
> +		usb_free_urb(urb);
> +		/* TODO check rx queue length and refill *somewhere* */
> +		return;
> +	}
> +
> +	info = (struct rtl8187_rx_info *)skb->cb;
> +	info->urb = urb;
> +	info->dev = dev;
> +	urb->transfer_buffer = skb_tail_pointer(skb);
> +	urb->context = skb;
> +	skb_queue_tail(&priv->rx_queue, skb);
> +
> +	usb_submit_urb(urb, GFP_ATOMIC);
> +}
> +
> +static int rtl8187_init_urbs(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct urb *entry;
> +	struct sk_buff *skb;
> +	struct rtl8187_rx_info *info;
> +
> +	while (skb_queue_len(&priv->rx_queue) < 8) {
> +		skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
> +		if (!skb)
> +			break;
> +		entry = usb_alloc_urb(0, GFP_KERNEL);
> +		if (!entry) {
> +			kfree_skb(skb);
> +			break;
> +		}
> +		usb_fill_bulk_urb(entry, priv->udev,
> +				  usb_rcvbulkpipe(priv->udev, 1),
> +				  skb_tail_pointer(skb),
> +				  RTL8187_MAX_RX, rtl8187_rx_cb, skb);
> +		info = (struct rtl8187_rx_info *)skb->cb;
> +		info->urb = entry;
> +		info->dev = dev;
> +		skb_queue_tail(&priv->rx_queue, skb);
> +		usb_submit_urb(entry, GFP_KERNEL);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rtl8187_init_hw(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg;
> +	int i;
> +
> +	/* reset */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
> +
> +	mdelay(200);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
> +	mdelay(200);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg &= (1 << 1);
> +	reg |= RTL818X_CMD_RESET;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	i = 10;
> +	do {
> +		mdelay(2);
> +		if (!(rtl818x_ioread8(priv, &priv->map->CMD) &
> +		      RTL818X_CMD_RESET))
> +			break;
> +	} while (--i);
> +
> +	if (!i) {
> +		printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* reload registers from eeprom */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
> +
> +	i = 10;
> +	do {
> +		mdelay(4);
> +		if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) &
> +		      RTL818X_EEPROM_CMD_CONFIG))
> +			break;
> +	} while (--i);
> +
> +	if (!i) {
> +		printk(KERN_ERR "%s: eeprom reset timeout!\n",
> +		       wiphy_name(dev->wiphy));
> +		return -ETIMEDOUT;
> +	}
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	/* setup card */
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
> +
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
> +	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
> +
> +	rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
> +	reg &= 0x3F;
> +	reg |= 0x80;
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
> +	rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
> +	rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
> +
> +	// TODO: set RESP_RATE and BRSR properly
> +	rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
> +
> +	/* host_usb_init */
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
> +	reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
> +	rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
> +	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
> +	rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
> +	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80);
> +	mdelay(100);
> +
> +	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
> +	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
> +	mdelay(100);
> +
> +	priv->rf_init(dev);
> +
> +	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
> +	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
> +	rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
> +	rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
> +	rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
> +
> +	return 0;
> +}
> +
> +static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
> +{
> +	u32 reg;
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
> +	/* Enable TX loopback on MAC level to avoid TX during channel
> +	 * changes, as this has be seen to causes problems and the
> +	 * card will stop work until next reset
> +	 */
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
> +			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
> +	mdelay(10);
> +	rtl8225_rf_set_channel(dev, channel);
> +	mdelay(10);
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
> +}
> +
> +static int rtl8187_open(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u32 reg;
> +	int ret;
> +
> +	ret = rtl8187_init_hw(dev);
> +	if (ret)
> +		return ret;
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
> +
> +	rtl8187_init_urbs(dev);
> +
> +	reg = RTL818X_RX_CONF_ONLYERLPKT |
> +	      RTL818X_RX_CONF_RX_AUTORESETPHY |
> +	      RTL818X_RX_CONF_BSSID |
> +	      RTL818X_RX_CONF_MGMT |
> +	      RTL818X_RX_CONF_CTRL |
> +	      RTL818X_RX_CONF_DATA |
> +	      (7 << 13 /* RX FIFO threshold NONE */) |
> +	      (7 << 10 /* MAX RX DMA */) |
> +	      RTL818X_RX_CONF_BROADCAST |
> +	      RTL818X_RX_CONF_MULTICAST |
> +	      RTL818X_RX_CONF_NICMAC;
> +	if (priv->mode == IEEE80211_IF_TYPE_MNTR)
> +		reg |= RTL818X_RX_CONF_MONITOR;
> +
> +	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
> +	reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
> +	reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
> +	rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
> +	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
> +	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
> +	reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
> +	rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
> +
> +	reg  = RTL818X_TX_CONF_CW_MIN |
> +	       (7 << 21 /* MAX TX DMA */) |
> +	       RTL818X_TX_CONF_NO_ICV;
> +	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg |= RTL818X_CMD_TX_ENABLE;
> +	reg |= RTL818X_CMD_RX_ENABLE;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	return 0;
> +}
> +
> +static int rtl8187_stop(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	struct rtl8187_rx_info *info;
> +	struct sk_buff *skb;
> +	u32 reg;
> +
> +	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
> +
> +	reg = rtl818x_ioread8(priv, &priv->map->CMD);
> +	reg &= ~RTL818X_CMD_TX_ENABLE;
> +	reg &= ~RTL818X_CMD_RX_ENABLE;
> +	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
> +
> +	rtl8225_rf_stop(dev);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	while ((skb = skb_dequeue(&priv->rx_queue))) {
> +		info = (struct rtl8187_rx_info *)skb->cb;
> +		if (!info->urb)
> +			continue;
> +
> +		usb_kill_urb(info->urb);
> +		kfree_skb(skb);
> +	}
> +	return 0;
> +}
> +
> +static int rtl8187_add_interface(struct ieee80211_hw *dev,
> +				 struct ieee80211_if_init_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
> +	if (priv->mode != IEEE80211_IF_TYPE_MGMT)
> +		return -1;
> +
> +	switch (conf->type) {
> +	case IEEE80211_IF_TYPE_STA:
> +	case IEEE80211_IF_TYPE_MNTR:
> +		priv->mode = conf->type;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	priv->hwaddr = conf->mac_addr;
> +
> +	return 0;
> +}
> +
> +static void rtl8187_remove_interface(struct ieee80211_hw *dev,
> +				     struct ieee80211_if_init_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	priv->mode = IEEE80211_IF_TYPE_MGMT;
> +}
> +
> +static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	rtl8187_set_channel(dev, conf->channel);
> +
> +	rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
> +
> +	if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
> +		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
> +	else
> +		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
> +
> +	switch (conf->phymode) {
> +	case MODE_IEEE80211B:
> +		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
> +		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
> +		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
> +		break;
> +	case MODE_IEEE80211G:
> +		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
> +		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
> +		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
> +		break;
> +	default:
> +		BUG();
> +		break;
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
> +	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
> +	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
> +	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
> +	return 0;
> +}
> +
> +static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
> +				    struct ieee80211_if_conf *conf)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
> +
> +	if (is_valid_ether_addr(conf->bssid))
> +		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
> +	else
> +		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
> +
> +	return 0;
> +}
> +
> +static const struct ieee80211_ops rtl8187_ops = {
> +	.tx			= rtl8187_tx,
> +	.open			= rtl8187_open,
> +	.stop			= rtl8187_stop,
> +	.add_interface		= rtl8187_add_interface,
> +	.remove_interface	= rtl8187_remove_interface,
> +	.config			= rtl8187_config,
> +	.config_interface	= rtl8187_config_interface,
> +};
> +
> +static void rtl8187_register_read(struct eeprom_93cx6 *eeprom)
> +{
> +	struct ieee80211_hw *dev = eeprom->data;
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
> +
> +	eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
> +	eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
> +	eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
> +	eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
> +}
> +
> +static void rtl8187_register_write(struct eeprom_93cx6 *eeprom)
> +{
> +	struct ieee80211_hw *dev = eeprom->data;
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 reg = RTL818X_EEPROM_CMD_PROGRAM;
> +
> +	if (eeprom->reg_data_in)
> +		reg |= RTL818X_EEPROM_CMD_WRITE;
> +	if (eeprom->reg_data_out)
> +		reg |= RTL818X_EEPROM_CMD_READ;
> +	if (eeprom->reg_data_clock)
> +		reg |= RTL818X_EEPROM_CMD_CK;
> +	if (eeprom->reg_chip_select)
> +		reg |= RTL818X_EEPROM_CMD_CS;
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
> +	udelay(10);
> +}
> +
> +static int __devinit rtl8187_probe(struct usb_interface *intf,
> +				   const struct usb_device_id *id)
> +{
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	struct ieee80211_hw *dev;
> +	struct rtl8187_priv *priv;
> +	struct eeprom_93cx6 eeprom;
> +	struct ieee80211_channel *channel;
> +	u16 txpwr, reg;
> +	int err, i;
> +
> +	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
> +	if (!dev) {
> +		printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	priv = dev->priv;
> +
> +	SET_IEEE80211_DEV(dev, &intf->dev);
> +	usb_set_intfdata(intf, dev);
> +	priv->udev = udev;
> +
> +	usb_get_dev(udev);
> +
> +	skb_queue_head_init(&priv->rx_queue);
> +	memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
> +	memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
> +	priv->map = (struct rtl818x_csr *)0xFF00;
> +	priv->modes[0].mode = MODE_IEEE80211G;
> +	priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
> +	priv->modes[0].rates = priv->rates;
> +	priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
> +	priv->modes[0].channels = priv->channels;
> +	priv->modes[1].mode = MODE_IEEE80211B;
> +	priv->modes[1].num_rates = 4;
> +	priv->modes[1].rates = priv->rates;
> +	priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
> +	priv->modes[1].channels = priv->channels;
> +	priv->mode = IEEE80211_IF_TYPE_MGMT;
> +	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
> +		     IEEE80211_HW_RX_INCLUDES_FCS |
> +		     IEEE80211_HW_WEP_INCLUDE_IV |
> +		     IEEE80211_HW_DATA_NULLFUNC_ACK;
> +	dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
> +	dev->queues = 1;
> +	dev->max_rssi = 65;
> +	dev->max_signal = 64;
> +
> +	for (i = 0; i < 2; i++)
> +		if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
> +			goto err_free_dev;
> +
> +	eeprom.data = dev;
> +	eeprom.register_read = rtl8187_register_read;
> +	eeprom.register_write = rtl8187_register_write;
> +	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
> +		eeprom.width = PCI_EEPROM_WIDTH_93C66;
> +	else
> +		eeprom.width = PCI_EEPROM_WIDTH_93C46;
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	udelay(10);
> +
> +	eeprom_93cx6_multiread(&eeprom, 0x7,
> +			       (__le16 __force *)dev->wiphy->perm_addr, 3);
> +	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
> +		printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly generated MAC address\n");
> +		random_ether_addr(dev->wiphy->perm_addr);
> +	}
> +
> +	channel = priv->channels;
> +	for (i = 0; i < 3; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x16 + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +	for (i = 0; i < 2; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x3D + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +	for (i = 0; i < 2; i++) {
> +		eeprom_93cx6_read(&eeprom, 0x1B + i, &txpwr);
> +		(*channel++).val = txpwr & 0xFF;
> +		(*channel++).val = txpwr >> 8;
> +	}
> +
> +	eeprom_93cx6_read(&eeprom, 0x05, &priv->txpwr_base);
> +
> +	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
> +	/* 0 means asic B-cut, we should use SW 3 wire
> +	 * bit-by-bit banging for radio. 1 means we can use
> +	 * USB specific request to write radio registers */
> +	priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
> +	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write(dev, 0, 0x1B7);
> +
> +	if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
> +		priv->rf_init = rtl8225_rf_init;
> +	else
> +		priv->rf_init = rtl8225z2_rf_init;
> +
> +	rtl8225_write(dev, 0, 0x0B7);
> +
> +	err = ieee80211_register_hw(dev);
> +	if (err) {
> +		printk(KERN_ERR "rtl8187: Cannot register device\n");
> +		goto err_free_dev;
> +	}
> +
> +	printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
> +	       wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
> +	       priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
> +	       "rtl8225" : "rtl8225z2");
> +
> +	return 0;
> +
> + err_free_dev:
> +	ieee80211_free_hw(dev);
> +	usb_set_intfdata(intf, NULL);
> +	usb_put_dev(udev);
> +	return err;
> +}
> +
> +static void __devexit rtl8187_disconnect(struct usb_interface *intf)
> +{
> +	struct ieee80211_hw *dev = usb_get_intfdata(intf);
> +	struct rtl8187_priv *priv;
> +
> +	if (!dev)
> +		return;
> +
> +	ieee80211_unregister_hw(dev);
> +
> +	priv = dev->priv;
> +	usb_put_dev(interface_to_usbdev(intf));
> +	ieee80211_free_hw(dev);
> +}
> +
> +static struct usb_driver rtl8187_driver = {
> +	.name		= KBUILD_MODNAME,
> +	.id_table	= rtl8187_table,
> +	.probe		= rtl8187_probe,
> +	.disconnect	= rtl8187_disconnect,
> +};
> +
> +static int __init rtl8187_init(void)
> +{
> +	return usb_register(&rtl8187_driver);
> +}
> +
> +static void __exit rtl8187_exit(void)
> +{
> +	usb_deregister(&rtl8187_driver);
> +}
> +
> +module_init(rtl8187_init);
> +module_exit(rtl8187_exit);
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
> new file mode 100644
> index 0000000..a89f023
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
> @@ -0,0 +1,744 @@
> +
> +/*
> + * Radio tuning for RTL8225 on RTL8187
> + *
> + * Copyright 2007 Michael Wu <flamingice-R9e9/4HEdknk1uMJSBkQmQ@public.gmane.org>
> + * Copyright 2007 Andrea Merello <andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org>
> + *
> + * Based on the r8187 driver, which is:
> + * Copyright 2005 Andrea Merello <andreamrl-IWqWACnzNjyonA0d6jMUrA@public.gmane.org>, et al.
> + *
> + * Thanks to Realtek for their support!
> + *
> + * 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
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/usb.h>
> +#include <net/mac80211.h>
> +
> +#include "rtl8187.h"
> +#include "rtl8187_rtl8225.h"
> +
> +static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg84, reg82;
> +	u32 bangdata;
> +	int i;
> +
> +	bangdata = (data << 4) | (addr & 0xf);
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
> +
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(10);
> +
> +	for (i = 15; i >= 0; i--) {
> +		u16 reg = reg80 | (bangdata & (1 << i)) >> i;
> +
> +		if (i & 1)
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
> +
> +		if (!(i & 1))
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	mdelay(2);
> +}
> +
> +static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg82, reg84;
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +
> +	reg80 &= ~(0x3 << 2);
> +	reg84 &= ~0xF;
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(10);
> +
> +	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
> +			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
> +			addr, 0x8225, &data, sizeof(data), HZ / 2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(10);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	mdelay(2);
> +}
> +
> +void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	if (priv->asic_rev)
> +		rtl8225_write_8051(dev, addr, data);
> +	else
> +		rtl8225_write_bitbang(dev, addr, data);
> +}
> +
> +u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u16 reg80, reg82, reg84, out;
> +	int i;
> +
> +	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
> +	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
> +	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
> +
> +	reg80 &= ~0xF;
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
> +	udelay(4);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
> +	udelay(5);
> +
> +	for (i = 4; i >= 0; i--) {
> +		u16 reg = reg80 | ((addr >> i) & 1);
> +
> +		if (!(i & 1)) {
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +			udelay(1);
> +		}
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg | (1 << 1));
> +		udelay(2);
> +
> +		if (i & 1) {
> +			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
> +			udelay(1);
> +		}
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3) | (1 << 1));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3));
> +	udelay(2);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3));
> +	udelay(2);
> +
> +	out = 0;
> +	for (i = 11; i >= 0; i--) {
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3));
> +		udelay(1);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3) | (1 << 1));
> +		udelay(2);
> +
> +		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
> +			out |= 1 << i;
> +
> +		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +				  reg80 | (1 << 3));
> +		udelay(2);
> +	}
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
> +			  reg80 | (1 << 3) | (1 << 2));
> +	udelay(2);
> +
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
> +	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
> +
> +	return out;
> +}
> +
> +static const u16 rtl8225bcd_rxgain[] = {
> +	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
> +	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
> +	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
> +	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
> +	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
> +	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
> +	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
> +	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
> +	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
> +	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
> +	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
> +	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
> +};
> +
> +static const u8 rtl8225_agc[] = {
> +	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
> +	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
> +	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
> +	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
> +	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
> +	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
> +	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
> +	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
> +	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
> +	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
> +	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
> +	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
> +	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
> +	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
> +};
> +
> +static const u8 rtl8225_gain[] = {
> +	0x23, 0x88, 0x7c, 0xa5,	/* -82dBm */
> +	0x23, 0x88, 0x7c, 0xb5,	/* -82dBm */
> +	0x23, 0x88, 0x7c, 0xc5,	/* -82dBm */
> +	0x33, 0x80, 0x79, 0xc5,	/* -78dBm */
> +	0x43, 0x78, 0x76, 0xc5,	/* -74dBm */
> +	0x53, 0x60, 0x73, 0xc5,	/* -70dBm */
> +	0x63, 0x58, 0x70, 0xc5,	/* -66dBm */
> +};
> +
> +static const u8 rtl8225_threshold[] = {
> +	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
> +};
> +
> +static const u8 rtl8225_tx_gain_cck_ofdm[] = {
> +	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
> +};
> +
> +static const u8 rtl8225_tx_power_cck[] = {
> +	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
> +	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
> +	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
> +	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
> +	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
> +	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
> +};
> +
> +static const u8 rtl8225_tx_power_cck_ch14[] = {
> +	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
> +	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
> +	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
> +	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
> +	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
> +	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +static const u8 rtl8225_tx_power_ofdm[] = {
> +	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
> +};
> +
> +static const u32 rtl8225_chan[] = {
> +	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
> +	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
> +};
> +
> +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 cck_power, ofdm_power;
> +	const u8 *tmp;
> +	u32 reg;
> +	int i;
> +
> +	cck_power = priv->channels[channel - 1].val & 0xF;
> +	ofdm_power = priv->channels[channel - 1].val >> 4;
> +
> +	cck_power = min(cck_power, (u8)11);
> +	ofdm_power = min(ofdm_power, (u8)35);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
> +			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
> +
> +	if (channel == 14)
> +		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
> +	else
> +		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
> +
> +	for (i = 0; i < 8; i++)
> +		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
> +
> +	mdelay(1); // FIXME: optional?
> +
> +	/* anaparam2 on */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write_phy_ofdm(dev, 2, 0x42);
> +	rtl8225_write_phy_ofdm(dev, 6, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 8, 0x00);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
> +			 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
> +
> +	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
> +
> +	rtl8225_write_phy_ofdm(dev, 5, *tmp);
> +	rtl8225_write_phy_ofdm(dev, 7, *tmp);
> +
> +	mdelay(1);
> +}
> +
> +void rtl8225_rf_init(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	rtl8225_write(dev, 0x0, 0x067); mdelay(1);
> +	rtl8225_write(dev, 0x1, 0xFE0); mdelay(1);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
> +	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
> +	rtl8225_write(dev, 0x4, 0x486); mdelay(1);
> +	rtl8225_write(dev, 0x5, 0xBC0); mdelay(1);
> +	rtl8225_write(dev, 0x6, 0xAE6); mdelay(1);
> +	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
> +	rtl8225_write(dev, 0x8, 0x01F); mdelay(1);
> +	rtl8225_write(dev, 0x9, 0x334); mdelay(1);
> +	rtl8225_write(dev, 0xA, 0xFD4); mdelay(1);
> +	rtl8225_write(dev, 0xB, 0x391); mdelay(1);
> +	rtl8225_write(dev, 0xC, 0x050); mdelay(1);
> +	rtl8225_write(dev, 0xD, 0x6DB); mdelay(1);
> +	rtl8225_write(dev, 0xE, 0x029); mdelay(1);
> +	rtl8225_write(dev, 0xF, 0x914); mdelay(100);
> +
> +	rtl8225_write(dev, 0x2, 0xC4D); mdelay(200);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(200);
> +
> +	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
> +		rtl8225_write(dev, 0x02, 0x0c4d);
> +		mdelay(200);
> +		rtl8225_write(dev, 0x02, 0x044d);
> +		mdelay(100);
> +		if (!(rtl8225_read(dev, 6) & (1 << 7)))
> +			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
> +			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
> +	}
> +
> +	rtl8225_write(dev, 0x0, 0x127);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
> +		rtl8225_write(dev, 0x1, i + 1);
> +		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
> +	}
> +
> +	rtl8225_write(dev, 0x0, 0x027);
> +	rtl8225_write(dev, 0x0, 0x22F);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
> +		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
> +		mdelay(1);
> +		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
> +		mdelay(1);
> +	}
> +
> +	mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
> +
> +	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
> +	rtl8225_write_phy_cck(dev, 0x19, 0x00);
> +	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
> +	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
> +	rtl8225_write_phy_cck(dev, 0x40, 0x86);
> +	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x44, 0x1f); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x45, 0x1e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x46, 0x1a); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x47, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x48, 0x10); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x49, 0x0a); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4a, 0x05); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4b, 0x02); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
> +
> +	rtl8225_rf_set_tx_power(dev, 1);
> +
> +	/* RX antenna default to A */
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
> +	mdelay(1);
> +	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
> +
> +	/* set sensitivity */
> +	rtl8225_write(dev, 0x0c, 0x50);
> +	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
> +	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
> +}
> +
> +static const u8 rtl8225z2_tx_power_cck_ch14[] = {
> +	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +static const u8 rtl8225z2_tx_power_cck[] = {
> +	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
> +};
> +
> +static const u8 rtl8225z2_tx_power_ofdm[] = {
> +	0x42, 0x00, 0x40, 0x00, 0x40
> +};
> +
> +static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
> +	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
> +	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
> +	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
> +	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
> +	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
> +	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
> +};
> +
> +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	u8 cck_power, ofdm_power;
> +	const u8 *tmp;
> +	u32 reg;
> +	int i;
> +
> +	cck_power = priv->channels[channel - 1].val & 0xF;
> +	ofdm_power = priv->channels[channel - 1].val >> 4;
> +
> +	cck_power = min(cck_power, (u8)15);
> +	cck_power += priv->txpwr_base & 0xF;
> +	cck_power = min(cck_power, (u8)35);
> +
> +	ofdm_power = min(ofdm_power, (u8)15);
> +	ofdm_power += priv->txpwr_base >> 4;
> +	ofdm_power = min(ofdm_power, (u8)35);
> +
> +	if (channel == 14)
> +		tmp = rtl8225z2_tx_power_cck_ch14;
> +	else
> +		tmp = rtl8225z2_tx_power_cck;
> +
> +	for (i = 0; i < 8; i++)
> +		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
> +			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
> +	mdelay(1);
> +
> +	/* anaparam2 on */
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +
> +	rtl8225_write_phy_ofdm(dev, 2, 0x42);
> +	rtl8225_write_phy_ofdm(dev, 5, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 6, 0x40);
> +	rtl8225_write_phy_ofdm(dev, 7, 0x00);
> +	rtl8225_write_phy_ofdm(dev, 8, 0x40);
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
> +			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
> +	mdelay(1);
> +}
> +
> +static const u16 rtl8225z2_rxgain[] = {
> +	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
> +	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
> +	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
> +	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
> +	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
> +	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
> +	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
> +	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
> +	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
> +	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
> +	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
> +	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
> +};
> +
> +static const u8 rtl8225z2_gain_bg[] = {
> +	0x23, 0x15, 0xa5, /* -82-1dBm */
> +	0x23, 0x15, 0xb5, /* -82-2dBm */
> +	0x23, 0x15, 0xc5, /* -82-3dBm */
> +	0x33, 0x15, 0xc5, /* -78dBm */
> +	0x43, 0x15, 0xc5, /* -74dBm */
> +	0x53, 0x15, 0xc5, /* -70dBm */
> +	0x63, 0x15, 0xc5  /* -66dBm */
> +};
> +
> +void rtl8225z2_rf_init(struct ieee80211_hw *dev)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +	int i;
> +
> +	rtl8225_write(dev, 0x0, 0x2BF); mdelay(1);
> +	rtl8225_write(dev, 0x1, 0xEE0); mdelay(1);
> +	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
> +	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
> +	rtl8225_write(dev, 0x4, 0x8C3); mdelay(1);
> +	rtl8225_write(dev, 0x5, 0xC72); mdelay(1);
> +	rtl8225_write(dev, 0x6, 0x0E6); mdelay(1);
> +	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
> +	rtl8225_write(dev, 0x8, 0x03F); mdelay(1);
> +	rtl8225_write(dev, 0x9, 0x335); mdelay(1);
> +	rtl8225_write(dev, 0xa, 0x9D4); mdelay(1);
> +	rtl8225_write(dev, 0xb, 0x7BB); mdelay(1);
> +	rtl8225_write(dev, 0xc, 0x850); mdelay(1);
> +	rtl8225_write(dev, 0xd, 0xCDF); mdelay(1);
> +	rtl8225_write(dev, 0xe, 0x02B); mdelay(1);
> +	rtl8225_write(dev, 0xf, 0x114); mdelay(100);
> +
> +	rtl8225_write(dev, 0x0, 0x1B7);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
> +		rtl8225_write(dev, 0x1, i + 1);
> +		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
> +	}
> +
> +	rtl8225_write(dev, 0x3, 0x080);
> +	rtl8225_write(dev, 0x5, 0x004);
> +	rtl8225_write(dev, 0x0, 0x0B7);
> +	rtl8225_write(dev, 0x2, 0xc4D);
> +
> +	mdelay(200);
> +	rtl8225_write(dev, 0x2, 0x44D);
> +	mdelay(100);
> +
> +	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
> +		rtl8225_write(dev, 0x02, 0x0C4D);
> +		mdelay(200);
> +		rtl8225_write(dev, 0x02, 0x044D);
> +		mdelay(100);
> +		if (!(rtl8225_read(dev, 6) & (1 << 7)))
> +			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
> +			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
> +	}
> +
> +	mdelay(200);
> +
> +	rtl8225_write(dev, 0x0, 0x2BF);
> +
> +	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
> +		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
> +		mdelay(1);
> +		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
> +		mdelay(1);
> +	}
> +
> +	mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
> +	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x11, 0x07); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x17); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); mdelay(1); //FIXME: not needed?
> +	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x25, 0x00); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
> +	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
> +
> +	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
> +	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
> +	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
> +	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
> +
> +	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
> +	rtl8225_write_phy_cck(dev, 0x19, 0x00);
> +	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
> +	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
> +	rtl8225_write_phy_cck(dev, 0x40, 0x86);
> +	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x44, 0x36); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x45, 0x35); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x46, 0x2e); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x47, 0x25); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x48, 0x1c); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x49, 0x12); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4a, 0x09); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4b, 0x04); mdelay(1);
> +	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); mdelay(1);
> +
> +	rtl8225z2_rf_set_tx_power(dev, 1);
> +
> +	/* RX antenna default to A */
> +	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
> +	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
> +
> +	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
> +	mdelay(1);
> +	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
> +}
> +
> +void rtl8225_rf_stop(struct ieee80211_hw *dev)
> +{
> +	u8 reg;
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	rtl8225_write(dev, 0x4, 0x1f); mdelay(1);
> +
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
> +	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
> +	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
> +	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
> +	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
> +}
> +
> +void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
> +{
> +	struct rtl8187_priv *priv = dev->priv;
> +
> +	if (priv->rf_init == rtl8225_rf_init)
> +		rtl8225_rf_set_tx_power(dev, channel);
> +	else
> +		rtl8225z2_rf_set_tx_power(dev, channel);
> +
> +	rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
> +	mdelay(10);
> +}
> diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
> new file mode 100644
> index 0000000..ed28118
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
> @@ -0,0 +1,30 @@
> +#ifndef RTL8187_RTL8225_H
> +#define RTL8187_RTL8225_H
> +
> +#define RTL8225_ANAPARAM_ON	0xa0000a59
> +#define RTL8225_ANAPARAM2_ON	0x860c7312
> +#define RTL8225_ANAPARAM_OFF	0xa00beb59
> +#define RTL8225_ANAPARAM2_OFF	0x840dec11
> +
> +void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
> +u16  rtl8225_read(struct ieee80211_hw *, u8 addr);
> +
> +void rtl8225_rf_init(struct ieee80211_hw *);
> +void rtl8225z2_rf_init(struct ieee80211_hw *);
> +void rtl8225_rf_stop(struct ieee80211_hw *);
> +void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
> +
> +
> +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
> +					  u8 addr, u32 data)
> +{
> +	rtl8187_write_phy(dev, addr, data);
> +}
> +
> +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
> +					 u8 addr, u32 data)
> +{
> +	rtl8187_write_phy(dev, addr, data | 0x10000);
> +}
> +
> +#endif /* RTL8187_RTL8225_H */
> diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
> new file mode 100644
> index 0000000..e4ee946
> --- /dev/null
> +++ b/drivers/net/wireless/rtl818x/rtl818x.h
> @@ -0,0 +1,212 @@
> +#ifndef RTL818X_H
> +#define RTL818X_H
> +
> +struct rtl818x_csr {
> +	u8	MAC[6];
> +	u8	reserved_0[2];
> +	__le32	MAR[2];
> +	u8	RX_FIFO_COUNT;
> +	u8	reserved_1;
> +	u8	TX_FIFO_COUNT;
> +	u8	BQREQ;
> +	u8	reserved_2[4];
> +	__le32	TSFT[2];
> +	__le32	TLPDA;
> +	__le32	TNPDA;
> +	__le32	THPDA;
> +	__le16	BRSR;
> +	u8	BSSID[6];
> +	u8	RESP_RATE;
> +	u8	EIFS;
> +	u8	reserved_3[1];
> +	u8	CMD;
> +#define RTL818X_CMD_TX_ENABLE		(1 << 2)
> +#define RTL818X_CMD_RX_ENABLE		(1 << 3)
> +#define RTL818X_CMD_RESET		(1 << 4)
> +	u8	reserved_4[4];
> +	__le16	INT_MASK;
> +	__le16	INT_STATUS;
> +#define RTL818X_INT_RX_OK		(1 <<  0)
> +#define RTL818X_INT_RX_ERR		(1 <<  1)
> +#define RTL818X_INT_TXL_OK		(1 <<  2)
> +#define RTL818X_INT_TXL_ERR		(1 <<  3)
> +#define RTL818X_INT_RX_DU		(1 <<  4)
> +#define RTL818X_INT_RX_FO		(1 <<  5)
> +#define RTL818X_INT_TXN_OK		(1 <<  6)
> +#define RTL818X_INT_TXN_ERR		(1 <<  7)
> +#define RTL818X_INT_TXH_OK		(1 <<  8)
> +#define RTL818X_INT_TXH_ERR		(1 <<  9)
> +#define RTL818X_INT_TXB_OK		(1 << 10)
> +#define RTL818X_INT_TXB_ERR		(1 << 11)
> +#define RTL818X_INT_ATIM		(1 << 12)
> +#define RTL818X_INT_BEACON		(1 << 13)
> +#define RTL818X_INT_TIME_OUT		(1 << 14)
> +#define RTL818X_INT_TX_FO		(1 << 15)
> +	__le32	TX_CONF;
> +#define RTL818X_TX_CONF_LOOPBACK_MAC	(1 << 17)
> +#define RTL818X_TX_CONF_NO_ICV		(1 << 19)
> +#define RTL818X_TX_CONF_DISCW		(1 << 20)
> +#define RTL818X_TX_CONF_R8180_ABCD	(2 << 25)
> +#define RTL818X_TX_CONF_R8180_F		(3 << 25)
> +#define RTL818X_TX_CONF_R8185_ABC	(4 << 25)
> +#define RTL818X_TX_CONF_R8185_D		(5 << 25)
> +#define RTL818X_TX_CONF_HWVER_MASK	(7 << 25)
> +#define RTL818X_TX_CONF_CW_MIN		(1 << 31)
> +	__le32	RX_CONF;
> +#define RTL818X_RX_CONF_MONITOR		(1 <<  0)
> +#define RTL818X_RX_CONF_NICMAC		(1 <<  1)
> +#define RTL818X_RX_CONF_MULTICAST	(1 <<  2)
> +#define RTL818X_RX_CONF_BROADCAST	(1 <<  3)
> +#define RTL818X_RX_CONF_DATA		(1 << 18)
> +#define RTL818X_RX_CONF_CTRL		(1 << 19)
> +#define RTL818X_RX_CONF_MGMT		(1 << 20)
> +#define RTL818X_RX_CONF_BSSID		(1 << 23)
> +#define RTL818X_RX_CONF_RX_AUTORESETPHY	(1 << 28)
> +#define RTL818X_RX_CONF_ONLYERLPKT	(1 << 31)
> +	__le32	INT_TIMEOUT;
> +	__le32	TBDA;
> +	u8	EEPROM_CMD;
> +#define RTL818X_EEPROM_CMD_READ		(1 << 0)
> +#define RTL818X_EEPROM_CMD_WRITE	(1 << 1)
> +#define RTL818X_EEPROM_CMD_CK		(1 << 2)
> +#define RTL818X_EEPROM_CMD_CS		(1 << 3)
> +#define RTL818X_EEPROM_CMD_NORMAL	(0 << 6)
> +#define RTL818X_EEPROM_CMD_LOAD		(1 << 6)
> +#define RTL818X_EEPROM_CMD_PROGRAM	(2 << 6)
> +#define RTL818X_EEPROM_CMD_CONFIG	(3 << 6)
> +	u8	CONFIG0;
> +	u8	CONFIG1;
> +	u8	CONFIG2;
> +	__le32	ANAPARAM;
> +	u8	MSR;
> +#define RTL818X_MSR_NO_LINK		(0 << 2)
> +#define RTL818X_MSR_ADHOC		(1 << 2)
> +#define RTL818X_MSR_INFRA		(2 << 2)
> +	u8	CONFIG3;
> +#define RTL818X_CONFIG3_ANAPARAM_WRITE	(1 << 6)
> +	u8	CONFIG4;
> +#define RTL818X_CONFIG4_POWEROFF	(1 << 6)
> +#define RTL818X_CONFIG4_VCOOFF		(1 << 7)
> +	u8	TESTR;
> +	u8	reserved_9[2];
> +	__le16	PGSELECT;
> +	__le32	ANAPARAM2;
> +	u8	reserved_10[12];
> +	__le16	BEACON_INTERVAL;
> +	__le16	ATIM_WND;
> +	__le16	BEACON_INTERVAL_TIME;
> +	__le16	ATIMTR_INTERVAL;
> +	u8	reserved_11[4];
> +	u8	PHY[4];
> +	__le16	RFPinsOutput;
> +	__le16	RFPinsEnable;
> +	__le16	RFPinsSelect;
> +	__le16	RFPinsInput;
> +	__le32	RF_PARA;
> +	__le32	RF_TIMING;
> +	u8	GP_ENABLE;
> +	u8	GPIO;
> +	u8	reserved_12[10];
> +	u8	TX_AGC_CTL;
> +#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT		(1 << 0)
> +#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT	(1 << 1)
> +#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT			(1 << 2)
> +	u8	TX_GAIN_CCK;
> +	u8	TX_GAIN_OFDM;
> +	u8	TX_ANTENNA;
> +	u8	reserved_13[16];
> +	u8	WPA_CONF;
> +	u8	reserved_14[3];
> +	u8	SIFS;
> +	u8	DIFS;
> +	u8	SLOT;
> +	u8	reserved_15[5];
> +	u8	CW_CONF;
> +#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT	(1 << 0)
> +#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT	(1 << 1)
> +	u8	CW_VAL;
> +	u8	RATE_FALLBACK;
> +	u8	reserved_16[25];
> +	u8	CONFIG5;
> +	u8	TX_DMA_POLLING;
> +	u8	reserved_17[2];
> +	__le16	CWR;
> +	u8	RETRY_CTR;
> +	u8	reserved_18[5];
> +	__le32	RDSAR;
> +	u8	reserved_19[18];
> +	u16	TALLY_CNT;
> +	u8	TALLY_SEL;
> +} __attribute__((packed));
> +
> +static const struct ieee80211_rate rtl818x_rates[] = {
> +	{ .rate = 10,
> +	  .val = 0,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 20,
> +	  .val = 1,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 55,
> +	  .val = 2,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 110,
> +	  .val = 3,
> +	  .flags = IEEE80211_RATE_CCK },
> +	{ .rate = 60,
> +	  .val = 4,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 90,
> +	  .val = 5,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 120,
> +	  .val = 6,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 180,
> +	  .val = 7,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 240,
> +	  .val = 8,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 360,
> +	  .val = 9,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 480,
> +	  .val = 10,
> +	  .flags = IEEE80211_RATE_OFDM },
> +	{ .rate = 540,
> +	  .val = 11,
> +	  .flags = IEEE80211_RATE_OFDM },
> +};
> +
> +static const struct ieee80211_channel rtl818x_channels[] = {
> +	{ .chan = 1,
> +	  .freq = 2412},
> +	{ .chan = 2,
> +	  .freq = 2417},
> +	{ .chan = 3,
> +	  .freq = 2422},
> +	{ .chan = 4,
> +	  .freq = 2427},
> +	{ .chan = 5,
> +	  .freq = 2432},
> +	{ .chan = 6,
> +	  .freq = 2437},
> +	{ .chan = 7,
> +	  .freq = 2442},
> +	{ .chan = 8,
> +	  .freq = 2447},
> +	{ .chan = 9,
> +	  .freq = 2452},
> +	{ .chan = 10,
> +	  .freq = 2457},
> +	{ .chan = 11,
> +	  .freq = 2462},
> +	{ .chan = 12,
> +	  .freq = 2467},
> +	{ .chan = 13,
> +	  .freq = 2472},
> +	{ .chan = 14,
> +	  .freq = 2484}
> +};
> +
> +#endif /* RTL818X_H */
> diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
> index e04cffc..8459549 100644
> --- a/drivers/net/wireless/zd1211rw/zd_usb.c
> +++ b/drivers/net/wireless/zd1211rw/zd_usb.c
> @@ -40,6 +40,7 @@ static struct usb_device_id usb_ids[] = {
>  	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
> +	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
>  	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
> @@ -67,8 +68,11 @@ static struct usb_device_id usb_ids[] = {
>  	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
>  	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
>  	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
> +	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
> +	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
>  	/* "Driverless" devices that need ejecting */
>  	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
> +	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
>  	{}
>  };
>  
> diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
> new file mode 100644
> index 0000000..4b9be59
> --- /dev/null
> +++ b/include/linux/eeprom_93cx6.h
> @@ -0,0 +1,77 @@
> +/*
> +	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
> +	<http://rt2x00.serialmonkey.com>
> +
> +	This program is free software; you can redistribute it and/or modify
> +	it under the terms of the GNU General Public License as published by
> +	the Free Software Foundation; either version 2 of the License, or
> +	(at your option) any later version.
> +
> +	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.,
> +	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +/*
> +	Module: eeprom_93cx6
> +	Abstract: EEPROM reader datastructures for 93cx6 chipsets.
> +	Supported chipsets: 93c46 & 93c66.
> + */
> +
> +/*
> + * EEPROM operation defines.
> + */
> +#define PCI_EEPROM_WIDTH_93C46	6
> +#define PCI_EEPROM_WIDTH_93C66	8
> +#define PCI_EEPROM_WIDTH_OPCODE	3
> +#define PCI_EEPROM_WRITE_OPCODE	0x05
> +#define PCI_EEPROM_READ_OPCODE	0x06
> +#define PCI_EEPROM_EWDS_OPCODE	0x10
> +#define PCI_EEPROM_EWEN_OPCODE	0x13
> +
> +/**
> + * struct eeprom_93cx6 - control structure for setting the commands
> + * for reading the eeprom data.
> + * @data: private pointer for the driver.
> + * @register_read(struct eeprom_93cx6 *eeprom): handler to
> + * read the eeprom register, this function should set all reg_* fields.
> + * @register_write(struct eeprom_93cx6 *eeprom): handler to
> + * write to the eeprom register by using all reg_* fields.
> + * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines
> + * @reg_data_in: register field to indicate data input
> + * @reg_data_out: register field to indicate data output
> + * @reg_data_clock: register field to set the data clock
> + * @reg_chip_select: register field to set the chip select
> + *
> + * This structure is used for the communication between the driver
> + * and the eeprom_93cx6 handlers for reading the eeprom.
> + */
> +struct eeprom_93cx6 {
> +	void *data;
> +
> +	void (*register_read)(struct eeprom_93cx6 *eeprom);
> +	void (*register_write)(struct eeprom_93cx6 *eeprom);
> +
> +	int width;
> +
> +	char reg_data_in;
> +	char reg_data_out;
> +	char reg_data_clock;
> +	char reg_chip_select;
> +};
> +
> +extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
> +	const u8 word, u16 *data);
> +extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
> +	const u8 word, __le16 *data, const u16 words);
> +
> +extern void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom,
> +	const u8 word, u16 data);
> +extern void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom,
> +	const u8 word, __le16 *data, const u16 words);
> diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
> index d56b292..bbd85cd 100644
> --- a/include/net/ieee80211.h
> +++ b/include/net/ieee80211.h
> @@ -1291,6 +1291,8 @@ extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
>  extern const struct ieee80211_channel *ieee80211_get_channel(struct
>  							     ieee80211_device
>  							     *ieee, u8 channel);
> +extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
> +				      u8 channel);
>  
>  /* ieee80211_wx.c */
>  extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
> diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
> index 305a09d..960ad13 100644
> --- a/net/ieee80211/ieee80211_geo.c
> +++ b/net/ieee80211/ieee80211_geo.c
> @@ -94,6 +94,21 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
>  	return -1;
>  }
>  
> +u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
> +{
> +	const struct ieee80211_channel * ch;
> +
> +	/* Driver needs to initialize the geography map before using
> +	 * these helper functions */
> +	if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
> +		return 0;
> +
> +	ch = ieee80211_get_channel(ieee, channel);
> +	if (!ch->channel)
> +		return 0;
> +	return ch->freq;
> +}
> +
>  u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
>  {
>  	int i;
> @@ -174,6 +189,7 @@ EXPORT_SYMBOL(ieee80211_get_channel);
>  EXPORT_SYMBOL(ieee80211_get_channel_flags);
>  EXPORT_SYMBOL(ieee80211_is_valid_channel);
>  EXPORT_SYMBOL(ieee80211_freq_to_channel);
> +EXPORT_SYMBOL(ieee80211_channel_to_freq);
>  EXPORT_SYMBOL(ieee80211_channel_to_index);
>  EXPORT_SYMBOL(ieee80211_set_geo);
>  EXPORT_SYMBOL(ieee80211_get_geo);
> diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
> index cee5e13..523a137 100644
> --- a/net/ieee80211/ieee80211_wx.c
> +++ b/net/ieee80211/ieee80211_wx.c
> @@ -89,15 +89,17 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
>  		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
>  	}
>  
> -	/* Add frequency/channel */
> +	/* Add channel and frequency */
>  	iwe.cmd = SIOCGIWFREQ;
> -/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
> -	iwe.u.freq.e = 3; */
>  	iwe.u.freq.m = network->channel;
>  	iwe.u.freq.e = 0;
>  	iwe.u.freq.i = 0;
>  	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
>  
> +	iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
> +	iwe.u.freq.e = 6;
> +	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
> +
>  	/* Add encryption capability */
>  	iwe.cmd = SIOCGIWENCODE;
>  	if (network->capability & WLAN_CAPABILITY_PRIVACY)
> diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
> index 822917d..3e07e9d 100644
> --- a/net/mac80211/ieee80211_sta.c
> +++ b/net/mac80211/ieee80211_sta.c
> @@ -17,6 +17,7 @@
>   * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
>   *    SSID)
>   */
> +#include <linux/delay.h>
>  #include <linux/if_ether.h>
>  #include <linux/skbuff.h>
>  #include <linux/netdevice.h>
> @@ -27,7 +28,6 @@
>  #include <linux/rtnetlink.h>
>  #include <net/iw_handler.h>
>  #include <asm/types.h>
> -#include <asm/delay.h>
>  
>  #include <net/mac80211.h>
>  #include "ieee80211_i.h"

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2007-05-07 17:51 John W. Linville
  2007-05-07 21:15   ` Dan Williams
                   ` (2 more replies)
  0 siblings, 3 replies; 108+ messages in thread
From: John W. Linville @ 2007-05-07 17:51 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless, netdev

The following changes since commit 15700770ef7c5d12e2f1659d2ddbeb3f658d9f37:
  Linus Torvalds (1):
        Merge git://git.kernel.org/.../sam/kbuild

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Add ID for ZyXEL AG-225H v2

Geert Uytterhoeven (1):
      mac80211: include <linux/delay.h> instead of <asm/delay.h>

Ivo van Doorn (1):
      Add 93cx6 eeprom library

John W. Linville (1):
      libertas: fix for wireless Kconfig changes

Larry Finger (3):
      ieee80211: add ieee80211_channel_to_freq
      ieee80211: include frequency in scan results
      bcm43xx: Remove dead configuration variable CONFIG_947XX

Matthew Davidson (1):
      zd1211rw: Add ID for Sitecom WL-117

Michael Wu (1):
      Add rtl8187 wireless driver

Ulrich Kunitz (1):
      zd1211rw: Added new USB id for Planex GW-US54ZGL

 MAINTAINERS                                    |   10 +
 drivers/misc/Kconfig                           |    6 +
 drivers/misc/Makefile                          |    1 +
 drivers/misc/eeprom_93cx6.c                    |  347 +++++++++++
 drivers/net/wireless/Kconfig                   |    4 +-
 drivers/net/wireless/Makefile                  |    3 +
 drivers/net/wireless/bcm43xx/bcm43xx.h         |   18 +-
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c     |    4 -
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   81 ---
 drivers/net/wireless/bcm43xx/bcm43xx_main.h    |   19 -
 drivers/net/wireless/rtl818x/Kconfig           |   16 +
 drivers/net/wireless/rtl818x/Makefile          |    2 +
 drivers/net/wireless/rtl818x/rtl8187.h         |  125 ++++
 drivers/net/wireless/rtl818x/rtl8187_dev.c     |  730 +++++++++++++++++++++++
 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c |  744 ++++++++++++++++++++++++
 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h |   30 +
 drivers/net/wireless/rtl818x/rtl818x.h         |  212 +++++++
 drivers/net/wireless/zd1211rw/zd_usb.c         |    4 +
 include/linux/eeprom_93cx6.h                   |   77 +++
 include/net/ieee80211.h                        |    2 +
 net/ieee80211/ieee80211_geo.c                  |   16 +
 net/ieee80211/ieee80211_wx.c                   |    8 +-
 net/mac80211/ieee80211_sta.c                   |    2 +-
 23 files changed, 2338 insertions(+), 123 deletions(-)
 create mode 100644 drivers/misc/eeprom_93cx6.c
 create mode 100644 drivers/net/wireless/rtl818x/Kconfig
 create mode 100644 drivers/net/wireless/rtl818x/Makefile
 create mode 100644 drivers/net/wireless/rtl818x/rtl8187.h
 create mode 100644 drivers/net/wireless/rtl818x/rtl8187_dev.c
 create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
 create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
 create mode 100644 drivers/net/wireless/rtl818x/rtl818x.h
 create mode 100644 include/linux/eeprom_93cx6.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 0492dd8..c72774f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2935,6 +2935,16 @@ S:	Maintained
 RISCOM8 DRIVER
 S:	Orphan
 
+RTL818X WIRELESS DRIVER
+P:	Michael Wu
+M:	flamingice@sourmilk.net
+P:	Andrea Merello
+M:	andreamrl@tiscali.it
+L:	linux-wireless@vger.kernel.org
+W:	http://linuxwireless.org/
+T:	git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S:	Maintained
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 P:	Antonino Daplas
 M:	adaplas@gmail.com
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a3c525b..607a180 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -178,4 +178,10 @@ config THINKPAD_ACPI_BAY
 
 	  If you are not sure, say Y here.
 
+config EEPROM_93CX6
+	tristate "EEPROM 93CX6 support"
+	---help---
+	  This is a driver for the EEPROM chipsets 93c46 and 93c66.
+	  The driver supports both read as well as write commands.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e325164..42b34a9 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
 obj-$(CONFIG_THINKPAD_ACPI)	+= thinkpad_acpi.o
+obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
diff --git a/drivers/misc/eeprom_93cx6.c b/drivers/misc/eeprom_93cx6.c
new file mode 100644
index 0000000..a948ddc
--- /dev/null
+++ b/drivers/misc/eeprom_93cx6.c
@@ -0,0 +1,347 @@
+/*
+	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	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.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: eeprom_93cx6
+	Abstract: EEPROM reader routines for 93cx6 chipsets.
+	Supported chipsets: 93c46 & 93c66.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/eeprom_93cx6.h>
+
+MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
+MODULE_LICENSE("GPL");
+
+static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
+{
+	eeprom->reg_data_clock = 1;
+	eeprom->register_write(eeprom);
+	udelay(1);
+}
+
+static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
+{
+	eeprom->reg_data_clock = 0;
+	eeprom->register_write(eeprom);
+	udelay(1);
+}
+
+static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
+{
+	/*
+	 * Clear all flags, and enable chip select.
+	 */
+	eeprom->register_read(eeprom);
+	eeprom->reg_data_in = 0;
+	eeprom->reg_data_out = 0;
+	eeprom->reg_data_clock = 0;
+	eeprom->reg_chip_select = 1;
+	eeprom->register_write(eeprom);
+
+	/*
+	 * kick a pulse.
+	 */
+	eeprom_93cx6_pulse_high(eeprom);
+	eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
+{
+	/*
+	 * Clear chip_select and data_in flags.
+	 */
+	eeprom->register_read(eeprom);
+	eeprom->reg_data_in = 0;
+	eeprom->reg_chip_select = 0;
+	eeprom->register_write(eeprom);
+
+	/*
+	 * kick a pulse.
+	 */
+	eeprom_93cx6_pulse_high(eeprom);
+	eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
+	const u16 data, const u16 count)
+{
+	unsigned int i;
+
+	eeprom->register_read(eeprom);
+
+	/*
+	 * Clear data flags.
+	 */
+	eeprom->reg_data_in = 0;
+	eeprom->reg_data_out = 0;
+
+	/*
+	 * Start writing all bits.
+	 */
+	for (i = count; i > 0; i--) {
+		/*
+		 * Check if this bit needs to be set.
+		 */
+		eeprom->reg_data_in = !!(data & (1 << (i - 1)));
+
+		/*
+		 * Write the bit to the eeprom register.
+		 */
+		eeprom->register_write(eeprom);
+
+		/*
+		 * Kick a pulse.
+		 */
+		eeprom_93cx6_pulse_high(eeprom);
+		eeprom_93cx6_pulse_low(eeprom);
+	}
+
+	eeprom->reg_data_in = 0;
+	eeprom->register_write(eeprom);
+}
+
+static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
+	u16 *data, const u16 count)
+{
+	unsigned int i;
+	u16 buf = 0;
+
+	eeprom->register_read(eeprom);
+
+	/*
+	 * Clear data flags.
+	 */
+	eeprom->reg_data_in = 0;
+	eeprom->reg_data_out = 0;
+
+	/*
+	 * Start reading all bits.
+	 */
+	for (i = count; i > 0; i--) {
+		eeprom_93cx6_pulse_high(eeprom);
+
+		eeprom->register_read(eeprom);
+
+		/*
+		 * Clear data_in flag.
+		 */
+		eeprom->reg_data_in = 0;
+
+		/*
+		 * Read if the bit has been set.
+		 */
+		if (eeprom->reg_data_out)
+			buf |= (1 << (i - 1));
+
+		eeprom_93cx6_pulse_low(eeprom);
+	}
+
+	*data = buf;
+}
+
+static void eeprom_93cx6_ewen(struct eeprom_93cx6 *eeprom)
+{
+	/*
+	 * Initialize the eeprom register
+	 */
+	eeprom_93cx6_startup(eeprom);
+
+	/*
+	 * Select the read opcode and the word to be read.
+	 */
+	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWEN_OPCODE, 5);
+	eeprom_93cx6_write_bits(eeprom, 0, 6);
+
+	/*
+	 * Cleanup eeprom register.
+	 */
+	eeprom_93cx6_cleanup(eeprom);
+}
+
+static void eeprom_93cx6_ewds(struct eeprom_93cx6 *eeprom)
+{
+	/*
+	 * Initialize the eeprom register
+	 */
+	eeprom_93cx6_startup(eeprom);
+
+	/*
+	 * Select the read opcode and the word to be read.
+	 */
+	eeprom_93cx6_write_bits(eeprom, PCI_EEPROM_EWDS_OPCODE, 5);
+	eeprom_93cx6_write_bits(eeprom, 0, 6);
+
+	/*
+	 * Cleanup eeprom register.
+	 */
+	eeprom_93cx6_cleanup(eeprom);
+}
+
+/**
+ * eeprom_93cx6_read - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ *
+ * This function will read the eeprom data as host-endian word
+ * into the given data pointer.
+ */
+void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
+	u16 *data)
+{
+	u16 command;
+
+	/*
+	 * Initialize the eeprom register
+	 */
+	eeprom_93cx6_startup(eeprom);
+
+	/*
+	 * Select the read opcode and the word to be read.
+	 */
+	command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
+	eeprom_93cx6_write_bits(eeprom, command,
+		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+	/*
+	 * Read the requested 16 bits.
+	 */
+	eeprom_93cx6_read_bits(eeprom, data, 16);
+
+	/*
+	 * Cleanup eeprom register.
+	 */
+	eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
+
+/**
+ * eeprom_93cx6_multiread - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ * @words: Number of words that should be read.
+ *
+ * This function will read all requested words from the eeprom,
+ * this is done by calling eeprom_93cx6_read() multiple times.
+ * But with the additional change that while the eeprom_93cx6_read
+ * will return host ordered bytes, this method will return little
+ * endian words.
+ */
+void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
+	__le16 *data, const u16 words)
+{
+	unsigned int i;
+	u16 tmp;
+
+	for (i = 0; i < words; i++) {
+		tmp = 0;
+		eeprom_93cx6_read(eeprom, word + i, &tmp);
+		data[i] = cpu_to_le16(tmp);
+	}
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
+
+/**
+ * eeprom_93cx6_write - Write multiple words to the eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start writing
+ * @data: Data that will be written
+ *
+ * This function will write the eeprom data as host-endian word
+ * from the given data pointer.
+ */
+void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom, const u8 word,
+	u16 data)
+{
+	u16 command;
+
+	/*
+	 * select the ewen opcode.
+	 */
+	eeprom_93cx6_ewen(eeprom);
+
+	/*
+	 * Initialize the eeprom register
+	 */
+	eeprom_93cx6_startup(eeprom);
+
+	/*
+	 * Select the write opcode and the word to be read.
+	 */
+	command = (PCI_EEPROM_WRITE_OPCODE << eeprom->width) | word;
+	eeprom_93cx6_write_bits(eeprom, command,
+		PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+	/*
+	 * Write the requested 16 bits.
+	 */
+	eeprom_93cx6_write_bits(eeprom, data, 16);
+
+	/*
+	 * Cleanup eeprom register.
+	 */
+	eeprom_93cx6_cleanup(eeprom);
+
+	/*
+	 * Take a short break.
+	 */
+	msleep(10000);
+
+	/*
+	 * select the ewen opcode.
+	 */
+	eeprom_93cx6_ewds(eeprom);
+
+	/*
+	 * Cleanup eeprom register.
+	 */
+	eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_write);
+
+
+/**
+ * eeprom_93cx6_multiwrite - Write multiple words to the eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start writing
+ * @data: Pointer where the information will be read from
+ * @words: Number of words that should be written.
+ *
+ * This function will write all requested words to the eeprom,
+ * this is done by calling eeprom_93cx6_write() multiple times.
+ * This method accepts little endian data, so it will first be
+ * converted into host endian.
+ */
+void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom, const u8 word,
+	__le16 *data, const u16 words)
+{
+	unsigned int i;
+
+	for (i = 0; i < words; i++)
+		eeprom_93cx6_write(eeprom, word + i, le16_to_cpu(data[i]));
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_multiwrite);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 0184614..6ff5a8a 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -267,7 +267,7 @@ config IPW2200_DEBUG
 
 config LIBERTAS_USB
 	tristate "Marvell Libertas 8388 802.11a/b/g cards"
-	depends on NET_RADIO && USB
+	depends on USB && WLAN_80211
 	select FW_LOADER
 	---help---
 	  A driver for Marvell Libertas 8388 USB devices.
@@ -542,4 +542,6 @@ source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
 
+source "drivers/net/wireless/rtl818x/Kconfig"
+
 endmenu
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index d212460..198c992 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
 obj-$(CONFIG_LIBERTAS_USB)     += libertas/
+
+# Drivers using mac80211 stack (net/mac80211)
+obj-$(CONFIG_RTL818X)		+= rtl818x/
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index f8483c1..10e07e8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -658,12 +658,6 @@ struct bcm43xx_pio {
 
 #define BCM43xx_MAX_80211_CORES		2
 
-#ifdef CONFIG_BCM947XX
-#define core_offset(bcm) (bcm)->current_core_offset
-#else
-#define core_offset(bcm) 0
-#endif
-
 /* Generic information about a core. */
 struct bcm43xx_coreinfo {
 	u8 available:1,
@@ -789,10 +783,6 @@ struct bcm43xx_private {
 
 	/* The currently active core. */
 	struct bcm43xx_coreinfo *current_core;
-#ifdef CONFIG_BCM947XX
-	/** current core memory offset */
-	u32 current_core_offset;
-#endif
 	struct bcm43xx_coreinfo *active_80211_core;
 	/* coreinfo structs for all possible cores follow.
 	 * Note that a core might not exist.
@@ -943,25 +933,25 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
 static inline
 u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread16(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread16(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value)
 {
-	iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite16(value, bcm->mmio_addr + offset);
 }
 
 static inline
 u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset)
 {
-	return ioread32(bcm->mmio_addr + core_offset(bcm) + offset);
+	return ioread32(bcm->mmio_addr + offset);
 }
 
 static inline
 void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value)
 {
-	iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset);
+	iowrite32(value, bcm->mmio_addr + offset);
 }
 
 static inline
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index e3d2e61..1f7731f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -660,10 +660,6 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	ring->routing = BCM43xx_DMA32_CLIENTTRANS;
 	if (dma64)
 		ring->routing = BCM43xx_DMA64_CLIENTTRANS;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
-#endif
 
 	ring->bcm = bcm;
 	ring->nr_slots = nr_slots;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 5e96bca..ef6b253 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -61,10 +61,6 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_BCM947XX
-extern char *nvram_get(char *name);
-#endif
-
 #if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO)
 static int modparam_pio;
 module_param_named(pio, modparam_pio, int, 0444);
@@ -142,10 +138,6 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple fi
 	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 43XG 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#ifdef CONFIG_BCM947XX
-	/* SB bus on BCM947xx */
-	{ PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-#endif
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl);
@@ -786,9 +778,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 {
 	u16 value;
 	u16 *sprom;
-#ifdef CONFIG_BCM947XX
-	char *c;
-#endif
 
 	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
 			GFP_KERNEL);
@@ -796,28 +785,7 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 		printk(KERN_ERR PFX "sprom_extract OOM\n");
 		return -ENOMEM;
 	}
-#ifdef CONFIG_BCM947XX
-	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
-	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
-
-	if ((c = nvram_get("il0macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
-
-	if ((c = nvram_get("et1macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
-
-	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
-	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
-	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
-
-	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
-	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
-	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
-
-	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
-#else
 	bcm43xx_sprom_read(bcm, sprom);
-#endif
 
 	/* boardflags2 */
 	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];
@@ -1225,12 +1193,6 @@ static int _switch_core(struct bcm43xx_private *bcm, int core)
 			goto error;
 		udelay(10);
 	}
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0)
-		bcm->current_core_offset = 0x1000 * core;
-	else
-		bcm->current_core_offset = 0;
-#endif
 
 	return 0;
 error:
@@ -1387,19 +1349,6 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
 
 	if ((bcm43xx_core_enabled(bcm)) &&
 	    !bcm43xx_using_pio(bcm)) {
-//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
-#if 0
-#ifndef CONFIG_BCM947XX
-		/* reset all used DMA controllers. */
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE);
-		bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-		bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
-		if (bcm->current_core->rev < 5)
-			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
-#endif
-#endif
 	}
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -2140,32 +2089,11 @@ out:
 	return err;
 }
 
-#ifdef CONFIG_BCM947XX
-static struct pci_device_id bcm43xx_47xx_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
-	{ 0 }
-};
-#endif
-
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
 	int err;
 
 	bcm->irq = bcm->pci_dev->irq;
-#ifdef CONFIG_BCM947XX
-	if (bcm->pci_dev->bus->number == 0) {
-		struct pci_dev *d;
-		struct pci_device_id *id;
-		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
-			d = pci_get_device(id->vendor, id->device, NULL);
-			if (d != NULL) {
-				bcm->irq = d->irq;
-				pci_dev_put(d);
-				break;
-			}
-		}
-	}
-#endif
 	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
 			  IRQF_SHARED, KBUILD_MODNAME, bcm);
 	if (err)
@@ -2645,10 +2573,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
 			chip_id_16 = 0x4610;
 		else if ((pci_device >= 0x4710) && (pci_device <= 0x4715))
 			chip_id_16 = 0x4710;
-#ifdef CONFIG_BCM947XX
-		else if ((pci_device >= 0x4320) && (pci_device <= 0x4325))
-			chip_id_16 = 0x4309;
-#endif
 		else {
 			printk(KERN_ERR PFX "Could not determine Chip ID\n");
 			return -ENODEV;
@@ -4144,11 +4068,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
 	struct bcm43xx_private *bcm;
 	int err;
 
-#ifdef CONFIG_BCM947XX
-	if ((pdev->bus->number == 0) && (pdev->device != 0x0800))
-		return -ENODEV;
-#endif
-
 #ifdef DEBUG_SINGLE_DEVICE_ONLY
 	if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY))
 		return -ENODEV;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index f763571..c8f3c53 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -33,25 +33,6 @@
 
 #include "bcm43xx.h"
 
-#ifdef CONFIG_BCM947XX
-#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-
-static inline void e_aton(char *str, char *dest)
-{
-	int i = 0;
-	u16 *d = (u16 *) dest;
-
-	for (;;) {
-		dest[i++] = (char) simple_strtoul(str, NULL, 16);
-		str += 2;
-		if (!*str++ || i == 6)
-			break;
-	}
-	for (i = 0; i < 3; i++)
-		d[i] = cpu_to_be16(d[i]);
-}
-#endif
-
 #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
 /* Magic helper macro to pad structures. Ignore those above. It's magic. */
diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
new file mode 100644
index 0000000..e2c27f8
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/Kconfig
@@ -0,0 +1,16 @@
+config RTL818X
+	bool
+	default n
+
+config RTL8187
+	tristate "Realtek 8187 USB support"
+	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+	select RTL818X
+	select EEPROM_93CX6
+	---help---
+	  This is a driver for RTL8187 based cards.
+	  These are USB based chips found in cards such as:
+
+	  Netgear WG111v2
+
+	  Thanks to Realtek for their support!
diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile
new file mode 100644
index 0000000..fe5dd6f
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/Makefile
@@ -0,0 +1,2 @@
+rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
+obj-$(CONFIG_RTL8187)	+= rtl8187.o
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
new file mode 100644
index 0000000..bd0b6f9
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -0,0 +1,125 @@
+#ifndef RTL8187_H
+#define RTL8187_H
+
+#include "rtl818x.h"
+
+#define RTL8187_REQT_READ	0xC0
+#define RTL8187_REQT_WRITE	0x40
+#define RTL8187_REQ_GET_REG	0x05
+#define RTL8187_REQ_SET_REG	0x05
+
+#define RTL8187_MAX_RX		0x9C4
+
+struct rtl8187_rx_info {
+	struct urb *urb;
+	struct ieee80211_hw *dev;
+};
+
+struct rtl8187_rx_hdr {
+	__le16 len;
+	__le16 rate;
+	u8 noise;
+	u8 signal;
+	u8 agc;
+	u8 reserved;
+	__le64 mac_time;
+} __attribute__((packed));
+
+struct rtl8187_tx_info {
+	struct ieee80211_tx_control *control;
+	struct urb *urb;
+	struct ieee80211_hw *dev;
+};
+
+struct rtl8187_tx_hdr {
+	__le32 flags;
+#define RTL8187_TX_FLAG_NO_ENCRYPT	(1 << 15)
+#define RTL8187_TX_FLAG_MORE_FRAG	(1 << 17)
+#define RTL8187_TX_FLAG_CTS		(1 << 18)
+#define RTL8187_TX_FLAG_RTS		(1 << 23)
+	__le16 rts_duration;
+	__le16 len;
+	__le32 retry;
+} __attribute__((packed));
+
+struct rtl8187_priv {
+	/* common between rtl818x drivers */
+	struct rtl818x_csr *map;
+	void (*rf_init)(struct ieee80211_hw *);
+	int mode;
+
+	/* rtl8187 specific */
+	struct ieee80211_channel channels[14];
+	struct ieee80211_rate rates[12];
+	struct ieee80211_hw_mode modes[2];
+	struct usb_device *udev;
+	u8 *hwaddr;
+	u16 txpwr_base;
+	u8 asic_rev;
+	struct sk_buff_head rx_queue;
+};
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
+
+static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
+{
+	u8 val;
+
+	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+	return val;
+}
+
+static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
+{
+	__le16 val;
+
+	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+	return le16_to_cpu(val);
+}
+
+static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
+{
+	__le32 val;
+
+	usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+			RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+	return le32_to_cpu(val);
+}
+
+static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
+				    u8 *addr, u8 val)
+{
+	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+			(unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+}
+
+static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
+				     __le16 *addr, u16 val)
+{
+	__le16 buf = cpu_to_le16(val);
+
+	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
+				     __le32 *addr, u32 val)
+{
+	__le32 buf = cpu_to_le32(val);
+
+	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+			(unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+#endif /* RTL8187_H */
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
new file mode 100644
index 0000000..8f9e781
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -0,0 +1,730 @@
+
+/*
+ * Linux device driver for RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_DESCRIPTION("RTL8187 USB wireless driver");
+MODULE_LICENSE("GPL");
+
+static struct usb_device_id rtl8187_table[] __devinitdata = {
+	/* Realtek */
+	{USB_DEVICE(0x0bda, 0x8187)},
+	/* Netgear */
+	{USB_DEVICE(0x0846, 0x6100)},
+	{USB_DEVICE(0x0846, 0x6a00)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, rtl8187_table);
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	data <<= 8;
+	data |= addr | 0x80;
+
+	rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF);
+	rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
+	rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
+	rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
+
+	mdelay(1);
+}
+
+static void rtl8187_tx_cb(struct urb *urb)
+{
+	struct ieee80211_tx_status status = { {0} };
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+
+	usb_free_urb(info->urb);
+	if (info->control)
+		memcpy(&status.control, info->control, sizeof(status.control));
+	kfree(info->control);
+	skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
+	status.flags |= IEEE80211_TX_STATUS_ACK;
+	ieee80211_tx_status_irqsafe(info->dev, skb, &status);
+}
+
+static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+		      struct ieee80211_tx_control *control)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	struct rtl8187_tx_hdr *hdr;
+	struct rtl8187_tx_info *info;
+	struct urb *urb;
+	u32 tmp;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree_skb(skb);
+		return 0;
+	}
+
+	hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
+	tmp = skb->len - sizeof(*hdr);
+	tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
+	tmp |= control->rts_cts_rate << 19;
+	tmp |= control->tx_rate << 24;
+	if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
+		tmp |= RTL8187_TX_FLAG_MORE_FRAG;
+	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		tmp |= RTL8187_TX_FLAG_RTS;
+		hdr->rts_duration =
+			ieee80211_rts_duration(dev, skb->len, control);
+	}
+	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		tmp |= RTL8187_TX_FLAG_CTS;
+	hdr->flags = cpu_to_le32(tmp);
+	hdr->len = 0;
+	tmp = control->retry_limit << 8;
+	hdr->retry = cpu_to_le32(tmp);
+
+	info = (struct rtl8187_tx_info *)skb->cb;
+	info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
+	info->urb = urb;
+	info->dev = dev;
+	usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
+			  hdr, skb->len, rtl8187_tx_cb, skb);
+	usb_submit_urb(urb, GFP_ATOMIC);
+
+	return 0;
+}
+
+static void rtl8187_rx_cb(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
+	struct ieee80211_hw *dev = info->dev;
+	struct rtl8187_priv *priv = dev->priv;
+	struct rtl8187_rx_hdr *hdr;
+	struct ieee80211_rx_status rx_status = { 0 };
+	int rate, signal;
+
+	if (unlikely(urb->status)) {
+		info->urb = NULL;
+		usb_free_urb(urb);
+		return;
+	}
+
+	skb_unlink(skb, &priv->rx_queue);
+	skb_put(skb, urb->actual_length);
+	hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
+	skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+
+	signal = hdr->agc >> 1;
+	rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+	if (rate > 3) {	/* OFDM rate */
+		if (signal > 90)
+			signal = 90;
+		else if (signal < 25)
+			signal = 25;
+		signal = 90 - signal;
+	} else {	/* CCK rate */
+		if (signal > 95)
+			signal = 95;
+		else if (signal < 30)
+			signal = 30;
+		signal = 95 - signal;
+	}
+
+	rx_status.antenna = (hdr->signal >> 7) & 1;
+	rx_status.signal = 64 - min(hdr->noise, (u8)64);
+	rx_status.ssi = signal;
+	rx_status.rate = rate;
+	rx_status.freq = dev->conf.freq;
+	rx_status.channel = dev->conf.channel;
+	rx_status.phymode = dev->conf.phymode;
+	rx_status.mactime = le64_to_cpu(hdr->mac_time);
+	ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+	skb = dev_alloc_skb(RTL8187_MAX_RX);
+	if (unlikely(!skb)) {
+		usb_free_urb(urb);
+		/* TODO check rx queue length and refill *somewhere* */
+		return;
+	}
+
+	info = (struct rtl8187_rx_info *)skb->cb;
+	info->urb = urb;
+	info->dev = dev;
+	urb->transfer_buffer = skb_tail_pointer(skb);
+	urb->context = skb;
+	skb_queue_tail(&priv->rx_queue, skb);
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl8187_init_urbs(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	struct urb *entry;
+	struct sk_buff *skb;
+	struct rtl8187_rx_info *info;
+
+	while (skb_queue_len(&priv->rx_queue) < 8) {
+		skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
+		if (!skb)
+			break;
+		entry = usb_alloc_urb(0, GFP_KERNEL);
+		if (!entry) {
+			kfree_skb(skb);
+			break;
+		}
+		usb_fill_bulk_urb(entry, priv->udev,
+				  usb_rcvbulkpipe(priv->udev, 1),
+				  skb_tail_pointer(skb),
+				  RTL8187_MAX_RX, rtl8187_rx_cb, skb);
+		info = (struct rtl8187_rx_info *)skb->cb;
+		info->urb = entry;
+		info->dev = dev;
+		skb_queue_tail(&priv->rx_queue, skb);
+		usb_submit_urb(entry, GFP_KERNEL);
+	}
+
+	return 0;
+}
+
+static int rtl8187_init_hw(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u8 reg;
+	int i;
+
+	/* reset */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+	mdelay(200);
+	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
+	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
+	rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
+	mdelay(200);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= (1 << 1);
+	reg |= RTL818X_CMD_RESET;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	i = 10;
+	do {
+		mdelay(2);
+		if (!(rtl818x_ioread8(priv, &priv->map->CMD) &
+		      RTL818X_CMD_RESET))
+			break;
+	} while (--i);
+
+	if (!i) {
+		printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
+		return -ETIMEDOUT;
+	}
+
+	/* reload registers from eeprom */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
+
+	i = 10;
+	do {
+		mdelay(4);
+		if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) &
+		      RTL818X_EEPROM_CMD_CONFIG))
+			break;
+	} while (--i);
+
+	if (!i) {
+		printk(KERN_ERR "%s: eeprom reset timeout!\n",
+		       wiphy_name(dev->wiphy));
+		return -ETIMEDOUT;
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	/* setup card */
+	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
+	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+
+	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
+	rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
+
+	rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
+	reg &= 0x3F;
+	reg |= 0x80;
+	rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+	rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
+	rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+
+	// TODO: set RESP_RATE and BRSR properly
+	rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+	/* host_usb_init */
+	rtl818x_iowrite8(priv, (u8 *)0xFF85, 0);
+	rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+	reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
+	rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
+	rtl818x_iowrite8(priv, (u8 *)0xFF85, 4);
+	rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80);
+	mdelay(100);
+
+	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
+	mdelay(100);
+
+	priv->rf_init(dev);
+
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
+	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
+	rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
+	rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
+	rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
+	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+
+	return 0;
+}
+
+static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
+{
+	u32 reg;
+	struct rtl8187_priv *priv = dev->priv;
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	/* Enable TX loopback on MAC level to avoid TX during channel
+	 * changes, as this has be seen to causes problems and the
+	 * card will stop work until next reset
+	 */
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
+	mdelay(10);
+	rtl8225_rf_set_channel(dev, channel);
+	mdelay(10);
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+}
+
+static int rtl8187_open(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u32 reg;
+	int ret;
+
+	ret = rtl8187_init_hw(dev);
+	if (ret)
+		return ret;
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+
+	rtl8187_init_urbs(dev);
+
+	reg = RTL818X_RX_CONF_ONLYERLPKT |
+	      RTL818X_RX_CONF_RX_AUTORESETPHY |
+	      RTL818X_RX_CONF_BSSID |
+	      RTL818X_RX_CONF_MGMT |
+	      RTL818X_RX_CONF_CTRL |
+	      RTL818X_RX_CONF_DATA |
+	      (7 << 13 /* RX FIFO threshold NONE */) |
+	      (7 << 10 /* MAX RX DMA */) |
+	      RTL818X_RX_CONF_BROADCAST |
+	      RTL818X_RX_CONF_MULTICAST |
+	      RTL818X_RX_CONF_NICMAC;
+	if (priv->mode == IEEE80211_IF_TYPE_MNTR)
+		reg |= RTL818X_RX_CONF_MONITOR;
+
+	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+	reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
+	reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+	rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
+
+	reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+	reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+	reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+	rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
+	reg  = RTL818X_TX_CONF_CW_MIN |
+	       (7 << 21 /* MAX TX DMA */) |
+	       RTL818X_TX_CONF_NO_ICV;
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg |= RTL818X_CMD_TX_ENABLE;
+	reg |= RTL818X_CMD_RX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	return 0;
+}
+
+static int rtl8187_stop(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	struct rtl8187_rx_info *info;
+	struct sk_buff *skb;
+	u32 reg;
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= ~RTL818X_CMD_TX_ENABLE;
+	reg &= ~RTL818X_CMD_RX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	rtl8225_rf_stop(dev);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	while ((skb = skb_dequeue(&priv->rx_queue))) {
+		info = (struct rtl8187_rx_info *)skb->cb;
+		if (!info->urb)
+			continue;
+
+		usb_kill_urb(info->urb);
+		kfree_skb(skb);
+	}
+	return 0;
+}
+
+static int rtl8187_add_interface(struct ieee80211_hw *dev,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
+	if (priv->mode != IEEE80211_IF_TYPE_MGMT)
+		return -1;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->mode = conf->type;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	priv->hwaddr = conf->mac_addr;
+
+	return 0;
+}
+
+static void rtl8187_remove_interface(struct ieee80211_hw *dev,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
+static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	rtl8187_set_channel(dev, conf->channel);
+
+	rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+
+	if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+	else
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+
+	switch (conf->phymode) {
+	case MODE_IEEE80211B:
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
+		break;
+	case MODE_IEEE80211G:
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
+	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
+	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
+	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+	return 0;
+}
+
+static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
+
+	if (is_valid_ether_addr(conf->bssid))
+		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
+	else
+		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
+
+	return 0;
+}
+
+static const struct ieee80211_ops rtl8187_ops = {
+	.tx			= rtl8187_tx,
+	.open			= rtl8187_open,
+	.stop			= rtl8187_stop,
+	.add_interface		= rtl8187_add_interface,
+	.remove_interface	= rtl8187_remove_interface,
+	.config			= rtl8187_config,
+	.config_interface	= rtl8187_config_interface,
+};
+
+static void rtl8187_register_read(struct eeprom_93cx6 *eeprom)
+{
+	struct ieee80211_hw *dev = eeprom->data;
+	struct rtl8187_priv *priv = dev->priv;
+	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+
+	eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
+	eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
+	eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
+	eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
+}
+
+static void rtl8187_register_write(struct eeprom_93cx6 *eeprom)
+{
+	struct ieee80211_hw *dev = eeprom->data;
+	struct rtl8187_priv *priv = dev->priv;
+	u8 reg = RTL818X_EEPROM_CMD_PROGRAM;
+
+	if (eeprom->reg_data_in)
+		reg |= RTL818X_EEPROM_CMD_WRITE;
+	if (eeprom->reg_data_out)
+		reg |= RTL818X_EEPROM_CMD_READ;
+	if (eeprom->reg_data_clock)
+		reg |= RTL818X_EEPROM_CMD_CK;
+	if (eeprom->reg_chip_select)
+		reg |= RTL818X_EEPROM_CMD_CS;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
+	udelay(10);
+}
+
+static int __devinit rtl8187_probe(struct usb_interface *intf,
+				   const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct ieee80211_hw *dev;
+	struct rtl8187_priv *priv;
+	struct eeprom_93cx6 eeprom;
+	struct ieee80211_channel *channel;
+	u16 txpwr, reg;
+	int err, i;
+
+	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
+	if (!dev) {
+		printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n");
+		return -ENOMEM;
+	}
+
+	priv = dev->priv;
+
+	SET_IEEE80211_DEV(dev, &intf->dev);
+	usb_set_intfdata(intf, dev);
+	priv->udev = udev;
+
+	usb_get_dev(udev);
+
+	skb_queue_head_init(&priv->rx_queue);
+	memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
+	memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
+	priv->map = (struct rtl818x_csr *)0xFF00;
+	priv->modes[0].mode = MODE_IEEE80211G;
+	priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
+	priv->modes[0].rates = priv->rates;
+	priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
+	priv->modes[0].channels = priv->channels;
+	priv->modes[1].mode = MODE_IEEE80211B;
+	priv->modes[1].num_rates = 4;
+	priv->modes[1].rates = priv->rates;
+	priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
+	priv->modes[1].channels = priv->channels;
+	priv->mode = IEEE80211_IF_TYPE_MGMT;
+	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		     IEEE80211_HW_RX_INCLUDES_FCS |
+		     IEEE80211_HW_WEP_INCLUDE_IV |
+		     IEEE80211_HW_DATA_NULLFUNC_ACK;
+	dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
+	dev->queues = 1;
+	dev->max_rssi = 65;
+	dev->max_signal = 64;
+
+	for (i = 0; i < 2; i++)
+		if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
+			goto err_free_dev;
+
+	eeprom.data = dev;
+	eeprom.register_read = rtl8187_register_read;
+	eeprom.register_write = rtl8187_register_write;
+	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+		eeprom.width = PCI_EEPROM_WIDTH_93C66;
+	else
+		eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	udelay(10);
+
+	eeprom_93cx6_multiread(&eeprom, 0x7,
+			       (__le16 __force *)dev->wiphy->perm_addr, 3);
+	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+		printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly generated MAC address\n");
+		random_ether_addr(dev->wiphy->perm_addr);
+	}
+
+	channel = priv->channels;
+	for (i = 0; i < 3; i++) {
+		eeprom_93cx6_read(&eeprom, 0x16 + i, &txpwr);
+		(*channel++).val = txpwr & 0xFF;
+		(*channel++).val = txpwr >> 8;
+	}
+	for (i = 0; i < 2; i++) {
+		eeprom_93cx6_read(&eeprom, 0x3D + i, &txpwr);
+		(*channel++).val = txpwr & 0xFF;
+		(*channel++).val = txpwr >> 8;
+	}
+	for (i = 0; i < 2; i++) {
+		eeprom_93cx6_read(&eeprom, 0x1B + i, &txpwr);
+		(*channel++).val = txpwr & 0xFF;
+		(*channel++).val = txpwr >> 8;
+	}
+
+	eeprom_93cx6_read(&eeprom, 0x05, &priv->txpwr_base);
+
+	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
+	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
+	/* 0 means asic B-cut, we should use SW 3 wire
+	 * bit-by-bit banging for radio. 1 means we can use
+	 * USB specific request to write radio registers */
+	priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
+	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl8225_write(dev, 0, 0x1B7);
+
+	if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
+		priv->rf_init = rtl8225_rf_init;
+	else
+		priv->rf_init = rtl8225z2_rf_init;
+
+	rtl8225_write(dev, 0, 0x0B7);
+
+	err = ieee80211_register_hw(dev);
+	if (err) {
+		printk(KERN_ERR "rtl8187: Cannot register device\n");
+		goto err_free_dev;
+	}
+
+	printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
+	       wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+	       priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
+	       "rtl8225" : "rtl8225z2");
+
+	return 0;
+
+ err_free_dev:
+	ieee80211_free_hw(dev);
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(udev);
+	return err;
+}
+
+static void __devexit rtl8187_disconnect(struct usb_interface *intf)
+{
+	struct ieee80211_hw *dev = usb_get_intfdata(intf);
+	struct rtl8187_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+
+	priv = dev->priv;
+	usb_put_dev(interface_to_usbdev(intf));
+	ieee80211_free_hw(dev);
+}
+
+static struct usb_driver rtl8187_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= rtl8187_table,
+	.probe		= rtl8187_probe,
+	.disconnect	= rtl8187_disconnect,
+};
+
+static int __init rtl8187_init(void)
+{
+	return usb_register(&rtl8187_driver);
+}
+
+static void __exit rtl8187_exit(void)
+{
+	usb_deregister(&rtl8187_driver);
+}
+
+module_init(rtl8187_init);
+module_exit(rtl8187_exit);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
new file mode 100644
index 0000000..a89f023
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c
@@ -0,0 +1,744 @@
+
+/*
+ * Radio tuning for RTL8225 on RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u16 reg80, reg84, reg82;
+	u32 bangdata;
+	int i;
+
+	bangdata = (data << 4) | (addr & 0xf);
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
+
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	udelay(10);
+
+	for (i = 15; i >= 0; i--) {
+		u16 reg = reg80 | (bangdata & (1 << i)) >> i;
+
+		if (i & 1)
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+
+		if (!(i & 1))
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+	mdelay(2);
+}
+
+static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u16 reg80, reg82, reg84;
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+	reg80 &= ~(0x3 << 2);
+	reg84 &= ~0xF;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	udelay(2);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	udelay(10);
+
+	usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+			RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+			addr, 0x8225, &data, sizeof(data), HZ / 2);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+	mdelay(2);
+}
+
+void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	if (priv->asic_rev)
+		rtl8225_write_8051(dev, addr, data);
+	else
+		rtl8225_write_bitbang(dev, addr, data);
+}
+
+u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u16 reg80, reg82, reg84, out;
+	int i;
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+	reg80 &= ~0xF;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	udelay(4);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	udelay(5);
+
+	for (i = 4; i >= 0; i--) {
+		u16 reg = reg80 | ((addr >> i) & 1);
+
+		if (!(i & 1)) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			udelay(1);
+		}
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		udelay(2);
+
+		if (i & 1) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			udelay(1);
+		}
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 1));
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	udelay(2);
+
+	out = 0;
+	for (i = 11; i >= 0; i--) {
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		udelay(1);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		udelay(2);
+
+		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
+			out |= 1 << i;
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		udelay(2);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 2));
+	udelay(2);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
+
+	return out;
+}
+
+static const u16 rtl8225bcd_rxgain[] = {
+	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static const u8 rtl8225_agc[] = {
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
+	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
+	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
+	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
+	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
+	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
+	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
+	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
+	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const u8 rtl8225_gain[] = {
+	0x23, 0x88, 0x7c, 0xa5,	/* -82dBm */
+	0x23, 0x88, 0x7c, 0xb5,	/* -82dBm */
+	0x23, 0x88, 0x7c, 0xc5,	/* -82dBm */
+	0x33, 0x80, 0x79, 0xc5,	/* -78dBm */
+	0x43, 0x78, 0x76, 0xc5,	/* -74dBm */
+	0x53, 0x60, 0x73, 0xc5,	/* -70dBm */
+	0x63, 0x58, 0x70, 0xc5,	/* -66dBm */
+};
+
+static const u8 rtl8225_threshold[] = {
+	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
+};
+
+static const u8 rtl8225_tx_gain_cck_ofdm[] = {
+	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225_tx_power_cck[] = {
+	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225_tx_power_cck_ch14[] = {
+	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225_tx_power_ofdm[] = {
+	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225_chan[] = {
+	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
+	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
+};
+
+static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	u32 reg;
+	int i;
+
+	cck_power = priv->channels[channel - 1].val & 0xF;
+	ofdm_power = priv->channels[channel - 1].val >> 4;
+
+	cck_power = min(cck_power, (u8)11);
+	ofdm_power = min(ofdm_power, (u8)35);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
+
+	if (channel == 14)
+		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
+	else
+		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	mdelay(1); // FIXME: optional?
+
+	/* anaparam2 on */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl8225_write_phy_ofdm(dev, 2, 0x42);
+	rtl8225_write_phy_ofdm(dev, 6, 0x00);
+	rtl8225_write_phy_ofdm(dev, 8, 0x00);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+			 rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
+
+	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
+
+	rtl8225_write_phy_ofdm(dev, 5, *tmp);
+	rtl8225_write_phy_ofdm(dev, 7, *tmp);
+
+	mdelay(1);
+}
+
+void rtl8225_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	int i;
+
+	rtl8225_write(dev, 0x0, 0x067); mdelay(1);
+	rtl8225_write(dev, 0x1, 0xFE0); mdelay(1);
+	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
+	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
+	rtl8225_write(dev, 0x4, 0x486); mdelay(1);
+	rtl8225_write(dev, 0x5, 0xBC0); mdelay(1);
+	rtl8225_write(dev, 0x6, 0xAE6); mdelay(1);
+	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
+	rtl8225_write(dev, 0x8, 0x01F); mdelay(1);
+	rtl8225_write(dev, 0x9, 0x334); mdelay(1);
+	rtl8225_write(dev, 0xA, 0xFD4); mdelay(1);
+	rtl8225_write(dev, 0xB, 0x391); mdelay(1);
+	rtl8225_write(dev, 0xC, 0x050); mdelay(1);
+	rtl8225_write(dev, 0xD, 0x6DB); mdelay(1);
+	rtl8225_write(dev, 0xE, 0x029); mdelay(1);
+	rtl8225_write(dev, 0xF, 0x914); mdelay(100);
+
+	rtl8225_write(dev, 0x2, 0xC4D); mdelay(200);
+	rtl8225_write(dev, 0x2, 0x44D); mdelay(200);
+
+	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+		rtl8225_write(dev, 0x02, 0x0c4d);
+		mdelay(200);
+		rtl8225_write(dev, 0x02, 0x044d);
+		mdelay(100);
+		if (!(rtl8225_read(dev, 6) & (1 << 7)))
+			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+	}
+
+	rtl8225_write(dev, 0x0, 0x127);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x0, 0x027);
+	rtl8225_write(dev, 0x0, 0x22F);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		mdelay(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		mdelay(1);
+	}
+
+	mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x1f); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x1e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x1a); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x10); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x0a); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x05); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x02); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
+
+	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
+
+	rtl8225_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	mdelay(1);
+	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+
+	/* set sensitivity */
+	rtl8225_write(dev, 0x0c, 0x50);
+	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
+}
+
+static const u8 rtl8225z2_tx_power_cck_ch14[] = {
+	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225z2_tx_power_cck[] = {
+	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_ofdm[] = {
+	0x42, 0x00, 0x40, 0x00, 0x40
+};
+
+static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+	0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+	0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
+};
+
+static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	u32 reg;
+	int i;
+
+	cck_power = priv->channels[channel - 1].val & 0xF;
+	ofdm_power = priv->channels[channel - 1].val >> 4;
+
+	cck_power = min(cck_power, (u8)15);
+	cck_power += priv->txpwr_base & 0xF;
+	cck_power = min(cck_power, (u8)35);
+
+	ofdm_power = min(ofdm_power, (u8)15);
+	ofdm_power += priv->txpwr_base >> 4;
+	ofdm_power = min(ofdm_power, (u8)35);
+
+	if (channel == 14)
+		tmp = rtl8225z2_tx_power_cck_ch14;
+	else
+		tmp = rtl8225z2_tx_power_cck;
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+			 rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+	mdelay(1);
+
+	/* anaparam2 on */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl8225_write_phy_ofdm(dev, 2, 0x42);
+	rtl8225_write_phy_ofdm(dev, 5, 0x00);
+	rtl8225_write_phy_ofdm(dev, 6, 0x40);
+	rtl8225_write_phy_ofdm(dev, 7, 0x00);
+	rtl8225_write_phy_ofdm(dev, 8, 0x40);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+			 rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
+	mdelay(1);
+}
+
+static const u16 rtl8225z2_rxgain[] = {
+	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static const u8 rtl8225z2_gain_bg[] = {
+	0x23, 0x15, 0xa5, /* -82-1dBm */
+	0x23, 0x15, 0xb5, /* -82-2dBm */
+	0x23, 0x15, 0xc5, /* -82-3dBm */
+	0x33, 0x15, 0xc5, /* -78dBm */
+	0x43, 0x15, 0xc5, /* -74dBm */
+	0x53, 0x15, 0xc5, /* -70dBm */
+	0x63, 0x15, 0xc5  /* -66dBm */
+};
+
+void rtl8225z2_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8187_priv *priv = dev->priv;
+	int i;
+
+	rtl8225_write(dev, 0x0, 0x2BF); mdelay(1);
+	rtl8225_write(dev, 0x1, 0xEE0); mdelay(1);
+	rtl8225_write(dev, 0x2, 0x44D); mdelay(1);
+	rtl8225_write(dev, 0x3, 0x441); mdelay(1);
+	rtl8225_write(dev, 0x4, 0x8C3); mdelay(1);
+	rtl8225_write(dev, 0x5, 0xC72); mdelay(1);
+	rtl8225_write(dev, 0x6, 0x0E6); mdelay(1);
+	rtl8225_write(dev, 0x7, 0x82A); mdelay(1);
+	rtl8225_write(dev, 0x8, 0x03F); mdelay(1);
+	rtl8225_write(dev, 0x9, 0x335); mdelay(1);
+	rtl8225_write(dev, 0xa, 0x9D4); mdelay(1);
+	rtl8225_write(dev, 0xb, 0x7BB); mdelay(1);
+	rtl8225_write(dev, 0xc, 0x850); mdelay(1);
+	rtl8225_write(dev, 0xd, 0xCDF); mdelay(1);
+	rtl8225_write(dev, 0xe, 0x02B); mdelay(1);
+	rtl8225_write(dev, 0xf, 0x114); mdelay(100);
+
+	rtl8225_write(dev, 0x0, 0x1B7);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x3, 0x080);
+	rtl8225_write(dev, 0x5, 0x004);
+	rtl8225_write(dev, 0x0, 0x0B7);
+	rtl8225_write(dev, 0x2, 0xc4D);
+
+	mdelay(200);
+	rtl8225_write(dev, 0x2, 0x44D);
+	mdelay(100);
+
+	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+		rtl8225_write(dev, 0x02, 0x0C4D);
+		mdelay(200);
+		rtl8225_write(dev, 0x02, 0x044D);
+		mdelay(100);
+		if (!(rtl8225_read(dev, 6) & (1 << 7)))
+			printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+			       wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+	}
+
+	mdelay(200);
+
+	rtl8225_write(dev, 0x0, 0x2BF);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		mdelay(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		mdelay(1);
+	}
+
+	mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x42); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x07); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x17); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); mdelay(1); //FIXME: not needed?
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x00); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); mdelay(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
+	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
+	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x36); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x35); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x2e); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x25); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x1c); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x12); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x09); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x04); mdelay(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); mdelay(1);
+
+	rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); mdelay(1);
+
+	rtl8225z2_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); mdelay(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); mdelay(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	mdelay(1);
+	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+}
+
+void rtl8225_rf_stop(struct ieee80211_hw *dev)
+{
+	u8 reg;
+	struct rtl8187_priv *priv = dev->priv;
+
+	rtl8225_write(dev, 0x4, 0x1f); mdelay(1);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	if (priv->rf_init == rtl8225_rf_init)
+		rtl8225_rf_set_tx_power(dev, channel);
+	else
+		rtl8225z2_rf_set_tx_power(dev, channel);
+
+	rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
+	mdelay(10);
+}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
new file mode 100644
index 0000000..ed28118
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h
@@ -0,0 +1,30 @@
+#ifndef RTL8187_RTL8225_H
+#define RTL8187_RTL8225_H
+
+#define RTL8225_ANAPARAM_ON	0xa0000a59
+#define RTL8225_ANAPARAM2_ON	0x860c7312
+#define RTL8225_ANAPARAM_OFF	0xa00beb59
+#define RTL8225_ANAPARAM2_OFF	0x840dec11
+
+void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
+u16  rtl8225_read(struct ieee80211_hw *, u8 addr);
+
+void rtl8225_rf_init(struct ieee80211_hw *);
+void rtl8225z2_rf_init(struct ieee80211_hw *);
+void rtl8225_rf_stop(struct ieee80211_hw *);
+void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
+
+
+static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
+					  u8 addr, u32 data)
+{
+	rtl8187_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
+					 u8 addr, u32 data)
+{
+	rtl8187_write_phy(dev, addr, data | 0x10000);
+}
+
+#endif /* RTL8187_RTL8225_H */
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
new file mode 100644
index 0000000..e4ee946
--- /dev/null
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -0,0 +1,212 @@
+#ifndef RTL818X_H
+#define RTL818X_H
+
+struct rtl818x_csr {
+	u8	MAC[6];
+	u8	reserved_0[2];
+	__le32	MAR[2];
+	u8	RX_FIFO_COUNT;
+	u8	reserved_1;
+	u8	TX_FIFO_COUNT;
+	u8	BQREQ;
+	u8	reserved_2[4];
+	__le32	TSFT[2];
+	__le32	TLPDA;
+	__le32	TNPDA;
+	__le32	THPDA;
+	__le16	BRSR;
+	u8	BSSID[6];
+	u8	RESP_RATE;
+	u8	EIFS;
+	u8	reserved_3[1];
+	u8	CMD;
+#define RTL818X_CMD_TX_ENABLE		(1 << 2)
+#define RTL818X_CMD_RX_ENABLE		(1 << 3)
+#define RTL818X_CMD_RESET		(1 << 4)
+	u8	reserved_4[4];
+	__le16	INT_MASK;
+	__le16	INT_STATUS;
+#define RTL818X_INT_RX_OK		(1 <<  0)
+#define RTL818X_INT_RX_ERR		(1 <<  1)
+#define RTL818X_INT_TXL_OK		(1 <<  2)
+#define RTL818X_INT_TXL_ERR		(1 <<  3)
+#define RTL818X_INT_RX_DU		(1 <<  4)
+#define RTL818X_INT_RX_FO		(1 <<  5)
+#define RTL818X_INT_TXN_OK		(1 <<  6)
+#define RTL818X_INT_TXN_ERR		(1 <<  7)
+#define RTL818X_INT_TXH_OK		(1 <<  8)
+#define RTL818X_INT_TXH_ERR		(1 <<  9)
+#define RTL818X_INT_TXB_OK		(1 << 10)
+#define RTL818X_INT_TXB_ERR		(1 << 11)
+#define RTL818X_INT_ATIM		(1 << 12)
+#define RTL818X_INT_BEACON		(1 << 13)
+#define RTL818X_INT_TIME_OUT		(1 << 14)
+#define RTL818X_INT_TX_FO		(1 << 15)
+	__le32	TX_CONF;
+#define RTL818X_TX_CONF_LOOPBACK_MAC	(1 << 17)
+#define RTL818X_TX_CONF_NO_ICV		(1 << 19)
+#define RTL818X_TX_CONF_DISCW		(1 << 20)
+#define RTL818X_TX_CONF_R8180_ABCD	(2 << 25)
+#define RTL818X_TX_CONF_R8180_F		(3 << 25)
+#define RTL818X_TX_CONF_R8185_ABC	(4 << 25)
+#define RTL818X_TX_CONF_R8185_D		(5 << 25)
+#define RTL818X_TX_CONF_HWVER_MASK	(7 << 25)
+#define RTL818X_TX_CONF_CW_MIN		(1 << 31)
+	__le32	RX_CONF;
+#define RTL818X_RX_CONF_MONITOR		(1 <<  0)
+#define RTL818X_RX_CONF_NICMAC		(1 <<  1)
+#define RTL818X_RX_CONF_MULTICAST	(1 <<  2)
+#define RTL818X_RX_CONF_BROADCAST	(1 <<  3)
+#define RTL818X_RX_CONF_DATA		(1 << 18)
+#define RTL818X_RX_CONF_CTRL		(1 << 19)
+#define RTL818X_RX_CONF_MGMT		(1 << 20)
+#define RTL818X_RX_CONF_BSSID		(1 << 23)
+#define RTL818X_RX_CONF_RX_AUTORESETPHY	(1 << 28)
+#define RTL818X_RX_CONF_ONLYERLPKT	(1 << 31)
+	__le32	INT_TIMEOUT;
+	__le32	TBDA;
+	u8	EEPROM_CMD;
+#define RTL818X_EEPROM_CMD_READ		(1 << 0)
+#define RTL818X_EEPROM_CMD_WRITE	(1 << 1)
+#define RTL818X_EEPROM_CMD_CK		(1 << 2)
+#define RTL818X_EEPROM_CMD_CS		(1 << 3)
+#define RTL818X_EEPROM_CMD_NORMAL	(0 << 6)
+#define RTL818X_EEPROM_CMD_LOAD		(1 << 6)
+#define RTL818X_EEPROM_CMD_PROGRAM	(2 << 6)
+#define RTL818X_EEPROM_CMD_CONFIG	(3 << 6)
+	u8	CONFIG0;
+	u8	CONFIG1;
+	u8	CONFIG2;
+	__le32	ANAPARAM;
+	u8	MSR;
+#define RTL818X_MSR_NO_LINK		(0 << 2)
+#define RTL818X_MSR_ADHOC		(1 << 2)
+#define RTL818X_MSR_INFRA		(2 << 2)
+	u8	CONFIG3;
+#define RTL818X_CONFIG3_ANAPARAM_WRITE	(1 << 6)
+	u8	CONFIG4;
+#define RTL818X_CONFIG4_POWEROFF	(1 << 6)
+#define RTL818X_CONFIG4_VCOOFF		(1 << 7)
+	u8	TESTR;
+	u8	reserved_9[2];
+	__le16	PGSELECT;
+	__le32	ANAPARAM2;
+	u8	reserved_10[12];
+	__le16	BEACON_INTERVAL;
+	__le16	ATIM_WND;
+	__le16	BEACON_INTERVAL_TIME;
+	__le16	ATIMTR_INTERVAL;
+	u8	reserved_11[4];
+	u8	PHY[4];
+	__le16	RFPinsOutput;
+	__le16	RFPinsEnable;
+	__le16	RFPinsSelect;
+	__le16	RFPinsInput;
+	__le32	RF_PARA;
+	__le32	RF_TIMING;
+	u8	GP_ENABLE;
+	u8	GPIO;
+	u8	reserved_12[10];
+	u8	TX_AGC_CTL;
+#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT		(1 << 0)
+#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT	(1 << 1)
+#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT			(1 << 2)
+	u8	TX_GAIN_CCK;
+	u8	TX_GAIN_OFDM;
+	u8	TX_ANTENNA;
+	u8	reserved_13[16];
+	u8	WPA_CONF;
+	u8	reserved_14[3];
+	u8	SIFS;
+	u8	DIFS;
+	u8	SLOT;
+	u8	reserved_15[5];
+	u8	CW_CONF;
+#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT	(1 << 0)
+#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT	(1 << 1)
+	u8	CW_VAL;
+	u8	RATE_FALLBACK;
+	u8	reserved_16[25];
+	u8	CONFIG5;
+	u8	TX_DMA_POLLING;
+	u8	reserved_17[2];
+	__le16	CWR;
+	u8	RETRY_CTR;
+	u8	reserved_18[5];
+	__le32	RDSAR;
+	u8	reserved_19[18];
+	u16	TALLY_CNT;
+	u8	TALLY_SEL;
+} __attribute__((packed));
+
+static const struct ieee80211_rate rtl818x_rates[] = {
+	{ .rate = 10,
+	  .val = 0,
+	  .flags = IEEE80211_RATE_CCK },
+	{ .rate = 20,
+	  .val = 1,
+	  .flags = IEEE80211_RATE_CCK },
+	{ .rate = 55,
+	  .val = 2,
+	  .flags = IEEE80211_RATE_CCK },
+	{ .rate = 110,
+	  .val = 3,
+	  .flags = IEEE80211_RATE_CCK },
+	{ .rate = 60,
+	  .val = 4,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 90,
+	  .val = 5,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 120,
+	  .val = 6,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 180,
+	  .val = 7,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 240,
+	  .val = 8,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 360,
+	  .val = 9,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 480,
+	  .val = 10,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 540,
+	  .val = 11,
+	  .flags = IEEE80211_RATE_OFDM },
+};
+
+static const struct ieee80211_channel rtl818x_channels[] = {
+	{ .chan = 1,
+	  .freq = 2412},
+	{ .chan = 2,
+	  .freq = 2417},
+	{ .chan = 3,
+	  .freq = 2422},
+	{ .chan = 4,
+	  .freq = 2427},
+	{ .chan = 5,
+	  .freq = 2432},
+	{ .chan = 6,
+	  .freq = 2437},
+	{ .chan = 7,
+	  .freq = 2442},
+	{ .chan = 8,
+	  .freq = 2447},
+	{ .chan = 9,
+	  .freq = 2452},
+	{ .chan = 10,
+	  .freq = 2457},
+	{ .chan = 11,
+	  .freq = 2462},
+	{ .chan = 12,
+	  .freq = 2467},
+	{ .chan = 13,
+	  .freq = 2472},
+	{ .chan = 14,
+	  .freq = 2484}
+};
+
+#endif /* RTL818X_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index e04cffc..8459549 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -40,6 +40,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
@@ -67,8 +68,11 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
 	{}
 };
 
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
new file mode 100644
index 0000000..4b9be59
--- /dev/null
+++ b/include/linux/eeprom_93cx6.h
@@ -0,0 +1,77 @@
+/*
+	Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	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.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: eeprom_93cx6
+	Abstract: EEPROM reader datastructures for 93cx6 chipsets.
+	Supported chipsets: 93c46 & 93c66.
+ */
+
+/*
+ * EEPROM operation defines.
+ */
+#define PCI_EEPROM_WIDTH_93C46	6
+#define PCI_EEPROM_WIDTH_93C66	8
+#define PCI_EEPROM_WIDTH_OPCODE	3
+#define PCI_EEPROM_WRITE_OPCODE	0x05
+#define PCI_EEPROM_READ_OPCODE	0x06
+#define PCI_EEPROM_EWDS_OPCODE	0x10
+#define PCI_EEPROM_EWEN_OPCODE	0x13
+
+/**
+ * struct eeprom_93cx6 - control structure for setting the commands
+ * for reading the eeprom data.
+ * @data: private pointer for the driver.
+ * @register_read(struct eeprom_93cx6 *eeprom): handler to
+ * read the eeprom register, this function should set all reg_* fields.
+ * @register_write(struct eeprom_93cx6 *eeprom): handler to
+ * write to the eeprom register by using all reg_* fields.
+ * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines
+ * @reg_data_in: register field to indicate data input
+ * @reg_data_out: register field to indicate data output
+ * @reg_data_clock: register field to set the data clock
+ * @reg_chip_select: register field to set the chip select
+ *
+ * This structure is used for the communication between the driver
+ * and the eeprom_93cx6 handlers for reading the eeprom.
+ */
+struct eeprom_93cx6 {
+	void *data;
+
+	void (*register_read)(struct eeprom_93cx6 *eeprom);
+	void (*register_write)(struct eeprom_93cx6 *eeprom);
+
+	int width;
+
+	char reg_data_in;
+	char reg_data_out;
+	char reg_data_clock;
+	char reg_chip_select;
+};
+
+extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
+	const u8 word, u16 *data);
+extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
+	const u8 word, __le16 *data, const u16 words);
+
+extern void eeprom_93cx6_write(struct eeprom_93cx6 *eeprom,
+	const u8 word, u16 data);
+extern void eeprom_93cx6_multiwrite(struct eeprom_93cx6 *eeprom,
+	const u8 word, __le16 *data, const u16 words);
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d56b292..bbd85cd 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1291,6 +1291,8 @@ extern u8 ieee80211_get_channel_flags(struct ieee80211_device *ieee,
 extern const struct ieee80211_channel *ieee80211_get_channel(struct
 							     ieee80211_device
 							     *ieee, u8 channel);
+extern u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee,
+				      u8 channel);
 
 /* ieee80211_wx.c */
 extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c
index 305a09d..960ad13 100644
--- a/net/ieee80211/ieee80211_geo.c
+++ b/net/ieee80211/ieee80211_geo.c
@@ -94,6 +94,21 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel)
 	return -1;
 }
 
+u32 ieee80211_channel_to_freq(struct ieee80211_device * ieee, u8 channel)
+{
+	const struct ieee80211_channel * ch;
+
+	/* Driver needs to initialize the geography map before using
+	 * these helper functions */
+	if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
+		return 0;
+
+	ch = ieee80211_get_channel(ieee, channel);
+	if (!ch->channel)
+		return 0;
+	return ch->freq;
+}
+
 u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq)
 {
 	int i;
@@ -174,6 +189,7 @@ EXPORT_SYMBOL(ieee80211_get_channel);
 EXPORT_SYMBOL(ieee80211_get_channel_flags);
 EXPORT_SYMBOL(ieee80211_is_valid_channel);
 EXPORT_SYMBOL(ieee80211_freq_to_channel);
+EXPORT_SYMBOL(ieee80211_channel_to_freq);
 EXPORT_SYMBOL(ieee80211_channel_to_index);
 EXPORT_SYMBOL(ieee80211_set_geo);
 EXPORT_SYMBOL(ieee80211_get_geo);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index cee5e13..523a137 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -89,15 +89,17 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
 		start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
 	}
 
-	/* Add frequency/channel */
+	/* Add channel and frequency */
 	iwe.cmd = SIOCGIWFREQ;
-/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
-	iwe.u.freq.e = 3; */
 	iwe.u.freq.m = network->channel;
 	iwe.u.freq.e = 0;
 	iwe.u.freq.i = 0;
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
 
+	iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
+	iwe.u.freq.e = 6;
+	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
+
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
 	if (network->capability & WLAN_CAPABILITY_PRIVACY)
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 822917d..3e07e9d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -17,6 +17,7 @@
  * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
  *    SSID)
  */
+#include <linux/delay.h>
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -27,7 +28,6 @@
 #include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
-#include <asm/delay.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-03-27 18:26 ` Please pull 'upstream' " John W. Linville
@ 2007-03-29 12:31   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-03-29 12:31 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

John W. Linville wrote:
> The following changes since commit b1944354101f15f4afeffd842e12c7d70fb7e822:
>   John W. Linville (1):
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (3):
>       zd1211rw: Mark some data const
>       zd1211rw: Don't handle broken frames in monitor mode
>       zd1211rw: Add another ID for Linksys WUSBF54G
> 
> Jouni Malinen (1):
>       Update my email address from jkmaline@cc.hut.fi to j@w1.fi
> 
>  MAINTAINERS                                   |    5 +++--
>  crypto/michael_mic.c                          |    4 ++--
>  drivers/net/wireless/hostap/hostap_ap.c       |    4 ++--
>  drivers/net/wireless/hostap/hostap_cs.c       |    2 +-
>  drivers/net/wireless/hostap/hostap_hw.c       |    4 ++--
>  drivers/net/wireless/hostap/hostap_main.c     |    4 ++--
>  drivers/net/wireless/hostap/hostap_pci.c      |    2 +-
>  drivers/net/wireless/hostap/hostap_plx.c      |    2 +-
>  drivers/net/wireless/ipw2100.c                |    4 ++--
>  drivers/net/wireless/zd1211rw/zd_mac.c        |   13 ++-----------
>  drivers/net/wireless/zd1211rw/zd_rf.c         |    2 +-
>  drivers/net/wireless/zd1211rw/zd_rf_al7230b.c |    4 ++--
>  drivers/net/wireless/zd1211rw/zd_rf_rf2959.c  |    4 ++--
>  drivers/net/wireless/zd1211rw/zd_usb.c        |    1 +
>  include/linux/wireless.h                      |    2 +-
>  include/net/ieee80211.h                       |    4 ++--
>  include/net/ieee80211_crypt.h                 |    4 ++--
>  net/ieee80211/ieee80211_crypt.c               |    2 +-
>  net/ieee80211/ieee80211_crypt_ccmp.c          |    2 +-
>  net/ieee80211/ieee80211_crypt_tkip.c          |    2 +-
>  net/ieee80211/ieee80211_crypt_wep.c           |    2 +-
>  net/ieee80211/ieee80211_module.c              |    4 ++--
>  net/ieee80211/ieee80211_rx.c                  |    4 ++--
>  net/ieee80211/ieee80211_wx.c                  |    4 ++--
>  24 files changed, 39 insertions(+), 46 deletions(-)

hrm, it doesn't seem to like my #upstream, can you wait a bit for 
kernel.org propagation, and then redo with these already merged?  Also, 
please pull branch libertas into your #upstream.

Auto-merged MAINTAINERS
Auto-merged drivers/net/wireless/libertas/debugfs.c
CONFLICT (add/add): Merge conflict in 
drivers/net/wireless/libertas/debugfs.c
Auto-merged include/net/ieee80211_radiotap.h
CONFLICT (content): Merge conflict in include/net/ieee80211_radiotap.h
Automatic merge failed; fix conflicts and then commit the result.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-03-27 18:26 Please pull 'upstream-fixes' " John W. Linville
@ 2007-03-27 18:26 ` John W. Linville
  2007-03-29 12:31   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-03-27 18:26 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless

The following changes since commit b1944354101f15f4afeffd842e12c7d70fb7e822:
  John W. Linville (1):
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (3):
      zd1211rw: Mark some data const
      zd1211rw: Don't handle broken frames in monitor mode
      zd1211rw: Add another ID for Linksys WUSBF54G

Jouni Malinen (1):
      Update my email address from jkmaline@cc.hut.fi to j@w1.fi

 MAINTAINERS                                   |    5 +++--
 crypto/michael_mic.c                          |    4 ++--
 drivers/net/wireless/hostap/hostap_ap.c       |    4 ++--
 drivers/net/wireless/hostap/hostap_cs.c       |    2 +-
 drivers/net/wireless/hostap/hostap_hw.c       |    4 ++--
 drivers/net/wireless/hostap/hostap_main.c     |    4 ++--
 drivers/net/wireless/hostap/hostap_pci.c      |    2 +-
 drivers/net/wireless/hostap/hostap_plx.c      |    2 +-
 drivers/net/wireless/ipw2100.c                |    4 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c        |   13 ++-----------
 drivers/net/wireless/zd1211rw/zd_rf.c         |    2 +-
 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c |    4 ++--
 drivers/net/wireless/zd1211rw/zd_rf_rf2959.c  |    4 ++--
 drivers/net/wireless/zd1211rw/zd_usb.c        |    1 +
 include/linux/wireless.h                      |    2 +-
 include/net/ieee80211.h                       |    4 ++--
 include/net/ieee80211_crypt.h                 |    4 ++--
 net/ieee80211/ieee80211_crypt.c               |    2 +-
 net/ieee80211/ieee80211_crypt_ccmp.c          |    2 +-
 net/ieee80211/ieee80211_crypt_tkip.c          |    2 +-
 net/ieee80211/ieee80211_crypt_wep.c           |    2 +-
 net/ieee80211/ieee80211_module.c              |    4 ++--
 net/ieee80211/ieee80211_rx.c                  |    4 ++--
 net/ieee80211/ieee80211_wx.c                  |    4 ++--
 24 files changed, 39 insertions(+), 46 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index dd6978b..3fe1335 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1537,8 +1537,9 @@ S:	Supported
  
 HOST AP DRIVER
 P:	Jouni Malinen
-M:	jkmaline@cc.hut.fi
-L:	hostap@shmoo.com
+M:	j@w1.fi
+L:	hostap@shmoo.com (subscribers-only)
+L:	linux-wireless@vger.kernel.org
 W:	http://hostap.epitest.fi/
 S:	Maintained
 
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 094397b..9e917b8 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -3,7 +3,7 @@
  *
  * Michael MIC (IEEE 802.11i/TKIP) keyed digest
  *
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
  *
  * 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
@@ -173,4 +173,4 @@ module_exit(michael_mic_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index efb8cf3..9ec32fa 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1,8 +1,8 @@
 /*
  * Intersil Prism2 driver with Host AP (software access point) support
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * This file is to be included into hostap.c when S/W AP functionality is
  * compiled.
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 534da85..4b81c7d 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static dev_info_t dev_info = "hostap_cs";
 
 MODULE_AUTHOR("Jouni Malinen");
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 3079378..d21b8a9 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * 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/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 9077e6e..71ec281 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -3,8 +3,8 @@
  * Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
  *
  * 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/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index c4f6020..db4899e 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_pci";
 
 
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index e235e06..f0fd5ec 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,7 @@
 #include "hostap_wlan.h"
 
 
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
 static char *dev_info = "hostap_plx";
 
 
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index ad6e4a4..61706c9 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -28,8 +28,8 @@
 
   Portions of this file are based on the Host AP project,
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-    <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+    <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
   ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 19172f5..6753d24 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[] = {
-		{ CR_RX_FILTER, STA_RX_FILTER },
-		{ CR_SNIFFER_ON, 0U },
-	};
-
-	if (ieee->iw_mode == IW_MODE_MONITOR) {
-		ioreqs[0].value = 0xffffffff;
-		ioreqs[1].value = 0x1;
-	}
-
-	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
+	u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
+	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
 int zd_mac_open(struct net_device *netdev)
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index e6d604b..4ddc2cb 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@
 #include "zd_ieee80211.h"
 #include "zd_chip.h"
 
-static const char *rfs[] = {
+static const char * const rfs[] = {
 	[0]		= "unknown RF0",
 	[1]		= "unknown RF1",
 	[UW2451_RF]	= "UW2451_RF",
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index a289f95..bd07c9b 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -183,12 +183,12 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
 	const u32 *rv = chan_rv[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	struct zd_ioreq16 ioreqs_1[] = {
+	static const struct zd_ioreq16 ioreqs_1[] = {
 		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
 		{ CR38,  0x38 }, { CR136, 0xdf },
 	};
 
-	struct zd_ioreq16 ioreqs_2[] = {
+	static const struct zd_ioreq16 ioreqs_2[] = {
 		/* PLL_ON */
 		{ CR251, 0x3f },
 		{ CR203, 0x06 }, { CR240, 0x08 },
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 5824727..2d736bd 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -21,7 +21,7 @@
 #include "zd_usb.h"
 #include "zd_chip.h"
 
-static u32 rf2959_table[][2] = {
+static const u32 rf2959_table[][2] = {
 	RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
 	RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
 	RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf)
 static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
 {
 	int i, r;
-	u32 *rv = rf2959_table[channel-1];
+	const u32 *rv = rf2959_table[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
 	for (i = 0; i < 2; i++) {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 145ad61..55f4c61 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 48759b2..0987aa7 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -186,7 +186,7 @@
  *	- Wireless Event capability in struct iw_range
  *	- Add support for relative TxPower (yick !)
  *
- * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
  * ----------
  *	- Add support for WPA/WPA2
  *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index e02d85f..d56b292 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -6,8 +6,8 @@
  * LAN access point) driver for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index eb47641..b3d65e0 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3.
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  *
  * Adaption to a generic IEEE 802.11 stack by James Ketrenos
  * <jketreno@linux.intel.com>
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 5ed0a98..df5592c 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypto routines
  *
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index 35aa342..7ec8314 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
  *
  * 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/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index fc1f99a..bd0988f 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
  *
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
  *
  * 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/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index ec6d885..1213d70 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -1,7 +1,7 @@
 /*
  * Host AP crypt: host-based WEP encryption implementation for Host AP driver
  *
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
  *
  * 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/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index b1c6d1f..7630434 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   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
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 4084909..9d33546 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -3,8 +3,8 @@
  * for Intersil Prism2/2.5/3 - hostap.o module, common routines
  *
  * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2004-2005, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 40d7a55..cee5e13 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -5,8 +5,8 @@
   Portions of this file are based on the WEP enablement code provided by the
   Host AP project hostap-drivers v0.1.3
   Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
-  <jkmaline@cc.hut.fi>
-  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+  <j@w1.fi>
+  Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
 
   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
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-03-08  3:32 ` Please pull 'upstream' " John W. Linville
@ 2007-03-09 16:59   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-03-09 16:59 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

John W. Linville wrote:
> The following changes since commit 9b73d945c4269f61d2ecf0555150b577a965bc99:
>   John W. Linville (1):
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Andrew Morton (1):
>       ipw2200: fix ieee80211_get_geo typo
> 
> Jouni Malinen (1):
>       hostap: Add D-Link DWL-650 Rev. P1 product id
> 
> Sam Ravnborg (1):
>       bcm43xx: do not rebuild when kernel version changes
> 
>  drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c |    4 ++--
>  drivers/net/wireless/hostap/hostap_cs.c        |    5 +++++
>  drivers/net/wireless/ipw2200.c                 |    2 +-
>  3 files changed, 8 insertions(+), 3 deletions(-)
> 

pulled




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-03-08  3:30 Please pull 'upstream-fixes' " John W. Linville
@ 2007-03-08  3:32 ` John W. Linville
  2007-03-09 16:59   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-03-08  3:32 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless

The following changes since commit 9b73d945c4269f61d2ecf0555150b577a965bc99:
  John W. Linville (1):
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Andrew Morton (1):
      ipw2200: fix ieee80211_get_geo typo

Jouni Malinen (1):
      hostap: Add D-Link DWL-650 Rev. P1 product id

Sam Ravnborg (1):
      bcm43xx: do not rebuild when kernel version changes

 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c |    4 ++--
 drivers/net/wireless/hostap/hostap_cs.c        |    5 +++++
 drivers/net/wireless/ipw2200.c                 |    2 +-
 3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
index c947025..d2df6a0 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -32,7 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
 
 
 static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *
 	struct bcm43xx_private *bcm = bcm43xx_priv(dev);
 
 	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-	strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+	strncpy(info->version, utsname()->release, sizeof(info->version));
 	strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
 }
 
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 8d8f4b9..534da85 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -848,6 +848,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
 		"Intersil", "PRISM 2_5 PCMCIA ADAPTER",	"ISL37300P",
 		"Eval-RevA",
 		0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+	/* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
+	PCMCIA_DEVICE_PROD_ID1234(
+		"D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
+		"A3",
+		0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
 	PCMCIA_DEVICE_PROD_ID123(
 		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
 		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 99c517a..4372438 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1852,7 +1852,7 @@ static ssize_t show_channels(struct device *d,
 			     char *buf)
 {
 	struct ipw_priv *priv = dev_get_drvdata(d);
-	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
 	int len = 0, i;
 
 	len = sprintf(&buf[len],
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-02-27 20:51 ` Please pull 'upstream' " John W. Linville
@ 2007-03-03  0:42   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-03-03  0:42 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

John W. Linville wrote:
> The following changes since commit 357efd57f229716fd6a1494b970c5a66c0c465ef:
>   Stefano Brivio (1):
>         bcm43xx: fix for 4309
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> John W. Linville (1):
>       wireless: remove obsolete text files
> 
> Larry Finger (1):
>       bcm43xx: Update Documentation/bcm43xx.txt
> 
> Pavel Roskin (1):
>       Use offsetof() instead of own equivalent
> 
> Ulrich Kunitz (1):
>       zd1211rw: changed GFP_NOFS to GFP_KERNEL
> 
> Zhu Yi (1):
>       ipw2200: add channels sysfs entry
> 
>  Documentation/networking/bcm43xx.txt        |   97 +++++++++++++++++++++------
>  drivers/net/wireless/README                 |   25 -------
>  drivers/net/wireless/hostap/hostap_common.h |    4 +-
>  drivers/net/wireless/ipw2200.c              |   47 +++++++++++++
>  drivers/net/wireless/todo.txt               |   15 ----
>  drivers/net/wireless/zd1211rw/zd_chip.c     |    4 +-
>  drivers/net/wireless/zd1211rw/zd_usb.c      |   20 +++---
>  7 files changed, 136 insertions(+), 76 deletions(-)
>  delete mode 100644 drivers/net/wireless/README
>  delete mode 100644 drivers/net/wireless/todo.txt

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-02-27 20:50 Please pull 'upstream-fixes' " John W. Linville
@ 2007-02-27 20:51 ` John W. Linville
  2007-03-03  0:42   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-02-27 20:51 UTC (permalink / raw)
  To: jeff; +Cc: linux-wireless

The following changes since commit 357efd57f229716fd6a1494b970c5a66c0c465ef:
  Stefano Brivio (1):
        bcm43xx: fix for 4309

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

John W. Linville (1):
      wireless: remove obsolete text files

Larry Finger (1):
      bcm43xx: Update Documentation/bcm43xx.txt

Pavel Roskin (1):
      Use offsetof() instead of own equivalent

Ulrich Kunitz (1):
      zd1211rw: changed GFP_NOFS to GFP_KERNEL

Zhu Yi (1):
      ipw2200: add channels sysfs entry

 Documentation/networking/bcm43xx.txt        |   97 +++++++++++++++++++++------
 drivers/net/wireless/README                 |   25 -------
 drivers/net/wireless/hostap/hostap_common.h |    4 +-
 drivers/net/wireless/ipw2200.c              |   47 +++++++++++++
 drivers/net/wireless/todo.txt               |   15 ----
 drivers/net/wireless/zd1211rw/zd_chip.c     |    4 +-
 drivers/net/wireless/zd1211rw/zd_usb.c      |   20 +++---
 7 files changed, 136 insertions(+), 76 deletions(-)
 delete mode 100644 drivers/net/wireless/README
 delete mode 100644 drivers/net/wireless/todo.txt

diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt
index 28541d2..a136721 100644
--- a/Documentation/networking/bcm43xx.txt
+++ b/Documentation/networking/bcm43xx.txt
@@ -2,35 +2,88 @@
 			BCM43xx Linux Driver Project
 			============================
 
-About this software
--------------------
+Introduction
+------------
 
-The goal of this project is to develop a linux driver for Broadcom
-BCM43xx chips, based on the specification at 
-http://bcm-specs.sipsolutions.net/
+Many of the wireless devices found in modern notebook computers are
+based on the wireless chips produced by Broadcom. These devices have
+been a problem for Linux users as there is no open-source driver
+available. In addition, Broadcom has not released specifications
+for the device, and driver availability has been limited to the
+binary-only form used in the GPL versions of AP hardware such as the
+Linksys WRT54G, and the Windows and OS X drivers.  Before this project
+began, the only way to use these devices were to use the Windows or
+OS X drivers with either the Linuxant or ndiswrapper modules. There
+is a strong penalty if this method is used as loading the binary-only
+module "taints" the kernel, and no kernel developer will help diagnose
+any kernel problems.
 
-The project page is http://bcm43xx.berlios.de/
+Development
+-----------
 
+This driver has been developed using
+a clean-room technique that is described at
+http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+reasons, none of the clean-room crew works on the on the Linux driver,
+and none of the Linux developers sees anything but the specifications,
+which are the ultimate product of the reverse-engineering group.
 
-Requirements
-------------
+Software
+--------
+
+Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+distributed with the kernel source, and is prebuilt in most, if not
+all, distributions.  There is, however, additional software that is
+required. The firmware used by the chip is the intellectual property
+of Broadcom and they have not given the bcm43xx team redistribution
+rights to this firmware.  Since we cannot legally redistribute
+the firwmare we cannot include it with the driver. Furthermore, it
+cannot be placed in the downloadable archives of any distributing
+organization; therefore, the user is responsible for obtaining the
+firmware and placing it in the appropriate location so that the driver
+can find it when initializing.
+
+To help with this process, the bcm43xx developers provide a separate
+program named bcm43xx-fwcutter to "cut" the firmware out of a
+Windows or OS X driver and write the extracted files to the proper
+location. This program is usually provided with the distribution;
+however, it may be downloaded from
+
+http://developer.berlios.de/project/showfiles.php?group_id=4547
 
-1)	Linux Kernel 2.6.16 or later
-	http://www.kernel.org/
+The firmware is available in two versions. V3 firmware is used with
+the in-kernel bcm43xx driver that uses a software MAC layer called
+SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+V4 firmware is used by an out-of-kernel driver employing a variation of
+the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+a satisfactory level of development, it will replace bcm43xx-softmac
+in the kernel as it is much more flexible and powerful.
 
-	You may want to configure your kernel with:
+A source for the latest V3 firmware is
 
-	CONFIG_DEBUG_FS (optional):
-		-> Kernel hacking
-		  -> Debug Filesystem
+http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
 
-2)	SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
-	modules:
-	http://softmac.sipsolutions.net/
+Once this file is downloaded, the command
+'bcm43xx-fwcutter -w <dir> <filename>'
+will extract the microcode and write it to directory
+<dir>. The correct directory will depend on your distribution;
+however, most use '/lib/firmware'. Once this step is completed,
+the bcm3xx driver should load when the system is booted. To see
+any messages relating to the driver, issue the command 'dmesg |
+grep bcm43xx' from a terminal window. If there are any problems,
+please send that output to Bcm43xx-dev@lists.berlios.de.
 
-3)	Firmware Files
+Although the driver has been in-kernel since 2.6.17, the earliest
+version is quite limited in its capability. Patches that include
+all features of later versions are available for the stable kernel
+versions from 2.6.18. These will be needed if you use a BCM4318,
+or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+have an early BCM4306 and more than 1 GB RAM, your kernel will need
+to be patched.	These patches, which are being updated regularly,
+are available at ftp://lwfinger.dynalias.org/patches. Look for
+combined_2.6.YY.patch. Of course you will need kernel source downloaded
+from kernel.org, or the source from your distribution.
 
-	Please try fwcutter. Fwcutter can extract the firmware from various 
-	binary driver files. It supports driver files from Windows, MacOS and 
-	Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
-	Also, fwcutter comes with a README file for further instructions.
+If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+essential for solving any problems.
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README
deleted file mode 100644
index 0c274bf..0000000
--- a/drivers/net/wireless/README
+++ /dev/null
@@ -1,25 +0,0 @@
-	README
-	------
-
-	This directory is mostly for Wireless LAN drivers, in their
-various incarnations (ISA, PCI, Pcmcia...).
-	This separate directory is needed because a lot of driver work
-on different bus (typically PCI + Pcmcia) and share 95% of the
-code. This allow the code and the config options to be in one single
-place instead of scattered all over the driver tree, which is never
-100% satisfactory.
-
-	Note : if you want more info on the topic of Wireless LANs,
-you are kindly invited to have a look at the Wireless Howto :
-		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
-	Some Wireless LAN drivers, like orinoco_cs, require the use of
-Wireless Tools to be configured :
-		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
-
-	Special notes for distribution maintainers :
-	1) wvlan_cs will be discontinued soon in favor of orinoco_cs
-	2) Please add Wireless Tools support in your scripts
-
-	Have fun...
-
-	Jean
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 0162400..b31e6a0 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -368,9 +368,9 @@ enum {
 
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+offsetof(struct prism2_hostapd_param, u.rid.data)
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+offsetof(struct prism2_hostapd_param, u.generic_elem.data)
 
 /* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
  */
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index c878a2f..99c517a 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
 static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
 		   show_net_stats, store_net_stats);
 
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct ipw_priv *priv = dev_get_drvdata(d);
+	const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+	int len = 0, i;
+
+	len = sprintf(&buf[len],
+		      "Displaying %d channels in 2.4Ghz band "
+		      "(802.11bg):\n", geo->bg_channels);
+
+	for (i = 0; i < geo->bg_channels; i++) {
+		len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
+			       geo->bg[i].channel,
+			       geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+			       " (radar spectrum)" : "",
+			       ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
+				(geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+			       ? "" : ", IBSS",
+			       geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+			       "passive only" : "active/passive",
+			       geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+			       "B" : "B/G");
+	}
+
+	len += sprintf(&buf[len],
+		       "Displaying %d channels in 5.2Ghz band "
+		       "(802.11a):\n", geo->a_channels);
+	for (i = 0; i < geo->a_channels; i++) {
+		len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
+			       geo->a[i].channel,
+			       geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+			       " (radar spectrum)" : "",
+			       ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
+				(geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+			       ? "" : ", IBSS",
+			       geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+			       "passive only" : "active/passive");
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
 static void notify_wx_assoc_event(struct ipw_priv *priv)
 {
 	union iwreq_data wrqu;
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entries[] = {
 	&dev_attr_led.attr,
 	&dev_attr_speed_scan.attr,
 	&dev_attr_net_stats.attr,
+	&dev_attr_channels.attr,
 #ifdef CONFIG_IPW2200_PROMISCUOUS
 	&dev_attr_rtap_iface.attr,
 	&dev_attr_rtap_filter.attr,
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
deleted file mode 100644
index 3223401..0000000
--- a/drivers/net/wireless/todo.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-	Wireless Todo
-	-------------
-
-1) Bring other kernel Wireless LAN drivers here
-	Completed
-
-2) Bring new Wireless LAN driver not yet in the kernel there
-	See my web page for details
-	In particular : HostAP
-
-3) Misc
-	o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
-	o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
-
-	Jean II
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 9c64f89..f97288d 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -114,7 +114,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
 	/* Allocate a single memory block for values and addresses. */
 	count16 = 2*count;
 	a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
-		                   GFP_NOFS);
+		                   GFP_KERNEL);
 	if (!a16) {
 		dev_dbg_f(zd_chip_dev(chip),
 			  "error ENOMEM in allocation of a16\n");
@@ -163,7 +163,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
 
 	/* Allocate a single memory block for values and addresses. */
 	count16 = 2*count;
-	ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+	ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL);
 	if (!ioreqs16) {
 		r = -ENOMEM;
 		dev_dbg_f(zd_chip_dev(chip),
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index aac8a1c..5e67106 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -412,7 +412,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
 
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
-	urb = usb_alloc_urb(0, GFP_NOFS);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb) {
 		r = -ENOMEM;
 		goto out;
@@ -430,7 +430,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
 
 	/* TODO: make it a DMA buffer */
 	r = -ENOMEM;
-	transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+	transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
 	if (!transfer_buffer) {
 		dev_dbg_f(zd_usb_dev(usb),
 			"couldn't allocate transfer_buffer\n");
@@ -444,7 +444,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
 			 intr->interval);
 
 	dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
-	r = usb_submit_urb(urb, GFP_NOFS);
+	r = usb_submit_urb(urb, GFP_KERNEL);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
 			 "Couldn't submit urb. Error number %d\n", r);
@@ -593,10 +593,10 @@ static struct urb *alloc_urb(struct zd_usb *usb)
 	struct urb *urb;
 	void *buffer;
 
-	urb = usb_alloc_urb(0, GFP_NOFS);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return NULL;
-	buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+	buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
 		                  &urb->transfer_dma);
 	if (!buffer) {
 		usb_free_urb(urb);
@@ -629,7 +629,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
 	r = -ENOMEM;
-	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
 	if (!urbs)
 		goto error;
 	for (i = 0; i < URBS_COUNT; i++) {
@@ -650,7 +650,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 	spin_unlock_irq(&rx->lock);
 
 	for (i = 0; i < URBS_COUNT; i++) {
-		r = usb_submit_urb(urbs[i], GFP_NOFS);
+		r = usb_submit_urb(urbs[i], GFP_KERNEL);
 		if (r)
 			goto error_submit;
 	}
@@ -1156,7 +1156,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 	}
 
 	req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
@@ -1219,7 +1219,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
 
 	req_len = sizeof(struct usb_req_write_regs) +
 		  count * sizeof(struct reg_data);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
@@ -1299,7 +1299,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
 	bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
 
 	req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
-	req = kmalloc(req_len, GFP_NOFS);
+	req = kmalloc(req_len, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
 
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull "upstream" branch of wireless-2.6
@ 2007-02-09 21:12         ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-02-09 21:12 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev, linux-wireless

John W. Linville wrote:
> On Wed, Feb 07, 2007 at 04:11:17PM -0500, John W. Linville wrote:
>> On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
>>> Would you mind rebasing & resending, kind sir?
>> By your command! :-)
> 
> And once more, now with feeling! :-)
> 
> ---
> 
> The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
>   Linus Torvalds (1):
>         Linux 2.6.20
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Remove noisy debug message
> 
> Larry Finger (5):
>       bcm43xx: Fix problem with >1 GB RAM
>       bcm43xx: Fix scaling error for 'iwlist rate' information
>       bcm43xx: Fix scaling error for 'iwlist freq' information
>       bcm43xx: Check error returns in initialization routines
>       ieee80211: Fix sparse warning
> 
> Maxime Austruy (1):
>       zd1211rw: fix potential leak in usb_init
> 
> Michael Buesch (1):
>       bcm43xx: Enable fwpostfix in nondebug bcm43xx
> 
> Robert P. J. Day (2):
>       Rename IPW2100 debugging macros to not look like config options.
>       Replace incorrect macro name "WIRELESS_EXT" with "CONFIG_WIRELESS_EXT"
> 
> Ulrich Kunitz (3):
>       zd1211rw: Reset device in the probe call
>       zd1211rw: Fixed array size issue in reset_mode
>       zd1211rw: Added error stats update
> 
>  drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
>  drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c |   25 +++--
>  drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
>  drivers/net/wireless/ipw2100.c              |   16 ++--
>  drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
>  drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
>  net/core/net-sysfs.c                        |    4 +-
>  net/ieee80211/ieee80211_tx.c                |    3 -
>  9 files changed, 210 insertions(+), 94 deletions(-)

pulled, thanks



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull "upstream" branch of wireless-2.6
@ 2007-02-09 21:12         ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-02-09 21:12 UTC (permalink / raw)
  To: John W. Linville
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-wireless-u79uwXL29TY76Z2rM5mHXA

John W. Linville wrote:
> On Wed, Feb 07, 2007 at 04:11:17PM -0500, John W. Linville wrote:
>> On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
>>> Would you mind rebasing & resending, kind sir?
>> By your command! :-)
> 
> And once more, now with feeling! :-)
> 
> ---
> 
> The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
>   Linus Torvalds (1):
>         Linux 2.6.20
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (1):
>       zd1211rw: Remove noisy debug message
> 
> Larry Finger (5):
>       bcm43xx: Fix problem with >1 GB RAM
>       bcm43xx: Fix scaling error for 'iwlist rate' information
>       bcm43xx: Fix scaling error for 'iwlist freq' information
>       bcm43xx: Check error returns in initialization routines
>       ieee80211: Fix sparse warning
> 
> Maxime Austruy (1):
>       zd1211rw: fix potential leak in usb_init
> 
> Michael Buesch (1):
>       bcm43xx: Enable fwpostfix in nondebug bcm43xx
> 
> Robert P. J. Day (2):
>       Rename IPW2100 debugging macros to not look like config options.
>       Replace incorrect macro name "WIRELESS_EXT" with "CONFIG_WIRELESS_EXT"
> 
> Ulrich Kunitz (3):
>       zd1211rw: Reset device in the probe call
>       zd1211rw: Fixed array size issue in reset_mode
>       zd1211rw: Added error stats update
> 
>  drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
>  drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c |   25 +++--
>  drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
>  drivers/net/wireless/ipw2100.c              |   16 ++--
>  drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
>  drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
>  net/core/net-sysfs.c                        |    4 +-
>  net/ieee80211/ieee80211_tx.c                |    3 -
>  9 files changed, 210 insertions(+), 94 deletions(-)

pulled, thanks


-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull "upstream" branch of wireless-2.6
@ 2007-02-09 20:13       ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-02-09 20:13 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, linux-wireless

On Wed, Feb 07, 2007 at 04:11:17PM -0500, John W. Linville wrote:
> On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
> > Would you mind rebasing & resending, kind sir?
> 
> By your command! :-)

And once more, now with feeling! :-)

---

The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
  Linus Torvalds (1):
        Linux 2.6.20

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Remove noisy debug message

Larry Finger (5):
      bcm43xx: Fix problem with >1 GB RAM
      bcm43xx: Fix scaling error for 'iwlist rate' information
      bcm43xx: Fix scaling error for 'iwlist freq' information
      bcm43xx: Check error returns in initialization routines
      ieee80211: Fix sparse warning

Maxime Austruy (1):
      zd1211rw: fix potential leak in usb_init

Michael Buesch (1):
      bcm43xx: Enable fwpostfix in nondebug bcm43xx

Robert P. J. Day (2):
      Rename IPW2100 debugging macros to not look like config options.
      Replace incorrect macro name "WIRELESS_EXT" with "CONFIG_WIRELESS_EXT"

Ulrich Kunitz (3):
      zd1211rw: Reset device in the probe call
      zd1211rw: Fixed array size issue in reset_mode
      zd1211rw: Added error stats update

 drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |   25 +++--
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
 drivers/net/wireless/ipw2100.c              |   16 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
 drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
 net/core/net-sysfs.c                        |    4 +-
 net/ieee80211/ieee80211_tx.c                |    3 -
 9 files changed, 210 insertions(+), 94 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..4168b1a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -766,6 +766,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed09..6e0dc76 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_dev,
 					 buf, len,
-					 DMA_FROM_DEVICE);
-	}
+					 direction);
 
 	return dmaaddr;
 }
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_TO_DEVICE);
+				 PCI_DMA_TODEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_FROM_DEVICE);
+				 PCI_DMA_FROMDEVICE);
 	}
 }
 
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
-				addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_FROMDEVICE);
 }
 
 static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
-				   addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_TODEVICE);
 }
 
 /* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
-
-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase));
 	if (!ring->descbase) {
-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
-		return -ENOMEM;
+		/* Allocation may have failed due to pci_alloc_consistent
+		   insisting on use of GFP_DMA, which is more restrictive
+		   than necessary...  */
+		struct dma_desc *rx_ring;
+		dma_addr_t rx_ring_dma;
+
+		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+		if (!rx_ring)
+			goto out_err;
+
+		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+					     BCM43xx_DMA_RINGMEMSIZE,
+					     PCI_DMA_BIDIRECTIONAL);
+
+		if (pci_dma_mapping_error(rx_ring_dma) ||
+		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+			/* Sigh... */
+			if (!pci_dma_mapping_error(rx_ring_dma))
+				pci_unmap_single(ring->bcm->pci_dev,
+						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			if (pci_dma_mapping_error(rx_ring_dma) ||
+			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+				assert(0);
+				if (!pci_dma_mapping_error(rx_ring_dma))
+					pci_unmap_single(ring->bcm->pci_dev,
+							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+							 PCI_DMA_BIDIRECTIONAL);
+				goto out_err;
+			}
+                }
+
+                ring->descbase = rx_ring;
+                ring->dmabase = rx_ring_dma;
 	}
 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
+out_err:
+	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+	return -ENOMEM;
 }
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	/* This hardware bug work-around adapted from the b44 driver.
+	   The chip may be unable to do PCI DMA to/from anything above 1GB */
+	if (pci_dma_mapping_error(dmaaddr) ||
+	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+		/* This one has 30-bit addressing... */
+		if (!pci_dma_mapping_error(dmaaddr))
+			pci_unmap_single(ring->bcm->pci_dev,
+					 dmaaddr, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+		if (skb == NULL)
+			return -ENOMEM;
+		dmaaddr = pci_map_single(ring->bcm->pci_dev,
+					 skb->data, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(dmaaddr) ||
+		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+			assert(0);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	err = dmacontroller_setup(ring);
 	if (err)
 		goto err_free_ringmemory;
+	return ring;
 
 out:
+	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
 	return ring;
 
 err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
 	int dma64 = 0;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	if (mask == DMA_64BIT_MASK) {
+	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+	if (bcm->dma_mask == DMA_64BIT_MASK)
 		dma64 = 1;
-		nobits = 64;
-	} else if (mask == DMA_32BIT_MASK)
-		nobits = 32;
-	else
-		nobits = 30;
-	err = pci_set_dma_mask(bcm->pci_dev, mask);
-	err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
-	if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-		printk(KERN_WARNING PFX "DMA not supported on this device."
-					" Falling back to PIO.\n");
-		bcm->__using_pio = 1;
-		return -ENOSYS;
-#else
-		printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-				    "Please recompile the driver with PIO support.\n");
-		return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-	}
+	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
+	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
 
 	/* setup TX DMA channels. */
 	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
 out:
 	return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
 err_destroy_tx0:
 	bcm43xx_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
-	goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+	printk(KERN_WARNING PFX "DMA not supported on this device."
+				" Falling back to PIO.\n");
+	bcm->__using_pio = 1;
+	return -ENOSYS;
+#else
+	printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+			    "Please recompile the driver with PIO support.\n");
+	return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
 }
 
 /* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	dma_addr_t dmaaddr;
+	struct sk_buff *bounce_skb;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 			       skb->len - sizeof(struct bcm43xx_txhdr),
 			       (cur_frag == 0),
 			       generate_cookie(ring, slot));
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+		if (!dma_mapping_error(dmaaddr))
+			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return;
+		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+			if (!dma_mapping_error(dmaaddr))
+				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+			dev_kfree_skb_any(bounce_skb);
+			assert(0);
+			return;
+		}
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+	}
 
 	meta->skb = skb;
-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	meta->dmaaddr = dmaaddr;
 
 	fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e..63fc16f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
 module_param_named(noleds, modparam_noleds, int, 0444);
 MODULE_PARM_DESC(noleds, "Turn off all LED activity");
 
-#ifdef CONFIG_BCM43XX_DEBUG
 static char modparam_fwpostfix[64];
 module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix  ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
 
 
 /* If you want to debug with just a single device, enable this,
@@ -2980,8 +2976,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
 	if (err)
 		goto out;
-	bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
-	bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
+	err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
+	if (err)
+		goto out;
+	err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
 
 out:
 	return err;
@@ -3778,12 +3776,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
 	}
 	net_dev->base_addr = (unsigned long)bcm->mmio_addr;
 
-	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
+	err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
 	                          &bcm->board_vendor);
-	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
 	                          &bcm->board_type);
-	bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
 	                          &bcm->board_revision);
+	if (err)
+		goto err_iounmap;
 
 	err = bcm43xx_chipset_attach(bcm);
 	if (err)
@@ -3874,6 +3878,7 @@ err_pci_release:
 	pci_release_regions(pci_dev);
 err_pci_disable:
 	pci_disable_device(pci_dev);
+	printk(KERN_ERR PFX "Unable to attach board\n");
 	goto out;
 }
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442..6961be6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 	if (phy->type == BCM43xx_PHYTYPE_A ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates = 8;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
 	}
 	if (phy->type == BCM43xx_PHYTYPE_B ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates += 4;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
 	}
 
 	geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].m = geo->a[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].m = geo->bg[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a..d0639a4 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
+#define IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 	priv->snapshot[0] = NULL;
 }
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
  * The size of the constructed ethernet
  *
  */
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
 static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	u32 match, reg;
 	int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 	}
 #endif
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	/* Halt the fimrware so we can get a good image */
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 
 	skb_put(packet->skb, status->frame_size);
 
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
 	memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 		IPW_DEBUG_DROP("%s: Non consumed packet:\n",
 			       priv->net_dev->name);
 		printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 	else
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
 	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a085241..4c5f78e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[3] = {
+	struct zd_ioreq32 ioreqs[] = {
 		{ CR_RX_FILTER, STA_RX_FILTER },
 		{ CR_SNIFFER_ON, 0U },
 	};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 		ioreqs[0].value = 0xffffffff;
 		ioreqs[1].value = 0x1;
-		ioreqs[2].value = ENC_SNIFFER;
 	}
 
-	return zd_iowrite32a(&mac->chip, ioreqs, 3);
+	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
 	int i, r;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
 	for (i = 0; i < txb->nr_frags; i++) {
 		struct sk_buff *skb = txb->fragments[i];
 
 		r = fill_ctrlset(mac, txb, i);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 	}
 
 	/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
 	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
 	if (status->frame_status & ZD_RX_ERROR) {
-		/* FIXME: update? */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+			ieee->stats.rx_missed_errors++;
+		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+			ieee->stats.rx_fifo_errors++;
+		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+			ieee->ieee_stats.rx_discards_undecryptable++;
+		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+			ieee->stats.rx_crc_errors++;
+			ieee->ieee_stats.rx_fcs_errors++;
+		}
+		else if (status->frame_status & ZD_RX_CRC16_ERROR)
+			ieee->stats.rx_crc_errors++;
 		return -EINVAL;
 	}
+
 	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
 	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
 		               + sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
 	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
 	{
-		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
-			 skb->len);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		goto free_skb;
 	}
 
 	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
 	if (r) {
-		/* Only packets with rx errors are included here. */
+		/* Only packets with rx errors are included here.
+		 * The error stats have already been set in fill_rx_stats.
+		 */
 		goto free_skb;
 	}
 
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 
 	r = filter_rx(ieee, skb->data, skb->len, &stats);
 	if (r <= 0) {
-		if (r < 0)
+		if (r < 0) {
+			ieee->stats.rx_errors++;
 			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		}
 		goto free_skb;
 	}
 
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb) {
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		ieee->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 	skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..a3217a8 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -401,6 +401,12 @@ out:
 
 static inline void handle_retry_failed_int(struct urb *urb)
 {
+	struct zd_usb *usb = urb->context;
+	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	ieee->stats.tx_errors++;
+	ieee->ieee_stats.tx_retry_limit_exceeded++;
 	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
 }
 
@@ -575,6 +581,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -1027,6 +1036,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
+	usb_reset_device(interface_to_usbdev(intf));
+
 	netdev = zd_netdev_alloc(intf);
 	if (netdev == NULL) {
 		r = -ENOMEM;
@@ -1128,6 +1139,7 @@ static int __init usb_init(void)
 
 	r = usb_register(&driver);
 	if (r) {
+		destroy_workqueue(zd_workqueue);
 		printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
 		       driver.name, r);
 		return r;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index f47f319..44e69a2 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -329,7 +329,7 @@ static struct attribute_group netstat_group = {
 	.attrs  = netstat_attrs,
 };
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 /* helper function that does all the locking etc for wireless stats */
 static ssize_t wireless_show(struct class_device *cd, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
@@ -462,7 +462,7 @@ int netdev_register_sysfs(struct net_device *net)
 	if (net->get_stats)
 		*groups++ = &netstat_group;
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 		*groups++ = &wireless_group;
 #endif
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 854fc13..54e0116 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -502,9 +502,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 		if (host_encrypt)
 			ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
 		else if (host_build_iv) {
-			struct ieee80211_crypt_data *crypt;
-
-			crypt = ieee->crypt[ieee->tx_keyidx];
 			atomic_inc(&crypt->refcnt);
 			if (crypt->ops->build_iv)
 				crypt->ops->build_iv(skb_frag, hdr_len,
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull "upstream" branch of wireless-2.6
@ 2007-02-09 20:13       ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-02-09 20:13 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-wireless-u79uwXL29TY76Z2rM5mHXA

On Wed, Feb 07, 2007 at 04:11:17PM -0500, John W. Linville wrote:
> On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
> > Would you mind rebasing & resending, kind sir?
> 
> By your command! :-)

And once more, now with feeling! :-)

---

The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
  Linus Torvalds (1):
        Linux 2.6.20

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Remove noisy debug message

Larry Finger (5):
      bcm43xx: Fix problem with >1 GB RAM
      bcm43xx: Fix scaling error for 'iwlist rate' information
      bcm43xx: Fix scaling error for 'iwlist freq' information
      bcm43xx: Check error returns in initialization routines
      ieee80211: Fix sparse warning

Maxime Austruy (1):
      zd1211rw: fix potential leak in usb_init

Michael Buesch (1):
      bcm43xx: Enable fwpostfix in nondebug bcm43xx

Robert P. J. Day (2):
      Rename IPW2100 debugging macros to not look like config options.
      Replace incorrect macro name "WIRELESS_EXT" with "CONFIG_WIRELESS_EXT"

Ulrich Kunitz (3):
      zd1211rw: Reset device in the probe call
      zd1211rw: Fixed array size issue in reset_mode
      zd1211rw: Added error stats update

 drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |   25 +++--
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
 drivers/net/wireless/ipw2100.c              |   16 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
 drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
 net/core/net-sysfs.c                        |    4 +-
 net/ieee80211/ieee80211_tx.c                |    3 -
 9 files changed, 210 insertions(+), 94 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..4168b1a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -766,6 +766,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed09..6e0dc76 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_dev,
 					 buf, len,
-					 DMA_FROM_DEVICE);
-	}
+					 direction);
 
 	return dmaaddr;
 }
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_TO_DEVICE);
+				 PCI_DMA_TODEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_FROM_DEVICE);
+				 PCI_DMA_FROMDEVICE);
 	}
 }
 
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
-				addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_FROMDEVICE);
 }
 
 static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
-				   addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_TODEVICE);
 }
 
 /* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
-
-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase));
 	if (!ring->descbase) {
-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
-		return -ENOMEM;
+		/* Allocation may have failed due to pci_alloc_consistent
+		   insisting on use of GFP_DMA, which is more restrictive
+		   than necessary...  */
+		struct dma_desc *rx_ring;
+		dma_addr_t rx_ring_dma;
+
+		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+		if (!rx_ring)
+			goto out_err;
+
+		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+					     BCM43xx_DMA_RINGMEMSIZE,
+					     PCI_DMA_BIDIRECTIONAL);
+
+		if (pci_dma_mapping_error(rx_ring_dma) ||
+		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+			/* Sigh... */
+			if (!pci_dma_mapping_error(rx_ring_dma))
+				pci_unmap_single(ring->bcm->pci_dev,
+						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			if (pci_dma_mapping_error(rx_ring_dma) ||
+			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+				assert(0);
+				if (!pci_dma_mapping_error(rx_ring_dma))
+					pci_unmap_single(ring->bcm->pci_dev,
+							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+							 PCI_DMA_BIDIRECTIONAL);
+				goto out_err;
+			}
+                }
+
+                ring->descbase = rx_ring;
+                ring->dmabase = rx_ring_dma;
 	}
 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
+out_err:
+	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+	return -ENOMEM;
 }
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	/* This hardware bug work-around adapted from the b44 driver.
+	   The chip may be unable to do PCI DMA to/from anything above 1GB */
+	if (pci_dma_mapping_error(dmaaddr) ||
+	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+		/* This one has 30-bit addressing... */
+		if (!pci_dma_mapping_error(dmaaddr))
+			pci_unmap_single(ring->bcm->pci_dev,
+					 dmaaddr, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+		if (skb == NULL)
+			return -ENOMEM;
+		dmaaddr = pci_map_single(ring->bcm->pci_dev,
+					 skb->data, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(dmaaddr) ||
+		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+			assert(0);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	err = dmacontroller_setup(ring);
 	if (err)
 		goto err_free_ringmemory;
+	return ring;
 
 out:
+	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
 	return ring;
 
 err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
 	int dma64 = 0;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	if (mask == DMA_64BIT_MASK) {
+	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+	if (bcm->dma_mask == DMA_64BIT_MASK)
 		dma64 = 1;
-		nobits = 64;
-	} else if (mask == DMA_32BIT_MASK)
-		nobits = 32;
-	else
-		nobits = 30;
-	err = pci_set_dma_mask(bcm->pci_dev, mask);
-	err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
-	if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-		printk(KERN_WARNING PFX "DMA not supported on this device."
-					" Falling back to PIO.\n");
-		bcm->__using_pio = 1;
-		return -ENOSYS;
-#else
-		printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-				    "Please recompile the driver with PIO support.\n");
-		return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-	}
+	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
+	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
 
 	/* setup TX DMA channels. */
 	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
 out:
 	return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
 err_destroy_tx0:
 	bcm43xx_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
-	goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+	printk(KERN_WARNING PFX "DMA not supported on this device."
+				" Falling back to PIO.\n");
+	bcm->__using_pio = 1;
+	return -ENOSYS;
+#else
+	printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+			    "Please recompile the driver with PIO support.\n");
+	return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
 }
 
 /* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	dma_addr_t dmaaddr;
+	struct sk_buff *bounce_skb;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 			       skb->len - sizeof(struct bcm43xx_txhdr),
 			       (cur_frag == 0),
 			       generate_cookie(ring, slot));
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+		if (!dma_mapping_error(dmaaddr))
+			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return;
+		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+			if (!dma_mapping_error(dmaaddr))
+				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+			dev_kfree_skb_any(bounce_skb);
+			assert(0);
+			return;
+		}
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+	}
 
 	meta->skb = skb;
-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	meta->dmaaddr = dmaaddr;
 
 	fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e..63fc16f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
 module_param_named(noleds, modparam_noleds, int, 0444);
 MODULE_PARM_DESC(noleds, "Turn off all LED activity");
 
-#ifdef CONFIG_BCM43XX_DEBUG
 static char modparam_fwpostfix[64];
 module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix  ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
 
 
 /* If you want to debug with just a single device, enable this,
@@ -2980,8 +2976,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
 	if (err)
 		goto out;
-	bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
-	bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
+	err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
+	if (err)
+		goto out;
+	err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
 
 out:
 	return err;
@@ -3778,12 +3776,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
 	}
 	net_dev->base_addr = (unsigned long)bcm->mmio_addr;
 
-	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
+	err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
 	                          &bcm->board_vendor);
-	bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
 	                          &bcm->board_type);
-	bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
+	if (err)
+		goto err_iounmap;
+	err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
 	                          &bcm->board_revision);
+	if (err)
+		goto err_iounmap;
 
 	err = bcm43xx_chipset_attach(bcm);
 	if (err)
@@ -3874,6 +3878,7 @@ err_pci_release:
 	pci_release_regions(pci_dev);
 err_pci_disable:
 	pci_disable_device(pci_dev);
+	printk(KERN_ERR PFX "Unable to attach board\n");
 	goto out;
 }
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442..6961be6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 	if (phy->type == BCM43xx_PHYTYPE_A ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates = 8;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
 	}
 	if (phy->type == BCM43xx_PHYTYPE_B ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates += 4;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
 	}
 
 	geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].m = geo->a[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].m = geo->bg[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a..d0639a4 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
+#define IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 	priv->snapshot[0] = NULL;
 }
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
  * The size of the constructed ethernet
  *
  */
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
 static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	u32 match, reg;
 	int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 	}
 #endif
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	/* Halt the fimrware so we can get a good image */
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 
 	skb_put(packet->skb, status->frame_size);
 
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
 	memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 		IPW_DEBUG_DROP("%s: Non consumed packet:\n",
 			       priv->net_dev->name);
 		printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 	else
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
 	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a085241..4c5f78e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[3] = {
+	struct zd_ioreq32 ioreqs[] = {
 		{ CR_RX_FILTER, STA_RX_FILTER },
 		{ CR_SNIFFER_ON, 0U },
 	};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 		ioreqs[0].value = 0xffffffff;
 		ioreqs[1].value = 0x1;
-		ioreqs[2].value = ENC_SNIFFER;
 	}
 
-	return zd_iowrite32a(&mac->chip, ioreqs, 3);
+	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
 	int i, r;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
 	for (i = 0; i < txb->nr_frags; i++) {
 		struct sk_buff *skb = txb->fragments[i];
 
 		r = fill_ctrlset(mac, txb, i);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 	}
 
 	/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
 	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
 	if (status->frame_status & ZD_RX_ERROR) {
-		/* FIXME: update? */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+			ieee->stats.rx_missed_errors++;
+		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+			ieee->stats.rx_fifo_errors++;
+		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+			ieee->ieee_stats.rx_discards_undecryptable++;
+		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+			ieee->stats.rx_crc_errors++;
+			ieee->ieee_stats.rx_fcs_errors++;
+		}
+		else if (status->frame_status & ZD_RX_CRC16_ERROR)
+			ieee->stats.rx_crc_errors++;
 		return -EINVAL;
 	}
+
 	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
 	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
 		               + sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
 	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
 	{
-		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
-			 skb->len);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		goto free_skb;
 	}
 
 	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
 	if (r) {
-		/* Only packets with rx errors are included here. */
+		/* Only packets with rx errors are included here.
+		 * The error stats have already been set in fill_rx_stats.
+		 */
 		goto free_skb;
 	}
 
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 
 	r = filter_rx(ieee, skb->data, skb->len, &stats);
 	if (r <= 0) {
-		if (r < 0)
+		if (r < 0) {
+			ieee->stats.rx_errors++;
 			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		}
 		goto free_skb;
 	}
 
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb) {
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		ieee->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 	skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..a3217a8 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -401,6 +401,12 @@ out:
 
 static inline void handle_retry_failed_int(struct urb *urb)
 {
+	struct zd_usb *usb = urb->context;
+	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	ieee->stats.tx_errors++;
+	ieee->ieee_stats.tx_retry_limit_exceeded++;
 	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
 }
 
@@ -575,6 +581,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -1027,6 +1036,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
+	usb_reset_device(interface_to_usbdev(intf));
+
 	netdev = zd_netdev_alloc(intf);
 	if (netdev == NULL) {
 		r = -ENOMEM;
@@ -1128,6 +1139,7 @@ static int __init usb_init(void)
 
 	r = usb_register(&driver);
 	if (r) {
+		destroy_workqueue(zd_workqueue);
 		printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
 		       driver.name, r);
 		return r;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index f47f319..44e69a2 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -329,7 +329,7 @@ static struct attribute_group netstat_group = {
 	.attrs  = netstat_attrs,
 };
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 /* helper function that does all the locking etc for wireless stats */
 static ssize_t wireless_show(struct class_device *cd, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
@@ -462,7 +462,7 @@ int netdev_register_sysfs(struct net_device *net)
 	if (net->get_stats)
 		*groups++ = &netstat_group;
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 		*groups++ = &wireless_group;
 #endif
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 854fc13..54e0116 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -502,9 +502,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 		if (host_encrypt)
 			ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
 		else if (host_build_iv) {
-			struct ieee80211_crypt_data *crypt;
-
-			crypt = ieee->crypt[ieee->tx_keyidx];
 			atomic_inc(&crypt->refcnt);
 			if (crypt->ops->build_iv)
 				crypt->ops->build_iv(skb_frag, hdr_len,
-- 
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull "upstream" branch of wireless-2.6
@ 2007-02-07 21:11     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-02-07 21:11 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, linux-wireless

On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
> Would you mind rebasing & resending, kind sir?

By your command! :-)

---

The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
  Linus Torvalds (1):
        Linux 2.6.20

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Remove noisy debug message

Larry Finger (3):
      bcm43xx: Fix problem with >1 GB RAM
      bcm43xx: Fix scaling error for 'iwlist rate' information
      bcm43xx: Fix scaling error for 'iwlist freq' information

Maxime Austruy (1):
      zd1211rw: fix potential leak in usb_init

Michael Buesch (1):
      bcm43xx: Enable fwpostfix in nondebug bcm43xx

Robert P. J. Day (1):
      Rename IPW2100 debugging macros to not look like config options.

Ulrich Kunitz (3):
      zd1211rw: Reset device in the probe call
      zd1211rw: Fixed array size issue in reset_mode
      zd1211rw: Added error stats update

 drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |    6 +-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
 drivers/net/wireless/ipw2100.c              |   16 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
 drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
 7 files changed, 194 insertions(+), 84 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..4168b1a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -766,6 +766,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed09..6e0dc76 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_dev,
 					 buf, len,
-					 DMA_FROM_DEVICE);
-	}
+					 direction);
 
 	return dmaaddr;
 }
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_TO_DEVICE);
+				 PCI_DMA_TODEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_FROM_DEVICE);
+				 PCI_DMA_FROMDEVICE);
 	}
 }
 
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
-				addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_FROMDEVICE);
 }
 
 static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
-				   addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_TODEVICE);
 }
 
 /* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
-
-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase));
 	if (!ring->descbase) {
-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
-		return -ENOMEM;
+		/* Allocation may have failed due to pci_alloc_consistent
+		   insisting on use of GFP_DMA, which is more restrictive
+		   than necessary...  */
+		struct dma_desc *rx_ring;
+		dma_addr_t rx_ring_dma;
+
+		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+		if (!rx_ring)
+			goto out_err;
+
+		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+					     BCM43xx_DMA_RINGMEMSIZE,
+					     PCI_DMA_BIDIRECTIONAL);
+
+		if (pci_dma_mapping_error(rx_ring_dma) ||
+		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+			/* Sigh... */
+			if (!pci_dma_mapping_error(rx_ring_dma))
+				pci_unmap_single(ring->bcm->pci_dev,
+						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			if (pci_dma_mapping_error(rx_ring_dma) ||
+			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+				assert(0);
+				if (!pci_dma_mapping_error(rx_ring_dma))
+					pci_unmap_single(ring->bcm->pci_dev,
+							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+							 PCI_DMA_BIDIRECTIONAL);
+				goto out_err;
+			}
+                }
+
+                ring->descbase = rx_ring;
+                ring->dmabase = rx_ring_dma;
 	}
 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
+out_err:
+	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+	return -ENOMEM;
 }
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	/* This hardware bug work-around adapted from the b44 driver.
+	   The chip may be unable to do PCI DMA to/from anything above 1GB */
+	if (pci_dma_mapping_error(dmaaddr) ||
+	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+		/* This one has 30-bit addressing... */
+		if (!pci_dma_mapping_error(dmaaddr))
+			pci_unmap_single(ring->bcm->pci_dev,
+					 dmaaddr, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+		if (skb == NULL)
+			return -ENOMEM;
+		dmaaddr = pci_map_single(ring->bcm->pci_dev,
+					 skb->data, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(dmaaddr) ||
+		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+			assert(0);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	err = dmacontroller_setup(ring);
 	if (err)
 		goto err_free_ringmemory;
+	return ring;
 
 out:
+	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
 	return ring;
 
 err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
 	int dma64 = 0;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	if (mask == DMA_64BIT_MASK) {
+	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+	if (bcm->dma_mask == DMA_64BIT_MASK)
 		dma64 = 1;
-		nobits = 64;
-	} else if (mask == DMA_32BIT_MASK)
-		nobits = 32;
-	else
-		nobits = 30;
-	err = pci_set_dma_mask(bcm->pci_dev, mask);
-	err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
-	if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-		printk(KERN_WARNING PFX "DMA not supported on this device."
-					" Falling back to PIO.\n");
-		bcm->__using_pio = 1;
-		return -ENOSYS;
-#else
-		printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-				    "Please recompile the driver with PIO support.\n");
-		return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-	}
+	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
+	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
 
 	/* setup TX DMA channels. */
 	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
 out:
 	return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
 err_destroy_tx0:
 	bcm43xx_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
-	goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+	printk(KERN_WARNING PFX "DMA not supported on this device."
+				" Falling back to PIO.\n");
+	bcm->__using_pio = 1;
+	return -ENOSYS;
+#else
+	printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+			    "Please recompile the driver with PIO support.\n");
+	return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
 }
 
 /* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	dma_addr_t dmaaddr;
+	struct sk_buff *bounce_skb;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 			       skb->len - sizeof(struct bcm43xx_txhdr),
 			       (cur_frag == 0),
 			       generate_cookie(ring, slot));
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+		if (!dma_mapping_error(dmaaddr))
+			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return;
+		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+			if (!dma_mapping_error(dmaaddr))
+				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+			dev_kfree_skb_any(bounce_skb);
+			assert(0);
+			return;
+		}
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+	}
 
 	meta->skb = skb;
-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	meta->dmaaddr = dmaaddr;
 
 	fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e..62c6235 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
 module_param_named(noleds, modparam_noleds, int, 0444);
 MODULE_PARM_DESC(noleds, "Turn off all LED activity");
 
-#ifdef CONFIG_BCM43XX_DEBUG
 static char modparam_fwpostfix[64];
 module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix  ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
 
 
 /* If you want to debug with just a single device, enable this,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442..6961be6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 	if (phy->type == BCM43xx_PHYTYPE_A ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates = 8;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
 	}
 	if (phy->type == BCM43xx_PHYTYPE_B ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates += 4;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
 	}
 
 	geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].m = geo->a[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].m = geo->bg[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a..d0639a4 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
+#define IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 	priv->snapshot[0] = NULL;
 }
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
  * The size of the constructed ethernet
  *
  */
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
 static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	u32 match, reg;
 	int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 	}
 #endif
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	/* Halt the fimrware so we can get a good image */
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 
 	skb_put(packet->skb, status->frame_size);
 
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
 	memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 		IPW_DEBUG_DROP("%s: Non consumed packet:\n",
 			       priv->net_dev->name);
 		printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 	else
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
 	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a085241..4c5f78e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[3] = {
+	struct zd_ioreq32 ioreqs[] = {
 		{ CR_RX_FILTER, STA_RX_FILTER },
 		{ CR_SNIFFER_ON, 0U },
 	};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 		ioreqs[0].value = 0xffffffff;
 		ioreqs[1].value = 0x1;
-		ioreqs[2].value = ENC_SNIFFER;
 	}
 
-	return zd_iowrite32a(&mac->chip, ioreqs, 3);
+	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
 	int i, r;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
 	for (i = 0; i < txb->nr_frags; i++) {
 		struct sk_buff *skb = txb->fragments[i];
 
 		r = fill_ctrlset(mac, txb, i);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 	}
 
 	/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
 	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
 	if (status->frame_status & ZD_RX_ERROR) {
-		/* FIXME: update? */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+			ieee->stats.rx_missed_errors++;
+		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+			ieee->stats.rx_fifo_errors++;
+		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+			ieee->ieee_stats.rx_discards_undecryptable++;
+		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+			ieee->stats.rx_crc_errors++;
+			ieee->ieee_stats.rx_fcs_errors++;
+		}
+		else if (status->frame_status & ZD_RX_CRC16_ERROR)
+			ieee->stats.rx_crc_errors++;
 		return -EINVAL;
 	}
+
 	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
 	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
 		               + sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
 	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
 	{
-		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
-			 skb->len);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		goto free_skb;
 	}
 
 	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
 	if (r) {
-		/* Only packets with rx errors are included here. */
+		/* Only packets with rx errors are included here.
+		 * The error stats have already been set in fill_rx_stats.
+		 */
 		goto free_skb;
 	}
 
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 
 	r = filter_rx(ieee, skb->data, skb->len, &stats);
 	if (r <= 0) {
-		if (r < 0)
+		if (r < 0) {
+			ieee->stats.rx_errors++;
 			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		}
 		goto free_skb;
 	}
 
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb) {
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		ieee->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 	skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..a3217a8 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -401,6 +401,12 @@ out:
 
 static inline void handle_retry_failed_int(struct urb *urb)
 {
+	struct zd_usb *usb = urb->context;
+	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	ieee->stats.tx_errors++;
+	ieee->ieee_stats.tx_retry_limit_exceeded++;
 	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
 }
 
@@ -575,6 +581,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -1027,6 +1036,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
+	usb_reset_device(interface_to_usbdev(intf));
+
 	netdev = zd_netdev_alloc(intf);
 	if (netdev == NULL) {
 		r = -ENOMEM;
@@ -1128,6 +1139,7 @@ static int __init usb_init(void)
 
 	r = usb_register(&driver);
 	if (r) {
+		destroy_workqueue(zd_workqueue);
 		printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
 		       driver.name, r);
 		return r;

-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull "upstream" branch of wireless-2.6
@ 2007-02-07 21:11     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-02-07 21:11 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-wireless-u79uwXL29TY76Z2rM5mHXA

On Tue, Feb 06, 2007 at 07:06:07PM -0500, Jeff Garzik wrote:
> Would you mind rebasing & resending, kind sir?

By your command! :-)

---

The following changes since commit 62d0cfcb27cf755cebdc93ca95dabc83608007cd:
  Linus Torvalds (1):
        Linux 2.6.20

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Remove noisy debug message

Larry Finger (3):
      bcm43xx: Fix problem with >1 GB RAM
      bcm43xx: Fix scaling error for 'iwlist rate' information
      bcm43xx: Fix scaling error for 'iwlist freq' information

Maxime Austruy (1):
      zd1211rw: fix potential leak in usb_init

Michael Buesch (1):
      bcm43xx: Enable fwpostfix in nondebug bcm43xx

Robert P. J. Day (1):
      Rename IPW2100 debugging macros to not look like config options.

Ulrich Kunitz (3):
      zd1211rw: Reset device in the probe call
      zd1211rw: Fixed array size issue in reset_mode
      zd1211rw: Added error stats update

 drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |    6 +-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
 drivers/net/wireless/ipw2100.c              |   16 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
 drivers/net/wireless/zd1211rw/zd_usb.c      |   12 ++
 7 files changed, 194 insertions(+), 84 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..4168b1a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -766,6 +766,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed09..6e0dc76 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_dev,
 					 buf, len,
-					 DMA_FROM_DEVICE);
-	}
+					 direction);
 
 	return dmaaddr;
 }
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_TO_DEVICE);
+				 PCI_DMA_TODEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_FROM_DEVICE);
+				 PCI_DMA_FROMDEVICE);
 	}
 }
 
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
-				addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_FROMDEVICE);
 }
 
 static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
-				   addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_TODEVICE);
 }
 
 /* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
-
-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase));
 	if (!ring->descbase) {
-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
-		return -ENOMEM;
+		/* Allocation may have failed due to pci_alloc_consistent
+		   insisting on use of GFP_DMA, which is more restrictive
+		   than necessary...  */
+		struct dma_desc *rx_ring;
+		dma_addr_t rx_ring_dma;
+
+		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+		if (!rx_ring)
+			goto out_err;
+
+		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+					     BCM43xx_DMA_RINGMEMSIZE,
+					     PCI_DMA_BIDIRECTIONAL);
+
+		if (pci_dma_mapping_error(rx_ring_dma) ||
+		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+			/* Sigh... */
+			if (!pci_dma_mapping_error(rx_ring_dma))
+				pci_unmap_single(ring->bcm->pci_dev,
+						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			if (pci_dma_mapping_error(rx_ring_dma) ||
+			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+				assert(0);
+				if (!pci_dma_mapping_error(rx_ring_dma))
+					pci_unmap_single(ring->bcm->pci_dev,
+							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+							 PCI_DMA_BIDIRECTIONAL);
+				goto out_err;
+			}
+                }
+
+                ring->descbase = rx_ring;
+                ring->dmabase = rx_ring_dma;
 	}
 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
+out_err:
+	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+	return -ENOMEM;
 }
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	/* This hardware bug work-around adapted from the b44 driver.
+	   The chip may be unable to do PCI DMA to/from anything above 1GB */
+	if (pci_dma_mapping_error(dmaaddr) ||
+	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+		/* This one has 30-bit addressing... */
+		if (!pci_dma_mapping_error(dmaaddr))
+			pci_unmap_single(ring->bcm->pci_dev,
+					 dmaaddr, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+		if (skb == NULL)
+			return -ENOMEM;
+		dmaaddr = pci_map_single(ring->bcm->pci_dev,
+					 skb->data, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(dmaaddr) ||
+		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+			assert(0);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	err = dmacontroller_setup(ring);
 	if (err)
 		goto err_free_ringmemory;
+	return ring;
 
 out:
+	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
 	return ring;
 
 err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
 	int dma64 = 0;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	if (mask == DMA_64BIT_MASK) {
+	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+	if (bcm->dma_mask == DMA_64BIT_MASK)
 		dma64 = 1;
-		nobits = 64;
-	} else if (mask == DMA_32BIT_MASK)
-		nobits = 32;
-	else
-		nobits = 30;
-	err = pci_set_dma_mask(bcm->pci_dev, mask);
-	err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
-	if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-		printk(KERN_WARNING PFX "DMA not supported on this device."
-					" Falling back to PIO.\n");
-		bcm->__using_pio = 1;
-		return -ENOSYS;
-#else
-		printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-				    "Please recompile the driver with PIO support.\n");
-		return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-	}
+	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
+	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
 
 	/* setup TX DMA channels. */
 	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
 out:
 	return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
 err_destroy_tx0:
 	bcm43xx_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
-	goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+	printk(KERN_WARNING PFX "DMA not supported on this device."
+				" Falling back to PIO.\n");
+	bcm->__using_pio = 1;
+	return -ENOSYS;
+#else
+	printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+			    "Please recompile the driver with PIO support.\n");
+	return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
 }
 
 /* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	dma_addr_t dmaaddr;
+	struct sk_buff *bounce_skb;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 			       skb->len - sizeof(struct bcm43xx_txhdr),
 			       (cur_frag == 0),
 			       generate_cookie(ring, slot));
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+		if (!dma_mapping_error(dmaaddr))
+			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return;
+		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+			if (!dma_mapping_error(dmaaddr))
+				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+			dev_kfree_skb_any(bounce_skb);
+			assert(0);
+			return;
+		}
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+	}
 
 	meta->skb = skb;
-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	meta->dmaaddr = dmaaddr;
 
 	fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e..62c6235 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
 module_param_named(noleds, modparam_noleds, int, 0444);
 MODULE_PARM_DESC(noleds, "Turn off all LED activity");
 
-#ifdef CONFIG_BCM43XX_DEBUG
 static char modparam_fwpostfix[64];
 module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix  ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
 
 
 /* If you want to debug with just a single device, enable this,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442..6961be6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 	if (phy->type == BCM43xx_PHYTYPE_A ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates = 8;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
 	}
 	if (phy->type == BCM43xx_PHYTYPE_B ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates += 4;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
 	}
 
 	geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].m = geo->a[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].m = geo->bg[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a..d0639a4 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
+#define IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 	priv->snapshot[0] = NULL;
 }
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
  * The size of the constructed ethernet
  *
  */
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
 static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	u32 match, reg;
 	int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 	}
 #endif
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	/* Halt the fimrware so we can get a good image */
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 
 	skb_put(packet->skb, status->frame_size);
 
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
 	memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 		IPW_DEBUG_DROP("%s: Non consumed packet:\n",
 			       priv->net_dev->name);
 		printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 	else
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
 	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a085241..4c5f78e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[3] = {
+	struct zd_ioreq32 ioreqs[] = {
 		{ CR_RX_FILTER, STA_RX_FILTER },
 		{ CR_SNIFFER_ON, 0U },
 	};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 		ioreqs[0].value = 0xffffffff;
 		ioreqs[1].value = 0x1;
-		ioreqs[2].value = ENC_SNIFFER;
 	}
 
-	return zd_iowrite32a(&mac->chip, ioreqs, 3);
+	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
 	int i, r;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
 	for (i = 0; i < txb->nr_frags; i++) {
 		struct sk_buff *skb = txb->fragments[i];
 
 		r = fill_ctrlset(mac, txb, i);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 	}
 
 	/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
 	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
 	if (status->frame_status & ZD_RX_ERROR) {
-		/* FIXME: update? */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+			ieee->stats.rx_missed_errors++;
+		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+			ieee->stats.rx_fifo_errors++;
+		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+			ieee->ieee_stats.rx_discards_undecryptable++;
+		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+			ieee->stats.rx_crc_errors++;
+			ieee->ieee_stats.rx_fcs_errors++;
+		}
+		else if (status->frame_status & ZD_RX_CRC16_ERROR)
+			ieee->stats.rx_crc_errors++;
 		return -EINVAL;
 	}
+
 	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
 	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
 		               + sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
 	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
 	{
-		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
-			 skb->len);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		goto free_skb;
 	}
 
 	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
 	if (r) {
-		/* Only packets with rx errors are included here. */
+		/* Only packets with rx errors are included here.
+		 * The error stats have already been set in fill_rx_stats.
+		 */
 		goto free_skb;
 	}
 
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 
 	r = filter_rx(ieee, skb->data, skb->len, &stats);
 	if (r <= 0) {
-		if (r < 0)
+		if (r < 0) {
+			ieee->stats.rx_errors++;
 			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		}
 		goto free_skb;
 	}
 
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb) {
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		ieee->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 	skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..a3217a8 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -401,6 +401,12 @@ out:
 
 static inline void handle_retry_failed_int(struct urb *urb)
 {
+	struct zd_usb *usb = urb->context;
+	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	ieee->stats.tx_errors++;
+	ieee->ieee_stats.tx_retry_limit_exceeded++;
 	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
 }
 
@@ -575,6 +581,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -1027,6 +1036,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
+	usb_reset_device(interface_to_usbdev(intf));
+
 	netdev = zd_netdev_alloc(intf);
 	if (netdev == NULL) {
 		r = -ENOMEM;
@@ -1128,6 +1139,7 @@ static int __init usb_init(void)
 
 	r = usb_register(&driver);
 	if (r) {
+		destroy_workqueue(zd_workqueue);
 		printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
 		       driver.name, r);
 		return r;

-- 
John W. Linville
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull "upstream" branch of wireless-2.6
  2007-02-02 21:27 Please pull "upstream-fixes" " John W. Linville
@ 2007-02-02 21:28 ` John W. Linville
  2007-02-07  0:06 ` Please pull "upstream-fixes" " Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-02-02 21:28 UTC (permalink / raw)
  To: jeff; +Cc: netdev, linux-wireless

This patches are intended for 2.6.21.

---

The following changes since commit 541c654cfdeb5cc6d2e945988985570384ee2a43:
  John W. Linville (1):
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (1):
      zd1211rw: Remove noisy debug message

Larry Finger (3):
      bcm43xx: Fix problem with >1 GB RAM
      bcm43xx: Fix scaling error for 'iwlist rate' information
      bcm43xx: Fix scaling error for 'iwlist freq' information

Michael Buesch (1):
      bcm43xx: Enable fwpostfix in nondebug bcm43xx

Robert P. J. Day (1):
      Rename IPW2100 debugging macros to not look like config options.

Ulrich Kunitz (3):
      zd1211rw: Reset device in the probe call
      zd1211rw: Fixed array size issue in reset_mode
      zd1211rw: Added error stats update

 drivers/net/wireless/bcm43xx/bcm43xx.h      |    1 +
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  171 +++++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |    6 +-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |   28 ++--
 drivers/net/wireless/ipw2100.c              |   16 ++--
 drivers/net/wireless/zd1211rw/zd_mac.c      |   44 ++++++--
 drivers/net/wireless/zd1211rw/zd_usb.c      |   11 ++
 7 files changed, 193 insertions(+), 84 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 3a064de..0e790ef 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -771,6 +771,7 @@ struct bcm43xx_private {
 	 * This is currently always BCM43xx_BUSTYPE_PCI
 	 */
 	u8 bustype;
+	u64 dma_mask;
 
 	u16 board_vendor;
 	u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed09..6e0dc76 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
 			  int tx)
 {
 	dma_addr_t dmaaddr;
+	int direction = PCI_DMA_FROMDEVICE;
 
-	if (tx) {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
-					 buf, len,
-					 DMA_TO_DEVICE);
-	} else {
-		dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+	if (tx)
+		direction = PCI_DMA_TODEVICE;
+
+	dmaaddr = pci_map_single(ring->bcm->pci_dev,
 					 buf, len,
-					 DMA_FROM_DEVICE);
-	}
+					 direction);
 
 	return dmaaddr;
 }
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
 		      int tx)
 {
 	if (tx) {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_TO_DEVICE);
+				 PCI_DMA_TODEVICE);
 	} else {
-		dma_unmap_single(&ring->bcm->pci_dev->dev,
+		pci_unmap_single(ring->bcm->pci_dev,
 				 addr, len,
-				 DMA_FROM_DEVICE);
+				 PCI_DMA_FROMDEVICE);
 	}
 }
 
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
-				addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_FROMDEVICE);
 }
 
 static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
 {
 	assert(!ring->tx);
 
-	dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
-				   addr, len, DMA_FROM_DEVICE);
+	pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+				    addr, len, PCI_DMA_TODEVICE);
 }
 
 /* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
 
 static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
 {
-	struct device *dev = &(ring->bcm->pci_dev->dev);
-
-	ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+	ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+					    &(ring->dmabase));
 	if (!ring->descbase) {
-		printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
-		return -ENOMEM;
+		/* Allocation may have failed due to pci_alloc_consistent
+		   insisting on use of GFP_DMA, which is more restrictive
+		   than necessary...  */
+		struct dma_desc *rx_ring;
+		dma_addr_t rx_ring_dma;
+
+		rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+		if (!rx_ring)
+			goto out_err;
+
+		rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+					     BCM43xx_DMA_RINGMEMSIZE,
+					     PCI_DMA_BIDIRECTIONAL);
+
+		if (pci_dma_mapping_error(rx_ring_dma) ||
+		    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+			/* Sigh... */
+			if (!pci_dma_mapping_error(rx_ring_dma))
+				pci_unmap_single(ring->bcm->pci_dev,
+						 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+						 rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+						 PCI_DMA_BIDIRECTIONAL);
+			if (pci_dma_mapping_error(rx_ring_dma) ||
+			    rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+				assert(0);
+				if (!pci_dma_mapping_error(rx_ring_dma))
+					pci_unmap_single(ring->bcm->pci_dev,
+							 rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+							 PCI_DMA_BIDIRECTIONAL);
+				goto out_err;
+			}
+                }
+
+                ring->descbase = rx_ring;
+                ring->dmabase = rx_ring_dma;
 	}
 	memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
 
 	return 0;
+out_err:
+	printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+	return -ENOMEM;
 }
 
 static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
 	if (unlikely(!skb))
 		return -ENOMEM;
 	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	/* This hardware bug work-around adapted from the b44 driver.
+	   The chip may be unable to do PCI DMA to/from anything above 1GB */
+	if (pci_dma_mapping_error(dmaaddr) ||
+	    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+		/* This one has 30-bit addressing... */
+		if (!pci_dma_mapping_error(dmaaddr))
+			pci_unmap_single(ring->bcm->pci_dev,
+					 dmaaddr, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(skb);
+		skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+		if (skb == NULL)
+			return -ENOMEM;
+		dmaaddr = pci_map_single(ring->bcm->pci_dev,
+					 skb->data, ring->rx_buffersize,
+					 PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(dmaaddr) ||
+		    dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+			assert(0);
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+	}
 	meta->skb = skb;
 	meta->dmaaddr = dmaaddr;
 	skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
 	err = dmacontroller_setup(ring);
 	if (err)
 		goto err_free_ringmemory;
+	return ring;
 
 out:
+	printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
 	return ring;
 
 err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 	struct bcm43xx_dmaring *ring;
 	int err = -ENOMEM;
 	int dma64 = 0;
-	u64 mask = bcm43xx_get_supported_dma_mask(bcm);
-	int nobits;
 
-	if (mask == DMA_64BIT_MASK) {
+	bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+	if (bcm->dma_mask == DMA_64BIT_MASK)
 		dma64 = 1;
-		nobits = 64;
-	} else if (mask == DMA_32BIT_MASK)
-		nobits = 32;
-	else
-		nobits = 30;
-	err = pci_set_dma_mask(bcm->pci_dev, mask);
-	err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
-	if (err) {
-#ifdef CONFIG_BCM43XX_PIO
-		printk(KERN_WARNING PFX "DMA not supported on this device."
-					" Falling back to PIO.\n");
-		bcm->__using_pio = 1;
-		return -ENOSYS;
-#else
-		printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
-				    "Please recompile the driver with PIO support.\n");
-		return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
-	}
+	err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
+	err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+	if (err)
+		goto no_dma;
 
 	/* setup TX DMA channels. */
 	ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
 		dma->rx_ring3 = ring;
 	}
 
-	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+	dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+		(bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+		(bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
 	err = 0;
 out:
 	return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
 err_destroy_tx0:
 	bcm43xx_destroy_dmaring(dma->tx_ring0);
 	dma->tx_ring0 = NULL;
-	goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+	printk(KERN_WARNING PFX "DMA not supported on this device."
+				" Falling back to PIO.\n");
+	bcm->__using_pio = 1;
+	return -ENOSYS;
+#else
+	printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+			    "Please recompile the driver with PIO support.\n");
+	return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
 }
 
 /* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 	struct bcm43xx_dmadesc_generic *desc;
 	struct bcm43xx_dmadesc_meta *meta;
 	dma_addr_t dmaaddr;
+	struct sk_buff *bounce_skb;
 
 	assert(skb_shinfo(skb)->nr_frags == 0);
 
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
 			       skb->len - sizeof(struct bcm43xx_txhdr),
 			       (cur_frag == 0),
 			       generate_cookie(ring, slot));
+	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+		/* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+		if (!dma_mapping_error(dmaaddr))
+			unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+		if (!bounce_skb)
+			return;
+		dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+		if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+			if (!dma_mapping_error(dmaaddr))
+				unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+			dev_kfree_skb_any(bounce_skb);
+			assert(0);
+			return;
+		}
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+	}
 
 	meta->skb = skb;
-	dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 	meta->dmaaddr = dmaaddr;
 
 	fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 23aaf1e..8c93419 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
 module_param_named(noleds, modparam_noleds, int, 0444);
 MODULE_PARM_DESC(noleds, "Turn off all LED activity");
 
-#ifdef CONFIG_BCM43XX_DEBUG
 static char modparam_fwpostfix[64];
 module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix  ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
 
 
 /* If you want to debug with just a single device, enable this,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442..6961be6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -261,22 +261,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 	if (phy->type == BCM43xx_PHYTYPE_A ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates = 8;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
-		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+		range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
 	}
 	if (phy->type == BCM43xx_PHYTYPE_B ||
 	    phy->type == BCM43xx_PHYTYPE_G) {
 		range->num_bitrates += 4;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
-		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+		range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
 	}
 
 	geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +286,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->a[i].freq;//FIXME?
+		range->freq[j].m = geo->a[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
@@ -294,7 +294,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
 		if (j == IW_MAX_FREQUENCIES)
 			break;
 		range->freq[j].i = j + 1;
-		range->freq[j].m = geo->bg[i].freq;//FIXME?
+		range->freq[j].m = geo->bg[i].freq * 100000;
 		range->freq[j].e = 1;
 		j++;
 	}
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a..d0639a4 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG	/* Reception debugging */
+#define IPW2100_RX_DEBUG	/* Reception debugging */
 #endif
 
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 	priv->snapshot[0] = NULL;
 }
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
 	int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
  * The size of the constructed ethernet
  *
  */
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
 static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	struct ipw2100_status *status = &priv->status_queue.drv[i];
 	u32 match, reg;
 	int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 	}
 #endif
 
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
 	/* Halt the fimrware so we can get a good image */
 	write_register(priv->net_dev, IPW_REG_RESET_REG,
 		       IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 
 	skb_put(packet->skb, status->frame_size);
 
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 	/* Make a copy of the frame so we can dump it to the logs if
 	 * ieee80211_rx fails */
 	memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 #endif
 
 	if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
 		IPW_DEBUG_DROP("%s: Non consumed packet:\n",
 			       priv->net_dev->name);
 		printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -4912,7 +4912,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
 	else
 		priv->power_mode = IPW_POWER_ENABLED | power_level;
 
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
 	if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
 		/* Set beacon interval */
 		cmd.host_command = TX_POWER_INDEX;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a085241..4c5f78e 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
 static int reset_mode(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_ioreq32 ioreqs[3] = {
+	struct zd_ioreq32 ioreqs[] = {
 		{ CR_RX_FILTER, STA_RX_FILTER },
 		{ CR_SNIFFER_ON, 0U },
 	};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
 		ioreqs[0].value = 0xffffffff;
 		ioreqs[1].value = 0x1;
-		ioreqs[2].value = ENC_SNIFFER;
 	}
 
-	return zd_iowrite32a(&mac->chip, ioreqs, 3);
+	return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
 static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
 {
 	int i, r;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 
 	for (i = 0; i < txb->nr_frags; i++) {
 		struct sk_buff *skb = txb->fragments[i];
 
 		r = fill_ctrlset(mac, txb, i);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r)
+		if (r) {
+			ieee->stats.tx_dropped++;
 			return r;
+		}
 	}
 
 	/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
 
 	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
 	if (status->frame_status & ZD_RX_ERROR) {
-		/* FIXME: update? */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+			ieee->stats.rx_missed_errors++;
+		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+			ieee->stats.rx_fifo_errors++;
+		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+			ieee->ieee_stats.rx_discards_undecryptable++;
+		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+			ieee->stats.rx_crc_errors++;
+			ieee->ieee_stats.rx_fcs_errors++;
+		}
+		else if (status->frame_status & ZD_RX_CRC16_ERROR)
+			ieee->stats.rx_crc_errors++;
 		return -EINVAL;
 	}
+
 	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
 	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
 		               + sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
 	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
 	{
-		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
-			 skb->len);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		goto free_skb;
 	}
 
 	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
 	if (r) {
-		/* Only packets with rx errors are included here. */
+		/* Only packets with rx errors are included here.
+		 * The error stats have already been set in fill_rx_stats.
+		 */
 		goto free_skb;
 	}
 
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 
 	r = filter_rx(ieee, skb->data, skb->len, &stats);
 	if (r <= 0) {
-		if (r < 0)
+		if (r < 0) {
+			ieee->stats.rx_errors++;
 			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		}
 		goto free_skb;
 	}
 
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
 
 	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
 	if (!skb) {
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		ieee->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 	skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 49e6c26..aac8a1c 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -313,6 +313,12 @@ out:
 
 static inline void handle_retry_failed_int(struct urb *urb)
 {
+	struct zd_usb *usb = urb->context;
+	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	ieee->stats.tx_errors++;
+	ieee->ieee_stats.tx_retry_limit_exceeded++;
 	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
 }
 
@@ -487,6 +493,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
+		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+		ieee->stats.rx_errors++;
+		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -923,6 +932,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
+	usb_reset_device(interface_to_usbdev(intf));
+
 	netdev = zd_netdev_alloc(intf);
 	if (netdev == NULL) {
 		r = -ENOMEM;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-01-18 15:49 ` Please pull 'upstream' " John W. Linville
  2007-01-19  3:10   ` Jeff Garzik
@ 2007-01-23  5:36   ` Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2007-01-23  5:36 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit 10764889c6355cbb335cf0578ce12427475d1a65:
>   Larry Finger (1):
>         bcm43xx: Fix failure to deliver PCI-E interrupts
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (6):
>       zd1211rw: Generic HMAC initialization
>       zd1211rw: 2 new ZD1211B device ID's
>       zd1211rw: Consistency for address space constants
>       zd1211rw: Remove addressing abstraction
>       zd1211rw: Add ID for Linksys WUSBF54G
>       zd1211rw: Add ID for ZyXEL ZyAIR G-220 v2
> 
> John W. Linville (1):
>       softmac: avoid assert in ieee80211softmac_wx_get_rate
> 
> Kai Engert (1):
>       prism54: add ethtool -i interface
> 
> Larry Finger (1):
>       bcm43xx: Interrogate hardware-enable switch and update LEDs
> 
> Michael Buesch (1):
>       Update Prism54 MAINTAINERS entry
> 
> Zhu Yi (1):
>       ipw2200: add iwconfig rts/frag auto support

pulled, thanks



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-01-19  3:10   ` Jeff Garzik
@ 2007-01-19  8:42     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-01-19  8:42 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

On Thu, Jan 18, 2007 at 10:10:47PM -0500, Jeff Garzik wrote:
> John W. Linville wrote:
> >The following changes since commit 
> >10764889c6355cbb335cf0578ce12427475d1a65:
> >  Larry Finger (1):
> >        bcm43xx: Fix failure to deliver PCI-E interrupts
> >
> >are found in the git repository at:
> >
> >  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git 
> >  upstream
> 
> ACK.  Open question of parentage, though:  I just rebased 
> netdev-2.6.git#upstream.  Is your wireless-2.6 affected by this rebase?
> 
> If not, I will go ahead and pull.

Right now it looks like this:

	Linus's tree -> my upstream-fixes branch -> my upstream branch

So, I think it should be fine for your you to pull.

Thanks,

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-01-18 15:49 ` Please pull 'upstream' " John W. Linville
@ 2007-01-19  3:10   ` Jeff Garzik
  2007-01-19  8:42     ` John W. Linville
  2007-01-23  5:36   ` Jeff Garzik
  1 sibling, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2007-01-19  3:10 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit 10764889c6355cbb335cf0578ce12427475d1a65:
>   Larry Finger (1):
>         bcm43xx: Fix failure to deliver PCI-E interrupts
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

ACK.  Open question of parentage, though:  I just rebased 
netdev-2.6.git#upstream.  Is your wireless-2.6 affected by this rebase?

If not, I will go ahead and pull.

	Jeff




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-01-18 15:48 Please pull 'upstream-fixes' " John W. Linville
@ 2007-01-18 15:49 ` John W. Linville
  2007-01-19  3:10   ` Jeff Garzik
  2007-01-23  5:36   ` Jeff Garzik
  0 siblings, 2 replies; 108+ messages in thread
From: John W. Linville @ 2007-01-18 15:49 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 10764889c6355cbb335cf0578ce12427475d1a65:
  Larry Finger (1):
        bcm43xx: Fix failure to deliver PCI-E interrupts

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (6):
      zd1211rw: Generic HMAC initialization
      zd1211rw: 2 new ZD1211B device ID's
      zd1211rw: Consistency for address space constants
      zd1211rw: Remove addressing abstraction
      zd1211rw: Add ID for Linksys WUSBF54G
      zd1211rw: Add ID for ZyXEL ZyAIR G-220 v2

John W. Linville (1):
      softmac: avoid assert in ieee80211softmac_wx_get_rate

Kai Engert (1):
      prism54: add ethtool -i interface

Larry Finger (1):
      bcm43xx: Interrogate hardware-enable switch and update LEDs

Michael Buesch (1):
      Update Prism54 MAINTAINERS entry

Zhu Yi (1):
      ipw2200: add iwconfig rts/frag auto support

 MAINTAINERS                                   |    2 +-
 drivers/net/wireless/bcm43xx/bcm43xx.h        |    7 +-
 drivers/net/wireless/bcm43xx/bcm43xx_leds.c   |   11 +-
 drivers/net/wireless/bcm43xx/bcm43xx_main.c   |   36 ++++--
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c  |    2 +
 drivers/net/wireless/bcm43xx/bcm43xx_radio.h  |   16 +++
 drivers/net/wireless/ipw2200.c                |    4 +-
 drivers/net/wireless/prism54/islpci_dev.c     |   13 ++
 drivers/net/wireless/prism54/islpci_dev.h     |    4 +
 drivers/net/wireless/prism54/islpci_hotplug.c |    3 -
 drivers/net/wireless/zd1211rw/zd_chip.c       |  126 ++++++++++----------
 drivers/net/wireless/zd1211rw/zd_chip.h       |  158 ++++++++++++++-----------
 drivers/net/wireless/zd1211rw/zd_def.h        |    2 +
 drivers/net/wireless/zd1211rw/zd_ieee80211.h  |    1 -
 drivers/net/wireless/zd1211rw/zd_rf.h         |    2 -
 drivers/net/wireless/zd1211rw/zd_types.h      |   71 -----------
 drivers/net/wireless/zd1211rw/zd_usb.c        |  128 ++------------------
 drivers/net/wireless/zd1211rw/zd_usb.h        |    6 +-
 net/ieee80211/softmac/ieee80211softmac_wx.c   |    6 +
 19 files changed, 256 insertions(+), 342 deletions(-)
 delete mode 100644 drivers/net/wireless/zd1211rw/zd_types.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 1b1491d..42b57cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2654,7 +2654,7 @@ S:	Supported
 
 PRISM54 WIRELESS DRIVER
 P:	Prism54 Development Team
-M:	prism54-private@prism54.org
+M:	developers@islsm.org
 L:	netdev@vger.kernel.org
 W:	http://prism54.org
 S:	Maintained
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..3a064de 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -352,6 +352,10 @@
 #define BCM43xx_UCODEFLAG_UNKPACTRL	0x0040
 #define BCM43xx_UCODEFLAG_JAPAN		0x0080
 
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
 /* Generic-Interrupt reasons. */
 #define BCM43xx_IRQ_READY		(1 << 0)
 #define BCM43xx_IRQ_BEACON		(1 << 1)
@@ -758,7 +762,8 @@ struct bcm43xx_private {
 	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
 	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
 	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
-	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
+	    firmware_norelease:1,	/* Do not release the firmware. Used on suspend. */
+	    radio_hw_enable:1;		/* TRUE if radio is hardware enabled */
 
 	struct bcm43xx_stats stats;
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a2..8f198be 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
 */
 
 #include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
 #include "bcm43xx.h"
 
 #include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
 	switch (led_index) {
 	case 0:
 		led->behaviour = BCM43xx_LED_ACTIVITY;
+		led->activelow = 1;
 		if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
 			led->behaviour = BCM43xx_LED_RADIO_ALL;
 		break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
 			turn_on = activity;
 			break;
 		case BCM43xx_LED_RADIO_ALL:
-			turn_on = radio->enabled;
+			turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
 			break;
 		case BCM43xx_LED_RADIO_A:
 		case BCM43xx_LED_BCM4303_2:
-			turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+				   phy->type == BCM43xx_PHYTYPE_A);
 			break;
 		case BCM43xx_LED_RADIO_B:
 		case BCM43xx_LED_BCM4303_1:
-			turn_on = (radio->enabled &&
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
 				   (phy->type == BCM43xx_PHYTYPE_B ||
 				    phy->type == BCM43xx_PHYTYPE_G));
 			break;
 		case BCM43xx_LED_MODE_BG:
-			if (phy->type == BCM43xx_PHYTYPE_G &&
+			if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
 			    1/*FIXME: using G rates.*/)
 				turn_on = 1;
 			break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e..23aaf1e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
 	if (err)
 		goto err_gpio_cleanup;
 	bcm43xx_radio_turn_on(bcm);
+	bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+		(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
 
 	bcm43xx_write16(bcm, 0x03E6, 0x0000);
 	err = bcm43xx_phy_init(bcm);
@@ -3175,9 +3178,24 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
 
 static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
 {
+	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int radio_hw_enable;
 
+	/* check if radio hardware enabled status changed */
+	radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+		bcm->radio_hw_enable = radio_hw_enable;
+		dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+		       (radio_hw_enable == 0) ? "disabled" : "enabled");
+		bcm43xx_leds_update(bcm, 0);
+	}
 	if (phy->type == BCM43xx_PHYTYPE_G) {
 		//TODO: update_aci_moving_average
 		if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3201,21 +3219,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
 			//TODO: implement rev1 workaround
 		}
 	}
-	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
-	//TODO for APHY (temperature?)
 }
 
 static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	if (bcm->periodic_state % 8 == 0)
+	if (bcm->periodic_state % 120 == 0)
 		bcm43xx_periodic_every120sec(bcm);
-	if (bcm->periodic_state % 4 == 0)
+	if (bcm->periodic_state % 60 == 0)
 		bcm43xx_periodic_every60sec(bcm);
-	if (bcm->periodic_state % 2 == 0)
+	if (bcm->periodic_state % 30 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	bcm43xx_periodic_every15sec(bcm);
+	if (bcm->periodic_state % 15 == 0)
+		bcm43xx_periodic_every15sec(bcm);
+	bcm43xx_periodic_every1sec(bcm);
 
-	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+	schedule_delayed_work(&bcm->periodic_work, HZ);
 }
 
 static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3228,7 +3246,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
@@ -3260,7 +3278,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
 
 	do_periodic_work(bcm);
 
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		spin_lock_irqsave(&bcm->irq_lock, flags);
 		tasklet_enable(&bcm->isr_tasklet);
 		bcm43xx_interrupt_enable(bcm, savedirqs);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484..af19a07 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
 	}
 	radio->enabled = 1;
 	dprintk(KERN_INFO PFX "Radio turned on\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 	
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
 		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
 	radio->enabled = 0;
 	dprintk(KERN_INFO PFX "Radio turned off\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 
 void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed1803..77a98a5 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
 
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+	/* function to return state of hardware enable of radio
+	 * returns 0 if radio disabled, 1 if radio enabled
+	 */
+	if (bcm->current_core->rev >= 3)
+		return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+					& BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+					== 0) ? 1 : 0;
+	else
+		return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+					& BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+					== 0) ? 0 : 1;
+}
+
 int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
 				int synthetic_pu_workaround);
 
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 22cb3fb..c878a2f 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	mutex_lock(&priv->mutex);
-	if (wrqu->rts.disabled)
+	if (wrqu->rts.disabled || !wrqu->rts.fixed)
 		priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
 	else {
 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	mutex_lock(&priv->mutex);
-	if (wrqu->frag.disabled)
+	if (wrqu->frag.disabled || !wrqu->frag.fixed)
 		priv->ieee->fts = DEFAULT_FTS;
 	else {
 		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9..a037b11 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
 }
 #endif
 
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+	.get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
 	ndev->do_ioctl = &prism54_ioctl;
 	ndev->wireless_handlers =
 	    (struct iw_handler_def *) &prism54_handler_def;
+	ndev->ethtool_ops = &islpci_ethtool_ops;
 
 	ndev->hard_start_xmit = &islpci_eth_transmit;
 	/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa166..736666d 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
 
 int islpci_free_memory(islpci_private *);
 struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME	"prism54"
+#define DRV_VERSION	"1.2"
+
 #endif				/* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b4..3dcb13b 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
 #include "islpci_mgt.h"		/* for pc_debug */
 #include "isl_oid.h"
 
-#define DRV_NAME	"prism54"
-#define DRV_VERSION	"1.2"
-
 MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
 MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 78ea72f..12dfc0b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
 	dev_info(zd_chip_dev(chip), "%s\n", buffer);
 }
 
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+	u16 a = (u16)addr;
+	/* Control registers use byte addressing, but everything else uses word
+	 * addressing. */
+	if ((a & 0xf000) == CR_START)
+		a += 2;
+	else
+		a += 1;
+	return (zd_addr_t)a;
+}
+
 /* Read a variable number of 32-bit values. Parameter count is not allowed to
  * exceed USB_MAX_IOREAD32_COUNT.
  */
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
 	for (i = 0; i < count; i++) {
 		int j = 2*i;
 		/* We read the high word always first. */
-		a16[j] = zd_inc_word(addr[i]);
+		a16[j] = inc_addr(addr[i]);
 		a16[j+1] = addr[i];
 	}
 
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
 		j = 2*i;
 		/* We write the high word always first. */
 		ioreqs16[j].value   = ioreqs[i].value >> 16;
-		ioreqs16[j].addr    = zd_inc_word(ioreqs[i].addr);
+		ioreqs16[j].addr    = inc_addr(ioreqs[i].addr);
 		ioreqs16[j+1].value = ioreqs[i].value;
 		ioreqs16[j+1].addr  = ioreqs[i].addr;
 	}
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
 
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	for (i = 0;;) {
-		r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+		r = zd_ioread32_locked(chip, &v,
+			               (zd_addr_t)((u16)e2p_addr+i/2));
 		if (r)
 			return r;
 		v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip)
 static int zd1211_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211_RETRY_MAX,		0x2 },
-		{ CR_SNIFFER_ON,		0 },
-		{ CR_RX_FILTER,			STA_RX_FILTER },
-		{ CR_GROUP_HASH_P1,		0x00 },
-		{ CR_GROUP_HASH_P2,		0x80000000 },
-		{ CR_REG1,			0xa4 },
-		{ CR_ADDA_PWR_DWN,		0x7f },
-		{ CR_BCN_PLCP_CFG,		0x00f00401 },
-		{ CR_PHY_DELAY,			0x00 },
-		{ CR_ACK_TIMEOUT_EXT,		0x80 },
-		{ CR_ADDA_PWR_DWN,		0x00 },
-		{ CR_ACK_TIME_80211,		0x100 },
-		{ CR_RX_PE_DELAY,		0x70 },
-		{ CR_PS_CTRL,			0x10000000 },
-		{ CR_RTS_CTS_RATE,		0x02030203 },
 		{ CR_RX_THRESHOLD,		0x000c0640 },
-		{ CR_AFTER_PNP,			0x1 },
-		{ CR_WEP_PROTECT,		0x114 },
 	};
 
-	int r;
-
 	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
-	if (r) {
-		dev_err(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-#endif /* DEBUG */
-	return r;
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211B_RETRY_MAX,		0x02020202 },
 		{ CR_ZD1211B_TX_PWR_CTL4,	0x007f003f },
 		{ CR_ZD1211B_TX_PWR_CTL3,	0x007f003f },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 		{ CR_ZD1211B_AIFS_CTL1,		0x00280028 },
 		{ CR_ZD1211B_AIFS_CTL2,		0x008C003C },
 		{ CR_ZD1211B_TXOP,		0x01800824 },
+		{ CR_RX_THRESHOLD,		0x000c0eff, },
+	};
+
+	dev_dbg_f(zd_chip_dev(chip), "\n");
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+	int r;
+	static const struct zd_ioreq32 ioreqs[] = {
+		{ CR_ACK_TIMEOUT_EXT,		0x20 },
+		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_SNIFFER_ON,		0 },
 		{ CR_RX_FILTER,			STA_RX_FILTER },
 		{ CR_GROUP_HASH_P1,		0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 		{ CR_RX_PE_DELAY,		0x70 },
 		{ CR_PS_CTRL,			0x10000000 },
 		{ CR_RTS_CTS_RATE,		0x02030203 },
-		{ CR_RX_THRESHOLD,		0x000c0eff, },
 		{ CR_AFTER_PNP,			0x1 },
 		{ CR_WEP_PROTECT,		0x114 },
+		{ CR_IFS_VALUE,			IFS_VALUE_DEFAULT },
 	};
 
-	int r;
-
-	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-	if (r) {
-		dev_dbg_f(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-	return r;
-}
+	if (r)
+		return r;
 
-static int hw_init_hmac(struct zd_chip *chip)
-{
 	return chip->is_zd1211b ?
 		zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
 }
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
 	if (r)
 		return r;
 
-	/* Although the vendor driver defaults to a different value during
-	 * init, it overwrites the IFS value with the following every time
-	 * the channel changes. We should aim to be more intelligent... */
-	r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
-	if (r)
-		return r;
-
 	return set_beacon_interval(chip, 100);
 }
 
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+	return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
 #ifdef DEBUG
 static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
 	           const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
 
 static void dump_fw_registers(struct zd_chip *chip)
 {
-	static const zd_addr_t addr[4] = {
-		FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
-		FW_LINK_STATUS
+	const zd_addr_t addr[4] = {
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+		fw_reg_addr(chip, FW_REG_USB_SPEED),
+		fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 	};
 
 	int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
 	int r;
 	u16 version;
 
-	r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+	r = zd_ioread16_locked(chip, &version,
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
 	if (r)
 		return r;
 
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
 	return r;
 }
 
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+	int r;
+
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+		               FWRAW_REGS_ADDR);
+	if (r)
+		return r;
+	dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+		  (u16)chip->fw_regs_base);
+
+	return 0;
+}
+
+
 int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 {
 	int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 	if (r)
 		goto out;
 
-	r = zd_usb_init_hw(&chip->usb);
+	r = read_fw_regs_offset(chip);
 	if (r)
 		goto out;
 
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
 
 int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
 {
-	static const zd_addr_t a[] = {
-		FW_LINK_STATUS,
+	const zd_addr_t a[] = {
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 		CR_LED,
 	};
 
 	int r;
 	u16 v[ARRAY_SIZE(a)];
 	struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
-		[0] = { FW_LINK_STATUS },
+		[0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
 		[1] = { CR_LED },
 	};
 	u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee..b07569e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
 #ifndef _ZD_CHIP_H
 #define _ZD_CHIP_H
 
-#include "zd_types.h"
 #include "zd_rf.h"
 #include "zd_usb.h"
 
@@ -27,6 +26,37 @@
  * adds a processor for handling the USB protocol.
  */
 
+/* Address space */
+enum {
+	/* CONTROL REGISTERS */
+	CR_START			= 0x9000,
+
+
+	/* FIRMWARE */
+	FW_START			= 0xee00,
+
+
+	/* EEPROM */
+	E2P_START			= 0xf800,
+	E2P_LEN				= 0x800,
+
+	/* EEPROM layout */
+	E2P_LOAD_CODE_LEN		= 0xe,		/* base 0xf800 */
+	E2P_LOAD_VECT_LEN		= 0x9,		/* base 0xf80e */
+	/* E2P_DATA indexes into this */
+	E2P_DATA_LEN			= 0x7e,		/* base 0xf817 */
+	E2P_BOOT_CODE_LEN		= 0x760,	/* base 0xf895 */
+	E2P_INTR_VECT_LEN		= 0xb,		/* base 0xfff5 */
+
+	/* Some precomputed offsets into the EEPROM */
+	E2P_DATA_OFFSET			= E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+	E2P_BOOT_CODE_OFFSET		= E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
 /* 8-bit hardware registers */
 #define CR0   CTL_REG(0x0000)
 #define CR1   CTL_REG(0x0004)
@@ -302,7 +332,7 @@
 
 #define CR_MAX_PHY_REG 255
 
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
  * driver.
  */
 
@@ -594,81 +624,71 @@
 /*
  * Upper 16 bit contains the regulatory domain.
  */
-#define E2P_SUBID		E2P_REG(0x00)
-#define E2P_POD			E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1		E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2		E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1	E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2	E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3	E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4      E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1	E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2	E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3	E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4	E2P_REG(0x16)
+#define E2P_SUBID		E2P_DATA(0x00)
+#define E2P_POD			E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1		E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2		E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1	E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2	E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3	E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4      E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1	E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2	E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3	E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4	E2P_DATA(0x16)
 
 /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
  * also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL	E2P_REG(0x18)
-
-#define E2P_PHY_REG		E2P_REG(0x1a)
-#define E2P_DEVICE_VER		E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1	E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2      E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3      E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4	E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1	E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2	E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3	E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4	E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1	E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2	E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3	E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4	E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1	E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2	E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3	E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4	E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1	E2P_REG(0x48)	/* ??? */
-#define E2P_54M_CAL_VALUE2	E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3	E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4	E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1	E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2	E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3	E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4	E2P_REG(0x56)
-
-/* All 16 bit values */
-#define FW_FIRMWARE_VER         FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED            FW_REG(1)
-#define FW_FIX_TX_RATE          FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS          FW_REG(3)
-#define FW_SOFT_RESET           FW_REG(4)
-#define FW_FLASH_CHK            FW_REG(5)
+#define E2P_ALLOWED_CHANNEL	E2P_DATA(0x18)
+
+#define E2P_PHY_REG		E2P_DATA(0x1a)
+#define E2P_DEVICE_VER		E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1	E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2      E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3      E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4	E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1	E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2	E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3	E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4	E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1	E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2	E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3	E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4	E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1	E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2	E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3	E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4	E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1	E2P_DATA(0x48)	/* ??? */
+#define E2P_54M_CAL_VALUE2	E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3	E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4	E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1	E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2	E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3	E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4	E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR		FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+	FW_REG_FIRMWARE_VER	= 0,
+	/* non-zero if USB high speed connection */
+	FW_REG_USB_SPEED	= 1,
+	FW_REG_FIX_TX_RATE	= 2,
+	/* Seems to be able to control LEDs over the firmware */
+	FW_REG_LED_LINK_STATUS	= 3,
+	FW_REG_SOFT_RESET	= 4,
+	FW_REG_FLASH_CHK	= 5,
+};
 
+/* Values for FW_LINK_STATUS */
 #define FW_LINK_OFF		0x0
 #define FW_LINK_TX		0x1
 /* 0x2 - link led on? */
 
 enum {
-	CR_BASE_OFFSET			= 0x9000,
-	FW_START_OFFSET			= 0xee00,
-	FW_BASE_ADDR_OFFSET		= FW_START_OFFSET + 0x1d,
-	EEPROM_START_OFFSET		= 0xf800,
-	EEPROM_SIZE			= 0x800, /* words */
-	LOAD_CODE_SIZE			= 0xe, /* words */
-	LOAD_VECT_SIZE			= 0x10000 - 0xfff7, /* words */
-	EEPROM_REGS_OFFSET		= LOAD_CODE_SIZE + LOAD_VECT_SIZE,
-	EEPROM_REGS_SIZE		= 0x7e, /* words */
-	E2P_BASE_OFFSET			= EEPROM_START_OFFSET +
-		                          EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR	USB_ADDR(FW_START_OFFSET + 0x1d)
-
-enum {
 	/* indices for ofdm_cal_values */
 	OFDM_36M_INDEX = 0,
 	OFDM_48M_INDEX = 1,
@@ -679,6 +699,8 @@ struct zd_chip {
 	struct zd_usb usb;
 	struct zd_rf rf;
 	struct mutex mutex;
+	/* Base address of FW_REG_ registers */
+	zd_addr_t fw_regs_base;
 	u8 e2p_mac[ETH_ALEN];
 	/* EepSetPoint in the vendor driver */
 	u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62..deb99d1 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 
+typedef u16 __nocast zd_addr_t;
+
 #define dev_printk_f(level, dev, fmt, args...) \
 	dev_printk(level, dev, "%s() " fmt, __func__, ##args)
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298..c4f36d3 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
 #define _ZD_IEEE80211_H
 
 #include <net/ieee80211.h>
-#include "zd_types.h"
 
 /* Additional definitions from the standards.
  */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b373..a57732e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
 #ifndef _ZD_RF_H
 #define _ZD_RF_H
 
-#include "zd_types.h"
-
 #define UW2451_RF			0x2
 #define UCHIP_RF			0x3
 #define AL2230_RF			0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a15..0000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
-	ADDR_BASE_MASK		= 0xff000000,
-	ADDR_OFFSET_MASK	= 0x0000ffff,
-	ADDR_ZERO_MASK		= 0x00ff0000,
-	NULL_BASE		= 0x00000000,
-	USB_BASE		= 0x01000000,
-	CR_BASE			= 0x02000000,
-	CR_MAX_OFFSET		= 0x0b30,
-	E2P_BASE		= 0x03000000,
-	E2P_MAX_OFFSET		= 0x007e,
-	FW_BASE			= 0x04000000,
-	FW_MAX_OFFSET		= 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
-	((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR    ((zd_addr_t)0)
-#define USB_REG(offset)  ZD_ADDR(USB_BASE, offset)	/* word addressing */
-#define CTL_REG(offset)  ZD_ADDR(CR_BASE, offset)	/* byte addressing */
-#define E2P_REG(offset)  ZD_ADDR(E2P_BASE, offset)	/* word addressing */
-#define FW_REG(offset)   ZD_ADDR(FW_BASE, offset)	/* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	offset += base == CR_BASE ? 2 : 1;
-
-	return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..75ef556 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
@@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
 #define FW_ZD1211_PREFIX	"zd1211/zd1211_"
 #define FW_ZD1211B_PREFIX	"zd1211/zd1211b_"
 
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	if ((u32)addr & ADDR_ZERO_MASK)
-		goto invalid_address;
-	switch (base) {
-	case USB_BASE:
-		break;
-	case CR_BASE:
-		if (offset > CR_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x larger than"
-				" CR_MAX_OFFSET %#10x\n",
-				offset, CR_MAX_OFFSET);
-			goto invalid_address;
-		}
-		if (offset & 1) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x is not a multiple of 2\n",
-				offset);
-			goto invalid_address;
-		}
-		break;
-	case E2P_BASE:
-		if (offset > E2P_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"E2P offset %#010x larger than"
-				" E2P_MAX_OFFSET %#010x\n",
-				offset, E2P_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	case FW_BASE:
-		if (!usb->fw_base_offset) {
-			dev_dbg(zd_usb_dev(usb),
-			       "ERROR: fw base offset has not been set\n");
-			return -EAGAIN;
-		}
-		if (offset > FW_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"FW offset %#10x is larger than"
-				" FW_MAX_OFFSET %#010x\n",
-				offset, FW_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	default:
-		dev_dbg(zd_usb_dev(usb),
-			"address has unsupported base %#010x\n", addr);
-		goto invalid_address;
-	}
-
-	return 0;
-invalid_address:
-	dev_dbg(zd_usb_dev(usb),
-		"ERROR: invalid address: %#010x\n", addr);
-	return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base;
-	u16 offset;
-
-	base = ZD_ADDR_BASE(addr);
-	offset = ZD_OFFSET(addr);
-
-	ZD_ASSERT(check_addr(usb, addr) == 0);
-
-	switch (base) {
-	case CR_BASE:
-		offset += CR_BASE_OFFSET;
-		break;
-	case E2P_BASE:
-		offset += E2P_BASE_OFFSET;
-		break;
-	case FW_BASE:
-		offset += usb->fw_base_offset;
-		break;
-	}
-
-	return offset;
-}
-
 /* USB device initialization */
 
 static int request_fw_file(
@@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
 	if (r)
 		goto error;
 
-	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
-		REBOOT);
+	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
 	if (r)
 		goto error;
 
-	offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+	offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
 	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
-		E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+		E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
 
 	/* At this point, the vendor driver downloads the whole firmware
 	 * image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
 	if (r)
 		goto error;
 
-	fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+	fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
 
 	if (fw_bcdDevice != bcdDevice) {
 		dev_info(&udev->dev,
@@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
 	if (r)
 		goto error;
 
-	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
-		        REBOOT);
+	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
 	if (r) {
 		dev_err(&udev->dev,
 			"Could not upload firmware code uph. Error number %d\n",
@@ -858,7 +770,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
 	spin_lock_init(&intr->lock);
 	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
 	init_completion(&intr->read_regs.completion);
-	intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+	intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
 }
 
 static inline void init_usb_rx(struct zd_usb *usb)
@@ -890,22 +802,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
 	init_usb_rx(usb);
 }
 
-int zd_usb_init_hw(struct zd_usb *usb)
-{
-	int r;
-	struct zd_chip *chip = zd_usb_to_chip(usb);
-
-	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_ioread16_locked(chip, &usb->fw_base_offset,
-		        USB_REG((u16)FW_BASE_ADDR_OFFSET));
-	if (r)
-		return r;
-	dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
-		 usb->fw_base_offset);
-
-	return 0;
-}
-
 void zd_usb_clear(struct zd_usb *usb)
 {
 	usb_set_intfdata(usb->intf, NULL);
@@ -1253,7 +1149,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 		return -ENOMEM;
 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
 	for (i = 0; i < count; i++)
-		req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+		req->addr[i] = cpu_to_le16((u16)addresses[i]);
 
 	udev = zd_usb_to_usbdev(usb);
 	prepare_read_regs_int(usb);
@@ -1318,7 +1214,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
 	req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
 	for (i = 0; i < count; i++) {
 		struct reg_data *rw  = &req->reg_writes[i];
-		rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+		rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
 		rw->value = cpu_to_le16(ioreqs[i].value);
 	}
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c..506ea6a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
 #include <linux/usb.h>
 
 #include "zd_def.h"
-#include "zd_types.h"
 
 enum devicetype {
 	DEVICE_ZD1211  = 0,
@@ -181,15 +180,14 @@ struct zd_usb_tx {
 	spinlock_t lock;
 };
 
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
  */
 struct zd_usb {
 	struct zd_usb_interrupt intr;
 	struct zd_usb_rx rx;
 	struct zd_usb_tx tx;
 	struct usb_interface *intf;
-	u16 fw_base_offset;
 };
 
 #define zd_usb_dev(usb) (&usb->intf->dev)
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index fa2f7da..fb58e03 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -265,6 +265,12 @@ ieee80211softmac_wx_get_rate(struct net_device *net_dev,
 	int err = -EINVAL;
 
 	spin_lock_irqsave(&mac->lock, flags);
+
+	if (unlikely(!mac->running)) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
 	switch (mac->txrates.default_rate) {
 	case IEEE80211_CCK_RATE_1MB:
 		data->bitrate.value = 1000000;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2007-01-03  2:42 ` Please pull 'upstream' " John W. Linville
@ 2007-01-18 12:16   ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-01-18 12:16 UTC (permalink / raw)
  To: jeff; +Cc: netdev

On Tue, Jan 02, 2007 at 09:42:47PM -0500, John W. Linville wrote:
> The following changes since commit fe5f8e2a1c5c040209c598a28e19c55f30e1040d:
>   Zhu Yi (1):
>         ipw2100: Fix dropping fragmented small packet problem
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake (5):
>       zd1211rw: Generic HMAC initialization
>       zd1211rw: 2 new ZD1211B device ID's
>       zd1211rw: Consistency for address space constants
>       zd1211rw: Remove addressing abstraction
>       zd1211rw: Add ID for Linksys WUSBF54G
> 
> John W. Linville (1):
>       softmac: avoid assert in ieee80211softmac_wx_get_rate
> 
> Kai Engert (1):
>       prism54: add ethtool -i interface
> 
> Larry Finger (1):
>       bcm43xx: Interrogate hardware-enable switch and update LEDs
> 
> Michael Buesch (1):
>       Update Prism54 MAINTAINERS entry

Jeff, it looks like you didn't pull this one yet.  I'm going to rebase
my upstream branch on top of my additions to my upstream-fixes branch.
So, just ignore this request and wait for the next round of pull
requests.

The next round is ready to go, except I can't login to
master.kernel.org today.  As soon as that is resolved, I'll push and
send the pull requests.

Thanks,

John

P.S.  If you haven't pulled due to some objection, please send me a
note to let me know why.
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2007-01-03  2:41 Please pull 'upstream-fixes' " John W. Linville
@ 2007-01-03  2:42 ` John W. Linville
  2007-01-18 12:16   ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2007-01-03  2:42 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit fe5f8e2a1c5c040209c598a28e19c55f30e1040d:
  Zhu Yi (1):
        ipw2100: Fix dropping fragmented small packet problem

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake (5):
      zd1211rw: Generic HMAC initialization
      zd1211rw: 2 new ZD1211B device ID's
      zd1211rw: Consistency for address space constants
      zd1211rw: Remove addressing abstraction
      zd1211rw: Add ID for Linksys WUSBF54G

John W. Linville (1):
      softmac: avoid assert in ieee80211softmac_wx_get_rate

Kai Engert (1):
      prism54: add ethtool -i interface

Larry Finger (1):
      bcm43xx: Interrogate hardware-enable switch and update LEDs

Michael Buesch (1):
      Update Prism54 MAINTAINERS entry

 MAINTAINERS                                   |    2 +-
 drivers/net/wireless/bcm43xx/bcm43xx.h        |    7 +-
 drivers/net/wireless/bcm43xx/bcm43xx_leds.c   |   11 +-
 drivers/net/wireless/bcm43xx/bcm43xx_main.c   |   36 ++++--
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c  |    2 +
 drivers/net/wireless/bcm43xx/bcm43xx_radio.h  |   16 +++
 drivers/net/wireless/prism54/islpci_dev.c     |   13 ++
 drivers/net/wireless/prism54/islpci_dev.h     |    4 +
 drivers/net/wireless/prism54/islpci_hotplug.c |    3 -
 drivers/net/wireless/zd1211rw/zd_chip.c       |  126 ++++++++++----------
 drivers/net/wireless/zd1211rw/zd_chip.h       |  158 ++++++++++++++-----------
 drivers/net/wireless/zd1211rw/zd_def.h        |    2 +
 drivers/net/wireless/zd1211rw/zd_ieee80211.h  |    1 -
 drivers/net/wireless/zd1211rw/zd_rf.h         |    2 -
 drivers/net/wireless/zd1211rw/zd_types.h      |   71 -----------
 drivers/net/wireless/zd1211rw/zd_usb.c        |  127 ++------------------
 drivers/net/wireless/zd1211rw/zd_usb.h        |    6 +-
 net/ieee80211/softmac/ieee80211softmac_wx.c   |    6 +
 18 files changed, 253 insertions(+), 340 deletions(-)
 delete mode 100644 drivers/net/wireless/zd1211rw/zd_types.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d5a97d3..edb4c39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2606,7 +2606,7 @@ S:	Supported
 
 PRISM54 WIRELESS DRIVER
 P:	Prism54 Development Team
-M:	prism54-private@prism54.org
+M:	developers@islsm.org
 L:	netdev@vger.kernel.org
 W:	http://prism54.org
 S:	Maintained
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678..3a064de 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -352,6 +352,10 @@
 #define BCM43xx_UCODEFLAG_UNKPACTRL	0x0040
 #define BCM43xx_UCODEFLAG_JAPAN		0x0080
 
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
 /* Generic-Interrupt reasons. */
 #define BCM43xx_IRQ_READY		(1 << 0)
 #define BCM43xx_IRQ_BEACON		(1 << 1)
@@ -758,7 +762,8 @@ struct bcm43xx_private {
 	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
 	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
 	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
-	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
+	    firmware_norelease:1,	/* Do not release the firmware. Used on suspend. */
+	    radio_hw_enable:1;		/* TRUE if radio is hardware enabled */
 
 	struct bcm43xx_stats stats;
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a2..8f198be 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
 */
 
 #include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
 #include "bcm43xx.h"
 
 #include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
 	switch (led_index) {
 	case 0:
 		led->behaviour = BCM43xx_LED_ACTIVITY;
+		led->activelow = 1;
 		if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
 			led->behaviour = BCM43xx_LED_RADIO_ALL;
 		break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
 			turn_on = activity;
 			break;
 		case BCM43xx_LED_RADIO_ALL:
-			turn_on = radio->enabled;
+			turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
 			break;
 		case BCM43xx_LED_RADIO_A:
 		case BCM43xx_LED_BCM4303_2:
-			turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+				   phy->type == BCM43xx_PHYTYPE_A);
 			break;
 		case BCM43xx_LED_RADIO_B:
 		case BCM43xx_LED_BCM4303_1:
-			turn_on = (radio->enabled &&
+			turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
 				   (phy->type == BCM43xx_PHYTYPE_B ||
 				    phy->type == BCM43xx_PHYTYPE_G));
 			break;
 		case BCM43xx_LED_MODE_BG:
-			if (phy->type == BCM43xx_PHYTYPE_G &&
+			if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
 			    1/*FIXME: using G rates.*/)
 				turn_on = 1;
 			break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 2ec2e5a..763625a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
 	if (err)
 		goto err_gpio_cleanup;
 	bcm43xx_radio_turn_on(bcm);
+	bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+		(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
 
 	bcm43xx_write16(bcm, 0x03E6, 0x0000);
 	err = bcm43xx_phy_init(bcm);
@@ -3172,9 +3175,24 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
 
 static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
 {
+	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+	int radio_hw_enable;
 
+	/* check if radio hardware enabled status changed */
+	radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+	if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+		bcm->radio_hw_enable = radio_hw_enable;
+		dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+		       (radio_hw_enable == 0) ? "disabled" : "enabled");
+		bcm43xx_leds_update(bcm, 0);
+	}
 	if (phy->type == BCM43xx_PHYTYPE_G) {
 		//TODO: update_aci_moving_average
 		if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3198,21 +3216,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
 			//TODO: implement rev1 workaround
 		}
 	}
-	bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
-	//TODO for APHY (temperature?)
 }
 
 static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	if (bcm->periodic_state % 8 == 0)
+	if (bcm->periodic_state % 120 == 0)
 		bcm43xx_periodic_every120sec(bcm);
-	if (bcm->periodic_state % 4 == 0)
+	if (bcm->periodic_state % 60 == 0)
 		bcm43xx_periodic_every60sec(bcm);
-	if (bcm->periodic_state % 2 == 0)
+	if (bcm->periodic_state % 30 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	bcm43xx_periodic_every15sec(bcm);
+	if (bcm->periodic_state % 15 == 0)
+		bcm43xx_periodic_every15sec(bcm);
+	bcm43xx_periodic_every1sec(bcm);
 
-	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+	schedule_delayed_work(&bcm->periodic_work, HZ);
 }
 
 static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3225,7 +3243,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
@@ -3257,7 +3275,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
 
 	do_periodic_work(bcm);
 
-	if (unlikely(bcm->periodic_state % 4 == 0)) {
+	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		spin_lock_irqsave(&bcm->irq_lock, flags);
 		tasklet_enable(&bcm->isr_tasklet);
 		bcm43xx_interrupt_enable(bcm, savedirqs);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484..af19a07 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
 	}
 	radio->enabled = 1;
 	dprintk(KERN_INFO PFX "Radio turned on\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 	
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
 		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
 	radio->enabled = 0;
 	dprintk(KERN_INFO PFX "Radio turned off\n");
+	bcm43xx_leds_update(bcm, 0);
 }
 
 void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed1803..77a98a5 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
 
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+	/* function to return state of hardware enable of radio
+	 * returns 0 if radio disabled, 1 if radio enabled
+	 */
+	if (bcm->current_core->rev >= 3)
+		return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+					& BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+					== 0) ? 1 : 0;
+	else
+		return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+					& BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+					== 0) ? 0 : 1;
+}
+
 int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
 				int synthetic_pu_workaround);
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9..a037b11 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
 }
 #endif
 
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+	.get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
 	ndev->do_ioctl = &prism54_ioctl;
 	ndev->wireless_handlers =
 	    (struct iw_handler_def *) &prism54_handler_def;
+	ndev->ethtool_ops = &islpci_ethtool_ops;
 
 	ndev->hard_start_xmit = &islpci_eth_transmit;
 	/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa166..736666d 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
 
 int islpci_free_memory(islpci_private *);
 struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME	"prism54"
+#define DRV_VERSION	"1.2"
+
 #endif				/* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b4..3dcb13b 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
 #include "islpci_mgt.h"		/* for pc_debug */
 #include "isl_oid.h"
 
-#define DRV_NAME	"prism54"
-#define DRV_VERSION	"1.2"
-
 MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
 MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 78ea72f..12dfc0b 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
 	dev_info(zd_chip_dev(chip), "%s\n", buffer);
 }
 
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+	u16 a = (u16)addr;
+	/* Control registers use byte addressing, but everything else uses word
+	 * addressing. */
+	if ((a & 0xf000) == CR_START)
+		a += 2;
+	else
+		a += 1;
+	return (zd_addr_t)a;
+}
+
 /* Read a variable number of 32-bit values. Parameter count is not allowed to
  * exceed USB_MAX_IOREAD32_COUNT.
  */
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
 	for (i = 0; i < count; i++) {
 		int j = 2*i;
 		/* We read the high word always first. */
-		a16[j] = zd_inc_word(addr[i]);
+		a16[j] = inc_addr(addr[i]);
 		a16[j+1] = addr[i];
 	}
 
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
 		j = 2*i;
 		/* We write the high word always first. */
 		ioreqs16[j].value   = ioreqs[i].value >> 16;
-		ioreqs16[j].addr    = zd_inc_word(ioreqs[i].addr);
+		ioreqs16[j].addr    = inc_addr(ioreqs[i].addr);
 		ioreqs16[j+1].value = ioreqs[i].value;
 		ioreqs16[j+1].addr  = ioreqs[i].addr;
 	}
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
 
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	for (i = 0;;) {
-		r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+		r = zd_ioread32_locked(chip, &v,
+			               (zd_addr_t)((u16)e2p_addr+i/2));
 		if (r)
 			return r;
 		v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip)
 static int zd1211_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211_RETRY_MAX,		0x2 },
-		{ CR_SNIFFER_ON,		0 },
-		{ CR_RX_FILTER,			STA_RX_FILTER },
-		{ CR_GROUP_HASH_P1,		0x00 },
-		{ CR_GROUP_HASH_P2,		0x80000000 },
-		{ CR_REG1,			0xa4 },
-		{ CR_ADDA_PWR_DWN,		0x7f },
-		{ CR_BCN_PLCP_CFG,		0x00f00401 },
-		{ CR_PHY_DELAY,			0x00 },
-		{ CR_ACK_TIMEOUT_EXT,		0x80 },
-		{ CR_ADDA_PWR_DWN,		0x00 },
-		{ CR_ACK_TIME_80211,		0x100 },
-		{ CR_RX_PE_DELAY,		0x70 },
-		{ CR_PS_CTRL,			0x10000000 },
-		{ CR_RTS_CTS_RATE,		0x02030203 },
 		{ CR_RX_THRESHOLD,		0x000c0640 },
-		{ CR_AFTER_PNP,			0x1 },
-		{ CR_WEP_PROTECT,		0x114 },
 	};
 
-	int r;
-
 	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
-	if (r) {
-		dev_err(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-#endif /* DEBUG */
-	return r;
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 {
 	static const struct zd_ioreq32 ioreqs[] = {
-		{ CR_ACK_TIMEOUT_EXT,		0x20 },
-		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_ZD1211B_RETRY_MAX,		0x02020202 },
 		{ CR_ZD1211B_TX_PWR_CTL4,	0x007f003f },
 		{ CR_ZD1211B_TX_PWR_CTL3,	0x007f003f },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 		{ CR_ZD1211B_AIFS_CTL1,		0x00280028 },
 		{ CR_ZD1211B_AIFS_CTL2,		0x008C003C },
 		{ CR_ZD1211B_TXOP,		0x01800824 },
+		{ CR_RX_THRESHOLD,		0x000c0eff, },
+	};
+
+	dev_dbg_f(zd_chip_dev(chip), "\n");
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+	int r;
+	static const struct zd_ioreq32 ioreqs[] = {
+		{ CR_ACK_TIMEOUT_EXT,		0x20 },
+		{ CR_ADDA_MBIAS_WARMTIME,	0x30000808 },
 		{ CR_SNIFFER_ON,		0 },
 		{ CR_RX_FILTER,			STA_RX_FILTER },
 		{ CR_GROUP_HASH_P1,		0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 		{ CR_RX_PE_DELAY,		0x70 },
 		{ CR_PS_CTRL,			0x10000000 },
 		{ CR_RTS_CTS_RATE,		0x02030203 },
-		{ CR_RX_THRESHOLD,		0x000c0eff, },
 		{ CR_AFTER_PNP,			0x1 },
 		{ CR_WEP_PROTECT,		0x114 },
+		{ CR_IFS_VALUE,			IFS_VALUE_DEFAULT },
 	};
 
-	int r;
-
-	dev_dbg_f(zd_chip_dev(chip), "\n");
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
 	r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-	if (r) {
-		dev_dbg_f(zd_chip_dev(chip),
-			"error in zd_iowrite32a_locked. Error number %d\n", r);
-	}
-	return r;
-}
+	if (r)
+		return r;
 
-static int hw_init_hmac(struct zd_chip *chip)
-{
 	return chip->is_zd1211b ?
 		zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
 }
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
 	if (r)
 		return r;
 
-	/* Although the vendor driver defaults to a different value during
-	 * init, it overwrites the IFS value with the following every time
-	 * the channel changes. We should aim to be more intelligent... */
-	r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
-	if (r)
-		return r;
-
 	return set_beacon_interval(chip, 100);
 }
 
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+	return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
 #ifdef DEBUG
 static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
 	           const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
 
 static void dump_fw_registers(struct zd_chip *chip)
 {
-	static const zd_addr_t addr[4] = {
-		FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
-		FW_LINK_STATUS
+	const zd_addr_t addr[4] = {
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+		fw_reg_addr(chip, FW_REG_USB_SPEED),
+		fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 	};
 
 	int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
 	int r;
 	u16 version;
 
-	r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+	r = zd_ioread16_locked(chip, &version,
+		fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
 	if (r)
 		return r;
 
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
 	return r;
 }
 
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+	int r;
+
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+		               FWRAW_REGS_ADDR);
+	if (r)
+		return r;
+	dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+		  (u16)chip->fw_regs_base);
+
+	return 0;
+}
+
+
 int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 {
 	int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 	if (r)
 		goto out;
 
-	r = zd_usb_init_hw(&chip->usb);
+	r = read_fw_regs_offset(chip);
 	if (r)
 		goto out;
 
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
 
 int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
 {
-	static const zd_addr_t a[] = {
-		FW_LINK_STATUS,
+	const zd_addr_t a[] = {
+		fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
 		CR_LED,
 	};
 
 	int r;
 	u16 v[ARRAY_SIZE(a)];
 	struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
-		[0] = { FW_LINK_STATUS },
+		[0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
 		[1] = { CR_LED },
 	};
 	u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee..b07569e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
 #ifndef _ZD_CHIP_H
 #define _ZD_CHIP_H
 
-#include "zd_types.h"
 #include "zd_rf.h"
 #include "zd_usb.h"
 
@@ -27,6 +26,37 @@
  * adds a processor for handling the USB protocol.
  */
 
+/* Address space */
+enum {
+	/* CONTROL REGISTERS */
+	CR_START			= 0x9000,
+
+
+	/* FIRMWARE */
+	FW_START			= 0xee00,
+
+
+	/* EEPROM */
+	E2P_START			= 0xf800,
+	E2P_LEN				= 0x800,
+
+	/* EEPROM layout */
+	E2P_LOAD_CODE_LEN		= 0xe,		/* base 0xf800 */
+	E2P_LOAD_VECT_LEN		= 0x9,		/* base 0xf80e */
+	/* E2P_DATA indexes into this */
+	E2P_DATA_LEN			= 0x7e,		/* base 0xf817 */
+	E2P_BOOT_CODE_LEN		= 0x760,	/* base 0xf895 */
+	E2P_INTR_VECT_LEN		= 0xb,		/* base 0xfff5 */
+
+	/* Some precomputed offsets into the EEPROM */
+	E2P_DATA_OFFSET			= E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+	E2P_BOOT_CODE_OFFSET		= E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
 /* 8-bit hardware registers */
 #define CR0   CTL_REG(0x0000)
 #define CR1   CTL_REG(0x0004)
@@ -302,7 +332,7 @@
 
 #define CR_MAX_PHY_REG 255
 
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
  * driver.
  */
 
@@ -594,81 +624,71 @@
 /*
  * Upper 16 bit contains the regulatory domain.
  */
-#define E2P_SUBID		E2P_REG(0x00)
-#define E2P_POD			E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1		E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2		E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1	E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2	E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3	E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4      E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1	E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2	E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3	E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4	E2P_REG(0x16)
+#define E2P_SUBID		E2P_DATA(0x00)
+#define E2P_POD			E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1		E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2		E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1	E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2	E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3	E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4      E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1	E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2	E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3	E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4	E2P_DATA(0x16)
 
 /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
  * also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL	E2P_REG(0x18)
-
-#define E2P_PHY_REG		E2P_REG(0x1a)
-#define E2P_DEVICE_VER		E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1	E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2      E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3      E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4	E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1	E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2	E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3	E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4	E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1	E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2	E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3	E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4	E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1	E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2	E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3	E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4	E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1	E2P_REG(0x48)	/* ??? */
-#define E2P_54M_CAL_VALUE2	E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3	E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4	E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1	E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2	E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3	E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4	E2P_REG(0x56)
-
-/* All 16 bit values */
-#define FW_FIRMWARE_VER         FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED            FW_REG(1)
-#define FW_FIX_TX_RATE          FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS          FW_REG(3)
-#define FW_SOFT_RESET           FW_REG(4)
-#define FW_FLASH_CHK            FW_REG(5)
+#define E2P_ALLOWED_CHANNEL	E2P_DATA(0x18)
+
+#define E2P_PHY_REG		E2P_DATA(0x1a)
+#define E2P_DEVICE_VER		E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1	E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2      E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3      E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4	E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1	E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2	E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3	E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4	E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1	E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2	E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3	E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4	E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1	E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2	E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3	E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4	E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1	E2P_DATA(0x48)	/* ??? */
+#define E2P_54M_CAL_VALUE2	E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3	E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4	E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1	E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2	E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3	E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4	E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR		FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+	FW_REG_FIRMWARE_VER	= 0,
+	/* non-zero if USB high speed connection */
+	FW_REG_USB_SPEED	= 1,
+	FW_REG_FIX_TX_RATE	= 2,
+	/* Seems to be able to control LEDs over the firmware */
+	FW_REG_LED_LINK_STATUS	= 3,
+	FW_REG_SOFT_RESET	= 4,
+	FW_REG_FLASH_CHK	= 5,
+};
 
+/* Values for FW_LINK_STATUS */
 #define FW_LINK_OFF		0x0
 #define FW_LINK_TX		0x1
 /* 0x2 - link led on? */
 
 enum {
-	CR_BASE_OFFSET			= 0x9000,
-	FW_START_OFFSET			= 0xee00,
-	FW_BASE_ADDR_OFFSET		= FW_START_OFFSET + 0x1d,
-	EEPROM_START_OFFSET		= 0xf800,
-	EEPROM_SIZE			= 0x800, /* words */
-	LOAD_CODE_SIZE			= 0xe, /* words */
-	LOAD_VECT_SIZE			= 0x10000 - 0xfff7, /* words */
-	EEPROM_REGS_OFFSET		= LOAD_CODE_SIZE + LOAD_VECT_SIZE,
-	EEPROM_REGS_SIZE		= 0x7e, /* words */
-	E2P_BASE_OFFSET			= EEPROM_START_OFFSET +
-		                          EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR	USB_ADDR(FW_START_OFFSET + 0x1d)
-
-enum {
 	/* indices for ofdm_cal_values */
 	OFDM_36M_INDEX = 0,
 	OFDM_48M_INDEX = 1,
@@ -679,6 +699,8 @@ struct zd_chip {
 	struct zd_usb usb;
 	struct zd_rf rf;
 	struct mutex mutex;
+	/* Base address of FW_REG_ registers */
+	zd_addr_t fw_regs_base;
 	u8 e2p_mac[ETH_ALEN];
 	/* EepSetPoint in the vendor driver */
 	u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62..deb99d1 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 
+typedef u16 __nocast zd_addr_t;
+
 #define dev_printk_f(level, dev, fmt, args...) \
 	dev_printk(level, dev, "%s() " fmt, __func__, ##args)
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298..c4f36d3 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
 #define _ZD_IEEE80211_H
 
 #include <net/ieee80211.h>
-#include "zd_types.h"
 
 /* Additional definitions from the standards.
  */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b373..a57732e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
 #ifndef _ZD_RF_H
 #define _ZD_RF_H
 
-#include "zd_types.h"
-
 #define UW2451_RF			0x2
 #define UCHIP_RF			0x3
 #define AL2230_RF			0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a15..0000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
-	ADDR_BASE_MASK		= 0xff000000,
-	ADDR_OFFSET_MASK	= 0x0000ffff,
-	ADDR_ZERO_MASK		= 0x00ff0000,
-	NULL_BASE		= 0x00000000,
-	USB_BASE		= 0x01000000,
-	CR_BASE			= 0x02000000,
-	CR_MAX_OFFSET		= 0x0b30,
-	E2P_BASE		= 0x03000000,
-	E2P_MAX_OFFSET		= 0x007e,
-	FW_BASE			= 0x04000000,
-	FW_MAX_OFFSET		= 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
-	((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR    ((zd_addr_t)0)
-#define USB_REG(offset)  ZD_ADDR(USB_BASE, offset)	/* word addressing */
-#define CTL_REG(offset)  ZD_ADDR(CR_BASE, offset)	/* byte addressing */
-#define E2P_REG(offset)  ZD_ADDR(E2P_BASE, offset)	/* word addressing */
-#define FW_REG(offset)   ZD_ADDR(FW_BASE, offset)	/* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	offset += base == CR_BASE ? 2 : 1;
-
-	return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e..1b8ea88 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,9 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
@@ -73,96 +76,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
 #define FW_ZD1211_PREFIX	"zd1211/zd1211_"
 #define FW_ZD1211B_PREFIX	"zd1211/zd1211b_"
 
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base = ZD_ADDR_BASE(addr);
-	u32 offset = ZD_OFFSET(addr);
-
-	if ((u32)addr & ADDR_ZERO_MASK)
-		goto invalid_address;
-	switch (base) {
-	case USB_BASE:
-		break;
-	case CR_BASE:
-		if (offset > CR_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x larger than"
-				" CR_MAX_OFFSET %#10x\n",
-				offset, CR_MAX_OFFSET);
-			goto invalid_address;
-		}
-		if (offset & 1) {
-			dev_dbg(zd_usb_dev(usb),
-				"CR offset %#010x is not a multiple of 2\n",
-				offset);
-			goto invalid_address;
-		}
-		break;
-	case E2P_BASE:
-		if (offset > E2P_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"E2P offset %#010x larger than"
-				" E2P_MAX_OFFSET %#010x\n",
-				offset, E2P_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	case FW_BASE:
-		if (!usb->fw_base_offset) {
-			dev_dbg(zd_usb_dev(usb),
-			       "ERROR: fw base offset has not been set\n");
-			return -EAGAIN;
-		}
-		if (offset > FW_MAX_OFFSET) {
-			dev_dbg(zd_usb_dev(usb),
-				"FW offset %#10x is larger than"
-				" FW_MAX_OFFSET %#010x\n",
-				offset, FW_MAX_OFFSET);
-			goto invalid_address;
-		}
-		break;
-	default:
-		dev_dbg(zd_usb_dev(usb),
-			"address has unsupported base %#010x\n", addr);
-		goto invalid_address;
-	}
-
-	return 0;
-invalid_address:
-	dev_dbg(zd_usb_dev(usb),
-		"ERROR: invalid address: %#010x\n", addr);
-	return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-	u32 base;
-	u16 offset;
-
-	base = ZD_ADDR_BASE(addr);
-	offset = ZD_OFFSET(addr);
-
-	ZD_ASSERT(check_addr(usb, addr) == 0);
-
-	switch (base) {
-	case CR_BASE:
-		offset += CR_BASE_OFFSET;
-		break;
-	case E2P_BASE:
-		offset += E2P_BASE_OFFSET;
-		break;
-	case FW_BASE:
-		offset += usb->fw_base_offset;
-		break;
-	}
-
-	return offset;
-}
-
 /* USB device initialization */
 
 static int request_fw_file(
@@ -295,14 +208,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
 	if (r)
 		goto error;
 
-	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
-		REBOOT);
+	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
 	if (r)
 		goto error;
 
-	offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+	offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
 	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
-		E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+		E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
 
 	/* At this point, the vendor driver downloads the whole firmware
 	 * image, hacks around with version IDs, and uploads it again,
@@ -331,7 +243,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
 	if (r)
 		goto error;
 
-	fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+	fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
 
 	if (fw_bcdDevice != bcdDevice) {
 		dev_info(&udev->dev,
@@ -357,8 +269,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
 	if (r)
 		goto error;
 
-	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
-		        REBOOT);
+	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
 	if (r) {
 		dev_err(&udev->dev,
 			"Could not upload firmware code uph. Error number %d\n",
@@ -858,7 +769,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
 	spin_lock_init(&intr->lock);
 	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
 	init_completion(&intr->read_regs.completion);
-	intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+	intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
 }
 
 static inline void init_usb_rx(struct zd_usb *usb)
@@ -890,22 +801,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
 	init_usb_rx(usb);
 }
 
-int zd_usb_init_hw(struct zd_usb *usb)
-{
-	int r;
-	struct zd_chip *chip = zd_usb_to_chip(usb);
-
-	ZD_ASSERT(mutex_is_locked(&chip->mutex));
-	r = zd_ioread16_locked(chip, &usb->fw_base_offset,
-		        USB_REG((u16)FW_BASE_ADDR_OFFSET));
-	if (r)
-		return r;
-	dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
-		 usb->fw_base_offset);
-
-	return 0;
-}
-
 void zd_usb_clear(struct zd_usb *usb)
 {
 	usb_set_intfdata(usb->intf, NULL);
@@ -1253,7 +1148,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 		return -ENOMEM;
 	req->id = cpu_to_le16(USB_REQ_READ_REGS);
 	for (i = 0; i < count; i++)
-		req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+		req->addr[i] = cpu_to_le16((u16)addresses[i]);
 
 	udev = zd_usb_to_usbdev(usb);
 	prepare_read_regs_int(usb);
@@ -1318,7 +1213,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
 	req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
 	for (i = 0; i < count; i++) {
 		struct reg_data *rw  = &req->reg_writes[i];
-		rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+		rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
 		rw->value = cpu_to_le16(ioreqs[i].value);
 	}
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c..506ea6a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
 #include <linux/usb.h>
 
 #include "zd_def.h"
-#include "zd_types.h"
 
 enum devicetype {
 	DEVICE_ZD1211  = 0,
@@ -181,15 +180,14 @@ struct zd_usb_tx {
 	spinlock_t lock;
 };
 
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
  */
 struct zd_usb {
 	struct zd_usb_interrupt intr;
 	struct zd_usb_rx rx;
 	struct zd_usb_tx tx;
 	struct usb_interface *intf;
-	u16 fw_base_offset;
 };
 
 #define zd_usb_dev(usb) (&usb->intf->dev)
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index fa2f7da..fb58e03 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -265,6 +265,12 @@ ieee80211softmac_wx_get_rate(struct net_device *net_dev,
 	int err = -EINVAL;
 
 	spin_lock_irqsave(&mac->lock, flags);
+
+	if (unlikely(!mac->running)) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
 	switch (mac->txrates.default_rate) {
 	case IEEE80211_CCK_RATE_1MB:
 		data->bitrate.value = 1000000;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-12-28  0:10     ` John W. Linville
@ 2007-01-03  2:04       ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2007-01-03  2:04 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev, uberlord

On Wed, Dec 27, 2006 at 07:10:57PM -0500, John W. Linville wrote:
> On Tue, Dec 26, 2006 at 04:39:38PM -0500, Jeff Garzik wrote:
> > John W. Linville wrote:
> > >The following changes since commit 
> > >0c234ae655a45ac3ee53a25b2e56e9bb6c27d71d:
> > >  Ulrich Kunitz (1):
> > >        ieee80211softmac: Fix mutex_lock at exit of 
> > >        ieee80211_softmac_get_genie
> > >
> > >are found in the git repository at:
> > >
> > >  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git 
> > >  upstream
> > >
> > >Roy Marples (1):
> > >      prism54: set carrier flags correctly
> > 
> > Why is this not #upstream-fixes material?  What's the impact?
> 
> Just being cautious, really.  I have no objection if you want to pull
> it as a fix.

After further review...

Jeff, it looks like you have not pulled this one so far.  Based on
the commentary from Roger While [1], lets hold-off on this one.

Roy, please consider refactoring your patch based on Roger's comments.

Thanks,

John

[1] http://marc.10east.com/?l=linux-netdev&m=116740017623597&w=2

-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-12-26 21:39   ` Jeff Garzik
@ 2006-12-28  0:10     ` John W. Linville
  2007-01-03  2:04       ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-12-28  0:10 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

On Tue, Dec 26, 2006 at 04:39:38PM -0500, Jeff Garzik wrote:
> John W. Linville wrote:
> >The following changes since commit 
> >0c234ae655a45ac3ee53a25b2e56e9bb6c27d71d:
> >  Ulrich Kunitz (1):
> >        ieee80211softmac: Fix mutex_lock at exit of 
> >        ieee80211_softmac_get_genie
> >
> >are found in the git repository at:
> >
> >  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git 
> >  upstream
> >
> >Roy Marples (1):
> >      prism54: set carrier flags correctly
> 
> Why is this not #upstream-fixes material?  What's the impact?

Just being cautious, really.  I have no objection if you want to pull
it as a fix.

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-12-21  3:05 ` Please pull 'upstream' " John W. Linville
@ 2006-12-26 21:39   ` Jeff Garzik
  2006-12-28  0:10     ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2006-12-26 21:39 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit 0c234ae655a45ac3ee53a25b2e56e9bb6c27d71d:
>   Ulrich Kunitz (1):
>         ieee80211softmac: Fix mutex_lock at exit of ieee80211_softmac_get_genie
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Roy Marples (1):
>       prism54: set carrier flags correctly

Why is this not #upstream-fixes material?  What's the impact?

	Jeff



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-12-21  3:03 Please pull 'upstream-fixes' " John W. Linville
@ 2006-12-21  3:05 ` John W. Linville
  2006-12-26 21:39   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-12-21  3:05 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 0c234ae655a45ac3ee53a25b2e56e9bb6c27d71d:
  Ulrich Kunitz (1):
        ieee80211softmac: Fix mutex_lock at exit of ieee80211_softmac_get_genie

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Roy Marples (1):
      prism54: set carrier flags correctly

 drivers/net/wireless/prism54/isl_ioctl.c  |    5 ++++-
 drivers/net/wireless/prism54/islpci_dev.c |    4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 838d510..25d42ac 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2093,8 +2093,11 @@ link_changed(struct net_device *ndev, u32 bitrate)
 		} else
 			send_simple_event(netdev_priv(ndev),
 					  "Link established");
-	} else
+		netif_carrier_on(ndev);
+	} else {
 		send_simple_event(netdev_priv(ndev), "Link lost");
+		netif_carrier_off(ndev);
+	}
 }
 
 /* Beacon/ProbeResp payload header */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9..9c8c6f2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -386,7 +386,9 @@ islpci_open(struct net_device *ndev)
 	}
 
 	netif_start_queue(ndev);
-/*      netif_mark_up( ndev ); */
+
+	/* Turn off carrier unless we know we have associated */
+	netif_carrier_off(ndev);
 
 	return 0;
 }
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-12-12  0:21 John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-12-12  0:21 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 9202f32558601c2c99ddc438eb3218131d00d413:
  Ralf Baechle:
        [MIPS] Export local_flush_data_cache_page for sake of IDE.

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Roy Marples:
      prism54: set carrier flags correctly

Ulrich Kunitz:
      zd1211rw: Call ieee80211_rx in tasklet
      ieee80211softmac: Fix errors related to the work_struct changes
      ieee80211softmac: Fix mutex_lock at exit of ieee80211_softmac_get_genie

 drivers/net/wireless/prism54/isl_ioctl.c       |    5 +
 drivers/net/wireless/prism54/islpci_dev.c      |    4 +
 drivers/net/wireless/zd1211rw/zd_mac.c         |   96 ++++++++++++++++++------
 drivers/net/wireless/zd1211rw/zd_mac.h         |    5 +
 drivers/net/wireless/zd1211rw/zd_usb.c         |    4 +
 net/ieee80211/softmac/ieee80211softmac_assoc.c |    4 +
 net/ieee80211/softmac/ieee80211softmac_wx.c    |    2 -
 7 files changed, 86 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 96606ed..a6ffed1 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2093,8 +2093,11 @@ link_changed(struct net_device *ndev, u3
 		} else
 			send_simple_event(netdev_priv(ndev),
 					  "Link established");
-	} else
+		netif_carrier_on(ndev);
+	} else {
 		send_simple_event(netdev_priv(ndev), "Link lost");
+		netif_carrier_off(ndev);
+	}
 }
 
 /* Beacon/ProbeResp payload header */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9..9c8c6f2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -386,7 +386,9 @@ islpci_open(struct net_device *ndev)
 	}
 
 	netif_start_queue(ndev);
-/*      netif_mark_up( ndev ); */
+
+	/* Turn off carrier unless we know we have associated */
+	netif_carrier_off(ndev);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 00ca704..a085241 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -41,6 +41,8 @@ static void housekeeping_disable(struct 
 
 static void set_multicast_hash_handler(struct work_struct *work);
 
+static void do_rx(unsigned long mac_ptr);
+
 int zd_mac_init(struct zd_mac *mac,
 	        struct net_device *netdev,
 	        struct usb_interface *intf)
@@ -53,6 +55,10 @@ int zd_mac_init(struct zd_mac *mac,
 	INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
 	INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
 
+	skb_queue_head_init(&mac->rx_queue);
+	tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
+	tasklet_disable(&mac->rx_tasklet);
+
 	ieee_init(ieee);
 	softmac_init(ieee80211_priv(netdev));
 	zd_chip_init(&mac->chip, netdev, intf);
@@ -140,6 +146,8 @@ out:
 void zd_mac_clear(struct zd_mac *mac)
 {
 	flush_workqueue(zd_workqueue);
+	skb_queue_purge(&mac->rx_queue);
+	tasklet_kill(&mac->rx_tasklet);
 	zd_chip_clear(&mac->chip);
 	ZD_ASSERT(!spin_is_locked(&mac->lock));
 	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -168,6 +176,8 @@ int zd_mac_open(struct net_device *netde
 	struct zd_chip *chip = &mac->chip;
 	int r;
 
+	tasklet_enable(&mac->rx_tasklet);
+
 	r = zd_chip_enable_int(chip);
 	if (r < 0)
 		goto out;
@@ -218,6 +228,8 @@ int zd_mac_stop(struct net_device *netde
 	 */
 
 	zd_chip_disable_rx(chip);
+	skb_queue_purge(&mac->rx_queue);
+	tasklet_disable(&mac->rx_tasklet);
 	housekeeping_disable(mac);
 	ieee80211softmac_stop(netdev);
 
@@ -470,13 +482,13 @@ static void bssinfo_change(struct net_de
 
 	if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) {
 		/* Set RTS rate to highest available basic rate */
-		u8 rate = ieee80211softmac_highest_supported_rate(softmac,
+		u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac,
 			&bssinfo->supported_rates, 1);
-		rate = rate_to_zd_rate(rate);
+		hi_rate = rate_to_zd_rate(hi_rate);
 
 		spin_lock_irqsave(&mac->lock, flags);
-		if (rate != mac->rts_rate) {
-			mac->rts_rate = rate;
+		if (hi_rate != mac->rts_rate) {
+			mac->rts_rate = hi_rate;
 			need_set_rts_cts = 1;
 		}
 		spin_unlock_irqrestore(&mac->lock, flags);
@@ -1072,43 +1084,75 @@ static int fill_rx_stats(struct ieee8021
 	return 0;
 }
 
-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
 {
 	int r;
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 	struct ieee80211_rx_stats stats;
 	const struct rx_status *status;
-	struct sk_buff *skb;
 
-	if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
-	             IEEE80211_FCS_LEN + sizeof(struct rx_status))
-		return -EINVAL;
+	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
+	{
+		dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
+			 skb->len);
+		goto free_skb;
+	}
 
-	r = fill_rx_stats(&stats, &status, mac, buffer, length);
-	if (r)
-		return r;
+	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
+	if (r) {
+		/* Only packets with rx errors are included here. */
+		goto free_skb;
+	}
 
-	length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
-		  sizeof(struct rx_status);
-	buffer += ZD_PLCP_HEADER_SIZE;
+	__skb_pull(skb, ZD_PLCP_HEADER_SIZE);
+	__skb_trim(skb, skb->len -
+		        (IEEE80211_FCS_LEN + sizeof(struct rx_status)));
 
-	update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+	update_qual_rssi(mac, skb->data, skb->len, stats.signal,
+		         status->signal_strength);
 
-	r = filter_rx(ieee, buffer, length, &stats);
-	if (r <= 0)
-		return r;
+	r = filter_rx(ieee, skb->data, skb->len, &stats);
+	if (r <= 0) {
+		if (r < 0)
+			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+		goto free_skb;
+	}
 
-	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
-	if (!skb)
-		return -ENOMEM;
 	if (ieee->iw_mode == IW_MODE_MONITOR)
-		fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+		fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac,
 			       &stats, status);
-	memcpy(skb_put(skb, length), buffer, length);
 
 	r = ieee80211_rx(ieee, skb, &stats);
-	if (!r)
-		dev_kfree_skb_any(skb);
+	if (r)
+		return;
+free_skb:
+	/* We are always in a soft irq. */
+	dev_kfree_skb(skb);
+}
+
+static void do_rx(unsigned long mac_ptr)
+{
+	struct zd_mac *mac = (struct zd_mac *)mac_ptr;
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&mac->rx_queue)) != NULL)
+		zd_mac_rx(mac, skb);
+}
+
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+	if (!skb) {
+		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+		return -ENOMEM;
+	}
+	skb_reserve(skb, sizeof(struct zd_rt_hdr));
+	memcpy(__skb_put(skb, length), buffer, length);
+	skb_queue_tail(&mac->rx_queue, skb);
+	tasklet_schedule(&mac->rx_tasklet);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index f0cf05d..faf4c78 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -138,6 +138,9 @@ struct zd_mac {
 	struct delayed_work set_rts_cts_work;
 	struct delayed_work set_basic_rates_work;
 
+	struct tasklet_struct rx_tasklet;
+	struct sk_buff_head rx_queue;
+
 	unsigned int stats_count;
 	u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
 	u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
@@ -193,7 +196,7 @@ int zd_mac_stop(struct net_device *netde
 int zd_mac_set_mac_address(struct net_device *dev, void *p);
 void zd_mac_set_multicast_list(struct net_device *netdev);
 
-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length);
 
 int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
 u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index aa782e8..605e96e 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -598,13 +598,13 @@ static void handle_rx_packet(struct zd_u
 			n = l+k;
 			if (n > length)
 				return;
-			zd_mac_rx(mac, buffer+l, k);
+			zd_mac_rx_irq(mac, buffer+l, k);
 			if (i >= 2)
 				return;
 			l = (n+3) & ~3;
 		}
 	} else {
-		zd_mac_rx(mac, buffer, length);
+		zd_mac_rx_irq(mac, buffer, length);
 	}
 }
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index e3f37fd..a824852 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -167,7 +167,7 @@ static void
 ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
 {
 	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	ieee80211softmac_assoc_work((void*)mac);
+	ieee80211softmac_assoc_work(&mac->associnfo.work.work);
 }
 
 static void
@@ -177,7 +177,7 @@ ieee80211softmac_assoc_notify_auth(struc
 
 	switch (event_type) {
 	case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
-		ieee80211softmac_assoc_work((void*)mac);
+		ieee80211softmac_assoc_work(&mac->associnfo.work.work);
 		break;
 	case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
 	case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 480d72c..fa2f7da 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -463,7 +463,7 @@ ieee80211softmac_wx_get_genie(struct net
 			err = -E2BIG;
 	}
 	spin_unlock_irqrestore(&mac->lock, flags);
-	mutex_lock(&mac->associnfo.mutex);
+	mutex_unlock(&mac->associnfo.mutex);
 
 	return err;
 }
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-12-06  1:42 John W. Linville
@ 2006-12-07 10:03 ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-12-07 10:03 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit e62438630ca37539c8cc1553710bbfaa3cf960a7:
>   Matthew Wilcox:
>         Centralise definitions of sector_t and blkcnt_t
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

pulled, but there were workqueue-related conflicts.  let me know if 
#upstream doesn't match what you would like.




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-12-06  1:42 John W. Linville
  2006-12-07 10:03 ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-12-06  1:42 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit e62438630ca37539c8cc1553710bbfaa3cf960a7:
  Matthew Wilcox:
        Centralise definitions of sector_t and blkcnt_t

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      zd1211rw: zd_mac_rx isn't always called in IRQ context
      zd1211rw: Fill enc_capa in GIWRANGE handler

Maxime Austruy:
      softmac: fix unbalanced mutex_lock/unlock in ieee80211softmac_wx_set_mlme

Ulrich Kunitz:
      zd1211rw: Support for multicast addresses
      softmac: Fixed handling of deassociation from AP

Yan Burman:
      hostap: replace kmalloc+memset with kzalloc
      prism54: replace kmalloc+memset with kzalloc
      ipw2200: replace kmalloc+memset with kcalloc

Zhu Yi:
      ipw2200: Add IEEE80211_RADIOTAP_TSFT for promiscuous mode
      ipw2200: Update version stamp to 1.2.0
      ipw2200: Fix a typo
      ipw2200: Fix debug output endian issue

 drivers/net/wireless/hostap/hostap_ap.c        |    4 --
 drivers/net/wireless/hostap/hostap_cs.c        |    3 -
 drivers/net/wireless/hostap/hostap_download.c  |    4 --
 drivers/net/wireless/hostap/hostap_hw.c        |   12 +----
 drivers/net/wireless/hostap/hostap_info.c      |    3 -
 drivers/net/wireless/hostap/hostap_ioctl.c     |   12 +----
 drivers/net/wireless/hostap/hostap_pci.c       |    3 -
 drivers/net/wireless/hostap/hostap_plx.c       |    3 -
 drivers/net/wireless/ipw2100.c                 |    2 -
 drivers/net/wireless/ipw2200.c                 |   24 +++++++----
 drivers/net/wireless/prism54/isl_ioctl.c       |    9 +---
 drivers/net/wireless/prism54/oid_mgt.c         |    4 --
 drivers/net/wireless/zd1211rw/zd_chip.c        |   13 ++++++
 drivers/net/wireless/zd1211rw/zd_chip.h        |   43 +++++++++++++++++++
 drivers/net/wireless/zd1211rw/zd_mac.c         |   53 ++++++++++++++++++++++--
 drivers/net/wireless/zd1211rw/zd_mac.h         |    3 +
 drivers/net/wireless/zd1211rw/zd_netdev.c      |    2 -
 net/ieee80211/softmac/ieee80211softmac_assoc.c |   14 +++++-
 net/ieee80211/softmac/ieee80211softmac_auth.c  |    2 +
 net/ieee80211/softmac/ieee80211softmac_priv.h  |    2 +
 net/ieee80211/softmac/ieee80211softmac_wx.c    |    3 +
 21 files changed, 158 insertions(+), 60 deletions(-)

diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index ba13125..798a855 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1099,15 +1099,13 @@ static struct sta_info * ap_add_sta(stru
 {
 	struct sta_info *sta;
 
-	sta = (struct sta_info *)
-		kmalloc(sizeof(struct sta_info), GFP_ATOMIC);
+	sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC);
 	if (sta == NULL) {
 		PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
 		return NULL;
 	}
 
 	/* initialize STA info data */
-	memset(sta, 0, sizeof(struct sta_info));
 	sta->local = ap->local;
 	skb_queue_head_init(&sta->tx_buf);
 	memcpy(sta->addr, addr, ETH_ALEN);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index f63909e..ef470e6 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -566,12 +566,11 @@ static int prism2_config(struct pcmcia_d
 	PDEBUG(DEBUG_FLOW, "prism2_config()\n");
 
 	parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
-	hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
 	if (parse == NULL || hw_priv == NULL) {
 		ret = -ENOMEM;
 		goto failed;
 	}
-	memset(hw_priv, 0, sizeof(*hw_priv));
 
 	tuple.DesiredTuple = CISTPL_CONFIG;
 	tuple.Attributes = 0;
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
index ab26b52..24fc387 100644
--- a/drivers/net/wireless/hostap/hostap_download.c
+++ b/drivers/net/wireless/hostap/hostap_download.c
@@ -685,14 +685,12 @@ static int prism2_download(local_info_t 
 		goto out;
 	}
 
-	dl = kmalloc(sizeof(*dl) + param->num_areas *
+	dl = kzalloc(sizeof(*dl) + param->num_areas *
 		     sizeof(struct prism2_download_data_area), GFP_KERNEL);
 	if (dl == NULL) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	memset(dl, 0, sizeof(*dl) + param->num_areas *
-	       sizeof(struct prism2_download_data_area));
 	dl->dl_cmd = param->dl_cmd;
 	dl->start_addr = param->start_addr;
 	dl->num_areas = param->num_areas;
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index ed00ebb..9c50336 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -347,14 +347,12 @@ static int hfa384x_cmd(struct net_device
 	if (signal_pending(current))
 		return -EINTR;
 
-	entry = (struct hostap_cmd_queue *)
-		kmalloc(sizeof(*entry), GFP_ATOMIC);
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL) {
 		printk(KERN_DEBUG "%s: hfa384x_cmd - kmalloc failed\n",
 		       dev->name);
 		return -ENOMEM;
 	}
-	memset(entry, 0, sizeof(*entry));
 	atomic_set(&entry->usecnt, 1);
 	entry->type = CMD_SLEEP;
 	entry->cmd = cmd;
@@ -517,14 +515,12 @@ static int hfa384x_cmd_callback(struct n
 		return -1;
 	}
 
-	entry = (struct hostap_cmd_queue *)
-		kmalloc(sizeof(*entry), GFP_ATOMIC);
+	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	if (entry == NULL) {
 		printk(KERN_DEBUG "%s: hfa384x_cmd_callback - kmalloc "
 		       "failed\n", dev->name);
 		return -ENOMEM;
 	}
-	memset(entry, 0, sizeof(*entry));
 	atomic_set(&entry->usecnt, 1);
 	entry->type = CMD_CALLBACK;
 	entry->cmd = cmd;
@@ -3015,14 +3011,12 @@ static int prism2_set_tim(struct net_dev
 	iface = netdev_priv(dev);
 	local = iface->local;
 
-	new_entry = (struct set_tim_data *)
-		kmalloc(sizeof(*new_entry), GFP_ATOMIC);
+	new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
 	if (new_entry == NULL) {
 		printk(KERN_DEBUG "%s: prism2_set_tim: kmalloc failed\n",
 		       local->dev->name);
 		return -ENOMEM;
 	}
-	memset(new_entry, 0, sizeof(*new_entry));
 	new_entry->aid = aid;
 	new_entry->set = set;
 
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index 50f72d8..00ed638 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -327,11 +327,10 @@ static void prism2_info_hostscanresults(
 	ptr = (u8 *) pos;
 
 	new_count = left / result_size;
-	results = kmalloc(new_count * sizeof(struct hfa384x_hostscan_result),
+	results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
 			  GFP_ATOMIC);
 	if (results == NULL)
 		return;
-	memset(results, 0, new_count * sizeof(struct hfa384x_hostscan_result));
 
 	for (i = 0; i < new_count; i++) {
 		memcpy(&results[i], ptr, copy_len);
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index d061fb3..3b7b806 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -181,12 +181,10 @@ static int prism2_ioctl_siwencode(struct
 		struct ieee80211_crypt_data *new_crypt;
 
 		/* take WEP into use */
-		new_crypt = (struct ieee80211_crypt_data *)
-			kmalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL)
 			return -ENOMEM;
-		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
 		new_crypt->ops = ieee80211_get_crypto_ops("WEP");
 		if (!new_crypt->ops) {
 			request_module("ieee80211_crypt_wep");
@@ -3320,14 +3318,12 @@ static int prism2_ioctl_siwencodeext(str
 
 		prism2_crypt_delayed_deinit(local, crypt);
 
-		new_crypt = (struct ieee80211_crypt_data *)
-			kmalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
 			goto done;
 		}
-		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
 		new_crypt->ops = ops;
 		new_crypt->priv = new_crypt->ops->init(i);
 		if (new_crypt->priv == NULL) {
@@ -3538,14 +3534,12 @@ static int prism2_ioctl_set_encryption(l
 
 		prism2_crypt_delayed_deinit(local, crypt);
 
-		new_crypt = (struct ieee80211_crypt_data *)
-			kmalloc(sizeof(struct ieee80211_crypt_data),
+		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
 				GFP_KERNEL);
 		if (new_crypt == NULL) {
 			ret = -ENOMEM;
 			goto done;
 		}
-		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
 		new_crypt->ops = ops;
 		new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
 		if (new_crypt->priv == NULL) {
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index d1de976..c4f6020 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -300,10 +300,9 @@ static int prism2_pci_probe(struct pci_d
 	struct hostap_interface *iface;
 	struct hostap_pci_priv *hw_priv;
 
-	hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
 	if (hw_priv == NULL)
 		return -ENOMEM;
-	memset(hw_priv, 0, sizeof(*hw_priv));
 
 	if (pci_enable_device(pdev))
 		goto err_out_free;
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index bc81b13..e235e06 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -447,10 +447,9 @@ static int prism2_plx_probe(struct pci_d
 	int tmd7160;
 	struct hostap_plx_priv *hw_priv;
 
-	hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
+	hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
 	if (hw_priv == NULL)
 		return -ENOMEM;
-	memset(hw_priv, 0, sizeof(*hw_priv));
 
 	if (pci_enable_device(pdev))
 		goto err_out_free;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 79607b8..060018e 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -6215,7 +6215,7 @@ static int ipw2100_pci_init_one(struct p
 	/* Allocate and initialize the Tx/Rx queues and lists */
 	if (ipw2100_queues_allocate(priv)) {
 		printk(KERN_WARNING DRV_NAME
-		       "Error calilng ipw2100_queues_allocate.\n");
+		       "Error calling ipw2100_queues_allocate.\n");
 		err = -ENOMEM;
 		goto fail;
 	}
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index c692d01..d29f427 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -70,7 +70,7 @@ #else
 #define VQ
 #endif
 
-#define IPW2200_VERSION "1.1.4" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2200/2915 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
@@ -7656,7 +7656,8 @@ static void ipw_handle_data_packet_monit
 
 	/* Big bitfield of all the fields we provide in radiotap */
 	ipw_rt->rt_hdr.it_present =
-	    ((1 << IEEE80211_RADIOTAP_FLAGS) |
+	    ((1 << IEEE80211_RADIOTAP_TSFT) |
+	     (1 << IEEE80211_RADIOTAP_FLAGS) |
 	     (1 << IEEE80211_RADIOTAP_RATE) |
 	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
 	     (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7665,10 +7666,14 @@ static void ipw_handle_data_packet_monit
 
 	/* Zero the flags, we'll add to them as we go */
 	ipw_rt->rt_flags = 0;
-	ipw_rt->rt_tsf = 0ULL;
+	ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
+			       frame->parent_tsf[2] << 16 |
+			       frame->parent_tsf[1] << 8  |
+			       frame->parent_tsf[0]);
 
 	/* Convert signal to DBM */
 	ipw_rt->rt_dbmsignal = antsignal;
+	ipw_rt->rt_dbmnoise = frame->noise;
 
 	/* Convert the channel data and set the flags */
 	ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
@@ -7868,7 +7873,8 @@ static void ipw_handle_promiscuous_rx(st
 
 	/* Big bitfield of all the fields we provide in radiotap */
 	ipw_rt->rt_hdr.it_present =
-	    ((1 << IEEE80211_RADIOTAP_FLAGS) |
+	    ((1 << IEEE80211_RADIOTAP_TSFT) |
+	     (1 << IEEE80211_RADIOTAP_FLAGS) |
 	     (1 << IEEE80211_RADIOTAP_RATE) |
 	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
 	     (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7877,7 +7883,10 @@ static void ipw_handle_promiscuous_rx(st
 
 	/* Zero the flags, we'll add to them as we go */
 	ipw_rt->rt_flags = 0;
-	ipw_rt->rt_tsf = 0ULL;
+	ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
+			       frame->parent_tsf[2] << 16 |
+			       frame->parent_tsf[1] << 8  |
+			       frame->parent_tsf[0]);
 
 	/* Convert to DBM */
 	ipw_rt->rt_dbmsignal = signal;
@@ -8276,7 +8285,7 @@ #endif
 				    ("Notification: subtype=%02X flags=%02X size=%d\n",
 				     pkt->u.notification.subtype,
 				     pkt->u.notification.flags,
-				     pkt->u.notification.size);
+				     le16_to_cpu(pkt->u.notification.size));
 				ipw_rx_notification(priv, &pkt->u.notification);
 				break;
 			}
@@ -11129,14 +11138,13 @@ static int ipw_up(struct ipw_priv *priv)
 		return -EIO;
 
 	if (cmdlog && !priv->cmdlog) {
-		priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog,
+		priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog),
 				       GFP_KERNEL);
 		if (priv->cmdlog == NULL) {
 			IPW_ERROR("Error allocating %d command log entries.\n",
 				  cmdlog);
 			return -ENOMEM;
 		} else {
-			memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
 			priv->cmdlog_len = cmdlog;
 		}
 	}
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 4a20e45..a48edd1 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2140,11 +2140,9 @@ prism54_wpa_bss_ie_add(islpci_private *p
 					 struct islpci_bss_wpa_ie, list);
 			list_del(&bss->list);
 		} else {
-			bss = kmalloc(sizeof (*bss), GFP_ATOMIC);
-			if (bss != NULL) {
+			bss = kzalloc(sizeof (*bss), GFP_ATOMIC);
+			if (bss != NULL)
 				priv->num_bss_wpa++;
-				memset(bss, 0, sizeof (*bss));
-			}
 		}
 		if (bss != NULL) {
 			memcpy(bss->bssid, bssid, ETH_ALEN);
@@ -2684,11 +2682,10 @@ prism2_ioctl_set_generic_element(struct 
                return -EINVAL;
 
        alen = sizeof(*attach) + len;
-       attach = kmalloc(alen, GFP_KERNEL);
+       attach = kzalloc(alen, GFP_KERNEL);
        if (attach == NULL)
                return -ENOMEM;
 
-       memset(attach, 0, alen);
 #define WLAN_FC_TYPE_MGMT 0
 #define WLAN_FC_STYPE_ASSOC_REQ 0
 #define WLAN_FC_STYPE_REASSOC_REQ 2
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index fbc52b6..e6cf9df 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -235,12 +235,10 @@ mgt_init(islpci_private *priv)
 {
 	int i;
 
-	priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL);
+	priv->mib = kcalloc(OID_NUM_LAST, sizeof (void *), GFP_KERNEL);
 	if (!priv->mib)
 		return -ENOMEM;
 
-	memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *));
-
 	/* Alloc the cache */
 	for (i = 0; i < OID_NUM_LAST; i++) {
 		if (isl_oid[i].flags & OID_FLAG_CACHED) {
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 8be99eb..77e11dd 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -1673,3 +1673,16 @@ int zd_rfwritev_cr_locked(struct zd_chip
 
 	return 0;
 }
+
+int zd_chip_set_multicast_hash(struct zd_chip *chip,
+	                       struct zd_mc_hash *hash)
+{
+	struct zd_ioreq32 ioreqs[] = {
+		{ CR_GROUP_HASH_P1, hash->low },
+		{ CR_GROUP_HASH_P2, hash->high },
+	};
+
+	dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n",
+		ioreqs[0].value, ioreqs[1].value);
+	return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index ca892b9..a4e3cee 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -390,10 +390,19 @@ #define CR_MAC_ADDR_P2			CTL_REG(0x0614)
 #define CR_BSSID_P1			CTL_REG(0x0618)
 #define CR_BSSID_P2			CTL_REG(0x061C)
 #define CR_BCN_PLCP_CFG			CTL_REG(0x0620)
+
+/* Group hash table for filtering incoming packets.
+ *
+ * The group hash table is 64 bit large and split over two parts. The first
+ * part is the lower part. The upper 6 bits of the last byte of the target
+ * address are used as index. Packets are received if the hash table bit is
+ * set. This is used for multicast handling, but for broadcasts (address
+ * ff:ff:ff:ff:ff:ff) the highest bit in the second table must also be set.
+ */
 #define CR_GROUP_HASH_P1		CTL_REG(0x0624)
 #define CR_GROUP_HASH_P2		CTL_REG(0x0628)
-#define CR_RX_TIMEOUT			CTL_REG(0x062C)
 
+#define CR_RX_TIMEOUT			CTL_REG(0x062C)
 /* Basic rates supported by the BSS. When producing ACK or CTS messages, the
  * device will use a rate in this table that is less than or equal to the rate
  * of the incoming frame which prompted the response */
@@ -864,4 +873,36 @@ u8 zd_rx_strength_percent(u8 rssi);
 
 u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
 
+struct zd_mc_hash {
+	u32 low;
+	u32 high;
+};
+
+static inline void zd_mc_clear(struct zd_mc_hash *hash)
+{
+	hash->low = 0;
+	/* The interfaces must always received broadcasts.
+	 * The hash of the broadcast address ff:ff:ff:ff:ff:ff is 63.
+	 */
+	hash->high = 0x80000000;
+}
+
+static inline void zd_mc_add_all(struct zd_mc_hash *hash)
+{
+	hash->low = hash->high = 0xffffffff;
+}
+
+static inline void zd_mc_add_addr(struct zd_mc_hash *hash, u8 *addr)
+{
+	unsigned int i = addr[5] >> 2;
+	if (i < 32) {
+		hash->low |= 1 << i;
+	} else {
+		hash->high |= 1 << (i-32);
+	}
+}
+
+int zd_chip_set_multicast_hash(struct zd_chip *chip,
+	                       struct zd_mc_hash *hash);
+
 #endif /* _ZD_CHIP_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 2696f95..1dd3f76 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -39,6 +39,8 @@ static void housekeeping_init(struct zd_
 static void housekeeping_enable(struct zd_mac *mac);
 static void housekeeping_disable(struct zd_mac *mac);
 
+static void set_multicast_hash_handler(void *mac_ptr);
+
 int zd_mac_init(struct zd_mac *mac,
 	        struct net_device *netdev,
 	        struct usb_interface *intf)
@@ -55,6 +57,8 @@ int zd_mac_init(struct zd_mac *mac,
 	softmac_init(ieee80211_priv(netdev));
 	zd_chip_init(&mac->chip, netdev, intf);
 	housekeeping_init(mac);
+	INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler,
+		  mac);
 	return 0;
 }
 
@@ -136,6 +140,7 @@ out:
 
 void zd_mac_clear(struct zd_mac *mac)
 {
+	flush_workqueue(zd_workqueue);
 	zd_chip_clear(&mac->chip);
 	ZD_ASSERT(!spin_is_locked(&mac->lock));
 	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -256,6 +261,42 @@ int zd_mac_set_mac_address(struct net_de
 	return 0;
 }
 
+static void set_multicast_hash_handler(void *mac_ptr)
+{
+	struct zd_mac *mac = mac_ptr;
+	struct zd_mc_hash hash;
+
+	spin_lock_irq(&mac->lock);
+	hash = mac->multicast_hash;
+	spin_unlock_irq(&mac->lock);
+
+	zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
+void zd_mac_set_multicast_list(struct net_device *dev)
+{
+	struct zd_mc_hash hash;
+	struct zd_mac *mac = zd_netdev_mac(dev);
+	struct dev_mc_list *mc;
+	unsigned long flags;
+
+	if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+		zd_mc_add_all(&hash);
+	} else {
+		zd_mc_clear(&hash);
+		for (mc = dev->mc_list; mc; mc = mc->next) {
+			dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
+				  MAC_ARG(mc->dmi_addr));
+			zd_mc_add_addr(&hash, mc->dmi_addr);
+		}
+	}
+
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->multicast_hash = hash;
+	spin_unlock_irqrestore(&mac->lock, flags);
+	queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+}
+
 int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
 {
 	int r;
@@ -615,6 +656,9 @@ int zd_mac_get_range(struct zd_mac *mac,
 	range->we_version_compiled = WIRELESS_EXT;
 	range->we_version_source = 20;
 
+	range->enc_capa = IW_ENC_CAPA_WPA |  IW_ENC_CAPA_WPA2 |
+			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
 	ZD_ASSERT(!irqs_disabled());
 	spin_lock_irq(&mac->lock);
 	regdomain = mac->regdomain;
@@ -927,7 +971,8 @@ static int is_data_packet_for_us(struct 
 	}
 
 	return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
-	       is_multicast_ether_addr(hdr->addr1) ||
+	       (is_multicast_ether_addr(hdr->addr1) &&
+		memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
 	       (netdev->flags & IFF_PROMISC);
 }
 
@@ -1059,10 +1104,8 @@ int zd_mac_rx(struct zd_mac *mac, const 
 	memcpy(skb_put(skb, length), buffer, length);
 
 	r = ieee80211_rx(ieee, skb, &stats);
-	if (!r) {
-		ZD_ASSERT(in_irq());
-		dev_kfree_skb_irq(skb);
-	}
+	if (!r)
+		dev_kfree_skb_any(skb);
 	return 0;
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 5dcfb25..77f1268 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -133,6 +133,8 @@ struct zd_mac {
 	struct iw_statistics iw_stats;
 
 	struct housekeeping housekeeping;
+	struct work_struct set_multicast_hash_work;
+	struct zd_mc_hash multicast_hash;
 	struct work_struct set_rts_cts_work;
 	struct work_struct set_basic_rates_work;
 
@@ -189,6 +191,7 @@ int zd_mac_init_hw(struct zd_mac *mac, u
 int zd_mac_open(struct net_device *netdev);
 int zd_mac_stop(struct net_device *netdev);
 int zd_mac_set_mac_address(struct net_device *dev, void *p);
+void zd_mac_set_multicast_list(struct net_device *netdev);
 
 int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
 
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 60f1b0f..8bda48d 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -242,7 +242,7 @@ struct net_device *zd_netdev_alloc(struc
 	netdev->open = zd_mac_open;
 	netdev->stop = zd_mac_stop;
 	/* netdev->get_stats = */
-	/* netdev->set_multicast_list = */
+	netdev->set_multicast_list = zd_mac_set_multicast_list;
 	netdev->set_mac_address = zd_mac_set_mac_address;
 	netdev->wireless_handlers = &iw_handler_def;
 	/* netdev->ethtool_ops = */
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index cf51c87..614aa8d 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -427,6 +427,17 @@ ieee80211softmac_handle_assoc_response(s
 	return 0;
 }
 
+void
+ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->associnfo.associating = 1;
+	schedule_work(&mac->associnfo.work);
+	spin_unlock_irqrestore(&mac->lock, flags);
+}
+
 int
 ieee80211softmac_handle_disassoc(struct net_device * dev,
 				 struct ieee80211_disassoc *disassoc)
@@ -445,8 +456,7 @@ ieee80211softmac_handle_disassoc(struct 
 	dprintk(KERN_INFO PFX "got disassoc frame\n");
 	ieee80211softmac_disassoc(mac);
 
-	/* try to reassociate */
-	schedule_work(&mac->associnfo.work);
+	ieee80211softmac_try_reassoc(mac);
 
 	return 0;
 }
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 0612015..ec44900 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -334,6 +334,8 @@ ieee80211softmac_deauth_from_net(struct 
 	/* can't transmit data right now... */
 	netif_carrier_off(mac->dev);
 	spin_unlock_irqrestore(&mac->lock, flags);
+
+	ieee80211softmac_try_reassoc(mac);
 }
 
 /* 
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index 0642e09..3ae894f 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -238,4 +238,6 @@ void ieee80211softmac_call_events_locked
 int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
 	int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
 
+void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
+
 #endif /* IEEE80211SOFTMAC_PRIV_H_ */
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 23068a8..5b7b5b4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -495,7 +495,8 @@ ieee80211softmac_wx_set_mlme(struct net_
 			printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
 			goto out;
 		}
-		return ieee80211softmac_deauth_req(mac, net, reason);
+		err =  ieee80211softmac_deauth_req(mac, net, reason);
+		goto out;
 	case IW_MLME_DISASSOC:
 		ieee80211softmac_send_disassoc_req(mac, reason);
 		mac->associnfo.associated = 0;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-11-15  1:31 ` Please pull 'upstream' " John W. Linville
@ 2006-11-28 19:13   ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-11-28 19:13 UTC (permalink / raw)
  To: jeff; +Cc: netdev

On Tue, Nov 14, 2006 at 08:31:12PM -0500, John W. Linville wrote:
> The following changes since commit 4c5d3c72166676663c3917839a030b86fa758b23:
>   John W. Linville:
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Please ignore this request, in favor of the one to be posted later
today.

-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-11-15  1:29 Please pull 'upstream-fixes' " John W. Linville
@ 2006-11-15  1:31 ` John W. Linville
  2006-11-28 19:13   ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-11-15  1:31 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 4c5d3c72166676663c3917839a030b86fa758b23:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

John W. Linville:
      prism54: correct overly aggressive check of return from pci_set_mwi

Larry Finger:
      bcm43xx: correct "Move IV/ICV stripping into ieee80211_rx"

 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c   |    1 +
 drivers/net/wireless/prism54/islpci_hotplug.c |    4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index a957bc8..3e24626 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -543,6 +543,7 @@ int bcm43xx_rx(struct bcm43xx_private *b
 		break;
 	}
 
+	frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
 	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
 	case IEEE80211_FTYPE_MGMT:
 		ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index e0bca3a..58257b4 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -170,8 +170,8 @@ #endif
 	pci_set_master(pdev);
 
 	/* enable MWI */
-	if (pci_set_mwi(pdev))
-		goto do_pci_release_regions;
+	if (!pci_set_mwi(pdev))
+		printk(KERN_INFO "%s: pci_set_mwi(pdev) succeeded\n", DRV_NAME);
 
 	/* setup the network device interface and its structure */
 	if (!(ndev = islpci_setup(pdev))) {
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-11-08  4:59 ` Please pull 'upstream' " John W. Linville
  2006-11-08 19:48   ` John W. Linville
@ 2006-11-14 15:29   ` Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-11-14 15:29 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit d4f748365129ccfc9dadf6fb14331e45e33cc4ed:
>   John W. Linville:
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> John W. Linville:
>       wireless: clean-up some "check return code" warnings
> 
> Larry Finger:
>       bcm43xx: remove badness variable and related routine
>       bcm43xx: Remove useless core enable/disable messages
>       ieee80211softmac: fix verbosity when debug disabled
> 
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c   |   56 +++++--------------------
>  drivers/net/wireless/hostap/hostap_pci.c      |    8 +++-
>  drivers/net/wireless/ipw2100.c                |    8 +++-
>  drivers/net/wireless/ipw2200.c                |    8 +++-
>  drivers/net/wireless/orinoco_pci.h            |    7 +++
>  drivers/net/wireless/prism54/islpci_hotplug.c |   20 +++++++--
>  net/ieee80211/softmac/ieee80211softmac_auth.c |   10 ++--
>  7 files changed, 60 insertions(+), 57 deletions(-)

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-11-08  4:59 ` Please pull 'upstream' " John W. Linville
@ 2006-11-08 19:48   ` John W. Linville
  2006-11-14 15:29   ` Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-11-08 19:48 UTC (permalink / raw)
  To: jeff; +Cc: netdev

On Tue, Nov 07, 2006 at 11:59:27PM -0500, John W. Linville wrote:
> The following changes since commit d4f748365129ccfc9dadf6fb14331e45e33cc4ed:
>   John W. Linville:
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> John W. Linville:
>       wireless: clean-up some "check return code" warnings

Jeff, hold-off on this pull.  You can still go ahead and pull the
'upstream-fixes' branch at your pleasure.

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-11-08  4:58 Please pull 'upstream-fixes' " John W. Linville
@ 2006-11-08  4:59 ` John W. Linville
  2006-11-08 19:48   ` John W. Linville
  2006-11-14 15:29   ` Jeff Garzik
  0 siblings, 2 replies; 108+ messages in thread
From: John W. Linville @ 2006-11-08  4:59 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit d4f748365129ccfc9dadf6fb14331e45e33cc4ed:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

John W. Linville:
      wireless: clean-up some "check return code" warnings

Larry Finger:
      bcm43xx: remove badness variable and related routine
      bcm43xx: Remove useless core enable/disable messages
      ieee80211softmac: fix verbosity when debug disabled

 drivers/net/wireless/bcm43xx/bcm43xx_main.c   |   56 +++++--------------------
 drivers/net/wireless/hostap/hostap_pci.c      |    8 +++-
 drivers/net/wireless/ipw2100.c                |    8 +++-
 drivers/net/wireless/ipw2200.c                |    8 +++-
 drivers/net/wireless/orinoco_pci.h            |    7 +++
 drivers/net/wireless/prism54/islpci_hotplug.c |   20 +++++++--
 net/ieee80211/softmac/ieee80211softmac_auth.c |   10 ++--
 7 files changed, 60 insertions(+), 57 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index c6bd868..60a9745 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2684,14 +2684,10 @@ #endif
 		bcm->chip_id, bcm->chip_rev);
 	dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count);
 	if (bcm->core_chipcommon.available) {
-		dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
-			core_id, core_rev, core_vendor,
-			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled");
-	}
-
-	if (bcm->core_chipcommon.available)
+		dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x\n",
+			core_id, core_rev, core_vendor);
 		current_core = 1;
-	else
+	} else
 		current_core = 0;
 	for ( ; current_core < core_count; current_core++) {
 		struct bcm43xx_coreinfo *core;
@@ -2709,9 +2705,8 @@ #endif
 		core_rev = (sb_id_hi & 0xF);
 		core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
 
-		dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n",
-			current_core, core_id, core_rev, core_vendor,
-			bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" );
+		dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x\n",
+			current_core, core_id, core_rev, core_vendor);
 
 		core = NULL;
 		switch (core_id) {
@@ -3209,55 +3204,27 @@ static void bcm43xx_periodic_every15sec(
 
 static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	unsigned int state;
-
-	state = bcm->periodic_state;
-	if (state % 8 == 0)
+	if (bcm->periodic_state % 8 == 0)
 		bcm43xx_periodic_every120sec(bcm);
-	if (state % 4 == 0)
+	if (bcm->periodic_state % 4 == 0)
 		bcm43xx_periodic_every60sec(bcm);
-	if (state % 2 == 0)
+	if (bcm->periodic_state % 2 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	if (state % 1 == 0)
-		bcm43xx_periodic_every15sec(bcm);
-	bcm->periodic_state = state + 1;
+	bcm43xx_periodic_every15sec(bcm);
 
 	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
 }
 
-/* Estimate a "Badness" value based on the periodic work
- * state-machine state. "Badness" is worse (bigger), if the
- * periodic work will take longer.
- */
-static int estimate_periodic_work_badness(unsigned int state)
-{
-	int badness = 0;
-
-	if (state % 8 == 0) /* every 120 sec */
-		badness += 10;
-	if (state % 4 == 0) /* every 60 sec */
-		badness += 5;
-	if (state % 2 == 0) /* every 30 sec */
-		badness += 1;
-	if (state % 1 == 0) /* every 15 sec */
-		badness += 1;
-
-#define BADNESS_LIMIT	4
-	return badness;
-}
-
 static void bcm43xx_periodic_work_handler(void *d)
 {
 	struct bcm43xx_private *bcm = d;
 	struct net_device *net_dev = bcm->net_dev;
 	unsigned long flags;
 	u32 savedirqs = 0;
-	int badness;
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
-	badness = estimate_periodic_work_badness(bcm->periodic_state);
-	if (badness > BADNESS_LIMIT) {
+	if (unlikely(bcm->periodic_state % 4 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
@@ -3289,7 +3256,7 @@ static void bcm43xx_periodic_work_handle
 
 	do_periodic_work(bcm);
 
-	if (badness > BADNESS_LIMIT) {
+	if (unlikely(bcm->periodic_state % 4 == 0)) {
 		spin_lock_irqsave(&bcm->irq_lock, flags);
 		tasklet_enable(&bcm->isr_tasklet);
 		bcm43xx_interrupt_enable(bcm, savedirqs);
@@ -3300,6 +3267,7 @@ static void bcm43xx_periodic_work_handle
 		net_dev->trans_start = orig_trans_start;
 	}
 	mmiowb();
+	bcm->periodic_state++;
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	mutex_unlock(&bcm->mutex);
 }
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index c2fa011..d1de976 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -425,8 +425,14 @@ static int prism2_pci_suspend(struct pci
 static int prism2_pci_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
+	int err;
 
-	pci_enable_device(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
+		       dev->name);
+		return err;
+	}
 	pci_restore_state(pdev);
 	prism2_hw_config(dev, 0);
 	if (netif_running(dev)) {
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 4e4eaa2..2324e06 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -6423,6 +6423,7 @@ static int ipw2100_resume(struct pci_dev
 {
 	struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
 	struct net_device *dev = priv->net_dev;
+	int err;
 	u32 val;
 
 	if (IPW2100_PM_DISABLED)
@@ -6433,7 +6434,12 @@ static int ipw2100_resume(struct pci_dev
 	IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
 
 	pci_set_power_state(pci_dev, PCI_D0);
-	pci_enable_device(pci_dev);
+	err = pci_enable_device(pci_dev);
+	if (err) {
+		printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
+		       dev->name);
+		return err;
+	}
 	pci_restore_state(pci_dev);
 
 	/*
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 1f74281..a60714e 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -11727,12 +11727,18 @@ static int ipw_pci_resume(struct pci_dev
 {
 	struct ipw_priv *priv = pci_get_drvdata(pdev);
 	struct net_device *dev = priv->net_dev;
+	int err;
 	u32 val;
 
 	printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
 
 	pci_set_power_state(pdev, PCI_D0);
-	pci_enable_device(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
+		       dev->name);
+		return err;
+	}
 	pci_restore_state(pdev);
 
 	/*
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h
index be1abea..f4e5e06 100644
--- a/drivers/net/wireless/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco_pci.h
@@ -60,7 +60,12 @@ static int orinoco_pci_resume(struct pci
 	int err;
 
 	pci_set_power_state(pdev, 0);
-	pci_enable_device(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
+		       dev->name);
+		return err;
+	}
 	pci_restore_state(pdev);
 
 	err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index f6354b1..e0bca3a 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -170,14 +170,15 @@ #endif
 	pci_set_master(pdev);
 
 	/* enable MWI */
-	pci_set_mwi(pdev);
+	if (pci_set_mwi(pdev))
+		goto do_pci_release_regions;
 
 	/* setup the network device interface and its structure */
 	if (!(ndev = islpci_setup(pdev))) {
 		/* error configuring the driver as a network device */
 		printk(KERN_ERR "%s: could not configure network device\n",
 		       DRV_NAME);
-		goto do_pci_release_regions;
+		goto do_pci_clear_mwi;
 	}
 
 	priv = netdev_priv(ndev);
@@ -207,6 +208,8 @@ #endif
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(ndev);
 	priv = NULL;
+      do_pci_clear_mwi:
+	pci_clear_mwi(pdev);
       do_pci_release_regions:
 	pci_release_regions(pdev);
       do_pci_disable_device:
@@ -254,6 +257,8 @@ prism54_remove(struct pci_dev *pdev)
 	free_netdev(ndev);
 	priv = NULL;
 
+	pci_clear_mwi(pdev);
+
 	pci_release_regions(pdev);
 
 	pci_disable_device(pdev);
@@ -287,12 +292,19 @@ prism54_resume(struct pci_dev *pdev)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
 	islpci_private *priv = ndev ? netdev_priv(ndev) : NULL;
-	BUG_ON(!priv);
+	int err;
 
-	pci_enable_device(pdev);
+	BUG_ON(!priv);
 
 	printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
 
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
+		       ndev->name);
+		return err;
+	}
+
 	pci_restore_state(pdev);
 
 	/* alright let's go into the PREBOOT state */
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 4cef39e..95e5287 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -158,7 +158,7 @@ ieee80211softmac_auth_resp(struct net_de
 	/* Make sure that we've got an auth queue item for this request */
 	if(aq == NULL)
 	{
-		printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
+		dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
 		/* Error #? */
 		return -1;
 	}			
@@ -166,7 +166,7 @@ ieee80211softmac_auth_resp(struct net_de
 	/* Check for out of order authentication */
 	if(!net->authenticating)
 	{
-		printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
+		dprintkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
 		return -1;
 	}
 
@@ -342,7 +342,7 @@ ieee80211softmac_deauth_req(struct ieee8
 	/* Make sure the network is authenticated */
 	if (!net->authenticated)
 	{
-		printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
+		dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
 		/* Error okay? */
 		return -EPERM;
 	}
@@ -376,7 +376,7 @@ ieee80211softmac_deauth_resp(struct net_
 	net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
 	
 	if (net == NULL) {
-		printkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n",
+		dprintkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n",
 			MAC_ARG(deauth->header.addr2));
 		return 0;
 	}
@@ -384,7 +384,7 @@ ieee80211softmac_deauth_resp(struct net_
 	/* Make sure the network is authenticated */
 	if(!net->authenticated)
 	{
-		printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
+		dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
 		/* Error okay? */
 		return -EPERM;
 	}
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-10-17 21:35 ` Please pull 'upstream' " John W. Linville
@ 2006-10-21 18:22   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-10-21 18:22 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit 41072a1be57f63bf83afc31c44d72de018d800fa:
>   John W. Linville:
>         zd1211rw: fix build-break caused by association race fix
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Alexey Dobriyan:
>       prism54: use BUILD_BUG_ON
> 
> Daniel Drake:
>       zd1211rw: Add 3 more device IDs
>       ieee80211: Move IV/ICV stripping into ieee80211_rx
> 
> Dmitry Torokhov:
>       atmel: save on array initialization
>       atmel: use ARRAY_SIZE()
>       atmel: whitespace cleanup
>       prism54: fix potential race in reset scheduling
>       prism54: whitespace cleanup
> 
> Holden Karau:
>       atmel: output signal strength information
> 
> Larry Finger:
>       bcm43xx: output proper link quality with scans
>       ieee80211: Drop and count duplicate data frames to remove 'replay detected' log messages
> 
> matthieu castet:
>       ieee80211: allow mtu bigger than 1500
> 
> Stefano Brivio:
>       bcm43xx: add PCI-E code

pulled


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-10-17 21:34 Please pull 'upstream-fixes' " John W. Linville
@ 2006-10-17 21:35 ` John W. Linville
  2006-10-21 18:22   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-10-17 21:35 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 41072a1be57f63bf83afc31c44d72de018d800fa:
  John W. Linville:
        zd1211rw: fix build-break caused by association race fix

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Alexey Dobriyan:
      prism54: use BUILD_BUG_ON

Daniel Drake:
      zd1211rw: Add 3 more device IDs
      ieee80211: Move IV/ICV stripping into ieee80211_rx

Dmitry Torokhov:
      atmel: save on array initialization
      atmel: use ARRAY_SIZE()
      atmel: whitespace cleanup
      prism54: fix potential race in reset scheduling
      prism54: whitespace cleanup

Holden Karau:
      atmel: output signal strength information

Larry Finger:
      bcm43xx: output proper link quality with scans
      ieee80211: Drop and count duplicate data frames to remove 'replay detected' log messages

matthieu castet:
      ieee80211: allow mtu bigger than 1500

Stefano Brivio:
      bcm43xx: add PCI-E code

 drivers/net/wireless/atmel.c                  |   36 ++++--
 drivers/net/wireless/atmel_cs.c               |   74 ++++++-------
 drivers/net/wireless/atmel_pci.c              |   10 +-
 drivers/net/wireless/bcm43xx/bcm43xx.h        |   32 ++++++
 drivers/net/wireless/bcm43xx/bcm43xx_main.c   |  145 +++++++++++++++++++------
 drivers/net/wireless/bcm43xx/bcm43xx_power.c  |   28 ++++-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c     |    4 -
 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c   |   19 ---
 drivers/net/wireless/prism54/isl_38xx.c       |   17 +--
 drivers/net/wireless/prism54/isl_38xx.h       |    7 +
 drivers/net/wireless/prism54/isl_ioctl.c      |   61 +++++------
 drivers/net/wireless/prism54/isl_ioctl.h      |    1 
 drivers/net/wireless/prism54/isl_oid.h        |   48 ++++----
 drivers/net/wireless/prism54/islpci_dev.c     |   13 +-
 drivers/net/wireless/prism54/islpci_dev.h     |   11 +-
 drivers/net/wireless/prism54/islpci_eth.c     |   30 +++--
 drivers/net/wireless/prism54/islpci_eth.h     |    1 
 drivers/net/wireless/prism54/islpci_hotplug.c |   23 ++--
 drivers/net/wireless/prism54/islpci_mgt.c     |    3 -
 drivers/net/wireless/prism54/islpci_mgt.h     |    5 -
 drivers/net/wireless/prism54/oid_mgt.c        |    6 +
 drivers/net/wireless/prism54/prismcompat.h    |    4 -
 drivers/net/wireless/zd1211rw/zd_usb.c        |    3 +
 include/net/ieee80211.h                       |    6 +
 net/ieee80211/ieee80211_module.c              |    9 ++
 net/ieee80211/ieee80211_rx.c                  |   61 +++++++++--
 26 files changed, 409 insertions(+), 248 deletions(-)

diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 0c07b8b..10bcb48 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -595,7 +595,7 @@ static void atmel_join_bss(struct atmel_
 static void atmel_smooth_qual(struct atmel_private *priv);
 static void atmel_writeAR(struct net_device *dev, u16 data);
 static int probe_atmel_card(struct net_device *dev);
-static int reset_atmel_card(struct net_device *dev );
+static int reset_atmel_card(struct net_device *dev);
 static void atmel_enter_state(struct atmel_private *priv, int new_state);
 int atmel_open (struct net_device *dev);
 
@@ -784,11 +784,11 @@ static void tx_update_descriptor(struct 
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
+	static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 	struct atmel_private *priv = netdev_priv(dev);
 	struct ieee80211_hdr_4addr header;
 	unsigned long flags;
 	u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-	u8 SNAP_RFC1024[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
 
 	if (priv->card && priv->present_callback &&
 	    !(*priv->present_callback)(priv->card)) {
@@ -1193,7 +1193,7 @@ static irqreturn_t service_interrupt(int
 
 		atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */
 
-		for (i = 0; i < sizeof(irq_order)/sizeof(u8); i++)
+		for (i = 0; i < ARRAY_SIZE(irq_order); i++)
 			if (isr & irq_order[i])
 				break;
 
@@ -1345,10 +1345,10 @@ int atmel_open(struct net_device *dev)
 		atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain);
 	} else {
 		priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS);
-		for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(channel_table); i++)
 			if (priv->reg_domain == channel_table[i].reg_domain)
 				break;
-		if (i == sizeof(channel_table)/sizeof(channel_table[0])) {
+		if (i == ARRAY_SIZE(channel_table)) {
 			priv->reg_domain = REG_DOMAIN_MKK1;
 			printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name);
 		}
@@ -1393,7 +1393,7 @@ static int atmel_validate_channel(struct
 	   else return suitable default channel */
 	int i;
 
-	for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(channel_table); i++)
 		if (priv->reg_domain == channel_table[i].reg_domain) {
 			if (channel >= channel_table[i].min &&
 			    channel <= channel_table[i].max)
@@ -1437,7 +1437,7 @@ static int atmel_proc_output (char *buf,
 		}
 
 		r = "<unknown>";
-		for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(channel_table); i++)
 			if (priv->reg_domain == channel_table[i].reg_domain)
 				r = channel_table[i].name;
 
@@ -1736,7 +1736,7 @@ static int atmel_set_encode(struct net_d
 				/* Disable the key */
 				priv->wep_key_len[index] = 0;
 		/* Check if the key is not marked as invalid */
-		if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
+		if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
 			/* Cleanup */
 			memset(priv->wep_keys[index], 0, 13);
 			/* Copy the key in the driver */
@@ -1907,7 +1907,7 @@ static int atmel_get_encodeext(struct ne
 
 	encoding->flags = idx + 1;
 	memset(ext, 0, sizeof(*ext));
-	
+
 	if (!priv->wep_is_on) {
 		ext->alg = IW_ENCODE_ALG_NONE;
 		ext->key_len = 0;
@@ -2343,6 +2343,14 @@ static int atmel_get_scan(struct net_dev
 		iwe.u.freq.e = 0;
 		current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN);
 
+		/* Add quality statistics */
+		iwe.cmd = IWEVQUAL;
+		iwe.u.qual.level = priv->BSSinfo[i].RSSI;
+		iwe.u.qual.qual  = iwe.u.qual.level;
+		/* iwe.u.qual.noise  = SOMETHING */
+		current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA , &iwe, IW_EV_QUAL_LEN);
+
+
 		iwe.cmd = SIOCGIWENCODE;
 		if (priv->BSSinfo[i].UsingWEP)
 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
@@ -2373,7 +2381,7 @@ static int atmel_get_range(struct net_de
 	range->min_nwid = 0x0000;
 	range->max_nwid = 0x0000;
 	range->num_channels = 0;
-	for (j = 0; j < sizeof(channel_table)/sizeof(channel_table[0]); j++)
+	for (j = 0; j < ARRAY_SIZE(channel_table); j++)
 		if (priv->reg_domain == channel_table[j].reg_domain) {
 			range->num_channels = channel_table[j].max - channel_table[j].min + 1;
 			break;
@@ -2579,9 +2587,9 @@ static const struct iw_priv_args atmel_p
 
 static const struct iw_handler_def atmel_handler_def =
 {
-	.num_standard	= sizeof(atmel_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(atmel_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(atmel_handler),
+	.num_private	= ARRAY_SIZE(atmel_private_handler),
+	.num_private_args = ARRAY_SIZE(atmel_private_args),
 	.standard	= (iw_handler *) atmel_handler,
 	.private	= (iw_handler *) atmel_private_handler,
 	.private_args	= (struct iw_priv_args *) atmel_private_args,
@@ -2645,7 +2653,7 @@ static int atmel_ioctl(struct net_device
 
 		domain[REGDOMAINSZ] = 0;
 		rc = -EINVAL;
-		for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) {
+		for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
 			/* strcasecmp doesn't exist in the library */
 			char *a = channel_table[i].name;
 			char *b = domain;
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 7856640..5c41098 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -5,12 +5,12 @@
         Copyright 2000-2001 ATMEL Corporation.
         Copyright 2003 Simon Kelley.
 
-    This code was developed from version 2.1.1 of the Atmel drivers, 
-    released by Atmel corp. under the GPL in December 2002. It also 
-    includes code from the Linux aironet drivers (C) Benjamin Reed, 
-    and the Linux PCMCIA package, (C) David Hinds. 
+    This code was developed from version 2.1.1 of the Atmel drivers,
+    released by Atmel corp. under the GPL in December 2002. It also
+    includes code from the Linux aironet drivers (C) Benjamin Reed,
+    and the Linux PCMCIA package, (C) David Hinds.
 
-    For all queries about this code, please contact the current author, 
+    For all queries about this code, please contact the current author,
     Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
 
     This program is free software; you can redistribute it and/or modify
@@ -87,7 +87,7 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x 
    event is received.  The config() and release() entry points are
    used to configure or release a socket, in response to card
    insertion and ejection events.  They are invoked from the atmel_cs
-   event handler. 
+   event handler.
 */
 
 static int atmel_config(struct pcmcia_device *link);
@@ -133,22 +133,22 @@ static void atmel_detach(struct pcmcia_d
    device IO routines can use a flag like this to throttle IO to a
    card that is not ready to accept it.
 */
-   
+
 typedef struct local_info_t {
 	dev_node_t	node;
 	struct net_device *eth_dev;
 } local_info_t;
 
 /*======================================================================
-  
+
   atmel_attach() creates an "instance" of the driver, allocating
   local data structures for one device.  The device is registered
   with Card Services.
-  
+
   The dev_link structure is initialized, but we don't actually
   configure the card at this point -- we wait until we receive a
   card insertion event.
-  
+
   ======================================================================*/
 
 static int atmel_probe(struct pcmcia_device *p_dev)
@@ -184,12 +184,12 @@ static int atmel_probe(struct pcmcia_dev
 } /* atmel_attach */
 
 /*======================================================================
-  
+
   This deletes a driver "instance".  The device is de-registered
   with Card Services.  If it has been released, all local data
   structures are freed.  Otherwise, the structures will be freed
   when the device is released.
-  
+
   ======================================================================*/
 
 static void atmel_detach(struct pcmcia_device *link)
@@ -202,11 +202,11 @@ static void atmel_detach(struct pcmcia_d
 }
 
 /*======================================================================
-  
+
   atmel_config() is scheduled to run after a CARD_INSERTION event
   is received, to configure the PCMCIA socket, and to make the
   device available to the system.
-  
+
   ======================================================================*/
 
 #define CS_CHECK(fn, ret) \
@@ -237,12 +237,12 @@ static int atmel_config(struct pcmcia_de
 	did = handle_to_dev(link).driver_data;
 
 	DEBUG(0, "atmel_config(0x%p)\n", link);
-	
+
 	tuple.Attributes = 0;
 	tuple.TupleData = buf;
 	tuple.TupleDataMax = sizeof(buf);
 	tuple.TupleOffset = 0;
-	
+
 	/*
 	  This reads the card's CONFIG tuple to find its configuration
 	  registers.
@@ -258,7 +258,7 @@ static int atmel_config(struct pcmcia_de
 	  In this loop, we scan the CIS for configuration table entries,
 	  each of which describes a valid card configuration, including
 	  voltage, IO window, memory window, and interrupt settings.
-	  
+
 	  We make no assumptions about the card to be configured: we use
 	  just the information available in the CIS.  In an ideal world,
 	  this would work for any PCMCIA card, but it requires a complete
@@ -274,17 +274,17 @@ static int atmel_config(struct pcmcia_de
 		if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
 				pcmcia_parse_tuple(link, &tuple, &parse) != 0)
 			goto next_entry;
-		
+
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
 		if (cfg->index == 0) goto next_entry;
 		link->conf.ConfigIndex = cfg->index;
-		
+
 		/* Does this card need audio output? */
 		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
 			link->conf.Attributes |= CONF_ENABLE_SPKR;
 			link->conf.Status = CCSR_AUDIO_ENA;
 		}
-		
+
 		/* Use power settings for Vcc and Vpp if present */
 		/*  Note that the CIS values need to be rescaled */
 		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
@@ -293,11 +293,11 @@ static int atmel_config(struct pcmcia_de
 		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
 			link->conf.Vpp =
 				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-		
+
 		/* Do we need to allocate an interrupt? */
 		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
 			link->conf.Attributes |= CONF_ENABLE_IRQ;
-		
+
 		/* IO window settings */
 		link->io.NumPorts1 = link->io.NumPorts2 = 0;
 		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
@@ -315,18 +315,18 @@ static int atmel_config(struct pcmcia_de
 				link->io.NumPorts2 = io->win[1].len;
 			}
 		}
-		
+
 		/* This reserves IO space but doesn't actually enable it */
 		if (pcmcia_request_io(link, &link->io) != 0)
 			goto next_entry;
 
 		/* If we got this far, we're cool! */
 		break;
-		
+
 	next_entry:
 		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
 	}
-	
+
 	/*
 	  Allocate an interrupt line.  Note that this does not assign a
 	  handler to the interrupt, unless the 'Handler' member of the
@@ -334,31 +334,31 @@ static int atmel_config(struct pcmcia_de
 	*/
 	if (link->conf.Attributes & CONF_ENABLE_IRQ)
 		CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-	
+
 	/*
 	  This actually configures the PCMCIA socket -- setting up
 	  the I/O windows and the interrupt mapping, and putting the
 	  card and host interface into "Memory and IO" mode.
 	*/
 	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
-	
+
 	if (link->irq.AssignedIRQ == 0) {
-		printk(KERN_ALERT 
+		printk(KERN_ALERT
 		       "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config.");
 		goto cs_failed;
 	}
-       
-	((local_info_t*)link->priv)->eth_dev = 
+
+	((local_info_t*)link->priv)->eth_dev =
 		init_atmel_card(link->irq.AssignedIRQ,
 				link->io.BasePort1,
 				did ? did->driver_info : ATMEL_FW_TYPE_NONE,
 				&handle_to_dev(link),
-				card_present, 
+				card_present,
 				link);
-	if (!((local_info_t*)link->priv)->eth_dev) 
+	if (!((local_info_t*)link->priv)->eth_dev)
 			goto cs_failed;
-	
-	
+
+
 	/*
 	  At this point, the dev_node_t structure(s) need to be
 	  initialized and arranged in a linked list at link->dev_node.
@@ -376,11 +376,11 @@ static int atmel_config(struct pcmcia_de
 }
 
 /*======================================================================
-  
+
   After a card is removed, atmel_release() will unregister the
   device, and release the PCMCIA configuration.  If the device is
   still open, this will be postponed until it is closed.
-  
+
   ======================================================================*/
 
 static void atmel_release(struct pcmcia_device *link)
@@ -517,7 +517,7 @@ static void atmel_cs_cleanup(void)
     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.    
+    POSSIBILITY OF SUCH DAMAGE.
 */
 
 module_init(atmel_cs_init);
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
index 3bfa791..92f87fb 100644
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -53,18 +53,18 @@ static int __devinit atmel_pci_probe(str
 				     const struct pci_device_id *pent)
 {
 	struct net_device *dev;
-		
+
 	if (pci_enable_device(pdev))
 		return -ENODEV;
-	
+
 	pci_set_master(pdev);
-	
-	dev = init_atmel_card(pdev->irq, pdev->resource[1].start, 
+
+	dev = init_atmel_card(pdev->irq, pdev->resource[1].start,
 			      ATMEL_FW_TYPE_506,
 			      &pdev->dev, NULL, NULL);
 	if (!dev)
 		return -ENODEV;
-	
+
 	pci_set_drvdata(pdev, dev);
 	return 0;
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index d6a8bf0..94dfb92 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -159,6 +159,7 @@ #define BCM43xx_MACFILTER_ASSOC		0x0003
 
 /* Chipcommon registers. */
 #define BCM43xx_CHIPCOMMON_CAPABILITIES 	0x04
+#define BCM43xx_CHIPCOMMON_CTL			0x28
 #define BCM43xx_CHIPCOMMON_PLLONDELAY		0xB0
 #define BCM43xx_CHIPCOMMON_FREFSELDELAY		0xB4
 #define BCM43xx_CHIPCOMMON_SLOWCLKCTL		0xB8
@@ -172,6 +173,33 @@ #define BCM43xx_PCICORE_SBTOPCI2	0x108
 /* SBTOPCI2 values. */
 #define BCM43xx_SBTOPCI2_PREFETCH	0x4
 #define BCM43xx_SBTOPCI2_BURST		0x8
+#define BCM43xx_SBTOPCI2_MEMREAD_MULTI	0x20
+
+/* PCI-E core registers. */
+#define BCM43xx_PCIECORE_REG_ADDR      0x0130
+#define BCM43xx_PCIECORE_REG_DATA      0x0134
+#define BCM43xx_PCIECORE_MDIO_CTL      0x0128
+#define BCM43xx_PCIECORE_MDIO_DATA     0x012C
+
+/* PCI-E registers. */
+#define BCM43xx_PCIE_TLP_WORKAROUND    0x0004
+#define BCM43xx_PCIE_DLLP_LINKCTL      0x0100
+
+/* PCI-E MDIO bits. */
+#define BCM43xx_PCIE_MDIO_ST   0x40000000
+#define BCM43xx_PCIE_MDIO_WT   0x10000000
+#define BCM43xx_PCIE_MDIO_DEV  22
+#define BCM43xx_PCIE_MDIO_REG  18
+#define BCM43xx_PCIE_MDIO_TA   0x00020000
+#define BCM43xx_PCIE_MDIO_TC   0x0100
+
+/* MDIO devices. */
+#define BCM43xx_MDIO_SERDES_RX	0x1F
+
+/* SERDES RX registers. */
+#define BCM43xx_SERDES_RXTIMER	0x2
+#define BCM43xx_SERDES_CDR	0x6
+#define BCM43xx_SERDES_CDR_BW	0x7
 
 /* Chipcommon capabilities. */
 #define BCM43xx_CAPABILITIES_PCTL		0x00040000
@@ -221,6 +249,7 @@ #define BCM43xx_COREID_USB11_DEV        
 #define BCM43xx_COREID_USB20_HOST       0x819
 #define BCM43xx_COREID_USB20_DEV        0x81a
 #define BCM43xx_COREID_SDIO_HOST        0x81b
+#define BCM43xx_COREID_PCIE		0x820
 
 /* Core Information Registers */
 #define BCM43xx_CIR_BASE		0xf00
@@ -365,6 +394,9 @@ #define BCM43xx_DEFAULT_RTS_THRESHOLD		B
 #define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT	7
 #define BCM43xx_DEFAULT_LONG_RETRY_LIMIT	4
 
+/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
+#define RX_RSSI_MAX				60
+
 /* Max size of a security key */
 #define BCM43xx_SEC_KEYSIZE			16
 /* Security algorithms. */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index a94c6d8..78db999 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -130,6 +130,10 @@ #endif /* CONFIG_BCM43XX_DEBUG*/
 	{ PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 4307 802.11b */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4311 802.11(a)/b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4312 802.11a/b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 4318 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 4319 802.11a/b/g */
@@ -2583,8 +2587,9 @@ static int bcm43xx_probe_cores(struct bc
 	/* fetch sb_id_hi from core information registers */
 	sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI);
 
-	core_id = (sb_id_hi & 0xFFF0) >> 4;
-	core_rev = (sb_id_hi & 0xF);
+	core_id = (sb_id_hi & 0x8FF0) >> 4;
+	core_rev = (sb_id_hi & 0x7000) >> 8;
+	core_rev |= (sb_id_hi & 0xF);
 	core_vendor = (sb_id_hi & 0xFFFF0000) >> 16;
 
 	/* if present, chipcommon is always core 0; read the chipid from it */
@@ -2694,6 +2699,7 @@ #endif
 		core = NULL;
 		switch (core_id) {
 		case BCM43xx_COREID_PCI:
+		case BCM43xx_COREID_PCIE:
 			core = &bcm->core_pci;
 			if (core->available) {
 				printk(KERN_WARNING PFX "Multiple PCI cores found.\n");
@@ -2732,12 +2738,12 @@ #endif
 			case 6:
 			case 7:
 			case 9:
+			case 10:
 				break;
 			default:
-				printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n",
+				printk(KERN_WARNING PFX
+				       "Unsupported 80211 core revision %u\n",
 				       core_rev);
-				err = -ENODEV;
-				goto out;
 			}
 			bcm->nr_80211_available++;
 			core->priv = ext_80211;
@@ -2851,16 +2857,11 @@ static int bcm43xx_wireless_core_init(st
 	u32 sbimconfiglow;
 	u8 limit;
 
-	if (bcm->chip_rev < 5) {
+	if (bcm->core_pci.rev <= 5 && bcm->core_pci.id != BCM43xx_COREID_PCIE) {
 		sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
 		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
 		sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
-		if (bcm->bustype == BCM43xx_BUSTYPE_PCI)
-			sbimconfiglow |= 0x32;
-		else if (bcm->bustype == BCM43xx_BUSTYPE_SB)
-			sbimconfiglow |= 0x53;
-		else
-			assert(0);
+		sbimconfiglow |= 0x32;
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow);
 	}
 
@@ -2987,22 +2988,64 @@ static void bcm43xx_pcicore_broadcast_va
 
 static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm)
 {
-	int err;
-	struct bcm43xx_coreinfo *old_core;
+	int err = 0;
 
-	old_core = bcm->current_core;
-	err = bcm43xx_switch_core(bcm, &bcm->core_pci);
-	if (err)
-		goto out;
+	bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 
-	bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+	if (bcm->core_chipcommon.available) {
+		err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
+		if (err)
+			goto out;
+
+		bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+		/* this function is always called when a PCI core is mapped */
+		err = bcm43xx_switch_core(bcm, &bcm->core_pci);
+		if (err)
+			goto out;
+	} else
+		bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000);
+
+	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 
-	bcm43xx_switch_core(bcm, old_core);
-	assert(err == 0);
 out:
 	return err;
 }
 
+static u32 bcm43xx_pcie_reg_read(struct bcm43xx_private *bcm, u32 address)
+{
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
+	return bcm43xx_read32(bcm, BCM43xx_PCIECORE_REG_DATA);
+}
+
+static void bcm43xx_pcie_reg_write(struct bcm43xx_private *bcm, u32 address,
+				    u32 data)
+{
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_ADDR, address);
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_REG_DATA, data);
+}
+
+static void bcm43xx_pcie_mdio_write(struct bcm43xx_private *bcm, u8 dev, u8 reg,
+				    u16 data)
+{
+	int i;
+
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0x0082);
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_DATA, BCM43xx_PCIE_MDIO_ST |
+			BCM43xx_PCIE_MDIO_WT | (dev << BCM43xx_PCIE_MDIO_DEV) |
+			(reg << BCM43xx_PCIE_MDIO_REG) | BCM43xx_PCIE_MDIO_TA |
+			data);
+	udelay(10);
+
+	for (i = 0; i < 10; i++) {
+		if (bcm43xx_read32(bcm, BCM43xx_PCIECORE_MDIO_CTL) &
+		    BCM43xx_PCIE_MDIO_TC)
+			break;
+		msleep(1);
+	}
+	bcm43xx_write32(bcm, BCM43xx_PCIECORE_MDIO_CTL, 0);
+}
+
 /* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable.
  * To enable core 0, pass a core_mask of 1<<0
  */
@@ -3022,7 +3065,8 @@ static int bcm43xx_setup_backplane_pci_c
 	if (err)
 		goto out;
 
-	if (bcm->core_pci.rev < 6) {
+	if (bcm->current_core->rev < 6 ||
+		bcm->current_core->id == BCM43xx_COREID_PCI) {
 		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC);
 		value |= (1 << backplane_flag_nr);
 		bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value);
@@ -3040,21 +3084,46 @@ static int bcm43xx_setup_backplane_pci_c
 		}
 	}
 
-	value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
-	value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
-	bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
-
-	if (bcm->core_pci.rev < 5) {
-		value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
-		value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
-			 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
-		value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
-			 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
-		bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
-		err = bcm43xx_pcicore_commit_settings(bcm);
-		assert(err == 0);
+	if (bcm->current_core->id == BCM43xx_COREID_PCI) {
+		value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+		value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST;
+		bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+
+		if (bcm->current_core->rev < 5) {
+			value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW);
+			value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT)
+				 & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK;
+			value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT)
+				 & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK;
+			bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value);
+			err = bcm43xx_pcicore_commit_settings(bcm);
+			assert(err == 0);
+		} else if (bcm->current_core->rev >= 11) {
+			value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2);
+			value |= BCM43xx_SBTOPCI2_MEMREAD_MULTI;
+			bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value);
+		}
+	} else {
+		if (bcm->current_core->rev == 0 || bcm->current_core->rev == 1) {
+			value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_TLP_WORKAROUND);
+			value |= 0x8;
+			bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_TLP_WORKAROUND,
+					       value);
+		}
+		if (bcm->current_core->rev == 0) {
+			bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+						BCM43xx_SERDES_RXTIMER, 0x8128);
+			bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+						BCM43xx_SERDES_CDR, 0x0100);
+			bcm43xx_pcie_mdio_write(bcm, BCM43xx_MDIO_SERDES_RX,
+						BCM43xx_SERDES_CDR_BW, 0x1466);
+		} else if (bcm->current_core->rev == 1) {
+			value = bcm43xx_pcie_reg_read(bcm, BCM43xx_PCIE_DLLP_LINKCTL);
+			value |= 0x40;
+			bcm43xx_pcie_reg_write(bcm, BCM43xx_PCIE_DLLP_LINKCTL,
+					       value);
+		}
 	}
-
 out_switch_back:
 	err = bcm43xx_switch_core(bcm, old_core);
 out:
@@ -3644,7 +3713,7 @@ static int bcm43xx_read_phyinfo(struct b
 		bcm->ieee->freq_band = IEEE80211_24GHZ_BAND;
 		break;
 	case BCM43xx_PHYTYPE_G:
-		if (phy_rev > 7)
+		if (phy_rev > 8)
 			phy_rev_ok = 0;
 		bcm->ieee->modulation = IEEE80211_OFDM_MODULATION |
 					IEEE80211_CCK_MODULATION;
@@ -3656,6 +3725,8 @@ static int bcm43xx_read_phyinfo(struct b
 		       phy_type);
 		return -ENODEV;
 	};
+	bcm->ieee->perfect_rssi = RX_RSSI_MAX;
+	bcm->ieee->worst_rssi = 0;
 	if (!phy_rev_ok) {
 		printk(KERN_WARNING PFX "Invalid PHY Revision %x\n",
 		       phy_rev);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
index 6569da3..7e774f4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
@@ -153,8 +153,6 @@ int bcm43xx_pctl_init(struct bcm43xx_pri
 	int err, maxfreq;
 	struct bcm43xx_coreinfo *old_core;
 
-	if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
-		return 0;
 	old_core = bcm->current_core;
 	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
 	if (err == -ENODEV)
@@ -162,11 +160,27 @@ int bcm43xx_pctl_init(struct bcm43xx_pri
 	if (err)
 		goto out;
 
-	maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
-	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
-			(maxfreq * 150 + 999999) / 1000000);
-	bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
-			(maxfreq * 15 + 999999) / 1000000);
+	if (bcm->chip_id == 0x4321) {
+		if (bcm->chip_rev == 0)
+			bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4);
+		if (bcm->chip_rev == 1)
+			bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4);
+	}
+
+	if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) {
+		if (bcm->current_core->rev >= 10) {
+			/* Set Idle Power clock rate to 1Mhz */
+			bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL,
+				       (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL)
+				       & 0x0000FFFF) | 0x40000);
+		} else {
+			maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
+			bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
+				       (maxfreq * 150 + 999999) / 1000000);
+			bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
+				       (maxfreq * 15 + 999999) / 1000000);
+		}
+	}
 
 	err = bcm43xx_switch_core(bcm, old_core);
 	assert(err == 0);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index d27016f..a659442 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,9 +47,6 @@ #include "bcm43xx_phy.h"
 #define BCM43xx_WX_VERSION	18
 
 #define MAX_WX_STRING		80
-/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
-#define RX_RSSI_MAX		60
-
 
 static int bcm43xx_wx_get_name(struct net_device *net_dev,
                                struct iw_request_info *info,
@@ -693,6 +690,7 @@ static int bcm43xx_wx_set_swencryption(s
 	bcm->ieee->host_encrypt = !!on;
 	bcm->ieee->host_decrypt = !!on;
 	bcm->ieee->host_build_iv = !on;
+	bcm->ieee->host_strip_iv_icv = !on;
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	mutex_unlock(&bcm->mutex);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index 0159e4e..a957bc8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -543,25 +543,6 @@ int bcm43xx_rx(struct bcm43xx_private *b
 		break;
 	}
 
-	frame_ctl = le16_to_cpu(wlhdr->frame_ctl);
-	if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) {
-		frame_ctl &= ~IEEE80211_FCTL_PROTECTED;
-		wlhdr->frame_ctl = cpu_to_le16(frame_ctl);		
-		/* trim IV and ICV */
-		/* FIXME: this must be done only for WEP encrypted packets */
-		if (skb->len < 32) {
-			dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag "
-					      "set and length < 32)\n");
-			return -EINVAL;
-		} else {		
-			memmove(skb->data + 4, skb->data, 24);
-			skb_pull(skb, 4);
-			skb_trim(skb, skb->len - 4);
-			stats.len -= 8;
-		}
-		wlhdr = (struct ieee80211_hdr_4addr *)(skb->data);
-	}
-	
 	switch (WLAN_FC_GET_TYPE(frame_ctl)) {
 	case IEEE80211_FTYPE_MGMT:
 		ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats);
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index 23deee6..02fc67b 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
  *
@@ -38,7 +37,7 @@ #include "islpci_mgt.h"
  * isl38xx_disable_interrupts - disable all interrupts
  * @device: pci memory base address
  *
- *  Instructs the device to disable all interrupt reporting by asserting 
+ *  Instructs the device to disable all interrupt reporting by asserting
  *  the IRQ line. New events may still show up in the interrupt identification
  *  register located at offset %ISL38XX_INT_IDENT_REG.
  */
@@ -204,17 +203,19 @@ #endif
 	/* enable the interrupt for detecting initialization */
 
 	/* Note: Do not enable other interrupts here. We want the
-	 * device to have come up first 100% before allowing any other 
+	 * device to have come up first 100% before allowing any other
 	 * interrupts. */
 	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
 }
 
 void
-isl38xx_enable_common_interrupts(void __iomem *device_base) {
+isl38xx_enable_common_interrupts(void __iomem *device_base)
+{
 	u32 reg;
-	reg = ( ISL38XX_INT_IDENT_UPDATE | 
-			ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP);
+
+	reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP |
+	      ISL38XX_INT_IDENT_WAKEUP;
 	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);
 }
@@ -234,23 +235,21 @@ isl38xx_in_queue(isl38xx_control_block *
 		/* send queues */
 	case ISL38XX_CB_TX_MGMTQ:
 		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
+
 	case ISL38XX_CB_TX_DATA_LQ:
 	case ISL38XX_CB_TX_DATA_HQ:
 		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
 		return delta;
-		break;
 
 		/* receive queues */
 	case ISL38XX_CB_RX_MGMTQ:
 		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
 		return ISL38XX_CB_MGMT_QSIZE - delta;
-		break;
 
 	case ISL38XX_CB_RX_DATA_LQ:
 	case ISL38XX_CB_RX_DATA_HQ:
 		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
 		return ISL38XX_CB_RX_QSIZE - delta;
-		break;
 	}
 	BUG();
 	return 0;
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
index 8af2098..3fadcb6 100644
--- a/drivers/net/wireless/prism54/isl_38xx.h
+++ b/drivers/net/wireless/prism54/isl_38xx.h
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -67,10 +66,10 @@ #define ISL38XX_PCI_POSTING_FLUSH		ISL38
  * @base: (host) memory base address of the device
  * @val: 32bit value (host order) to write
  * @offset: byte offset into @base to write value to
- * 
+ *
  *  This helper takes care of writing a 32bit datum to the
- *  specified offset into the device's pci memory space, and making sure 
- *  the pci memory buffers get flushed by performing one harmless read 
+ *  specified offset into the device's pci memory space, and making sure
+ *  the pci memory buffers get flushed by performing one harmless read
  *  from the %ISL38XX_PCI_POSTING_FLUSH offset.
  */
 static inline void
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 286325c..4a20e45 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *            (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  *            (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
@@ -55,12 +54,12 @@ static const unsigned char scan_rate_lis
  * prism54_mib_mode_helper - MIB change mode helper function
  * @mib: the &struct islpci_mib object to modify
  * @iw_mode: new mode (%IW_MODE_*)
- * 
+ *
  *  This is a helper function, hence it does not lock. Make sure
- *  caller deals with locking *if* necessary. This function sets the 
- *  mode-dependent mib values and does the mapping of the Linux 
- *  Wireless API modes to Device firmware modes. It also checks for 
- *  correct valid Linux wireless modes. 
+ *  caller deals with locking *if* necessary. This function sets the
+ *  mode-dependent mib values and does the mapping of the Linux
+ *  Wireless API modes to Device firmware modes. It also checks for
+ *  correct valid Linux wireless modes.
  */
 static int
 prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
@@ -118,7 +117,7 @@ prism54_mib_mode_helper(islpci_private *
  *
  *  this function initializes the struct given as @mib with defaults,
  *  of which many are retrieved from the global module parameter
- *  variables.  
+ *  variables.
  */
 
 void
@@ -134,7 +133,7 @@ prism54_mib_init(islpci_private *priv)
 	authen = CARD_DEFAULT_AUTHEN;
 	wep = CARD_DEFAULT_WEP;
 	filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
-	dot1x = CARD_DEFAULT_DOT1X; 
+	dot1x = CARD_DEFAULT_DOT1X;
 	mlme = CARD_DEFAULT_MLME_MODE;
 	conformance = CARD_DEFAULT_CONFORMANCE;
 	power = 127;
@@ -228,7 +227,7 @@ prism54_get_wireless_stats(struct net_de
 	} else
 		priv->iwstatistics.qual.updated = 0;
 
-	/* Update our wireless stats, but do not schedule to often 
+	/* Update our wireless stats, but do not schedule to often
 	 * (max 1 HZ) */
 	if ((priv->stats_timestamp == 0) ||
 	    time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
@@ -705,7 +704,7 @@ prism54_get_scan(struct net_device *ndev
 	* Starting with WE-17, the buffer can be as big as needed.
 	* But the device won't repport anything if you change the value
 	* of IWMAX_BSS=24. */
-	
+
 	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
 	bsslist = r.ptr;
 
@@ -785,7 +784,7 @@ prism54_get_essid(struct net_device *nde
 	return rvalue;
 }
 
-/* Provides no functionality, just completes the ioctl. In essence this is a 
+/* Provides no functionality, just completes the ioctl. In essence this is a
  * just a cosmetic ioctl.
  */
 static int
@@ -1104,7 +1103,7 @@ prism54_set_encode(struct net_device *nd
 					    &key);
 		}
 		/*
-		 * If a valid key is set, encryption should be enabled 
+		 * If a valid key is set, encryption should be enabled
 		 * (user may turn it off later).
 		 * This is also how "iwconfig ethX key on" works
 		 */
@@ -1126,7 +1125,7 @@ prism54_set_encode(struct net_device *nd
 	}
 	/* now read the flags */
 	if (dwrq->flags & IW_ENCODE_DISABLED) {
-		/* Encoding disabled, 
+		/* Encoding disabled,
 		 * authen = DOT11_AUTH_OS;
 		 * invoke = 0;
 		 * exunencrypt = 0; */
@@ -1214,7 +1213,7 @@ prism54_get_txpower(struct net_device *n
 	vwrq->value = (s32) r.u / 4;
 	vwrq->fixed = 1;
 	/* radio is not turned of
-	 * btw: how is possible to turn off only the radio 
+	 * btw: how is possible to turn off only the radio
 	 */
 	vwrq->disabled = 0;
 
@@ -2354,17 +2353,17 @@ prism54_process_trap_helper(islpci_priva
 		handle_request(priv, mlme, oid);
 		send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
 
-		if (priv->iw_mode != IW_MODE_MASTER 
+		if (priv->iw_mode != IW_MODE_MASTER
 				&& mlmeex->state != DOT11_STATE_AUTHING)
 			break;
 
 		confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
 
-		if (!confirm) 
+		if (!confirm)
 			break;
 
 		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
-		printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+		printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
 				mlmeex->address[0],
 				mlmeex->address[1],
 				mlmeex->address[2],
@@ -2398,10 +2397,10 @@ prism54_process_trap_helper(islpci_priva
 		handle_request(priv, mlme, oid);
 		send_formatted_event(priv, "Associate request (ex)", mlme, 1);
 
-		if (priv->iw_mode != IW_MODE_MASTER 
+		if (priv->iw_mode != IW_MODE_MASTER
 				&& mlmeex->state != DOT11_STATE_ASSOCING)
 			break;
-		
+
 		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
 
 		if (!confirm)
@@ -2417,7 +2416,7 @@ prism54_process_trap_helper(islpci_priva
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
-					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
 				mlmeex->address[0],
 				mlmeex->address[1],
 				mlmeex->address[2],
@@ -2435,14 +2434,14 @@ prism54_process_trap_helper(islpci_priva
 		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
 
 		kfree(confirm);
-		
+
 		break;
 
 	case DOT11_OID_REASSOCIATEEX:
 		handle_request(priv, mlme, oid);
 		send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
 
-		if (priv->iw_mode != IW_MODE_MASTER 
+		if (priv->iw_mode != IW_MODE_MASTER
 				&& mlmeex->state != DOT11_STATE_ASSOCING)
 			break;
 
@@ -2461,7 +2460,7 @@ prism54_process_trap_helper(islpci_priva
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
-					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
 				mlmeex->address[0],
 				mlmeex->address[1],
 				mlmeex->address[2],
@@ -2473,13 +2472,13 @@ prism54_process_trap_helper(islpci_priva
 			break;
 		}
 
-		confirm->size = wpa_ie_len; 
+		confirm->size = wpa_ie_len;
 		memcpy(&confirm->data, wpa_ie, wpa_ie_len);
 
 		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
 
 		kfree(confirm);
-		
+
 		break;
 
 	default:
@@ -2545,10 +2544,10 @@ #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
 ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
 
-/* Maximum length for algorithm names (-1 for nul termination) 
+/* Maximum length for algorithm names (-1 for nul termination)
  * used in ioctl() */
 #define HOSTAP_CRYPT_ALG_NAME_LEN 16
-	
+
 struct prism2_hostapd_param {
 	u32 cmd;
 	u8 sta_addr[ETH_ALEN];
@@ -2621,7 +2620,7 @@ prism2_ioctl_set_encryption(struct net_d
 					    &key);
 		}
 		/*
-		 * If a valid key is set, encryption should be enabled 
+		 * If a valid key is set, encryption should be enabled
 		 * (user may turn it off later).
 		 * This is also how "iwconfig ethX key on" works
 		 */
@@ -2643,7 +2642,7 @@ prism2_ioctl_set_encryption(struct net_d
 	}
 	/* now read the flags */
 	if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
-		/* Encoding disabled, 
+		/* Encoding disabled,
 		 * authen = DOT11_AUTH_OS;
 		 * invoke = 0;
 		 * exunencrypt = 0; */
@@ -2710,7 +2709,7 @@ #define WLAN_FC_STYPE_REASSOC_REQ 2
 
 	       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
 
-	       if (ret == 0) 
+	       if (ret == 0)
 		       printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
 				       ndev->name);
        }
@@ -2870,7 +2869,7 @@ prism54_set_wpa(struct net_device *ndev,
 			mlme = DOT11_MLME_AUTO;
 			printk("%s: Disabling WPA\n", ndev->name);
 			break;
-		case 2: 
+		case 2:
 		case 1: /* WPA */
 			printk("%s: Enabling WPA\n", ndev->name);
 			break;
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
index 65f33ac..e8183d3 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *            (C) 2003 Aurelien Alleaume <slts@free.fr>
  *            (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
index 419edf7..b7534c2 100644
--- a/drivers/net/wireless/prism54/isl_oid.h
+++ b/drivers/net/wireless/prism54/isl_oid.h
@@ -1,6 +1,4 @@
 /*
- *
- *  
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *  Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -23,7 +21,7 @@
 #if !defined(_ISL_OID_H)
 #define _ISL_OID_H
 
-/* 
+/*
  * MIB related constant and structure definitions for communicating
  * with the device firmware
  */
@@ -99,21 +97,21 @@ struct obj_attachment {
 	char data[0];
 } __attribute__((packed));
 
-/* 
+/*
  * in case everything's ok, the inlined function below will be
  * optimized away by the compiler...
  */
 static inline void
 __bug_on_wrong_struct_sizes(void)
 {
-	BUG_ON(sizeof (struct obj_ssid) != 34);
-	BUG_ON(sizeof (struct obj_key) != 34);
-	BUG_ON(sizeof (struct obj_mlme) != 12);
-	BUG_ON(sizeof (struct obj_mlmeex) != 14);
-	BUG_ON(sizeof (struct obj_buffer) != 8);
-	BUG_ON(sizeof (struct obj_bss) != 60);
-	BUG_ON(sizeof (struct obj_bsslist) != 4);
-	BUG_ON(sizeof (struct obj_frequencies) != 2);
+	BUILD_BUG_ON(sizeof (struct obj_ssid) != 34);
+	BUILD_BUG_ON(sizeof (struct obj_key) != 34);
+	BUILD_BUG_ON(sizeof (struct obj_mlme) != 12);
+	BUILD_BUG_ON(sizeof (struct obj_mlmeex) != 14);
+	BUILD_BUG_ON(sizeof (struct obj_buffer) != 8);
+	BUILD_BUG_ON(sizeof (struct obj_bss) != 60);
+	BUILD_BUG_ON(sizeof (struct obj_bsslist) != 4);
+	BUILD_BUG_ON(sizeof (struct obj_frequencies) != 2);
 }
 
 enum dot11_state_t {
@@ -154,13 +152,13 @@ enum dot11_priv_t {
 
 /* Prism "Nitro" / Frameburst / "Packet Frame Grouping"
  * Value is in microseconds. Represents the # microseconds
- * the firmware will take to group frames before sending out then out 
+ * the firmware will take to group frames before sending out then out
  * together with a CSMA contention. Without this all frames are
- * sent with a CSMA contention. 
- * Bibliography: 
+ * sent with a CSMA contention.
+ * Bibliography:
  * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html
  */
-enum dot11_maxframeburst_t { 
+enum dot11_maxframeburst_t {
 	/* Values for DOT11_OID_MAXFRAMEBURST */
 	DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */
 	DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */
@@ -176,9 +174,9 @@ enum dot11_maxframeburst_t { 
 /* Support for 802.11 long and short frame preambles.
  * Long	 preamble uses 128-bit sync field, 8-bit  CRC
  * Short preamble uses 56-bit  sync field, 16-bit CRC
- * 
+ *
  * 802.11a -- not sure, both optionally ?
- * 802.11b supports long and optionally short 
+ * 802.11b supports long and optionally short
  * 802.11g supports both */
 enum dot11_preamblesettings_t {
 	DOT11_PREAMBLESETTING_LONG = 0,
@@ -194,7 +192,7 @@ enum dot11_preamblesettings_t {
  * Long uses 802.11a slot timing  (9 usec ?)
  * Short uses 802.11b slot timing (20 use ?) */
 enum dot11_slotsettings_t {
-	DOT11_SLOTSETTINGS_LONG = 0, 
+	DOT11_SLOTSETTINGS_LONG = 0,
 		/* Allows *only* long 802.11b slot timing */
 	DOT11_SLOTSETTINGS_SHORT = 1,
 		/* Allows *only* long 802.11a slot timing */
@@ -203,7 +201,7 @@ enum dot11_slotsettings_t {
 };
 
 /* All you need to know, ERP is "Extended Rate PHY".
- * An Extended Rate PHY (ERP) STA or AP shall support three different 
+ * An Extended Rate PHY (ERP) STA or AP shall support three different
  * preamble and header formats:
  * Long  preamble (refer to above)
  * Short preamble (refer to above)
@@ -221,7 +219,7 @@ enum do11_nonerpstatus_t {
 /* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-*
  * The key here is DOT11 NON ERP NEVER protects against
  * NON ERP STA's. You *don't* want this unless
- * you know what you are doing. It means you will only 
+ * you know what you are doing. It means you will only
  * get Extended Rate capabilities */
 enum dot11_nonerpprotection_t {
 	DOT11_NONERP_NEVER = 0,
@@ -229,13 +227,13 @@ enum dot11_nonerpprotection_t {
 	DOT11_NONERP_DYNAMIC = 2
 };
 
-/* Preset OID configuration for 802.11 modes 
- * Note: DOT11_OID_CW[MIN|MAX] hold the values of the 
+/* Preset OID configuration for 802.11 modes
+ * Note: DOT11_OID_CW[MIN|MAX] hold the values of the
  * DCS MIN|MAX backoff used */
 enum dot11_profile_t { /* And set/allowed values */
 	/* Allowed values for DOT11_OID_PROFILES */
 	DOT11_PROFILE_B_ONLY = 0,
-		/* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps 
+		/* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps
 		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
 		 * DOT11_OID_CWMIN: 31
 		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
@@ -275,7 +273,7 @@ enum oid_inl_conformance_t {
 	OID_INL_CONFORMANCE_NONE = 0,	/* Perform active scanning */
 	OID_INL_CONFORMANCE_STRICT = 1,	/* Strictly adhere to 802.11d */
 	OID_INL_CONFORMANCE_FLEXIBLE = 2,	/* Use passed 802.11d info to
-		* determine channel AND/OR just make assumption that active 
+		* determine channel AND/OR just make assumption that active
 		* channels are valid  channels */
 };
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index ec1c00f..1e0603c 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
@@ -413,7 +412,7 @@ prism54_bring_down(islpci_private *priv)
 	islpci_set_state(priv, PRV_STATE_PREBOOT);
 
 	/* disable all device interrupts in case they weren't */
-	isl38xx_disable_interrupts(priv->device_base);  
+	isl38xx_disable_interrupts(priv->device_base);
 
 	/* For safety reasons, we may want to ensure that no DMA transfer is
 	 * currently in progress by emptying the TX and RX queues. */
@@ -480,7 +479,7 @@ islpci_reset_if(islpci_private *priv)
 
 	DEFINE_WAIT(wait);
 	prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE);
-	
+
 	/* now the last step is to reset the interface */
 	isl38xx_interface_reset(priv->device_base, priv->device_host_address);
 	islpci_set_state(priv, PRV_STATE_PREINIT);
@@ -488,7 +487,7 @@ islpci_reset_if(islpci_private *priv)
         for(count = 0; count < 2 && result; count++) {
 		/* The software reset acknowledge needs about 220 msec here.
 		 * Be conservative and wait for up to one second. */
-	
+
 		remaining = schedule_timeout_uninterruptible(HZ);
 
 		if(remaining > 0) {
@@ -496,7 +495,7 @@ islpci_reset_if(islpci_private *priv)
 			break;
 		}
 
-		/* If we're here it's because our IRQ hasn't yet gone through. 
+		/* If we're here it's because our IRQ hasn't yet gone through.
 		 * Retry a bit more...
 		 */
 		printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
@@ -514,7 +513,7 @@ islpci_reset_if(islpci_private *priv)
 
 	/* Now that the device is 100% up, let's allow
 	 * for the other interrupts --
-	 * NOTE: this is not *yet* true since we've only allowed the 
+	 * NOTE: this is not *yet* true since we've only allowed the
 	 * INIT interrupt on the IRQ line. We can perhaps poll
 	 * the IRQ line until we know for sure the reset went through */
 	isl38xx_enable_common_interrupts(priv->device_base);
@@ -716,7 +715,7 @@ #endif
 
 	prism54_acl_init(&priv->acl);
 	prism54_wpa_bss_ie_init(priv);
-	if (mgt_init(priv)) 
+	if (mgt_init(priv))
 		goto out_free;
 
 	return 0;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 2f7e525..a9aa166 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -1,6 +1,5 @@
 /*
- *  
- *  Copyright (C) 2002 Intersil Americas Inc. 
+ *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
  *  Copyright (C) 2003 Aurelien Alleaume <slts@free.fr>
@@ -72,12 +71,12 @@ struct islpci_bss_wpa_ie {
 	u8 bssid[ETH_ALEN];
 	u8 wpa_ie[MAX_WPA_IE_LEN];
 	size_t wpa_ie_len;
-	
+
 };
 
 typedef struct {
 	spinlock_t slock;	/* generic spinlock; */
-	
+
 	u32 priv_oid;
 
 	/* our mib cache */
@@ -85,7 +84,7 @@ typedef struct {
         struct rw_semaphore mib_sem;
 	void **mib;
 	char nickname[IW_ESSID_MAX_SIZE+1];
-	
+
 	/* Take care of the wireless stats */
 	struct work_struct stats_work;
 	struct semaphore stats_sem;
@@ -120,7 +119,7 @@ typedef struct {
 	struct net_device *ndev;
 
 	/* device queue interface members */
-	struct isl38xx_cb *control_block;	/* device control block 
+	struct isl38xx_cb *control_block;	/* device control block
 							   (== driver_mem_address!) */
 
 	/* Each queue has three indexes:
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index a8261d8..676d838 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
  *  This program is free software; you can redistribute it and/or modify
@@ -48,7 +47,7 @@ islpci_eth_cleanup_transmit(islpci_priva
 		/* read the index of the first fragment to be freed */
 		index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE;
 
-		/* check for holes in the arrays caused by multi fragment frames 
+		/* check for holes in the arrays caused by multi fragment frames
 		 * searching for the last fragment of a frame */
 		if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) {
 			/* entry is the last fragment of a frame
@@ -253,6 +252,7 @@ islpci_monitor_rx(islpci_private *priv, 
 	 * header and without the FCS. But there a is a bit that
 	 * indicates if the packet is corrupted :-) */
 	struct rfmon_header *hdr = (struct rfmon_header *) (*skb)->data;
+
 	if (hdr->flags & 0x01)
 		/* This one is bad. Drop it ! */
 		return -1;
@@ -284,7 +284,7 @@ islpci_monitor_rx(islpci_private *priv, 
 		    (struct avs_80211_1_header *) skb_push(*skb,
 							   sizeof (struct
 								   avs_80211_1_header));
-		
+
 		avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
 		avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
 		avs->mactime = cpu_to_be64(le64_to_cpu(clock));
@@ -390,7 +390,7 @@ #endif
 			struct rx_annex_header *annex =
 			    (struct rx_annex_header *) skb->data;
 			wstats.level = annex->rfmon.rssi;
-			/* The noise value can be a bit outdated if nobody's 
+			/* The noise value can be a bit outdated if nobody's
 			 * reading wireless stats... */
 			wstats.noise = priv->local_iwstatistics.qual.noise;
 			wstats.qual = wstats.level - wstats.noise;
@@ -464,10 +464,8 @@ #endif
 			break;
 		}
 		/* update the fragment address */
-		control_block->rx_data_low[index].address = cpu_to_le32((u32)
-									priv->
-									pci_map_rx_address
-									[index]);
+		control_block->rx_data_low[index].address =
+			cpu_to_le32((u32)priv->pci_map_rx_address[index]);
 		wmb();
 
 		/* increment the driver read pointer */
@@ -484,10 +482,12 @@ #endif
 void
 islpci_do_reset_and_wake(void *data)
 {
-	islpci_private *priv = (islpci_private *) data;
+	islpci_private *priv = data;
+
 	islpci_reset(priv, 1);
-	netif_wake_queue(priv->ndev);
 	priv->reset_task_pending = 0;
+	smp_wmb();
+	netif_wake_queue(priv->ndev);
 }
 
 void
@@ -499,12 +499,14 @@ islpci_eth_tx_timeout(struct net_device 
 	/* increment the transmit error counter */
 	statistics->tx_errors++;
 
-	printk(KERN_WARNING "%s: tx_timeout", ndev->name);
 	if (!priv->reset_task_pending) {
-		priv->reset_task_pending = 1;
-		printk(", scheduling a reset");
+		printk(KERN_WARNING
+			"%s: tx_timeout, scheduling reset", ndev->name);
 		netif_stop_queue(ndev);
+		priv->reset_task_pending = 1;
 		schedule_work(&priv->reset_task);
+	} else {
+		printk(KERN_WARNING
+			"%s: tx_timeout, waiting for reset", ndev->name);
 	}
-	printk("\n");
 }
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index bc9d7a6..2678945 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index f692dcc..f6354b1 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
  *
@@ -40,8 +39,8 @@ static int	init_pcitm = 0;
 module_param(init_pcitm, int, 0);
 
 /* In this order: vendor, device, subvendor, subdevice, class, class_mask,
- * driver_data 
- * If you have an update for this please contact prism54-devel@prism54.org 
+ * driver_data
+ * If you have an update for this please contact prism54-devel@prism54.org
  * The latest list can be found at http://prism54.org/supported_cards.php */
 static const struct pci_device_id prism54_id_tbl[] = {
 	/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
@@ -132,15 +131,15 @@ #endif
 
 	/* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT)
 	 * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT)
-	 * 	The RETRY_TIMEOUT is used to set the number of retries that the core, as a
-	 * 	Master, will perform before abandoning a cycle. The default value for
-	 * 	RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
-	 * 	devices. A write of zero to the RETRY_TIMEOUT register disables this
-	 * 	function to allow use with any non-compliant legacy devices that may
-	 * 	execute more retries.
+	 *	The RETRY_TIMEOUT is used to set the number of retries that the core, as a
+	 *	Master, will perform before abandoning a cycle. The default value for
+	 *	RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new
+	 *	devices. A write of zero to the RETRY_TIMEOUT register disables this
+	 *	function to allow use with any non-compliant legacy devices that may
+	 *	execute more retries.
 	 *
-	 * 	Writing zero to both these two registers will disable both timeouts and
-	 * 	*can* solve problems caused by devices that are slow to respond.
+	 *	Writing zero to both these two registers will disable both timeouts and
+	 *	*can* solve problems caused by devices that are slow to respond.
 	 *	Make this configurable - MSW
 	 */
 	if ( init_pcitm >= 0 ) {
@@ -241,7 +240,7 @@ prism54_remove(struct pci_dev *pdev)
 		isl38xx_disable_interrupts(priv->device_base);
 		islpci_set_state(priv, PRV_STATE_OFF);
 		/* This bellow causes a lockup at rmmod time. It might be
-		 * because some interrupts still linger after rmmod time, 
+		 * because some interrupts still linger after rmmod time,
 		 * see bug #17 */
 		/* pci_set_power_state(pdev, 3);*/	/* try to power-off */
 	}
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index 2e061a8..036a875 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright 2004 Jens Maurer <Jens.Maurer@gmx.net>
  *
@@ -502,7 +501,7 @@ islpci_mgt_transaction(struct net_device
 	printk(KERN_WARNING "%s: timeout waiting for mgmt response\n",
 	       ndev->name);
 
-	/* TODO: we should reset the device here */     
+	/* TODO: we should reset the device here */
  out:
 	finish_wait(&priv->mgmt_wqueue, &wait);
 	up(&priv->mgmt_sem);
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
index 2982be3..fc53b58 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.h
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -1,5 +1,4 @@
 /*
- *  
  *  Copyright (C) 2002 Intersil Americas Inc.
  *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
  *
@@ -36,8 +35,8 @@ #define init_wds 0	/* help compiler opti
 
 
 /* General driver definitions */
-#define PCIDEVICE_LATENCY_TIMER_MIN 		0x40
-#define PCIDEVICE_LATENCY_TIMER_VAL 		0x50
+#define PCIDEVICE_LATENCY_TIMER_MIN		0x40
+#define PCIDEVICE_LATENCY_TIMER_VAL		0x50
 
 /* Debugging verbose definitions */
 #define SHOW_NOTHING                            0x00	/* overrules everything */
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index ebb2387..fbc52b6 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -1,4 +1,4 @@
-/*   
+/*
  *  Copyright (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -503,7 +503,7 @@ mgt_set_varlen(islpci_private *priv, enu
 		}
 		if (ret || response_op == PIMFOR_OP_ERROR)
 			ret = -EIO;
-	} else 
+	} else
 		ret = -EIO;
 
 	/* re-set given data to what it was */
@@ -727,7 +727,7 @@ mgt_commit(islpci_private *priv)
  * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
  * FREQUENCY,EXTENDEDRATES.
  *
- * The way to do this is to set ESSID. Note though that they may get 
+ * The way to do this is to set ESSID. Note though that they may get
  * unlatch before though by setting another OID. */
 #if 0
 void
diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h
index d71eca5..aa1d174 100644
--- a/drivers/net/wireless/prism54/prismcompat.h
+++ b/drivers/net/wireless/prism54/prismcompat.h
@@ -1,4 +1,4 @@
-/*  
+/*
  *  (C) 2004 Margit Schubert-While <margitsw@t-online.de>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
  *
  */
 
-/*  
+/*
  *	Compatibility header file to aid support of different kernel versions
  */
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 3faaeb2..005ca7a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -47,6 +47,9 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index b174ebb..e6af381 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1037,6 +1037,10 @@ struct ieee80211_device {
 	/* host performs multicast decryption */
 	int host_mc_decrypt;
 
+	/* host should strip IV and ICV from protected frames */
+	/* meaningful only when hardware decryption is being used */
+	int host_strip_iv_icv;
+
 	int host_open_frag;
 	int host_build_iv;
 	int ieee802_1x;		/* is IEEE 802.1X used */
@@ -1076,6 +1080,8 @@ struct ieee80211_device {
 	int perfect_rssi;
 	int worst_rssi;
 
+	u16 prev_seq_ctl;	/* used to drop duplicate frames */
+
 	/* Callback functions */
 	void (*set_security) (struct net_device * dev,
 			      struct ieee80211_security * sec);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index 13b1e5f..2b14c2f 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -118,6 +118,14 @@ static void ieee80211_networks_initializ
 			      &ieee->network_free_list);
 }
 
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 struct net_device *alloc_ieee80211(int sizeof_priv)
 {
 	struct ieee80211_device *ieee;
@@ -133,6 +141,7 @@ struct net_device *alloc_ieee80211(int s
 	}
 	ieee = netdev_priv(dev);
 	dev->hard_start_xmit = ieee80211_xmit;
+	dev->change_mtu = ieee80211_change_mtu;
 
 	ieee->dev = dev;
 
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 7707041..50699b5 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -415,17 +415,16 @@ #endif
 	    ieee->host_mc_decrypt : ieee->host_decrypt;
 
 	if (can_be_decrypted) {
-		int idx = 0;
 		if (skb->len >= hdrlen + 3) {
 			/* Top two-bits of byte 3 are the key index */
-			idx = skb->data[hdrlen + 3] >> 6;
+			keyidx = skb->data[hdrlen + 3] >> 6;
 		}
 
-		/* ieee->crypt[] is WEP_KEY (4) in length.  Given that idx
-		 * is only allowed 2-bits of storage, no value of idx can
-		 * be provided via above code that would result in idx
+		/* ieee->crypt[] is WEP_KEY (4) in length.  Given that keyidx
+		 * is only allowed 2-bits of storage, no value of keyidx can
+		 * be provided via above code that would result in keyidx
 		 * being out of range */
-		crypt = ieee->crypt[idx];
+		crypt = ieee->crypt[keyidx];
 
 #ifdef NOT_YET
 		sta = NULL;
@@ -479,6 +478,11 @@ #ifdef NOT_YET
 			goto rx_exit;
 	}
 #endif
+	/* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
+	if (sc == ieee->prev_seq_ctl)
+		goto rx_dropped;
+	else
+		ieee->prev_seq_ctl = sc;
 
 	/* Data frame - extract src/dst addresses */
 	if (skb->len < IEEE80211_3ADDR_LEN)
@@ -655,6 +659,51 @@ #endif
 		goto rx_dropped;
 	}
 
+	/* If the frame was decrypted in hardware, we may need to strip off
+	 * any security data (IV, ICV, etc) that was left behind */
+	if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
+	    ieee->host_strip_iv_icv) {
+	    	int trimlen = 0;
+
+		/* Top two-bits of byte 3 are the key index */
+		if (skb->len >= hdrlen + 3)
+			keyidx = skb->data[hdrlen + 3] >> 6;
+
+		/* To strip off any security data which appears before the
+		 * payload, we simply increase hdrlen (as the header gets
+		 * chopped off immediately below). For the security data which
+		 * appears after the payload, we use skb_trim. */
+
+		switch (ieee->sec.encode_alg[keyidx]) {
+		case SEC_ALG_WEP:
+			/* 4 byte IV */
+			hdrlen += 4;
+			/* 4 byte ICV */
+			trimlen = 4;
+			break;
+		case SEC_ALG_TKIP:
+			/* 4 byte IV, 4 byte ExtIV */
+			hdrlen += 8;
+			/* 8 byte MIC, 4 byte ICV */
+			trimlen = 12;
+			break;
+		case SEC_ALG_CCMP:
+			/* 8 byte CCMP header */
+			hdrlen += 8;
+			/* 8 byte MIC */
+			trimlen = 8;
+			break;
+		}
+
+		if (skb->len < trimlen)
+			goto rx_dropped;
+
+		__skb_trim(skb, skb->len - trimlen);
+
+		if (skb->len < hdrlen)
+			goto rx_dropped;
+	}
+
 	/* skb: hdr + (possible reassembled) full plaintext payload */
 
 	payload = skb->data + hdrlen;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-09-11 23:59 ` Please pull 'upstream' " John W. Linville
  2006-09-12 15:43   ` Jeff Garzik
@ 2006-09-12 19:49   ` Michael Buesch
  1 sibling, 0 replies; 108+ messages in thread
From: Michael Buesch @ 2006-09-12 19:49 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, jeff, netdev

On Tuesday 12 September 2006 01:59, John W. Linville wrote:
> +	value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				     BCM43xx_UCODE_REVISION);
> +
> +	dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
> +		"(20%.2i-%.2i-%.2i  %.2i:%.2i:%.2i)\n", value16,
> +		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				   BCM43xx_UCODE_PATCHLEVEL),
> +		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				    BCM43xx_UCODE_DATE) >> 12) & 0xf,
> +		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				    BCM43xx_UCODE_DATE) >> 8) & 0xf,
> +		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				   BCM43xx_UCODE_DATE) & 0xff,
> +		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				   BCM43xx_UCODE_TIME) >> 11) & 0x1f,
> +		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				   BCM43xx_UCODE_TIME) >> 5) & 0x3f,
> +		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
> +				   BCM43xx_UCODE_TIME) & 0x1f);
> +
> +	if ( value16 > 0x128 ) {
> +		dprintk(KERN_ERR PFX
> +			"Firmware: no support for microcode rev > 0x128\n");
> +		err = -1;
> +		goto err_release_fw;
> +	}

Hm, this mustn't be a dprintk, as it's compiled away if
debugging is disabled. So it silently fails.
The text could be clarified, too.
returning -1 as error code is also very bad, as it's
propagated to userspace. I suggest EOPNOTSUPP, but maybe there's
something better.
Larry, can you do a patch which changes it to something like the following?

	if ( value16 > 0x128 ) {
		printk(KERN_ERR PFX
			"Firmware: no support for microcode extracted "
			"from version 4.x binary drivers.\n");
		err = -EOPNOTSUPP;
		goto err_release_fw;
	}

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-09-11 23:59 ` Please pull 'upstream' " John W. Linville
@ 2006-09-12 15:43   ` Jeff Garzik
  2006-09-12 19:49   ` Michael Buesch
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-09-12 15:43 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

pulled


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-09-11 23:58 Please pull 'upstream-fixes' " John W. Linville
@ 2006-09-11 23:59 ` John W. Linville
  2006-09-12 15:43   ` Jeff Garzik
  2006-09-12 19:49   ` Michael Buesch
  0 siblings, 2 replies; 108+ messages in thread
From: John W. Linville @ 2006-09-11 23:59 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 34fa0e319c760189f1fc226acc5b3b387dc58099:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Christian Steineck:
      hostap_cs: added support for Proxim Harmony PCI W-Lan card

Daniel Drake:
      zd1211rw: Add ID for Siemens Gigaset USB Stick 54
      zd1211rw: Add ID for Asus WL-159g

Jean Tourrilhes:
      Prism54 : add bitrates to scan result

Larry Finger:
      bcm43xx-softmac: Init, shutdown and restart fixes
      bcm43xx: Correct out of sequence initialization step
      bcm43xx: remove dead statistics code
      bcm43xx: Add firmware version printout
      bcm43xx: ucode debug status via sysfs
      bcm43xx: remove dead code in bcm43xx_sysfs.c

Ulrich Kunitz:
      zd1211rw: Removed unneeded packed attributes

 drivers/net/wireless/bcm43xx/bcm43xx.h       |    7 ++
 drivers/net/wireless/bcm43xx/bcm43xx_main.c  |   78 +++++++++++++++++---------
 drivers/net/wireless/bcm43xx/bcm43xx_main.h  |    3 +
 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c |   74 ++++++++++++++++++++++---
 drivers/net/wireless/hostap/hostap_cs.c      |    1 
 drivers/net/wireless/prism54/isl_ioctl.c     |   30 ++++++++++
 drivers/net/wireless/zd1211rw/zd_ieee80211.h |    2 -
 drivers/net/wireless/zd1211rw/zd_mac.c       |    2 -
 drivers/net/wireless/zd1211rw/zd_mac.h       |    4 +
 drivers/net/wireless/zd1211rw/zd_usb.c       |    2 +
 drivers/net/wireless/zd1211rw/zd_usb.h       |   14 ++---
 11 files changed, 169 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 62fd7e2..6d4ea36 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -306,6 +306,13 @@ #define BCM43xx_SBF_NO_SSID_BCAST	0x0800
 #define BCM43xx_SBF_TIME_UPDATE		0x10000000
 #define BCM43xx_SBF_80000000		0x80000000 /*FIXME: fix name*/
 
+/* Microcode */
+#define BCM43xx_UCODE_REVISION		0x0000
+#define BCM43xx_UCODE_PATCHLEVEL	0x0002
+#define BCM43xx_UCODE_DATE		0x0004
+#define BCM43xx_UCODE_TIME		0x0006
+#define BCM43xx_UCODE_STATUS		0x0040
+
 /* MicrocodeFlagsBitfield (addr + lo-word values?)*/
 #define BCM43xx_UCODEFLAGS_OFFSET	0x005E
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 966815b..cb9a3ae 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -519,6 +519,7 @@ static int bcm43xx_disable_interrupts_sy
 		return -EBUSY;
 	}
 	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	bcm43xx_synchronize_irq(bcm);
 
@@ -1545,17 +1546,7 @@ static void handle_irq_noise(struct bcm4
 		else
 			average -= 48;
 
-/* FIXME: This is wrong, but people want fancy stats. well... */
-bcm->stats.noise = average;
-		if (average > -65)
-			bcm->stats.link_quality = 0;
-		else if (average > -75)
-			bcm->stats.link_quality = 1;
-		else if (average > -85)
-			bcm->stats.link_quality = 2;
-		else
-			bcm->stats.link_quality = 3;
-//		dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
+		bcm->stats.noise = average;
 drop_calculation:
 		bcm->noisecalc.calculation_running = 0;
 		return;
@@ -2393,6 +2384,33 @@ static int bcm43xx_chip_init(struct bcm4
 	}
 	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
 
+	value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				     BCM43xx_UCODE_REVISION);
+
+	dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
+		"(20%.2i-%.2i-%.2i  %.2i:%.2i:%.2i)\n", value16,
+		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				   BCM43xx_UCODE_PATCHLEVEL),
+		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODE_DATE) >> 12) & 0xf,
+		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODE_DATE) >> 8) & 0xf,
+		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				   BCM43xx_UCODE_DATE) & 0xff,
+		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				   BCM43xx_UCODE_TIME) >> 11) & 0x1f,
+		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				   BCM43xx_UCODE_TIME) >> 5) & 0x3f,
+		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				   BCM43xx_UCODE_TIME) & 0x1f);
+
+	if ( value16 > 0x128 ) {
+		dprintk(KERN_ERR PFX
+			"Firmware: no support for microcode rev > 0x128\n");
+		err = -1;
+		goto err_release_fw;
+	}
+
 	err = bcm43xx_gpio_init(bcm);
 	if (err)
 		goto err_release_fw;
@@ -3150,6 +3168,7 @@ static void bcm43xx_periodic_work_handle
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
+		mutex_lock(&bcm->mutex);
 		netif_stop_queue(bcm->net_dev);
 		synchronize_net();
 		spin_lock_irqsave(&bcm->irq_lock, flags);
@@ -3158,7 +3177,6 @@ static void bcm43xx_periodic_work_handle
 			bcm43xx_pio_freeze_txqueues(bcm);
 		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 		spin_unlock_irqrestore(&bcm->irq_lock, flags);
-		mutex_lock(&bcm->mutex);
 		bcm43xx_synchronize_irq(bcm);
 	} else {
 		/* Periodic work should take short time, so we want low
@@ -3172,13 +3190,11 @@ static void bcm43xx_periodic_work_handle
 
 	if (badness > BADNESS_LIMIT) {
 		spin_lock_irqsave(&bcm->irq_lock, flags);
-		if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
-			tasklet_enable(&bcm->isr_tasklet);
-			bcm43xx_interrupt_enable(bcm, savedirqs);
-			if (bcm43xx_using_pio(bcm))
-				bcm43xx_pio_thaw_txqueues(bcm);
-			bcm43xx_mac_enable(bcm);
-		}
+		tasklet_enable(&bcm->isr_tasklet);
+		bcm43xx_interrupt_enable(bcm, savedirqs);
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_thaw_txqueues(bcm);
+		bcm43xx_mac_enable(bcm);
 		netif_wake_queue(bcm->net_dev);
 	}
 	mmiowb();
@@ -3186,12 +3202,12 @@ static void bcm43xx_periodic_work_handle
 	mutex_unlock(&bcm->mutex);
 }
 
-static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
+void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
 {
 	cancel_rearming_delayed_work(&bcm->periodic_work);
 }
 
-static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
+void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
 	struct work_struct *work = &(bcm->periodic_work);
 
@@ -3539,14 +3555,13 @@ static int bcm43xx_init_board(struct bcm
 	err = bcm43xx_select_wireless_core(bcm, -1);
 	if (err)
 		goto err_crystal_off;
-
-	bcm43xx_periodic_tasks_setup(bcm);
 	err = bcm43xx_sysfs_register(bcm);
 	if (err)
 		goto err_wlshutdown;
 	err = bcm43xx_rng_init(bcm);
 	if (err)
 		goto err_sysfs_unreg;
+	bcm43xx_periodic_tasks_setup(bcm);
 
 	/*FIXME: This should be handled by softmac instead. */
 	schedule_work(&bcm->softmac->associnfo.work);
@@ -3969,6 +3984,7 @@ static int bcm43xx_net_stop(struct net_d
 	err = bcm43xx_disable_interrupts_sync(bcm);
 	assert(!err);
 	bcm43xx_free_board(bcm);
+	flush_scheduled_work();
 
 	return 0;
 }
@@ -4119,11 +4135,16 @@ static void bcm43xx_chip_reset(void *_bc
 {
 	struct bcm43xx_private *bcm = _bcm;
 	struct bcm43xx_phyinfo *phy;
-	int err;
+	int err = -ENODEV;
 
 	mutex_lock(&(bcm)->mutex);
-	phy = bcm43xx_current_phy(bcm);
-	err = bcm43xx_select_wireless_core(bcm, phy->type);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+		bcm43xx_periodic_tasks_delete(bcm);
+		phy = bcm43xx_current_phy(bcm);
+		err = bcm43xx_select_wireless_core(bcm, phy->type);
+		if (!err)
+			bcm43xx_periodic_tasks_setup(bcm);
+	}
 	mutex_unlock(&(bcm)->mutex);
 
 	printk(KERN_ERR PFX "Controller restart%s\n",
@@ -4132,11 +4153,12 @@ static void bcm43xx_chip_reset(void *_bc
 
 /* Hard-reset the chip.
  * This can be called from interrupt or process context.
+ * bcm->irq_lock must be locked.
  */
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
 {
-	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-	bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
+		return;
 	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
 	INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
 	schedule_work(&bcm->restart_work);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 505c86e..f763571 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -141,6 +141,9 @@ void bcm43xx_wireless_core_reset(struct 
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
 
+void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
+
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
 
 int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index ece3351..c71b998 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -176,7 +176,6 @@ static ssize_t bcm43xx_attr_interfmode_s
 					    char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	int err;
 	ssize_t count = 0;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -197,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_s
 	default:
 		assert(0);
 	}
-	err = 0;
 
 	mutex_unlock(&bcm->mutex);
 
-	return err ? err : count;
+	return count;
 
 }
 
@@ -259,7 +257,6 @@ static ssize_t bcm43xx_attr_preamble_sho
 					  char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	int err;
 	ssize_t count;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -272,10 +269,9 @@ static ssize_t bcm43xx_attr_preamble_sho
 	else
 		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
-	err = 0;
 	mutex_unlock(&bcm->mutex);
 
-	return err ? err : count;
+	return count;
 }
 
 static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
@@ -284,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_sto
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
 	unsigned long flags;
-	int err;
 	int value;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -298,11 +293,10 @@ static ssize_t bcm43xx_attr_preamble_sto
 
 	bcm->short_preamble = !!value;
 
-	err = 0;
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	mutex_unlock(&bcm->mutex);
 
-	return err ? err : count;
+	return count;
 }
 
 static DEVICE_ATTR(shortpreamble, 0644,
@@ -333,8 +327,11 @@ static ssize_t bcm43xx_attr_phymode_stor
 		goto out;
 	}
 
+	bcm43xx_periodic_tasks_delete(bcm);
 	mutex_lock(&(bcm)->mutex);
 	err = bcm43xx_select_wireless_core(bcm, phytype);
+	if (!err)
+		bcm43xx_periodic_tasks_setup(bcm);
 	mutex_unlock(&(bcm)->mutex);
 	if (err == -ESRCH)
 		err = -ENODEV;
@@ -373,6 +370,59 @@ static DEVICE_ATTR(phymode, 0644,
 		   bcm43xx_attr_phymode_show,
 		   bcm43xx_attr_phymode_store);
 
+static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	unsigned long flags;
+	struct bcm43xx_private *bcm = dev_to_bcm(dev);
+	ssize_t count = 0;
+	u16 status;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&(bcm)->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+	status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+				    BCM43xx_UCODE_STATUS);
+
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&(bcm)->mutex);
+	switch (status) {
+	case 0x0000:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
+				 status);
+		break;
+	case 0x0001:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
+				 status);
+		break;
+	case 0x0002:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
+				 status);
+		break;
+	case 0x0003:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
+				 status);
+		break;
+	case 0x0004:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
+				 status);
+		break;
+	default:
+		count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
+				 status);
+		break;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(microcodestatus, 0444,
+		   bcm43xx_attr_microcode_show,
+		   NULL);
+
 int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
 {
 	struct device *dev = &bcm->pci_dev->dev;
@@ -392,9 +442,14 @@ int bcm43xx_sysfs_register(struct bcm43x
 	err = device_create_file(dev, &dev_attr_phymode);
 	if (err)
 		goto err_remove_shortpreamble;
+	err = device_create_file(dev, &dev_attr_microcodestatus);
+	if (err)
+		goto err_remove_phymode;
 
 out:
 	return err;
+err_remove_phymode:
+	device_remove_file(dev, &dev_attr_phymode);
 err_remove_shortpreamble:
 	device_remove_file(dev, &dev_attr_shortpreamble);
 err_remove_interfmode:
@@ -408,6 +463,7 @@ void bcm43xx_sysfs_unregister(struct bcm
 {
 	struct device *dev = &bcm->pci_dev->dev;
 
+	device_remove_file(dev, &dev_attr_microcodestatus);
 	device_remove_file(dev, &dev_attr_phymode);
 	device_remove_file(dev, &dev_attr_shortpreamble);
 	device_remove_file(dev, &dev_attr_interference);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 52e6df5..686d895 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -847,6 +847,7 @@ static struct pcmcia_device_id hostap_cs
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
+	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
 	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
 					 0x74c5e40d),
 	PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 0c30fe7..c09fbf7 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -46,6 +46,10 @@ static size_t prism54_wpa_bss_ie_get(isl
 static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
 				__u32 *, char *);
 
+/* In 500 kbps */
+static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
+						12, 18, 24, 36,
+						48, 72, 96, 108 };
 
 /**
  * prism54_mib_mode_helper - MIB change mode helper function
@@ -644,6 +648,32 @@ #define CAP_CRYPT 0x10
 		current_ev = iwe_stream_add_point(current_ev, end_buf,
 				&iwe, wpa_ie);
 	}
+	/* Do the bitrates */
+	{
+		char *	current_val = current_ev + IW_EV_LCP_LEN;
+		int i;
+		int mask;
+
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+		/* Parse the bitmask */
+		mask = 0x1;
+		for(i = 0; i < sizeof(scan_rate_list); i++) {
+			if(bss->rates & mask) {
+				iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
+				current_val = iwe_stream_add_value(current_ev, current_val,
+								   end_buf, &iwe,
+								   IW_EV_PARAM_LEN);
+			}
+			mask <<= 1;
+		}
+		/* Check if we added any event */
+		if ((current_val - current_ev) > IW_EV_LCP_LEN)
+			current_ev = current_val;
+	}
+
 	return current_ev;
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 3632989..f63245b 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -64,7 +64,7 @@ struct cck_plcp_header {
 	u8 service;
 	__le16 length;
 	__le16 crc16;
-} __attribute__((packed));
+};
 
 static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
 {
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 0ddccf8..1989f1c 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -714,7 +714,7 @@ struct zd_rt_hdr {
 	u8  rt_rate;
 	u16 rt_channel;
 	u16 rt_chbitmask;
-} __attribute__((packed));
+};
 
 static void fill_rt_header(void *buffer, struct zd_mac *mac,
 	                   const struct ieee80211_rx_stats *stats,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 2b596cc..29b51fd 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -82,7 +82,7 @@ #define ZD_PLCP_HEADER_SIZE		5
 struct rx_length_info {
 	__le16 length[3];
 	__le16 tag;
-} __attribute__((packed));
+};
 
 #define RX_LENGTH_INFO_TAG		0x697e
 
@@ -93,7 +93,7 @@ struct rx_status {
 	u8 signal_quality_ofdm;
 	u8 decryption_type;
 	u8 frame_status;
-} __attribute__((packed));
+};
 
 /* rx_status field decryption_type */
 #define ZD_RX_NO_WEP	0
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 47489fe..31027e5 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -44,6 +44,8 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 92746f7..ded39de 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -74,17 +74,17 @@ enum control_requests {
 struct usb_req_read_regs {
 	__le16 id;
 	__le16 addr[0];
-} __attribute__((packed));
+};
 
 struct reg_data {
 	__le16 addr;
 	__le16 value;
-} __attribute__((packed));
+};
 
 struct usb_req_write_regs {
 	__le16 id;
 	struct reg_data reg_writes[0];
-} __attribute__((packed));
+};
 
 enum {
 	RF_IF_LE = 0x02,
@@ -101,7 +101,7 @@ struct usb_req_rfwrite {
 	/* RF2595: 24 */
 	__le16 bit_values[0];
 	/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
-} __attribute__((packed));
+};
 
 /* USB interrupt */
 
@@ -118,12 +118,12 @@ enum usb_int_flags {
 struct usb_int_header {
 	u8 type;	/* must always be 1 */
 	u8 id;
-} __attribute__((packed));
+};
 
 struct usb_int_regs {
 	struct usb_int_header hdr;
 	struct reg_data regs[0];
-} __attribute__((packed));
+};
 
 struct usb_int_retry_fail {
 	struct usb_int_header hdr;
@@ -131,7 +131,7 @@ struct usb_int_retry_fail {
 	u8 _dummy;
 	u8 addr[ETH_ALEN];
 	u8 ibss_wakeup_dest;
-} __attribute__((packed));
+};
 
 struct read_regs_int {
 	struct completion completion;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-08-30 15:05 John W. Linville
@ 2006-09-06 15:02 ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-09-06 15:02 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

pulled


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-08-30 15:05 John W. Linville
  2006-09-06 15:02 ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-08-30 15:05 UTC (permalink / raw)
  To: jeff; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 3100 bytes --]

The following changes since commit e4ac2663ea27d5dda88d97d117080995fcfcd6d5:
  John W. Linville:
        Merge branch 'from-linus' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Larry Finger:
      bcm43xx: optimization of DMA bitfields
      bcm43xx: return correct hard_start_xmit error code
      bcm43xx - set correct value in mac_suspended for ifdown/ifup sequence
      bcm43xx: Set floor of wireless signal and noise at -110 dBm

Michael Buesch:
      bcm43xx: >1G and 64bit DMA support
      bcm43xx: re-add bcm43xx_rng_init() call
      MAINTAINERS: Add Larry Finger for bcm43xx (softmac)

Pavel Roskin:
      orinoco: Don't use "extern inline" on locking functions
      orinoco: include linux/if_arp.h directly

Sukadev Bhattiprolu:
      kthread: airo.c

Zhu Yi:
      ieee80211: Fix header->qos_ctl endian issue
      ieee80211: remove ieee80211_tx() is_queue_full warning
      ieee80211: TKIP and CCMP replay check rework
      ieee80211: Fix TKIP and WEP decryption error on SMP machines
      ieee80211: Workaround malformed 802.11 frames from AP
      ipw2200: always enable frequently used debugging code
      ipw2200: SIOCGIWFREQ ioctl returns frequency rather than channel
      ipw2200: ipw_wx_set_essid fix
      ipw2200: Reassociate even if set the same essid.
      ipw2200: remove unused struct ipw_rx_buffer
      ipw2200: Fix ipw2200 QOS parameters endian issue
      ipw2200: remove the MAC timestamp present field from radiotap head
      ipw2200: mark "iwconfig retry 255" as invalid
      ipw2200: Fix kernel Oops if cmdlog debug is enabled
      ipw2200: Add pci .shutdown handler
      ipw2100: Fix deadlock detected by lockdep
      ipw2200: enable wireless extension passive scan
      ipw2200: Update version stamp to 1.1.4
      ipw2200: Fix compile error when CONFIG_IPW2200_DEBUG is not selected

 MAINTAINERS                                 |    6 
 drivers/net/wireless/Kconfig                |   23 -
 drivers/net/wireless/airo.c                 |   40 +-
 drivers/net/wireless/bcm43xx/bcm43xx.h      |   58 ++-
 drivers/net/wireless/bcm43xx/bcm43xx_dma.c  |  583 ++++++++++++++++++---------
 drivers/net/wireless/bcm43xx/bcm43xx_dma.h  |  296 ++++++++++----
 drivers/net/wireless/bcm43xx/bcm43xx_main.c |   97 +++-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c   |    4 
 drivers/net/wireless/ipw2100.c              |    5 
 drivers/net/wireless/ipw2200.c              |  215 ++++++----
 drivers/net/wireless/ipw2200.h              |   51 +-
 drivers/net/wireless/orinoco.c              |    1 
 drivers/net/wireless/orinoco.h              |    8 
 net/ieee80211/ieee80211_crypt_ccmp.c        |   23 +
 net/ieee80211/ieee80211_crypt_tkip.c        |  108 +++--
 net/ieee80211/ieee80211_crypt_wep.c         |   35 +-
 net/ieee80211/ieee80211_rx.c                |   17 -
 net/ieee80211/ieee80211_tx.c                |    9 
 18 files changed, 1027 insertions(+), 552 deletions(-)

Omnibus patch attached as upstream.patch.bz2.
-- 
John W. Linville
linville@tuxdriver.com

[-- Attachment #2: upstream.patch.bz2 --]
[-- Type: application/x-bzip2, Size: 23062 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-08-14 20:50 John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-08-14 20:50 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit e9ffb3d7ec94083a44a8721681391beca2ffd68c:
  John W. Linville:
        Merge branch 'from-linus' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      zd1211rw: ZD1211B ASIC/FWT, not jointly decoder
      zd1211rw: Match vendor driver IFS values
      zd1211rw: AL2230 ZD1211B vendor sync
      zd1211rw: Support AL7230B RF
      zd1211rw: Add ID for Senao NUB-8301
      zd1211rw: Add ID for Allnet ALLSPOT Hotspot finder
      zd1211rw: Firmware version vs bootcode version mismatch handling
      zd1211rw: Add ID for ZyXEL G220F
      zd1211rw: Convert installer CDROM device into WLAN device

Michael Wu:
      ray_cs: Remove dependency on ieee80211

Ulrich Kunitz:
      zd1211rw: USB id 1582:6003 for Longshine 8131G3 added
      zd1211rw: cleanups

 drivers/net/wireless/ray_cs.c                 |    2 
 drivers/net/wireless/zd1211rw/Makefile        |    1 
 drivers/net/wireless/zd1211rw/zd_chip.c       |   62 ++++--
 drivers/net/wireless/zd1211rw/zd_chip.h       |   15 +
 drivers/net/wireless/zd1211rw/zd_def.h        |    6 +
 drivers/net/wireless/zd1211rw/zd_mac.c        |    6 -
 drivers/net/wireless/zd1211rw/zd_mac.h        |    2 
 drivers/net/wireless/zd1211rw/zd_rf.c         |    7 +
 drivers/net/wireless/zd1211rw/zd_rf.h         |    1 
 drivers/net/wireless/zd1211rw/zd_rf_al2230.c  |  155 ++++++++++----
 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c |  274 +++++++++++++++++++++++++
 drivers/net/wireless/zd1211rw/zd_usb.c        |  120 ++++++++++-
 drivers/net/wireless/zd1211rw/zd_usb.h        |    1 
 13 files changed, 575 insertions(+), 77 deletions(-)
 create mode 100644 drivers/net/wireless/zd1211rw/zd_rf_al7230b.c

diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 61b83a5..8e112d1 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -52,8 +52,8 @@ #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/mem_op.h>
 
-#include <net/ieee80211.h>
 #include <linux/wireless.h>
+#include <net/iw_handler.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 500314f..6603ad5 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 zd1211rw-objs := zd_chip.o zd_ieee80211.o \
 		zd_mac.o zd_netdev.o \
 		zd_rf_al2230.o zd_rf_rf2959.o \
+		zd_rf_al7230b.o \
 		zd_rf.o zd_usb.o zd_util.o
 
 ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index da9d06b..5841998 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -42,12 +42,11 @@ void zd_chip_init(struct zd_chip *chip,
 
 void zd_chip_clear(struct zd_chip *chip)
 {
-	mutex_lock(&chip->mutex);
+	ZD_ASSERT(!mutex_is_locked(&chip->mutex));
 	zd_usb_clear(&chip->usb);
 	zd_rf_clear(&chip->rf);
-	mutex_unlock(&chip->mutex);
 	mutex_destroy(&chip->mutex);
-	memset(chip, 0, sizeof(*chip));
+	ZD_MEMCLEAR(chip, sizeof(*chip));
 }
 
 static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
@@ -68,10 +67,11 @@ static int scnprint_id(struct zd_chip *c
 	i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
 	i += scnprintf(buffer+i, size-i, " ");
 	i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
-	i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+	i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
 		chip->patch_cck_gain ? 'g' : '-',
 		chip->patch_cr157 ? '7' : '-',
-		chip->patch_6m_band_edge ? '6' : '-');
+		chip->patch_6m_band_edge ? '6' : '-',
+		chip->new_phy_layout ? 'N' : '-');
 	return i;
 }
 
@@ -330,13 +330,14 @@ static int read_pod(struct zd_chip *chip
 	chip->patch_cck_gain = (value >> 8) & 0x1;
 	chip->patch_cr157 = (value >> 13) & 0x1;
 	chip->patch_6m_band_edge = (value >> 21) & 0x1;
+	chip->new_phy_layout = (value >> 31) & 0x1;
 
 	dev_dbg_f(zd_chip_dev(chip),
 		"RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
-		"patch 6M %d\n",
+		"patch 6M %d new PHY %d\n",
 		zd_rf_name(*rf_type), *rf_type,
 		chip->pa_type, chip->patch_cck_gain,
-		chip->patch_cr157, chip->patch_6m_band_edge);
+		chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout);
 	return 0;
 error:
 	*rf_type = 0;
@@ -344,6 +345,7 @@ error:
 	chip->patch_cck_gain = 0;
 	chip->patch_cr157 = 0;
 	chip->patch_6m_band_edge = 0;
+	chip->new_phy_layout = 0;
 	return r;
 }
 
@@ -717,7 +719,7 @@ static int zd1211b_hw_reset_phy(struct z
 		{ CR21,  0x0e }, { CR22,  0x23 }, { CR23,  0x90 },
 		{ CR24,  0x14 }, { CR25,  0x40 }, { CR26,  0x10 },
 		{ CR27,  0x10 }, { CR28,  0x7f }, { CR29,  0x80 },
-		{ CR30,  0x49 }, /* jointly decoder, no ASIC */
+		{ CR30,  0x4b }, /* ASIC/FWT, no jointly decoder */
 		{ CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
 		{ CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
 		{ CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
@@ -807,7 +809,6 @@ static int zd1211_hw_init_hmac(struct zd
 		{ CR_ACK_TIMEOUT_EXT,		0x80 },
 		{ CR_ADDA_PWR_DWN,		0x00 },
 		{ CR_ACK_TIME_80211,		0x100 },
-		{ CR_IFS_VALUE,			0x547c032 },
 		{ CR_RX_PE_DELAY,		0x70 },
 		{ CR_PS_CTRL,			0x10000000 },
 		{ CR_RTS_CTS_RATE,		0x02030203 },
@@ -854,11 +855,10 @@ static int zd1211b_hw_init_hmac(struct z
 		{ CR_ACK_TIMEOUT_EXT,		0x80 },
 		{ CR_ADDA_PWR_DWN,		0x00 },
 		{ CR_ACK_TIME_80211,		0x100 },
-		{ CR_IFS_VALUE,			0x547c032 },
 		{ CR_RX_PE_DELAY,		0x70 },
 		{ CR_PS_CTRL,			0x10000000 },
 		{ CR_RTS_CTS_RATE,		0x02030203 },
-		{ CR_RX_THRESHOLD,		0x000c0640 },
+		{ CR_RX_THRESHOLD,		0x000c0eff, },
 		{ CR_AFTER_PNP,			0x1 },
 		{ CR_WEP_PROTECT,		0x114 },
 	};
@@ -970,10 +970,15 @@ static int hw_init(struct zd_chip *chip)
 	r = hw_init_hmac(chip);
 	if (r)
 		return r;
-	r = set_beacon_interval(chip, 100);
+
+	/* Although the vendor driver defaults to a different value during
+	 * init, it overwrites the IFS value with the following every time
+	 * the channel changes. We should aim to be more intelligent... */
+	r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
 	if (r)
 		return r;
-	return 0;
+
+	return set_beacon_interval(chip, 100);
 }
 
 #ifdef DEBUG
@@ -1613,3 +1618,34 @@ int zd_rfwritev_locked(struct zd_chip *c
 
 	return 0;
 }
+
+/*
+ * We can optionally program the RF directly through CR regs, if supported by
+ * the hardware. This is much faster than the older method.
+ */
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
+{
+	struct zd_ioreq16 ioreqs[] = {
+		{ CR244, (value >> 16) & 0xff },
+		{ CR243, (value >>  8) & 0xff },
+		{ CR242,  value        & 0xff },
+	};
+	ZD_ASSERT(mutex_is_locked(&chip->mutex));
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+	                  const u32 *values, unsigned int count)
+{
+	int r;
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		r = zd_rfwrite_cr_locked(chip, values[i]);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 069d2b4..4b12508 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -473,7 +473,15 @@ #define STA_RX_FILTER			0x0000ffff
 
 #define CR_ACK_TIMEOUT_EXT		CTL_REG(0x0690)
 #define CR_BCN_FIFO_SEMAPHORE		CTL_REG(0x0694)
+
 #define CR_IFS_VALUE			CTL_REG(0x0698)
+#define IFS_VALUE_DIFS_SH		0
+#define IFS_VALUE_EIFS_SH		12
+#define IFS_VALUE_SIFS_SH		24
+#define IFS_VALUE_DEFAULT		((  50 << IFS_VALUE_DIFS_SH) | \
+					 (1148 << IFS_VALUE_EIFS_SH) | \
+					 (  10 << IFS_VALUE_SIFS_SH))
+
 #define CR_RX_TIME_OUT			CTL_REG(0x069C)
 #define CR_TOTAL_RX_FRM			CTL_REG(0x06A0)
 #define CR_CRC32_CNT			CTL_REG(0x06A4)
@@ -630,6 +638,7 @@ enum {
 	LOAD_CODE_SIZE			= 0xe, /* words */
 	LOAD_VECT_SIZE			= 0x10000 - 0xfff7, /* words */
 	EEPROM_REGS_OFFSET		= LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+	EEPROM_REGS_SIZE		= 0x7e, /* words */
 	E2P_BASE_OFFSET			= EEPROM_START_OFFSET +
 		                          EEPROM_REGS_OFFSET,
 };
@@ -655,7 +664,7 @@ struct zd_chip {
 	/* SetPointOFDM in the vendor driver */
 	u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
 	u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
-	   is_zd1211b:1;
+	   new_phy_layout:1, is_zd1211b:1;
 };
 
 static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -739,8 +748,12 @@ static inline int zd_rfwrite_locked(stru
 	return zd_usb_rfwrite(&chip->usb, value, bits);
 }
 
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value);
+
 int zd_rfwritev_locked(struct zd_chip *chip,
 	               const u32* values, unsigned int count, u8 bits);
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+	                  const u32* values, unsigned int count);
 
 /* Locking functions for reading and writing registers.
  * The different parameters are intentional.
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index 4659068..a13ec72 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -45,4 +45,10 @@ #else
 #  define ZD_ASSERT(x) do { } while (0)
 #endif
 
+#ifdef DEBUG
+#  define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size))
+#else
+#  define ZD_MEMCLEAR(pointer, size) do { } while (0)
+#endif
+
 #endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index d6f3e02..0eda534 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -127,11 +127,9 @@ out:
 
 void zd_mac_clear(struct zd_mac *mac)
 {
-	/* Aquire the lock. */
-	spin_lock(&mac->lock);
-	spin_unlock(&mac->lock);
 	zd_chip_clear(&mac->chip);
-	memset(mac, 0, sizeof(*mac));
+	ZD_ASSERT(!spin_is_locked(&mac->lock));
+	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
 static int reset_mode(struct zd_mac *mac)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 71e382c..082bcf8 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -121,9 +121,9 @@ enum mac_flags {
 };
 
 struct zd_mac {
-	struct net_device *netdev;
 	struct zd_chip chip;
 	spinlock_t lock;
+	struct net_device *netdev;
 	/* Unlocked reading possible */
 	struct iw_statistics iw_stats;
 	u8 qual_average;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index d3770d2..f50cff3 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -56,7 +56,7 @@ void zd_rf_init(struct zd_rf *rf)
 
 void zd_rf_clear(struct zd_rf *rf)
 {
-	memset(rf, 0, sizeof(*rf));
+	ZD_MEMCLEAR(rf, sizeof(*rf));
 }
 
 int zd_rf_init_hw(struct zd_rf *rf, u8 type)
@@ -76,6 +76,11 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 t
 		if (r)
 			return r;
 		break;
+	case AL7230B_RF:
+		r = zd_rf_init_al7230b(rf);
+		if (r)
+			return r;
+		break;
 	default:
 		dev_err(zd_chip_dev(chip),
 			"RF %s %#x is not supported\n", zd_rf_name(type), type);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index ea30f69..676b373 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -78,5 +78,6 @@ int zd_switch_radio_off(struct zd_rf *rf
 
 int zd_rf_init_rf2959(struct zd_rf *rf);
 int zd_rf_init_al2230(struct zd_rf *rf);
+int zd_rf_init_al7230b(struct zd_rf *rf);
 
 #endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 0948b25..25323a1 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -21,7 +21,7 @@ #include "zd_rf.h"
 #include "zd_usb.h"
 #include "zd_chip.h"
 
-static const u32 al2230_table[][3] = {
+static const u32 zd1211_al2230_table[][3] = {
 	RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
 	RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
 	RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
@@ -38,6 +38,53 @@ static const u32 al2230_table[][3] = {
 	RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
 };
 
+static const u32 zd1211b_al2230_table[][3] = {
+	RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, },
+	RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, },
+	RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, },
+};
+
+static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
+	{ CR240, 0x57 }, { CR9,   0xe0 },
+};
+
+static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
+{
+	int r;
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR80,  0x30 }, { CR81,  0x30 }, { CR79,  0x58 },
+		{ CR12,  0xf0 }, { CR77,  0x1b }, { CR78,  0x58 },
+		{ CR203, 0x06 },
+		{ },
+
+		{ CR240, 0x80 },
+	};
+
+	r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+	if (r)
+		return r;
+
+	/* related to antenna selection? */
+	if (chip->new_phy_layout) {
+		r = zd_iowrite16_locked(chip, 0xe1, CR9);
+		if (r)
+			return r;
+	}
+
+	return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
 static int zd1211_al2230_init_hw(struct zd_rf *rf)
 {
 	int r;
@@ -139,7 +186,7 @@ static int zd1211b_al2230_init_hw(struct
 		{ CR47,  0x1e },
 
 		/* ZD1211B 05.06.10 */
-		{ CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
+		{ CR48,  0x06 }, { CR49,  0xf9 }, { CR51,  0x01 },
 		{ CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
 		{ CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
 		{ CR69,  0x28 },
@@ -172,79 +219,78 @@ static int zd1211b_al2230_init_hw(struct
 		{ CR137, 0x50 }, /* 5614 */
 		{ CR138, 0xa8 },
 		{ CR144, 0xac }, /* 5621 */
-		{ CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+		{ CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
 	};
 
 	static const u32 rv1[] = {
-		/* channel 1 */
-		0x03f790,
-		0x033331,
-		0x00000d,
-
-		0x0b3331,
-		0x03b812,
-		0x00fff3,
-		0x0005a4,
-		0x0f4dc5, /* fix freq shift 0x044dc5 */
-		0x0805b6,
-		0x0146c7,
-		0x000688,
-		0x0403b9, /* External control TX power (CR31) */
-		0x00dbba,
-		0x00099b,
-		0x0bdffc,
-		0x00000d,
-		0x00580f,
+		0x8cccd0,
+		0x481dc0,
+		0xcfff00,
+		0x25a000,
+
+		/* To improve AL2230 yield, improve phase noise, 4713 */
+		0x25a000,
+		0xa3b2f0,
+
+		0x6da010, /* Reg6 update for MP versio */
+		0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
+		0x116000,
+		0x9dc020, /* External control TX power (CR31) */
+		0x5ddb00, /* RegA update for MP version */
+		0xd99000, /* RegB update for MP version */
+		0x3ffbd0, /* RegC update for MP version */
+		0xb00000, /* RegD update for MP version */
+
+		/* improve phase noise and remove phase calibration,4713 */
+		0xf01a00,
 	};
 
 	static const struct zd_ioreq16 ioreqs2[] = {
-		{ CR47,  0x1e }, { CR_RFCFG, 0x03 },
+		{ CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+		{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
 	};
 
 	static const u32 rv2[] = {
-		0x00880f,
-		0x00080f,
+		/* To improve AL2230 yield, 4713 */
+		0xf01b00,
+		0xf01e00,
+		0xf01a00,
 	};
 
 	static const struct zd_ioreq16 ioreqs3[] = {
-		{ CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
-	};
-
-	static const u32 rv3[] = {
-		0x00d80f,
-		0x00780f,
-		0x00580f,
-	};
-
-	static const struct zd_ioreq16 ioreqs4[] = {
-		{ CR138, 0x28 }, { CR203, 0x06 },
+		/* related to 6M band edge patching, happens unconditionally */
+		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
 	};
 
+	r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+		ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+	if (r)
+		return r;
 	r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
 	if (r)
 		return r;
-	r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+	r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
 	if (r)
 		return r;
-	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+	r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
 	if (r)
 		return r;
-	r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+	r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
 	if (r)
 		return r;
-	r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+	r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
 	if (r)
 		return r;
-	r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+	r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
 	if (r)
 		return r;
-	return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+	return zd1211b_al2230_finalize_rf(chip);
 }
 
-static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
 {
 	int r;
-	const u32 *rv = al2230_table[channel-1];
+	const u32 *rv = zd1211_al2230_table[channel-1];
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 	static const struct zd_ioreq16 ioreqs[] = {
 		{ CR138, 0x28 },
@@ -257,6 +303,24 @@ static int al2230_set_channel(struct zd_
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
+static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+	int r;
+	const u32 *rv = zd1211b_al2230_table[channel-1];
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+		ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+	if (r)
+		return r;
+
+	r = zd_rfwritev_cr_locked(chip, rv, 3);
+	if (r)
+		return r;
+
+	return zd1211b_al2230_finalize_rf(chip);
+}
+
 static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -294,13 +358,14 @@ int zd_rf_init_al2230(struct zd_rf *rf)
 {
 	struct zd_chip *chip = zd_rf_to_chip(rf);
 
-	rf->set_channel = al2230_set_channel;
 	rf->switch_radio_off = al2230_switch_radio_off;
 	if (chip->is_zd1211b) {
 		rf->init_hw = zd1211b_al2230_init_hw;
+		rf->set_channel = zd1211b_al2230_set_channel;
 		rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
 	} else {
 		rf->init_hw = zd1211_al2230_init_hw;
+		rf->set_channel = zd1211_al2230_set_channel;
 		rf->switch_radio_on = zd1211_al2230_switch_radio_on;
 	}
 	rf->patch_6m_band_edge = 1;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
new file mode 100644
index 0000000..a289f95
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -0,0 +1,274 @@
+/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 chan_rv[][2] = {
+	RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 },
+	RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 },
+	RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 },
+	RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 },
+	RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 },
+	RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 },
+	RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 },
+	RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 },
+	RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 },
+	RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 },
+	RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 },
+	RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 },
+	RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 },
+	RF_CHANNEL(14) = { 0x03ec00, 0x866660 },
+};
+
+static const u32 std_rv[] = {
+	0x4ff821,
+	0xc5fbfc,
+	0x21ebfe,
+	0xafd401, /* freq shift 0xaad401 */
+	0x6cf56a,
+	0xe04073,
+	0x193d76,
+	0x9dd844,
+	0x500007,
+	0xd8c010,
+};
+
+static int al7230b_init_hw(struct zd_rf *rf)
+{
+	int i, r;
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	/* All of these writes are identical to AL2230 unless otherwise
+	 * specified */
+	static const struct zd_ioreq16 ioreqs_1[] = {
+		/* This one is 7230-specific, and happens before the rest */
+		{ CR240,  0x57 },
+		{ },
+
+		{ CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
+		{ CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
+		{ CR44,   0x33 },
+		/* This value is different for 7230 (was: 0x2a) */
+		{ CR106,  0x22 },
+		{ CR107,  0x1a }, { CR109,  0x09 }, { CR110,  0x27 },
+		{ CR111,  0x2b }, { CR112,  0x2b }, { CR119,  0x0a },
+		/* This happened further down in AL2230,
+		 * and the value changed (was: 0xe0) */
+		{ CR122,  0xfc },
+		{ CR10,   0x89 },
+		/* for newest (3rd cut) AL2300 */
+		{ CR17,   0x28 },
+		{ CR26,   0x93 }, { CR34,   0x30 },
+		/* for newest (3rd cut) AL2300 */
+		{ CR35,   0x3e },
+		{ CR41,   0x24 }, { CR44,   0x32 },
+		/* for newest (3rd cut) AL2300 */
+		{ CR46,   0x96 },
+		{ CR47,   0x1e }, { CR79,   0x58 }, { CR80,  0x30 },
+		{ CR81,   0x30 }, { CR87,   0x0a }, { CR89,  0x04 },
+		{ CR92,   0x0a }, { CR99,   0x28 },
+		/* This value is different for 7230 (was: 0x00) */
+		{ CR100,  0x02 },
+		{ CR101,  0x13 }, { CR102,  0x27 },
+		/* This value is different for 7230 (was: 0x24) */
+		{ CR106,  0x22 },
+		/* This value is different for 7230 (was: 0x2a) */
+		{ CR107,  0x3f },
+		{ CR109,  0x09 },
+		/* This value is different for 7230 (was: 0x13) */
+		{ CR110,  0x1f },
+		{ CR111,  0x1f }, { CR112,  0x1f }, { CR113, 0x27 },
+		{ CR114,  0x27 },
+		/* for newest (3rd cut) AL2300 */
+		{ CR115,  0x24 },
+		/* This value is different for 7230 (was: 0x24) */
+		{ CR116,  0x3f },
+		/* This value is different for 7230 (was: 0xf4) */
+		{ CR117,  0xfa },
+		{ CR118,  0xfc }, { CR119,  0x10 }, { CR120, 0x4f },
+		{ CR121,  0x77 }, { CR137,  0x88 },
+		/* This one is 7230-specific */
+		{ CR138,  0xa8 },
+		/* This value is different for 7230 (was: 0xff) */
+		{ CR252,  0x34 },
+		/* This value is different for 7230 (was: 0xff) */
+		{ CR253,  0x34 },
+
+		/* PLL_OFF */
+		{ CR251, 0x2f },
+	};
+
+	static const struct zd_ioreq16 ioreqs_2[] = {
+		/* PLL_ON */
+		{ CR251, 0x3f },
+		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+		{ CR38, 0x38 }, { CR136, 0xdf },
+	};
+
+	r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+	if (r)
+		return r;
+
+	r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+	if (r)
+		return r;
+
+	for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+		r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+		if (r)
+			return r;
+	}
+
+	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0x700000);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+	if (r)
+		return r;
+
+	r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+	if (r)
+		return r;
+
+	r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+	if (r)
+		return r;
+
+	r = zd_iowrite16_locked(chip, 0x06, CR203);
+	if (r)
+		return r;
+	r = zd_iowrite16_locked(chip, 0x80, CR240);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+	int i, r;
+	const u32 *rv = chan_rv[channel-1];
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	struct zd_ioreq16 ioreqs_1[] = {
+		{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+		{ CR38,  0x38 }, { CR136, 0xdf },
+	};
+
+	struct zd_ioreq16 ioreqs_2[] = {
+		/* PLL_ON */
+		{ CR251, 0x3f },
+		{ CR203, 0x06 }, { CR240, 0x08 },
+	};
+
+	r = zd_iowrite16_locked(chip, 0x57, CR240);
+	if (r)
+		return r;
+
+	/* PLL_OFF */
+	r = zd_iowrite16_locked(chip, 0x2f, CR251);
+	if (r)
+		return r;
+
+	for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+		r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+		if (r)
+			return r;
+	}
+
+	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+	if (r)
+		return r;
+	r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+	if (r)
+		return r;
+
+	r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+	if (r)
+		return r;
+
+	for (i = 0; i < 2; i++) {
+		r = zd_rfwrite_cr_locked(chip, rv[i]);
+		if (r)
+			return r;
+	}
+
+	r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+	if (r)
+		return r;
+
+	return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+}
+
+static int al7230b_switch_radio_on(struct zd_rf *rf)
+{
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR11,  0x00 },
+		{ CR251, 0x3f },
+	};
+
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al7230b_switch_radio_off(struct zd_rf *rf)
+{
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+	static const struct zd_ioreq16 ioreqs[] = {
+		{ CR11,  0x04 },
+		{ CR251, 0x2f },
+	};
+
+	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al7230b(struct zd_rf *rf)
+{
+	struct zd_chip *chip = zd_rf_to_chip(rf);
+
+	if (chip->is_zd1211b) {
+		dev_err(zd_chip_dev(chip), "AL7230B is currently not "
+			"supported for ZD1211B devices\n");
+		return -ENODEV;
+	}
+
+	rf->init_hw = al7230b_init_hw;
+	rf->set_channel = al7230b_set_channel;
+	rf->switch_radio_on = al7230b_switch_radio_on;
+	rf->switch_radio_off = al7230b_switch_radio_off;
+	rf->patch_6m_band_edge = 1;
+	return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 96551da..47489fe 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -16,6 +16,7 @@
  */
 
 #include <asm/unaligned.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/firmware.h>
@@ -40,10 +41,16 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+	/* "Driverless" devices that need ejecting */
+	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{}
 };
 
@@ -265,6 +272,39 @@ static char *get_fw_name(char *buffer, s
 	return buffer;
 }
 
+static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+	const struct firmware *ub_fw)
+{
+	const struct firmware *ur_fw = NULL;
+	int offset;
+	int r = 0;
+	char fw_name[128];
+
+	r = request_fw_file(&ur_fw,
+		get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+		&udev->dev);
+	if (r)
+		goto error;
+
+	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
+		REBOOT);
+	if (r)
+		goto error;
+
+	offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
+		E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+
+	/* At this point, the vendor driver downloads the whole firmware
+	 * image, hacks around with version IDs, and uploads it again,
+	 * completely overwriting the boot code. We do not do this here as
+	 * it is not required on any tested devices, and it is suspected to
+	 * cause problems. */
+error:
+	release_firmware(ur_fw);
+	return r;
+}
+
 static int upload_firmware(struct usb_device *udev, u8 device_type)
 {
 	int r;
@@ -284,15 +324,17 @@ static int upload_firmware(struct usb_de
 
 	fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
 
-	/* FIXME: do we have any reason to perform the kludge that the vendor
-	 * driver does when there is a version mismatch? (their driver uploads
-	 * different firmwares and stuff)
-	 */
 	if (fw_bcdDevice != bcdDevice) {
 		dev_info(&udev->dev,
-			"firmware device id %#06x and actual device id "
-			"%#06x differ, continuing anyway\n",
-			fw_bcdDevice, bcdDevice);
+			"firmware version %#06x and device bootcode version "
+			"%#06x differ\n", fw_bcdDevice, bcdDevice);
+		if (bcdDevice <= 0x4313)
+			dev_warn(&udev->dev, "device has old bootcode, please "
+				"report success or failure\n");
+
+		r = handle_version_mismatch(udev, device_type, ub_fw);
+		if (r)
+			goto error;
 	} else {
 		dev_dbg_f(&udev->dev,
 			"firmware device id %#06x is equal to the "
@@ -622,7 +664,7 @@ resubmit:
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
-struct urb *alloc_urb(struct zd_usb *usb)
+static struct urb *alloc_urb(struct zd_usb *usb)
 {
 	struct usb_device *udev = zd_usb_to_usbdev(usb);
 	struct urb *urb;
@@ -646,7 +688,7 @@ struct urb *alloc_urb(struct zd_usb *usb
 	return urb;
 }
 
-void free_urb(struct urb *urb)
+static void free_urb(struct urb *urb)
 {
 	if (!urb)
 		return;
@@ -866,7 +908,7 @@ void zd_usb_clear(struct zd_usb *usb)
 {
 	usb_set_intfdata(usb->intf, NULL);
 	usb_put_intf(usb->intf);
-	memset(usb, 0, sizeof(*usb));
+	ZD_MEMCLEAR(usb, sizeof(*usb));
 	/* FIXME: usb_interrupt, usb_tx, usb_rx? */
 }
 
@@ -912,6 +954,55 @@ #else
 #define print_id(udev) do { } while (0)
 #endif
 
+static int eject_installer(struct usb_interface *intf)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_host_interface *iface_desc = &intf->altsetting[0];
+	struct usb_endpoint_descriptor *endpoint;
+	unsigned char *cmd;
+	u8 bulk_out_ep;
+	int r;
+
+	/* Find bulk out endpoint */
+	endpoint = &iface_desc->endpoint[1].desc;
+	if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+	    (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+	    USB_ENDPOINT_XFER_BULK) {
+		bulk_out_ep = endpoint->bEndpointAddress;
+	} else {
+		dev_err(&udev->dev,
+			"zd1211rw: Could not find bulk out endpoint\n");
+		return -ENODEV;
+	}
+
+	cmd = kzalloc(31, GFP_KERNEL);
+	if (cmd == NULL)
+		return -ENODEV;
+
+	/* USB bulk command block */
+	cmd[0] = 0x55;	/* bulk command signature */
+	cmd[1] = 0x53;	/* bulk command signature */
+	cmd[2] = 0x42;	/* bulk command signature */
+	cmd[3] = 0x43;	/* bulk command signature */
+	cmd[14] = 6;	/* command length */
+
+	cmd[15] = 0x1b;	/* SCSI command: START STOP UNIT */
+	cmd[19] = 0x2;	/* eject disc */
+
+	dev_info(&udev->dev, "Ejecting virtual installer media...\n");
+	r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
+		cmd, 31, NULL, 2000);
+	kfree(cmd);
+	if (r)
+		return r;
+
+	/* At this point, the device disconnects and reconnects with the real
+	 * ID numbers. */
+
+	usb_set_intfdata(intf, NULL);
+	return 0;
+}
+
 static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	int r;
@@ -920,6 +1011,9 @@ static int probe(struct usb_interface *i
 
 	print_id(udev);
 
+	if (id->driver_info & DEVICE_INSTALLER)
+		return eject_installer(intf);
+
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
@@ -985,6 +1079,11 @@ static void disconnect(struct usb_interf
 	struct zd_mac *mac = zd_netdev_mac(netdev);
 	struct zd_usb *usb = &mac->chip.usb;
 
+	/* Either something really bad happened, or we're just dealing with
+	 * a DEVICE_INSTALLER. */
+	if (netdev == NULL)
+		return;
+
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
 	zd_netdev_disconnect(netdev);
@@ -1000,7 +1099,6 @@ static void disconnect(struct usb_interf
 	 */
 	usb_reset_device(interface_to_usbdev(intf));
 
-	/* If somebody still waits on this lock now, this is an error. */
 	zd_netdev_free(netdev);
 	dev_dbg(&intf->dev, "disconnected\n");
 }
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index d642028..92746f7 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -30,6 +30,7 @@ #include "zd_types.h"
 enum devicetype {
 	DEVICE_ZD1211  = 0,
 	DEVICE_ZD1211B = 1,
+	DEVICE_INSTALLER = 2,
 };
 
 enum endpoints {
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-07-28  0:23 ` Please pull 'upstream' " John W. Linville
@ 2006-07-29  4:33   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-07-29  4:33 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

pulled


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-07-28  0:22 Please pull 'upstream-fixes' " John W. Linville
@ 2006-07-28  0:23 ` John W. Linville
  2006-07-29  4:33   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-07-28  0:23 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 416512cb75f51f3d12e5e1aa57b6a36760fd12c9:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Dan Williams:
      prism54: update to WE-19 for WPA support

Daniel Drake:
      zd1211rw: Implement SIOCGIWNICKN
      Add zd1211rw MAINTAINERS entry
      ieee80211: small ERP handling additions
      softmac: ERP handling and driver-level notifications
      softmac: export highest_supported_rate function
      ieee80211: Make ieee80211_rx_any usable
      softmac: Add MAINTAINERS entry

Pavel Machek:
      cleanup // comments from ipw2200

Robert Schulze:
      airo: collapse debugging-messages in issuecommand to one line

 MAINTAINERS                                     |   21 +
 drivers/net/wireless/airo.c                     |   12 
 drivers/net/wireless/ipw2200.c                  |   29 -
 drivers/net/wireless/prism54/isl_ioctl.c        |  573 ++++++++++++++++++++++-
 drivers/net/wireless/prism54/isl_ioctl.h        |    6 
 drivers/net/wireless/prism54/islpci_dev.c       |    4 
 drivers/net/wireless/prism54/islpci_dev.h       |    2 
 drivers/net/wireless/zd1211rw/zd_netdev.c       |   17 +
 include/net/ieee80211.h                         |    9 
 include/net/ieee80211softmac.h                  |   60 ++
 net/ieee80211/ieee80211_rx.c                    |   39 +-
 net/ieee80211/softmac/ieee80211softmac_assoc.c  |   21 +
 net/ieee80211/softmac/ieee80211softmac_io.c     |   14 +
 net/ieee80211/softmac/ieee80211softmac_module.c |   90 ++--
 net/ieee80211/softmac/ieee80211softmac_priv.h   |    8 
 15 files changed, 777 insertions(+), 128 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index b2afc7a..4e14ee7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2588,6 +2588,18 @@ P:	Nicolas Pitre
 M:	nico@cam.org
 S:	Maintained
 
+SOFTMAC LAYER (IEEE 802.11)
+P:	Johannes Berg
+M:	johannes@sipsolutions.net
+P:	Joe Jezak
+M:	josejx@gentoo.org
+P:	Daniel Drake
+M:	dsd@gentoo.org
+W:	http://softmac.sipsolutions.net/
+L:	softmac-dev@sipsolutions.net
+L:	netdev@vger.kernel.org
+S:	Maintained
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -3296,6 +3308,15 @@ W:	http://www.qsl.net/dl1bke/
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+ZD1211RW WIRELESS DRIVER
+P:	Daniel Drake
+M:	dsd@gentoo.org
+P:	Ulrich Kunitz
+M:	kune@deine-taler.de
+W:	http://zd1211.ath.cx/wiki/DriverRewrite
+L:	zd1211-devs@lists.sourceforge.net (subscribers-only)
+S:	Maintained
+
 ZF MACHZ WATCHDOG
 P:	Fernando Fuganti
 M:	fuganti@netbank.com.br
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index a4dd139..16befbc 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -3950,13 +3950,11 @@ static u16 issuecommand(struct airo_info
 	pRsp->rsp0 = IN4500(ai, RESP0);
 	pRsp->rsp1 = IN4500(ai, RESP1);
 	pRsp->rsp2 = IN4500(ai, RESP2);
-	if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
-		airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
-		airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
-		airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
-		airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
-		airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
-	}
+	if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+		airo_print_err(ai->dev->name,
+			"cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+			pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+			pRsp->rsp2);
 
 	// clear stuck command busy if necessary
 	if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index b3300ff..758459e 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -2667,7 +2667,7 @@ static void ipw_fw_dma_abort(struct ipw_
 
 	IPW_DEBUG_FW(">> :\n");
 
-	//set the Stop and Abort bit
+	/* set the Stop and Abort bit */
 	control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
 	ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
 	priv->sram_desc.last_cb_index = 0;
@@ -3002,8 +3002,6 @@ static int ipw_load_ucode(struct ipw_pri
 	if (rc < 0)
 		return rc;
 
-//      spin_lock_irqsave(&priv->lock, flags);
-
 	for (addr = IPW_SHARED_LOWER_BOUND;
 	     addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
 		ipw_write32(priv, addr, 0);
@@ -3097,8 +3095,6 @@ static int ipw_load_ucode(struct ipw_pri
 	   firmware have problem getting alive resp. */
 	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
 
-//      spin_unlock_irqrestore(&priv->lock, flags);
-
 	return rc;
 }
 
@@ -6387,13 +6383,6 @@ static int ipw_wx_set_genie(struct net_d
 	    (wrqu->data.length && extra == NULL))
 		return -EINVAL;
 
-	//mutex_lock(&priv->mutex);
-
-	//if (!ieee->wpa_enabled) {
-	//      err = -EOPNOTSUPP;
-	//      goto out;
-	//}
-
 	if (wrqu->data.length) {
 		buf = kmalloc(wrqu->data.length, GFP_KERNEL);
 		if (buf == NULL) {
@@ -6413,7 +6402,6 @@ static int ipw_wx_set_genie(struct net_d
 
 	ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
       out:
-	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6426,13 +6414,6 @@ static int ipw_wx_get_genie(struct net_d
 	struct ieee80211_device *ieee = priv->ieee;
 	int err = 0;
 
-	//mutex_lock(&priv->mutex);
-
-	//if (!ieee->wpa_enabled) {
-	//      err = -EOPNOTSUPP;
-	//      goto out;
-	//}
-
 	if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
 		wrqu->data.length = 0;
 		goto out;
@@ -6447,7 +6428,6 @@ static int ipw_wx_get_genie(struct net_d
 	memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
 
       out:
-	//mutex_unlock(&priv->mutex);
 	return err;
 }
 
@@ -6558,7 +6538,6 @@ static int ipw_wx_set_auth(struct net_de
 		ieee->ieee802_1x = param->value;
 		break;
 
-		//case IW_AUTH_ROAMING_CONTROL:
 	case IW_AUTH_PRIVACY_INVOKED:
 		ieee->privacy_invoked = param->value;
 		break;
@@ -6680,7 +6659,7 @@ static int ipw_wx_set_mlme(struct net_de
 
 	switch (mlme->cmd) {
 	case IW_MLME_DEAUTH:
-		// silently ignore
+		/* silently ignore */
 		break;
 
 	case IW_MLME_DISASSOC:
@@ -9766,7 +9745,7 @@ #endif
 	return 0;
 }
 
-#endif				// CONFIG_IPW2200_MONITOR
+#endif				/* CONFIG_IPW2200_MONITOR */
 
 static int ipw_wx_reset(struct net_device *dev,
 			struct iw_request_info *info,
@@ -10009,7 +9988,7 @@ static  void init_sys_config(struct ipw_
 	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->pass_noise_stats_to_host = 1;	/* 1 -- fix for 256 */
 	sys_config->silence_threshold = 0x1e;
 }
 
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 989599a..0c30fe7 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -35,10 +35,14 @@ #include "oid_mgt.h"
 
 #include <net/iw_handler.h>	/* New driver API */
 
+#define KEY_SIZE_WEP104 13	/* 104/128-bit WEP keys */
+#define KEY_SIZE_WEP40  5	/* 40/64-bit WEP keys */
+/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
+#define KEY_SIZE_TKIP   32	/* TKIP keys */
 
-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
 				u8 *wpa_ie, size_t wpa_ie_len);
-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
 static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
 				__u32 *, char *);
 
@@ -468,6 +472,9 @@ prism54_get_range(struct net_device *nde
 	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 	range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
 
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+		IW_ENC_CAPA_CIPHER_TKIP;
+
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return 0;
 
@@ -567,6 +574,8 @@ prism54_translate_bss(struct net_device 
 	struct iw_event iwe;	/* Temporary buffer */
 	short cap;
 	islpci_private *priv = netdev_priv(ndev);
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
 
 	/* The first entry must be the MAC address */
 	memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@@ -627,27 +636,13 @@ #define CAP_CRYPT 0x10
 	current_ev =
 	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-	if (priv->wpa) {
-		u8 wpa_ie[MAX_WPA_IE_LEN];
-		char *buf, *p;
-		size_t wpa_ie_len;
-		int i;
-
-		wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
-		if (wpa_ie_len > 0 &&
-		    (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
-			p = buf;
-			p += sprintf(p, "wpa_ie=");
-			for (i = 0; i < wpa_ie_len; i++) {
-				p += sprintf(p, "%02x", wpa_ie[i]);
-			}
-			memset(&iwe, 0, sizeof (iwe));
-			iwe.cmd = IWEVCUSTOM;
-			iwe.u.data.length = strlen(buf);
-			current_ev = iwe_stream_add_point(current_ev, end_buf,
-							  &iwe, buf);
-			kfree(buf);
-		}
+	/* Add WPA/RSN Information Element, if any */
+	wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
+	if (wpa_ie_len > 0) {
+		iwe.cmd = IWEVGENIE;
+		iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+		current_ev = iwe_stream_add_point(current_ev, end_buf,
+				&iwe, wpa_ie);
 	}
 	return current_ev;
 }
@@ -1051,12 +1046,24 @@ prism54_set_encode(struct net_device *nd
 		current_index = r.u;
 		/* Verify that the key is not marked as invalid */
 		if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
-			key.length = dwrq->length > sizeof (key.key) ?
-			    sizeof (key.key) : dwrq->length;
-			memcpy(key.key, extra, key.length);
-			if (key.length == 32)
-				/* we want WPA-PSK */
+			if (dwrq->length > KEY_SIZE_TKIP) {
+				/* User-provided key data too big */
+				return -EINVAL;
+			}
+			if (dwrq->length > KEY_SIZE_WEP104) {
+				/* WPA-PSK TKIP */
 				key.type = DOT11_PRIV_TKIP;
+				key.length = KEY_SIZE_TKIP;
+			} else if (dwrq->length > KEY_SIZE_WEP40) {
+				/* WEP 104/128 */
+				key.length = KEY_SIZE_WEP104;
+			} else {
+				/* WEP 40/64 */
+				key.length = KEY_SIZE_WEP40;
+			}
+			memset(key.key, 0, sizeof (key.key));
+			memcpy(key.key, extra, dwrq->length);
+
 			if ((index < 0) || (index > 3))
 				/* no index provided use the current one */
 				index = current_index;
@@ -1210,6 +1217,489 @@ prism54_set_txpower(struct net_device *n
 	}
 }
 
+static int prism54_set_genie(struct net_device *ndev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int alen, ret = 0;
+	struct obj_attachment *attach;
+
+	if (data->length > MAX_WPA_IE_LEN ||
+	    (data->length && extra == NULL))
+		return -EINVAL;
+
+	memcpy(priv->wpa_ie, extra, data->length);
+	priv->wpa_ie_len = data->length;
+
+	alen = sizeof(*attach) + priv->wpa_ie_len;
+	attach = kzalloc(alen, GFP_KERNEL);
+	if (attach == NULL)
+		return -ENOMEM;
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+	/* Note: endianness is covered by mgt_set_varlen */
+	attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+               (WLAN_FC_STYPE_ASSOC_REQ << 4);
+	attach->id = -1;
+	attach->size = priv->wpa_ie_len;
+	memcpy(attach->data, extra, priv->wpa_ie_len);
+
+	ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+		priv->wpa_ie_len);
+	if (ret == 0) {
+		attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+			(WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+		ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+			priv->wpa_ie_len);
+		if (ret == 0)
+			printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+				ndev->name);
+	}
+
+	kfree(attach);
+	return ret;
+}
+
+
+static int prism54_get_genie(struct net_device *ndev,
+			     struct iw_request_info *info,
+			     struct iw_point *data, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int len = priv->wpa_ie_len;
+
+	if (len <= 0) {
+		data->length = 0;
+		return 0;
+	}
+
+	if (data->length < len)
+		return -E2BIG;
+
+	data->length = len;
+	memcpy(extra, priv->wpa_ie, len);
+
+	return 0;
+}
+
+static int prism54_set_auth(struct net_device *ndev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_param *param = &wrqu->param;
+	u32 mlmelevel = 0, authen = 0, dot1x = 0;
+	u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
+	u32 old_wpa;
+	int ret = 0;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	down_write(&priv->mib_sem);
+	wpa = old_wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+	ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	privinvoked = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+	dot1x = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
+	mlmelevel = r.u;
+
+	if (ret < 0)
+		goto out;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		/* Do the same thing as IW_AUTH_WPA_VERSION */
+		if (param->value) {
+			wpa = 1;
+			privinvoked = 1; /* For privacy invoked */
+			exunencrypt = 1; /* Filter out all unencrypted frames */
+			dot1x = 0x01; /* To enable eap filter */
+			mlmelevel = DOT11_MLME_EXTENDED;
+			authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+		} else {
+			wpa = 0;
+			privinvoked = 0;
+			exunencrypt = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlmelevel = DOT11_MLME_AUTO;
+		}
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+			wpa = 0;
+			privinvoked = 0;
+			exunencrypt = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlmelevel = DOT11_MLME_AUTO;
+		} else {
+			if (param->value & IW_AUTH_WPA_VERSION_WPA)
+				wpa = 1;
+			else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
+				wpa = 2;
+			privinvoked = 1; /* For privacy invoked */
+			exunencrypt = 1; /* Filter out all unencrypted frames */
+			dot1x = 0x01; /* To enable eap filter */
+			mlmelevel = DOT11_MLME_EXTENDED;
+			authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+		}
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		dot1x = param->value ? 1 : 0;
+		break;
+
+	case IW_AUTH_PRIVACY_INVOKED:
+		privinvoked = param->value ? 1 : 0;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		exunencrypt = param->value ? 1 : 0;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+			/* Only WEP uses _SK and _BOTH */
+			if (wpa > 0) {
+				ret = -EINVAL;
+				goto out;
+			}
+			authen = DOT11_AUTH_SK;
+		} else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+			authen = DOT11_AUTH_OS;
+		} else {
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Set all the values */
+	down_write(&priv->mib_sem);
+	priv->wpa = wpa;
+	up_write(&priv->mib_sem);
+	mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+	mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
+	mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
+	mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+	mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
+
+out:
+	return ret;
+}
+
+static int prism54_get_auth(struct net_device *ndev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_param *param = &wrqu->param;
+	u32 wpa = 0;
+	int ret = 0;
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	down_write(&priv->mib_sem);
+	wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * wpa_supplicant will control these internally
+		 */
+		ret = -EOPNOTSUPP;
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		switch (wpa) {
+		case 1:
+			param->value = IW_AUTH_WPA_VERSION_WPA;
+			break;
+		case 2:
+			param->value = IW_AUTH_WPA_VERSION_WPA2;
+			break;
+		case 0:
+		default:
+			param->value = IW_AUTH_WPA_VERSION_DISABLED;
+			break;
+		}
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+		if (ret >= 0) {
+			switch (r.u) {
+			case DOT11_AUTH_OS:
+				param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+				break;
+			case DOT11_AUTH_BOTH:
+			case DOT11_AUTH_SK:
+				param->value = IW_AUTH_ALG_SHARED_KEY;
+			case DOT11_AUTH_NONE:
+			default:
+				param->value = 0;
+				break;
+			}
+		}
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		param->value = wpa > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	case IW_AUTH_PRIVACY_INVOKED:
+		ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+		if (ret >= 0)
+			param->value = r.u > 0 ? 1 : 0;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int prism54_set_encodeext(struct net_device *ndev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, alg = ext->alg, set_key = 1;
+	union oid_res_t r;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+	int ret = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* Determine and validate the key index */
+	idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+	if (idx) {
+		if (idx < 0 || idx > 3)
+			return -EINVAL;
+	} else {
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		if (ret < 0)
+			goto out;
+		idx = r.u;
+	}
+
+	if (encoding->flags & IW_ENCODE_DISABLED)
+		alg = IW_ENCODE_ALG_NONE;
+
+	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+		/* Only set transmit key index here, actual
+		 * key is set below if needed.
+		 */
+		ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
+		set_key = ext->key_len > 0 ? 1 : 0;
+	}
+
+	if (set_key) {
+		struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+		switch (alg) {
+		case IW_ENCODE_ALG_NONE:
+			break;
+		case IW_ENCODE_ALG_WEP:
+			if (ext->key_len > KEY_SIZE_WEP104) {
+				ret = -EINVAL;
+				goto out;
+			}
+			if (ext->key_len > KEY_SIZE_WEP40)
+				key.length = KEY_SIZE_WEP104;
+			else
+				key.length = KEY_SIZE_WEP40;
+			break;
+		case IW_ENCODE_ALG_TKIP:
+			if (ext->key_len > KEY_SIZE_TKIP) {
+				ret = -EINVAL;
+				goto out;
+			}
+			key.type = DOT11_PRIV_TKIP;
+			key.length = KEY_SIZE_TKIP;
+		default:
+			return -EINVAL;
+		}
+
+		if (key.length) {
+			memset(key.key, 0, sizeof(key.key));
+			memcpy(key.key, ext->key, ext->key_len);
+			ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
+					    &key);
+			if (ret < 0)
+				goto out;
+		}
+	}
+
+	/* Read the flags */
+	if (encoding->flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled,
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (encoding->flags & IW_ENCODE_OPEN) {
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	}
+	if (encoding->flags & IW_ENCODE_RESTRICTED) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+
+	/* do the change if requested  */
+	if (encoding->flags & IW_ENCODE_MODE) {
+		ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
+				      &authen);
+		ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
+				      &invoke);
+		ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+				      &exunencrypt);
+	}
+
+out:
+	return ret;
+}
+
+
+static int prism54_get_encodeext(struct net_device *ndev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	struct iw_point *encoding = &wrqu->encoding;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int idx, max_key_len;
+	union oid_res_t r;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
+	int ret = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	/* first get the flags */
+	ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+	authen = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+	invoke = r.u;
+	ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+	exunencrypt = r.u;
+	if (ret < 0)
+		goto out;
+
+	max_key_len = encoding->length - sizeof(*ext);
+	if (max_key_len < 0)
+		return -EINVAL;
+
+	idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+	if (idx) {
+		if (idx < 0 || idx > 3)
+			return -EINVAL;
+	} else {
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		if (ret < 0)
+			goto out;
+		idx = r.u;
+	}
+
+	encoding->flags = idx + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	switch (authen) {
+	case DOT11_AUTH_BOTH:
+	case DOT11_AUTH_SK:
+		wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
+	case DOT11_AUTH_OS:
+	default:
+		wrqu->encoding.flags |= IW_ENCODE_OPEN;
+		break;
+	}
+
+	down_write(&priv->mib_sem);
+	wpa = priv->wpa;
+	up_write(&priv->mib_sem);
+
+	if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
+		/* No encryption */
+		ext->alg = IW_ENCODE_ALG_NONE;
+		ext->key_len = 0;
+		wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+	} else {
+		struct obj_key *key;
+
+		ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
+		if (ret < 0)
+			goto out;
+		key = r.ptr;
+		if (max_key_len < key->length) {
+			ret = -E2BIG;
+			goto out;
+		}
+		memcpy(ext->key, key->key, key->length);
+		ext->key_len = key->length;
+
+		switch (key->type) {
+		case DOT11_PRIV_TKIP:
+			ext->alg = IW_ENCODE_ALG_TKIP;
+			break;
+		default:
+		case DOT11_PRIV_WEP:
+			ext->alg = IW_ENCODE_ALG_WEP;
+			break;
+		}
+		wrqu->encoding.flags |= IW_ENCODE_ENABLED;
+	}
+
+out:
+	return ret;
+}
+
+
 static int
 prism54_reset(struct net_device *ndev, struct iw_request_info *info,
 	      __u32 * uwrq, char *extra)
@@ -1591,8 +2081,8 @@ #define MAC2STR(a) (a)[0], (a)[1], (a)[2
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 
 static void
-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
-		   u8 *wpa_ie, size_t wpa_ie_len)
+prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+		       u8 *wpa_ie, size_t wpa_ie_len)
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
@@ -1658,7 +2148,7 @@ prism54_wpa_ie_add(islpci_private *priv,
 }
 
 static size_t
-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
@@ -1683,14 +2173,14 @@ prism54_wpa_ie_get(islpci_private *priv,
 }
 
 void
-prism54_wpa_ie_init(islpci_private *priv)
+prism54_wpa_bss_ie_init(islpci_private *priv)
 {
 	INIT_LIST_HEAD(&priv->bss_wpa_list);
 	sema_init(&priv->wpa_sem, 1);
 }
 
 void
-prism54_wpa_ie_clean(islpci_private *priv)
+prism54_wpa_bss_ie_clean(islpci_private *priv)
 {
 	struct list_head *ptr, *n;
 
@@ -1722,7 +2212,7 @@ prism54_process_bss_data(islpci_private 
 		}
 		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
 		    memcmp(pos + 2, wpa_oid, 4) == 0) {
-			prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+			prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
 			return;
 		}
 		pos += 2 + pos[1];
@@ -1879,7 +2369,7 @@ prism54_process_trap_helper(islpci_priva
 		send_formatted_event(priv, "Associate request (ex)", mlme, 1);
 
 		if (priv->iw_mode != IW_MODE_MASTER 
-				&& mlmeex->state != DOT11_STATE_AUTHING)
+				&& mlmeex->state != DOT11_STATE_ASSOCING)
 			break;
 		
 		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@@ -1893,7 +2383,7 @@ prism54_process_trap_helper(islpci_priva
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
 
-		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
@@ -1937,7 +2427,7 @@ prism54_process_trap_helper(islpci_priva
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
 
-		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
 			printk(KERN_DEBUG "No WPA IE found from "
@@ -2553,6 +3043,15 @@ static const iw_handler prism54_handler[
 	(iw_handler) prism54_get_encode,	/* SIOCGIWENCODE */
 	(iw_handler) NULL,	/* SIOCSIWPOWER */
 	(iw_handler) NULL,	/* SIOCGIWPOWER */
+	NULL,			/* -- hole -- */
+	NULL,			/* -- hole -- */
+	(iw_handler) prism54_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) prism54_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) prism54_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) prism54_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
+	(iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
+	NULL,			/* SIOCSIWPMKSA */
 };
 
 /* The low order bit identify a SET (0) or a GET (1) ioctl.  */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
index 46d5cde..65f33ac 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -27,7 +27,7 @@ #include "islpci_dev.h"
 
 #include <net/iw_handler.h>	/* New driver API */
 
-#define SUPPORTED_WIRELESS_EXT                  16
+#define SUPPORTED_WIRELESS_EXT                  19
 
 void prism54_mib_init(islpci_private *);
 
@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl
 
 void prism54_process_trap(void *);
 
-void prism54_wpa_ie_init(islpci_private *priv);
-void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_bss_ie_init(islpci_private *priv);
+void prism54_wpa_bss_ie_clean(islpci_private *priv);
 
 int prism54_set_mac_address(struct net_device *, void *);
 
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 5ddf295..ab3c5a2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -715,7 +715,7 @@ #endif
 	}
 
 	prism54_acl_init(&priv->acl);
-	prism54_wpa_ie_init(priv);
+	prism54_wpa_bss_ie_init(priv);
 	if (mgt_init(priv)) 
 		goto out_free;
 
@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
 
 	/* Free the acces control list and the WPA list */
 	prism54_acl_clean(&priv->acl);
-	prism54_wpa_ie_clean(priv);
+	prism54_wpa_bss_ie_clean(priv);
 	mgt_clean(priv);
 
 	return 0;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 0705316..5049f37 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -179,6 +179,8 @@ typedef struct {
 	struct list_head bss_wpa_list;
 	int num_bss_wpa;
 	struct semaphore wpa_sem;
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	size_t wpa_ie_len;
 
 	struct work_struct reset_task;
 	int reset_task_pending;
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 9df232c..440ef24 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -72,10 +72,18 @@ static int iw_get_name(struct net_device
 	               struct iw_request_info *info,
 		       union iwreq_data *req, char *extra)
 {
-	/* FIXME: check whether 802.11a will also supported, add also
-	 *        zd1211B, if we support it.
-	 */
-	strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+	/* FIXME: check whether 802.11a will also supported */
+	strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
+	return 0;
+}
+
+static int iw_get_nick(struct net_device *netdev,
+	               struct iw_request_info *info,
+		       union iwreq_data *req, char *extra)
+{
+	strcpy(extra, "zd1211");
+	req->data.length = strlen(extra) + 1;
+	req->data.flags = 1;
 	return 0;
 }
 
@@ -181,6 +189,7 @@ #define WX(x) [(x)-SIOCIWFIRST]
 
 static const iw_handler zd_standard_iw_handlers[] = {
 	WX(SIOCGIWNAME)		= iw_get_name,
+	WX(SIOCGIWNICKN)	= iw_get_nick,
 	WX(SIOCSIWFREQ)		= iw_set_freq,
 	WX(SIOCGIWFREQ)		= iw_get_freq,
 	WX(SIOCSIWMODE)		= iw_set_mode,
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index ecc4286..b174ebb 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -240,6 +240,11 @@ #define WLAN_CAPABILITY_QOS (1<<9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
 #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
 
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
 /* Status codes */
 enum ieee80211_statuscode {
 	WLAN_STATUS_SUCCESS = 0,
@@ -747,6 +752,8 @@ #define NETWORK_HAS_QUIET               
 #define NETWORK_HAS_IBSS_DFS            (1<<8)
 #define NETWORK_HAS_TPC_REPORT          (1<<9)
 
+#define NETWORK_HAS_ERP_VALUE           (1<<10)
+
 #define QOS_QUEUE_NUM                   4
 #define QOS_OUI_LEN                     3
 #define QOS_OUI_TYPE                    2
@@ -1252,6 +1259,8 @@ extern int ieee80211_tx_frame(struct iee
 			      int total_len, int encrypt_mpdu);
 
 /* ieee80211_rx.c */
+extern void ieee80211_rx_any(struct ieee80211_device *ieee,
+		     struct sk_buff *skb, struct ieee80211_rx_stats *stats);
 extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 			struct ieee80211_rx_stats *rx_stats);
 /* make sure to set stats->len */
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 00ad810..425b3a5 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -86,9 +86,6 @@ struct ieee80211softmac_assoc_info {
 	
 	/* BSSID we're trying to associate to */
 	char bssid[ETH_ALEN];
-
-	/* Rates supported by the network */
-	struct ieee80211softmac_ratesinfo supported_rates;
 	
 	/* some flags.
 	 * static_essid is valid if the essid is constant,
@@ -103,6 +100,7 @@ struct ieee80211softmac_assoc_info {
 	 * bssfixed is used for SIOCSIWAP.
 	 */
 	u8 static_essid:1,
+	   short_preamble_available:1,
 	   associating:1,
 	   assoc_wait:1,
 	   bssvalid:1,
@@ -115,6 +113,19 @@ struct ieee80211softmac_assoc_info {
 	struct work_struct timeout;
 };
 
+struct ieee80211softmac_bss_info {
+	/* Rates supported by the network */
+	struct ieee80211softmac_ratesinfo supported_rates;
+
+	/* This indicates whether frames can currently be transmitted with
+	 * short preamble (only use this variable during TX at CCK rates) */
+	u8 short_preamble:1;
+
+	/* This indicates whether protection (e.g. self-CTS) should be used
+	 * when transmitting with OFDM modulation */
+	u8 use_protection:1;
+};
+
 enum {
 	IEEE80211SOFTMAC_AUTH_OPEN_REQUEST	= 1,
 	IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE	= 2,
@@ -157,6 +168,10 @@ #define IEEE80211SOFTMAC_TXRATECHG_DEFAU
 #define IEEE80211SOFTMAC_TXRATECHG_MCAST		(1 << 2) /* mcast_rate */
 #define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST		(1 << 3) /* mgt_mcast_rate */
 
+#define IEEE80211SOFTMAC_BSSINFOCHG_RATES		(1 << 0) /* supported_rates */
+#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE	(1 << 1) /* short_preamble */
+#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION		(1 << 2) /* use_protection */
+
 struct ieee80211softmac_device {
 	/* 802.11 structure for data stuff */
 	struct ieee80211_device *ieee;
@@ -200,10 +215,16 @@ struct ieee80211softmac_device {
 	 * The driver just needs to read them.
 	 */
 	struct ieee80211softmac_txrates txrates;
-	/* If the driver needs to do stuff on TX rate changes, assign this callback. */
+
+	/* If the driver needs to do stuff on TX rate changes, assign this
+	 * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */
 	void (*txrates_change)(struct net_device *dev,
-			       u32 changes, /* see IEEE80211SOFTMAC_TXRATECHG flags */
-			       const struct ieee80211softmac_txrates *rates_before_change);
+			       u32 changes);
+
+	/* If the driver needs to do stuff when BSS properties change, assign
+	 * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */
+	void (*bssinfo_change)(struct net_device *dev,
+			       u32 changes);
 
 	/* private stuff follows */
 	/* this lock protects this structure */
@@ -216,6 +237,7 @@ struct ieee80211softmac_device {
 	
 	struct ieee80211softmac_scaninfo *scaninfo;
 	struct ieee80211softmac_assoc_info associnfo;
+	struct ieee80211softmac_bss_info bssinfo;
 
 	struct list_head auth_queue;
 	struct list_head events;
@@ -257,6 +279,14 @@ extern void ieee80211softmac_fragment_lo
  * Note that the rates need to be sorted. */
 extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
 
+/* Finds the highest rate which is:
+ *  1. Present in ri (optionally a basic rate)
+ *  2. Supported by the device
+ *  3. Less than or equal to the user-defined rate
+ */
+extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
+	struct ieee80211softmac_ratesinfo *ri, int basic_only);
+
 /* Helper function which advises you the rate at which a frame should be
  * transmitted at. */
 static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
@@ -279,6 +309,24 @@ static inline u8 ieee80211softmac_sugges
 		return txrates->mcast_rate;
 }
 
+/* Helper function which advises you when it is safe to transmit with short
+ * preamble.
+ * You should only call this function when transmitting at CCK rates. */
+static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac,
+						    int is_multicast,
+						    int is_mgt)
+{
+	return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble;
+}
+
+/* Helper function which advises you whether protection (e.g. self-CTS) is
+ * needed. 1 = protection needed, 0 = no protection needed
+ * Only use this function when transmitting with OFDM modulation. */
+static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac)
+{
+	return mac->bssinfo.use_protection;
+}
+
 /* Start the SoftMAC. Call this after you initialized the device
  * and it is ready to run.
  */
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 72d4d4e..d60358d 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -779,33 +779,44 @@ #endif
 	return 0;
 }
 
-/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
-int ieee80211_rx_any(struct ieee80211_device *ieee,
+/* Filter out unrelated packets, call ieee80211_rx[_mgt]
+ * This function takes over the skb, it should not be used again after calling
+ * this function. */
+void ieee80211_rx_any(struct ieee80211_device *ieee,
 		     struct sk_buff *skb, struct ieee80211_rx_stats *stats)
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int is_packet_for_us;
 	u16 fc;
 
-	if (ieee->iw_mode == IW_MODE_MONITOR)
-		return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
+	if (ieee->iw_mode == IW_MODE_MONITOR) {
+		if (!ieee80211_rx(ieee, skb, stats))
+			dev_kfree_skb_irq(skb);
+		return;
+	}
+
+	if (skb->len < sizeof(struct ieee80211_hdr))
+		goto drop_free;
 
 	hdr = (struct ieee80211_hdr_4addr *)skb->data;
 	fc = le16_to_cpu(hdr->frame_ctl);
 
 	if ((fc & IEEE80211_FCTL_VERS) != 0)
-		return -EINVAL;
+		goto drop_free;
 		
 	switch (fc & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
+		if (skb->len < sizeof(struct ieee80211_hdr_3addr))
+			goto drop_free;
 		ieee80211_rx_mgt(ieee, hdr, stats);
-		return 0;
+		dev_kfree_skb_irq(skb);
+		return;
 	case IEEE80211_FTYPE_DATA:
 		break;
 	case IEEE80211_FTYPE_CTL:
-		return 0;
+		return;
 	default:
-		return -EINVAL;
+		return;
 	}
 
 	is_packet_for_us = 0;
@@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_de
 	}
 
 	if (is_packet_for_us)
-		return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
-	return 0;
+		if (!ieee80211_rx(ieee, skb, stats))
+			dev_kfree_skb_irq(skb);
+	return;
+
+drop_free:
+	dev_kfree_skb_irq(skb);
+	ieee->stats.rx_dropped++;
+	return;
 }
 
 #define MGMT_FRAME_FIXED_PART_LENGTH		0x24
@@ -1166,6 +1183,7 @@ #endif
 
 		case MFIE_TYPE_ERP_INFO:
 			network->erp_value = info_element->data[0];
+			network->flags |= NETWORK_HAS_ERP_VALUE;
 			IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
 					     network->erp_value);
 			break;
@@ -1729,5 +1747,6 @@ void ieee80211_rx_mgt(struct ieee80211_d
 	}
 }
 
+EXPORT_SYMBOL_GPL(ieee80211_rx_any);
 EXPORT_SYMBOL(ieee80211_rx_mgt);
 EXPORT_SYMBOL(ieee80211_rx);
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 44215ce..589f6d2 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -96,7 +96,7 @@ ieee80211softmac_disassoc(struct ieee802
 	mac->associated = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associnfo.associating = 0;
-	ieee80211softmac_init_txrates(mac);
+	ieee80211softmac_init_bss(mac);
 	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
 	spin_unlock_irqrestore(&mac->lock, flags);
 }
@@ -334,11 +334,19 @@ ieee80211softmac_associated(struct ieee8
 	struct ieee80211_assoc_response * resp,
 	struct ieee80211softmac_network *net)
 {
+	u16 cap = le16_to_cpu(resp->capability);
+	u8 erp_value = net->erp_value;
+
 	mac->associnfo.associating = 0;
-	mac->associnfo.supported_rates = net->supported_rates;
+	mac->bssinfo.supported_rates = net->supported_rates;
 	ieee80211softmac_recalc_txrates(mac);
 
 	mac->associated = 1;
+
+	mac->associnfo.short_preamble_available =
+		(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
+	ieee80211softmac_process_erp(mac, erp_value);
+
 	if (mac->set_bssid_filter)
 		mac->set_bssid_filter(mac->dev, net->bssid);
 	memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
@@ -351,9 +359,9 @@ ieee80211softmac_associated(struct ieee8
 int
 ieee80211softmac_handle_assoc_response(struct net_device * dev,
 				       struct ieee80211_assoc_response * resp,
-				       struct ieee80211_network * _ieee80211_network_do_not_use)
+				       struct ieee80211_network * _ieee80211_network)
 {
-	/* NOTE: the network parameter has to be ignored by
+	/* NOTE: the network parameter has to be mostly ignored by
 	 *       this code because it is the ieee80211's pointer
 	 *       to the struct, not ours (we made a copy)
 	 */
@@ -385,6 +393,11 @@ ieee80211softmac_handle_assoc_response(s
 	/* now that we know it was for us, we can cancel the timeout */
 	cancel_delayed_work(&mac->associnfo.timeout);
 
+	/* if the association response included an ERP IE, update our saved
+	 * copy */
+	if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
+		network->erp_value = _ieee80211_network->erp_value;
+
 	switch (status) {
 		case 0:
 			dprintk(KERN_INFO PFX "associated!\n");
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 6ae5a1d..82bfddb 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -467,3 +467,17 @@ ieee80211softmac_send_mgt_frame(struct i
 	kfree(pkt);
 	return 0;
 }
+
+/* Beacon handling */
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+	struct ieee80211_beacon *beacon,
+	struct ieee80211_network *network)
+{
+	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+	if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
+		ieee80211softmac_process_erp(mac, network->erp_value);
+
+	return 0;
+}
+
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 4b2e57d..addea1c 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softma
 	softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
 	softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
 	softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
+ 	softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
 	softmac->scaninfo = NULL;
 
 	softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
@@ -178,21 +179,14 @@ int ieee80211softmac_ratesinfo_rate_supp
 	return 0;
 }
 
-/* Finds the highest rate which is:
- *  1. Present in ri (optionally a basic rate)
- *  2. Supported by the device
- *  3. Less than or equal to the user-defined rate
- */
-static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
+u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
 	struct ieee80211softmac_ratesinfo *ri, int basic_only)
 {
 	u8 user_rate = mac->txrates.user_rate;
 	int i;
 
-	if (ri->count == 0) {
-		dprintk(KERN_ERR PFX "empty ratesinfo?\n");
+	if (ri->count == 0)
 		return IEEE80211_CCK_RATE_1MB;
-	}
 
 	for (i = ri->count - 1; i >= 0; i--) {
 		u8 rate = ri->rates[i];
@@ -208,36 +202,61 @@ static u8 highest_supported_rate(struct 
 	/* If we haven't found a suitable rate by now, just trust the user */
 	return user_rate;
 }
+EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
+
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+	u8 erp_value)
+{
+ 	int use_protection;
+	int short_preamble;
+ 	u32 changes = 0;
+
+	/* Barker preamble mode */
+	short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
+			  && mac->associnfo.short_preamble_available) ? 1 : 0;
+
+	/* Protection needed? */
+	use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+	if (mac->bssinfo.short_preamble != short_preamble) {
+		changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+		mac->bssinfo.short_preamble = short_preamble;
+	}
+
+	if (mac->bssinfo.use_protection != use_protection) {
+		changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+		mac->bssinfo.use_protection = use_protection;
+	}
+
+	if (mac->bssinfo_change && changes)
+		mac->bssinfo_change(mac->dev, changes);
+}
 
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
 {
 	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	struct ieee80211softmac_txrates oldrates;
 	u32 change = 0;
 
-	if (mac->txrates_change)
-		oldrates = mac->txrates;
-
 	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-	txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
+	txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
 
 	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
 	txrates->default_fallback = lower_rate(mac, txrates->default_rate);
 
 	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-	txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
+	txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
 
 	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change, &oldrates);
+		mac->txrates_change(mac->dev, change);
 
 }
 
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
 {
 	struct ieee80211_device *ieee = mac->ieee;
 	u32 change = 0;
 	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	struct ieee80211softmac_txrates oldrates;
+	struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
 
 	/* TODO: We need some kind of state machine to lower the default rates
 	 *       if we loose too many packets.
@@ -245,8 +264,6 @@ void ieee80211softmac_init_txrates(struc
 	/* Change the default txrate to the highest possible value.
 	 * The txrate machine will lower it, if it is too high.
 	 */
-	if (mac->txrates_change)
-		oldrates = mac->txrates;
 	/* FIXME: We don't correctly handle backing down to lower
 	   rates, so 801.11g devices start off at 11M for now. People
 	   can manually change it if they really need to, but 11M is
@@ -272,7 +289,23 @@ void ieee80211softmac_init_txrates(struc
 	change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
 
 	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change, &oldrates);
+		mac->txrates_change(mac->dev, change);
+
+	change = 0;
+
+	bssinfo->supported_rates.count = 0;
+	memset(bssinfo->supported_rates.rates, 0,
+		sizeof(bssinfo->supported_rates.rates));
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
+
+	bssinfo->short_preamble = 0;
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+
+	bssinfo->use_protection = 0;
+	change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+
+	if (mac->bssinfo_change)
+		mac->bssinfo_change(mac->dev, change);
 
 	mac->running = 1;
 }
@@ -282,7 +315,7 @@ void ieee80211softmac_start(struct net_d
 	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
 
 	ieee80211softmac_start_check_rates(mac);
-	ieee80211softmac_init_txrates(mac);
+	ieee80211softmac_init_bss(mac);
 }
 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
 
@@ -335,7 +368,6 @@ u8 ieee80211softmac_lower_rate_delta(str
 static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
 						 int amount)
 {
-	struct ieee80211softmac_txrates oldrates;
 	u8 default_rate = mac->txrates.default_rate;
 	u8 default_fallback = mac->txrates.default_fallback;
 	u32 changes = 0;
@@ -348,8 +380,6 @@ printk("badness %d\n", mac->txrate_badne
 	mac->txrate_badness += amount;
 	if (mac->txrate_badness <= -1000) {
 		/* Very small badness. Try a faster bitrate. */
-		if (mac->txrates_change)
-			memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
 		default_rate = raise_rate(mac, default_rate);
 		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
 		default_fallback = get_fallback_rate(mac, default_rate);
@@ -358,8 +388,6 @@ printk("badness %d\n", mac->txrate_badne
 printk("Bitrate raised to %u\n", default_rate);
 	} else if (mac->txrate_badness >= 10000) {
 		/* Very high badness. Try a slower bitrate. */
-		if (mac->txrates_change)
-			memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
 		default_rate = lower_rate(mac, default_rate);
 		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
 		default_fallback = get_fallback_rate(mac, default_rate);
@@ -372,7 +400,7 @@ printk("Bitrate lowered to %u\n", defaul
 	mac->txrates.default_fallback = default_fallback;
 
 	if (changes && mac->txrates_change)
-		mac->txrates_change(mac->dev, changes, &oldrates);
+		mac->txrates_change(mac->dev, changes);
 }
 
 void ieee80211softmac_fragment_lost(struct net_device *dev,
@@ -416,7 +444,11 @@ ieee80211softmac_create_network(struct i
 	memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
 	softnet->supported_rates.count += net->rates_ex_len;
 	sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-	
+
+	/* we save the ERP value because it is needed at association time, and
+	 * many AP's do not include an ERP IE in the association response. */
+	softnet->erp_value = net->erp_value;
+
 	softnet->capabilities = net->capability;
 	return softnet;
 }
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index fa1f8e3..0642e09 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(st
 	struct ieee80211softmac_essid *essid);
 
 /* Rates related */
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+	u8 erp_value);
 int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
 void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
 static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
 	return ieee80211softmac_lower_rate_delta(mac, rate, 1);
@@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struc
 /*** prototypes from _io.c */
 int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
 	void* ptrarg, u32 type, u32 arg);
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+	struct ieee80211_beacon *beacon,
+	struct ieee80211_network *network);
 
 /*** prototypes from _auth.c */
 /* do these have to go into the public header? */
@@ -189,6 +194,7 @@ struct ieee80211softmac_network {
 	    authenticated:1,
 	    auth_desynced_once:1;
 
+	u8 erp_value;				/* Saved ERP value */
 	u16 capabilities;			/* Capabilities bitfield */
 	u8 challenge_len;			/* Auth Challenge length */
 	char *challenge;			/* Challenge Text */
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-07-10 21:31 ` Please pull 'upstream' " John W. Linville
  2006-07-10 21:38   ` Michael Buesch
@ 2006-07-19 17:51   ` Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-07-19 17:51 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> These patches are to be queued for 2.6.19...
> 
> ---
> 
> The following changes since commit b312d799b324e895745ffe148def234fc60d5b74:
>   Daniel Drake:
>         zd1211rw: usb_clear_halt not allowed in IRQ context
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake:
>       zd1211rw: Add Sagem device ID's
> 
> Larry Finger:
>       bcm43xx: improved statistics
> 
> Michael Buesch:
>       bcm43xx: opencoded locking
>       bcm43xx: voluntary preemtion in the calibration loops
> 
>  drivers/net/wireless/bcm43xx/bcm43xx.h         |   64 ++-------
>  drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |   34 +++--
>  drivers/net/wireless/bcm43xx/bcm43xx_leds.c    |   10 +
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   64 +++++----
>  drivers/net/wireless/bcm43xx/bcm43xx_phy.c     |   33 +++--
>  drivers/net/wireless/bcm43xx/bcm43xx_pio.c     |    4 -
>  drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c   |   34 +++--
>  drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |  162 ++++++++++++++----------
>  drivers/net/wireless/zd1211rw/zd_usb.c         |    2 

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-07-10 21:38   ` Michael Buesch
@ 2006-07-10 21:58     ` Larry Finger
  0 siblings, 0 replies; 108+ messages in thread
From: Larry Finger @ 2006-07-10 21:58 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, netdev

Michael Buesch wrote:
> On Monday 10 July 2006 23:31, you wrote:
> Larry, I see that several patches from you got merged now.
> Please make sure that you also submit patches for bcm43xx-d80211.
> If you don't, your changes will all be lost, as soon as bcm43xx-d80211
> is merged upstream and softmac is dropped.
> 

Will do. A couple of days ago I downloaded a copy of the wireless-dev repository, and now have the 
master code so that I can prepare the patches.

Will the upstream merge of d80211 be made for 2.6.19 or later?

Larry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-07-10 21:31 ` Please pull 'upstream' " John W. Linville
@ 2006-07-10 21:38   ` Michael Buesch
  2006-07-10 21:58     ` Larry Finger
  2006-07-19 17:51   ` Jeff Garzik
  1 sibling, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-07-10 21:38 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev

On Monday 10 July 2006 23:31, you wrote:
> These patches are to be queued for 2.6.19...
> 
> ---
> 
> The following changes since commit b312d799b324e895745ffe148def234fc60d5b74:
>   Daniel Drake:
>         zd1211rw: usb_clear_halt not allowed in IRQ context
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Daniel Drake:
>       zd1211rw: Add Sagem device ID's
> 
> Larry Finger:
>       bcm43xx: improved statistics

Larry, I see that several patches from you got merged now.
Please make sure that you also submit patches for bcm43xx-d80211.
If you don't, your changes will all be lost, as soon as bcm43xx-d80211
is merged upstream and softmac is dropped.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-07-10 21:29 Please pull 'upstream-fixes' " John W. Linville
@ 2006-07-10 21:31 ` John W. Linville
  2006-07-10 21:38   ` Michael Buesch
  2006-07-19 17:51   ` Jeff Garzik
  0 siblings, 2 replies; 108+ messages in thread
From: John W. Linville @ 2006-07-10 21:31 UTC (permalink / raw)
  To: jeff; +Cc: netdev

These patches are to be queued for 2.6.19...

---

The following changes since commit b312d799b324e895745ffe148def234fc60d5b74:
  Daniel Drake:
        zd1211rw: usb_clear_halt not allowed in IRQ context

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      zd1211rw: Add Sagem device ID's

Larry Finger:
      bcm43xx: improved statistics

Michael Buesch:
      bcm43xx: opencoded locking
      bcm43xx: voluntary preemtion in the calibration loops

 drivers/net/wireless/bcm43xx/bcm43xx.h         |   64 ++-------
 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |   34 +++--
 drivers/net/wireless/bcm43xx/bcm43xx_leds.c    |   10 +
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   64 +++++----
 drivers/net/wireless/bcm43xx/bcm43xx_phy.c     |   33 +++--
 drivers/net/wireless/bcm43xx/bcm43xx_pio.c     |    4 -
 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c   |   34 +++--
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |  162 ++++++++++++++----------
 drivers/net/wireless/zd1211rw/zd_usb.c         |    2 
 9 files changed, 215 insertions(+), 192 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 17a5682..ee6571e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -649,6 +649,19 @@ enum {
 #define bcm43xx_status(bcm)		atomic_read(&(bcm)->init_status)
 #define bcm43xx_set_status(bcm, stat)	atomic_set(&(bcm)->init_status, (stat))
 
+/*    *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
+ *                   and the device registers. This mutex does _not_ protect
+ *                   against concurrency from the IRQ handler.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * Please note that, if you only take the irq_lock, you are not protected
+ * against concurrency from the periodic work handlers.
+ * Most times you want to take _both_ locks.
+ */
+
 struct bcm43xx_private {
 	struct ieee80211_device *ieee;
 	struct ieee80211softmac_device *softmac;
@@ -659,7 +672,6 @@ struct bcm43xx_private {
 
 	void __iomem *mmio_addr;
 
-	/* Locking, see "theory of locking" text below. */
 	spinlock_t irq_lock;
 	struct mutex mutex;
 
@@ -691,6 +703,7 @@ struct bcm43xx_private {
 	struct bcm43xx_sprominfo sprom;
 #define BCM43xx_NR_LEDS		4
 	struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+	spinlock_t leds_lock;
 
 	/* The currently active core. */
 	struct bcm43xx_coreinfo *current_core;
@@ -763,55 +776,6 @@ #endif
 };
 
 
-/*    *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
- *                   and the device registers.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * We have three types of helper function pairs to utilize these locks.
- *     (Always use the helper functions.)
- * 1) bcm43xx_{un}lock_noirq():
- *     Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
- *     so it is almost always unsafe, if device IRQs are enabled.
- *     So only use this, if device IRQs are masked.
- *     Locking may sleep.
- *     You can sleep within the critical section.
- * 2) bcm43xx_{un}lock_irqonly():
- *     Takes bcm->irq_lock. Does _not_ protect against
- *     bcm43xx_lock_noirq() critical sections.
- *     Does only protect against the IRQ handler path and other
- *     irqonly() critical sections.
- *     Locking does not sleep.
- *     You must not sleep within the critical section.
- * 3) bcm43xx_{un}lock_irqsafe():
- *     This is the cummulative lock and takes both, mutex and irq_lock.
- *     Protects against noirq() and irqonly() critical sections (and
- *     the IRQ handler path).
- *     Locking may sleep.
- *     You must not sleep within the critical section.
- */
-
-/* Lock type 1 */
-#define bcm43xx_lock_noirq(bcm)		mutex_lock(&(bcm)->mutex)
-#define bcm43xx_unlock_noirq(bcm)	mutex_unlock(&(bcm)->mutex)
-/* Lock type 2 */
-#define bcm43xx_lock_irqonly(bcm, flags)	\
-	spin_lock_irqsave(&(bcm)->irq_lock, flags)
-#define bcm43xx_unlock_irqonly(bcm, flags)	\
-	spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
-/* Lock type 3 */
-#define bcm43xx_lock_irqsafe(bcm, flags) do {	\
-	bcm43xx_lock_noirq(bcm);		\
-	bcm43xx_lock_irqonly(bcm, flags);	\
-		} while (0)
-#define bcm43xx_unlock_irqsafe(bcm, flags) do {	\
-	bcm43xx_unlock_irqonly(bcm, flags);	\
-	bcm43xx_unlock_noirq(bcm);		\
-		} while (0)
-
-
 static inline
 struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
 {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index ce2e40b..2600ee4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct 
 
 	down(&big_buffer_sem);
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -121,7 +122,8 @@ #undef fappend_core
 	fappend("\n");
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struc
 	unsigned long flags;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struc
 	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file
 	u64 tsf;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file
 		(unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct fil
 	        res = -EFAULT;
 		goto out_up;
 	}
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
 		res = -EFAULT;
@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct fil
 	res = buf_size;
 	
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_up:
 	up(&big_buffer_sem);
 	return res;
@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct f
 	int i, cnt, j = 0;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
 		BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -294,14 +303,15 @@ static ssize_t txstat_read_file(struct f
 			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
 	}
 
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (*ppos == pos) {
 		/* Done. Drop the copied data. */
 		e->xmitstatus_printing = 0;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	up(&big_buffer_sem);
 	return res;
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index ec80692..c3f90c8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned l
 	struct bcm43xx_private *bcm = led->bcm;
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	if (led->blink_interval) {
 		bcm43xx_led_changestate(led);
 		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
 	}
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_
 	int i, turn_on;
 	unsigned long interval = 0;
 	u16 ledctl;
+	unsigned long flags;
 
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
 		led = &(bcm->leds[i]);
@@ -266,6 +268,7 @@ #endif /* CONFIG_BCM43XX_DEBUG */
 			ledctl &= ~(1 << i);
 	}
 	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
 
 void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm4
 	u16 ledctl;
 	int i;
 	int bit_on;
+	unsigned long flags;
 
+	spin_lock_irqsave(&bcm->leds_lock, flags);
 	ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 	for (i = 0; i < BCM43xx_NR_LEDS; i++) {
 		led = &(bcm->leds[i]);
@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm4
 			ledctl &= ~(1 << i);
 	}
 	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&bcm->leds_lock, flags);
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 3889f79..ef9bc80 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -514,13 +514,13 @@ static int bcm43xx_disable_interrupts_sy
 	unsigned long flags;
 	u32 old;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
-		bcm43xx_unlock_irqonly(bcm, flags);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
 		return -EBUSY;
 	}
 	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 	bcm43xx_synchronize_irq(bcm);
 
 	if (oldstate)
@@ -1720,7 +1720,7 @@ #else
 # define bcmirq_handled(irq)	do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	reason = bcm->irq_reason;
 	dma_reason[0] = bcm->dma_reason[0];
 	dma_reason[1] = bcm->dma_reason[1];
@@ -1746,7 +1746,7 @@ #endif /* CONFIG_BCM43XX_DEBUG*/
 			dma_reason[2], dma_reason[3]);
 		bcm43xx_controller_restart(bcm, "DMA error");
 		mmiowb();
-		bcm43xx_unlock_irqonly(bcm, flags);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
 		return;
 	}
 	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1834,7 +1834,7 @@ #undef bcmirq_handled
 		bcm43xx_leds_update(bcm, activity);
 	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
 	mmiowb();
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -3182,25 +3182,26 @@ static void bcm43xx_periodic_work_handle
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
-		bcm43xx_lock_irqonly(bcm, flags);
 		netif_stop_queue(bcm->net_dev);
+		spin_lock_irqsave(&bcm->irq_lock, flags);
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_freeze_txqueues(bcm);
 		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-		bcm43xx_unlock_irqonly(bcm, flags);
-		bcm43xx_lock_noirq(bcm);
+		spin_unlock_irqrestore(&bcm->irq_lock, flags);
+		mutex_lock(&bcm->mutex);
 		bcm43xx_synchronize_irq(bcm);
 	} else {
 		/* Periodic work should take short time, so we want low
 		 * locking overhead.
 		 */
-		bcm43xx_lock_irqsafe(bcm, flags);
+		mutex_lock(&bcm->mutex);
+		spin_lock_irqsave(&bcm->irq_lock, flags);
 	}
 
 	do_periodic_work(bcm);
 
 	if (badness > BADNESS_LIMIT) {
-		bcm43xx_lock_irqonly(bcm, flags);
+		spin_lock_irqsave(&bcm->irq_lock, flags);
 		if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
 			tasklet_enable(&bcm->isr_tasklet);
 			bcm43xx_interrupt_enable(bcm, savedirqs);
@@ -3208,13 +3209,10 @@ static void bcm43xx_periodic_work_handle
 				bcm43xx_pio_thaw_txqueues(bcm);
 		}
 		netif_wake_queue(bcm->net_dev);
-		mmiowb();
-		bcm43xx_unlock_irqonly(bcm, flags);
-		bcm43xx_unlock_noirq(bcm);
-	} else {
-		mmiowb();
-		bcm43xx_unlock_irqsafe(bcm, flags);
 	}
+	mmiowb();
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
@@ -3276,7 +3274,7 @@ static void bcm43xx_free_board(struct bc
 {
 	int i, err;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	bcm43xx_sysfs_unregister(bcm);
 	bcm43xx_periodic_tasks_delete(bcm);
 
@@ -3297,7 +3295,7 @@ static void bcm43xx_free_board(struct bc
 	bcm43xx_pctl_set_crystal(bcm, 0);
 
 	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 }
 
 static int bcm43xx_init_board(struct bcm43xx_private *bcm)
@@ -3307,7 +3305,7 @@ static int bcm43xx_init_board(struct bcm
 
 	might_sleep();
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
 
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
@@ -3389,7 +3387,7 @@ static int bcm43xx_init_board(struct bcm
 
 	assert(err == 0);
 out:
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 
@@ -3647,7 +3645,8 @@ static void bcm43xx_ieee80211_set_chan(s
 	struct bcm43xx_radioinfo *radio;
 	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		bcm43xx_mac_suspend(bcm);
 		bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3656,7 +3655,8 @@ static void bcm43xx_ieee80211_set_chan(s
 		radio = bcm43xx_current_radio(bcm);
 		radio->initial_channel = channel;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3670,7 +3670,8 @@ static void bcm43xx_ieee80211_set_securi
 	
 	dprintk(KERN_INFO PFX "set security called");
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
 		if (sec->flags & (1<<keyidx)) {
@@ -3739,7 +3740,8 @@ static void bcm43xx_ieee80211_set_securi
 		} else
 				bcm43xx_clear_keys(bcm);
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3751,10 +3753,10 @@ static int bcm43xx_ieee80211_hard_start_
 	int err = -ENODEV;
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
 		err = bcm43xx_tx(bcm, txb);
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 
 	return err;
 }
@@ -3769,9 +3771,9 @@ static void bcm43xx_net_tx_timeout(struc
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm43xx_controller_restart(bcm, "TX timeout");
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3822,6 +3824,7 @@ static int bcm43xx_init_private(struct b
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
 	spin_lock_init(&bcm->irq_lock);
+	spin_lock_init(&bcm->leds_lock);
 	mutex_init(&bcm->mutex);
 	tasklet_init(&bcm->isr_tasklet,
 		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
@@ -4002,16 +4005,13 @@ static int bcm43xx_suspend(struct pci_de
 {
 	struct net_device *net_dev = pci_get_drvdata(pdev);
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int try_to_shutdown = 0, err;
 
 	dprintk(KERN_INFO PFX "Suspending...\n");
 
-	bcm43xx_lock_irqsafe(bcm, flags);
 	bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 	if (bcm->was_initialized)
 		try_to_shutdown = 1;
-	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	netif_device_detach(net_dev);
 	if (try_to_shutdown) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index f8200de..eafd0f6 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table
 static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
 
 
+static inline
+void bcm43xx_voluntary_preempt(void)
+{
+	assert(!in_atomic() && !in_irq() &&
+	       !in_interrupt() && !irqs_disabled());
+#ifndef CONFIG_PREEMPT
+	cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
 void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_pr
 void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-	unsigned long flags;
 
 	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
 	if (phy->calibrated)
 		return;
 	if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
-		/* We do not want to be preempted while calibrating
-		 * the hardware.
-		 */
-		local_irq_save(flags);
-
 		bcm43xx_wireless_core_reset(bcm, 0);
 		bcm43xx_phy_initg(bcm);
 		bcm43xx_wireless_core_reset(bcm, 1);
-
-		local_irq_restore(flags);
 	}
 	phy->calibrated = 1;
 }
@@ -1299,7 +1301,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str
 {
 	int i;
 	u16 ret = 0;
+	unsigned long flags;
 
+	local_irq_save(flags);
 	for (i = 0; i < 10; i++){
 		bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
 		udelay(1);
@@ -1309,6 +1313,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(str
 		udelay(40);
 		ret += bcm43xx_phy_read(bcm, 0x002C);
 	}
+	local_irq_restore(flags);
+	bcm43xx_voluntary_preempt();
 
 	return ret;
 }
@@ -1435,6 +1441,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(st
 	}
 	ret = bcm43xx_phy_read(bcm, 0x002D);
 	local_irq_restore(flags);
+	bcm43xx_voluntary_preempt();
 
 	return ret;
 }
@@ -1760,6 +1767,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
 			bcm43xx_radio_write16(bcm, 0x43, i);
 			bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
 			udelay(10);
+			bcm43xx_voluntary_preempt();
 
 			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1803,6 +1811,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
 					      radio->txctl2
 					      | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
 			udelay(10);
+			bcm43xx_voluntary_preempt();
 
 			bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
 
@@ -1824,6 +1833,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm
 		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
 		udelay(2);
 		bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+		bcm43xx_voluntary_preempt();
 	} else
 		bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
 	bcm43xx_phy_lo_adjust(bcm, is_initializing);
@@ -2188,12 +2198,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	int err = -ENODEV;
-	unsigned long flags;
-
-	/* We do not want to be preempted while calibrating
-	 * the hardware.
-	 */
-	local_irq_save(flags);
 
 	switch (phy->type) {
 	case BCM43xx_PHYTYPE_A:
@@ -2227,7 +2231,6 @@ int bcm43xx_phy_init(struct bcm43xx_priv
 		err = 0;
 		break;
 	}
-	local_irq_restore(flags);
 	if (err)
 		printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 574085c..c60c174 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
 	int err;
 	u16 txctl;
 
-	bcm43xx_lock_irqonly(bcm, flags);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	if (queue->tx_frozen)
 		goto out_unlock;
@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
 		continue;
 	}
 out_unlock:
-	bcm43xx_unlock_irqonly(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index 6a23bdc..cc1ff3c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(s
 			GFP_KERNEL);
 	if (!sprom)
 		return -ENOMEM;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	err = bcm43xx_sprom_read(bcm, sprom);
 	if (!err)
 		err = sprom2hex(sprom, buf, PAGE_SIZE);
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	kfree(sprom);
 
 	return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(
 	err = hex2sprom(sprom, buf, count);
 	if (err)
 		goto out_kfree;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+	spin_lock(&bcm->leds_lock);
 	err = bcm43xx_sprom_write(bcm, sprom);
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock(&bcm->leds_lock);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_kfree:
 	kfree(sprom);
 
@@ -176,7 +182,7 @@ static ssize_t bcm43xx_attr_interfmode_s
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 
 	switch (bcm43xx_current_radio(bcm)->interfmode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -193,7 +199,7 @@ static ssize_t bcm43xx_attr_interfmode_s
 	}
 	err = 0;
 
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 
@@ -229,7 +235,8 @@ static ssize_t bcm43xx_attr_interfmode_s
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 	if (err) {
@@ -237,7 +244,8 @@ static ssize_t bcm43xx_attr_interfmode_s
 				    "supported by device\n");
 	}
 	mmiowb();
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
@@ -257,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_sho
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 
 	if (bcm->short_preamble)
 		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -265,7 +273,7 @@ static ssize_t bcm43xx_attr_preamble_sho
 		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
 	err = 0;
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
@@ -285,12 +293,14 @@ static ssize_t bcm43xx_attr_preamble_sto
 	value = get_boolean(buf, count);
 	if (value < 0)
 		return value;
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 
 	bcm->short_preamble = !!value;
 
 	err = 0;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err ? err : count;
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 5c36e29..8ffd760 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,6 +47,9 @@ #include "bcm43xx_phy.h"
 #define BCM43xx_WX_VERSION	18
 
 #define MAX_WX_STRING		80
+/* FIXME: the next line is a guess as to what the maximum value of RX power
+          (in dBm) might be */
+#define RX_POWER_MAX		-10
 
 
 static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -56,12 +59,11 @@ static int bcm43xx_wx_get_name(struct ne
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	int i;
-	unsigned long flags;
 	struct bcm43xx_phyinfo *phy;
 	char suffix[7] = { 0 };
 	int have_a = 0, have_b = 0, have_g = 0;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 		phy = &(bcm->core_80211_ext[i].phy);
 		switch (phy->type) {
@@ -77,7 +79,7 @@ static int bcm43xx_wx_get_name(struct ne
 			assert(0);
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	i = 0;
 	if (have_a) {
@@ -111,7 +113,9 @@ static int bcm43xx_wx_set_channelfreq(st
 	int freq;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+
 	if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
 		channel = data->freq.m;
 		freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -131,7 +135,8 @@ static int bcm43xx_wx_set_channelfreq(st
 		err = 0;
 	}
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -143,11 +148,10 @@ static int bcm43xx_wx_get_channelfreq(st
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct bcm43xx_radioinfo *radio;
-	unsigned long flags;
 	int err = -ENODEV;
 	u16 channel;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	radio = bcm43xx_current_radio(bcm);
 	channel = radio->channel;
 	if (channel == 0xFF) {
@@ -162,7 +166,7 @@ static int bcm43xx_wx_get_channelfreq(st
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -180,13 +184,15 @@ static int bcm43xx_wx_set_mode(struct ne
 	if (mode == IW_MODE_AUTO)
 		mode = BCM43xx_INITIAL_IWMODE;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		if (bcm->ieee->iw_mode != mode)
 			bcm43xx_set_iwmode(bcm, mode);
 	} else
 		bcm->ieee->iw_mode = mode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -197,11 +203,10 @@ static int bcm43xx_wx_get_mode(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->mode = bcm->ieee->iw_mode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -214,7 +219,6 @@ static int bcm43xx_wx_get_rangeparams(st
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct iw_range *range = (struct iw_range *)extra;
 	const struct ieee80211_geo *geo;
-	unsigned long flags;
 	int i, j;
 	struct bcm43xx_phyinfo *phy;
 
@@ -227,14 +231,14 @@ static int bcm43xx_wx_get_rangeparams(st
 
 	range->max_qual.qual = 100;
 	/* TODO: Real max RSSI */
-	range->max_qual.level = 3;
-	range->max_qual.noise = 100;
-	range->max_qual.updated = 7;
+	range->max_qual.level = 0;
+	range->max_qual.noise = 0;
+	range->max_qual.updated = IW_QUAL_ALL_UPDATED;
 
-	range->avg_qual.qual = 70;
-	range->avg_qual.level = 2;
-	range->avg_qual.noise = 40;
-	range->avg_qual.updated = 7;
+	range->avg_qual.qual = 50;
+	range->avg_qual.level = 0;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
 
 	range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
 	range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -254,7 +258,7 @@ static int bcm43xx_wx_get_rangeparams(st
 			  IW_ENC_CAPA_CIPHER_TKIP |
 			  IW_ENC_CAPA_CIPHER_CCMP;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	phy = bcm43xx_current_phy(bcm);
 
 	range->num_bitrates = 0;
@@ -301,7 +305,7 @@ static int bcm43xx_wx_get_rangeparams(st
 	}
 	range->num_frequency = j;
 
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -314,11 +318,11 @@ static int bcm43xx_wx_set_nick(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	size_t len;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
 	memcpy(bcm->nick, extra, len);
 	bcm->nick[len] = '\0';
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -331,12 +335,12 @@ static int bcm43xx_wx_get_nick(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	size_t len;
 
-	bcm43xx_lock_noirq(bcm);
+	mutex_lock(&bcm->mutex);
 	len = strlen(bcm->nick) + 1;
 	memcpy(extra, bcm->nick, len);
 	data->data.length = (__u16)len;
 	data->data.flags = 1;
-	bcm43xx_unlock_noirq(bcm);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -350,7 +354,8 @@ static int bcm43xx_wx_set_rts(struct net
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (data->rts.disabled) {
 		bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
 		err = 0;
@@ -361,7 +366,8 @@ static int bcm43xx_wx_set_rts(struct net
 			err = 0;
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -372,13 +378,12 @@ static int bcm43xx_wx_get_rts(struct net
 			      char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->rts.value = bcm->rts_threshold;
 	data->rts.fixed = 0;
 	data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -392,7 +397,8 @@ static int bcm43xx_wx_set_frag(struct ne
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (data->frag.disabled) {
 		bcm->ieee->fts = MAX_FRAG_THRESHOLD;
 		err = 0;
@@ -403,7 +409,8 @@ static int bcm43xx_wx_set_frag(struct ne
 			err = 0;
 		}
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -414,13 +421,12 @@ static int bcm43xx_wx_get_frag(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	data->frag.value = bcm->ieee->fts;
 	data->frag.fixed = 0;
 	data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -442,7 +448,8 @@ static int bcm43xx_wx_set_xmitpower(stru
 		return -EOPNOTSUPP;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
@@ -466,7 +473,8 @@ static int bcm43xx_wx_set_xmitpower(stru
 	err = 0;
 
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -478,10 +486,9 @@ static int bcm43xx_wx_get_xmitpower(stru
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct bcm43xx_radioinfo *radio;
-	unsigned long flags;
 	int err = -ENODEV;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
@@ -493,7 +500,7 @@ static int bcm43xx_wx_get_xmitpower(stru
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -580,7 +587,8 @@ static int bcm43xx_wx_set_interfmode(str
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 		if (err) {
@@ -595,7 +603,8 @@ static int bcm43xx_wx_set_interfmode(str
 		} else
 			bcm43xx_current_radio(bcm)->interfmode = mode;
 	}
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return err;
 }
@@ -606,12 +615,11 @@ static int bcm43xx_wx_get_interfmode(str
 				     char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int mode;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	mode = bcm43xx_current_radio(bcm)->interfmode;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	switch (mode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -641,9 +649,11 @@ static int bcm43xx_wx_set_shortpreamble(
 	int on;
 
 	on = *((int *)extra);
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm->short_preamble = !!on;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -654,12 +664,11 @@ static int bcm43xx_wx_get_shortpreamble(
 					char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int on;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	on = bcm->short_preamble;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	if (on)
 		strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -681,11 +690,13 @@ static int bcm43xx_wx_set_swencryption(s
 	
 	on = *((int *)extra);
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	bcm->ieee->host_encrypt = !!on;
 	bcm->ieee->host_decrypt = !!on;
 	bcm->ieee->host_build_iv = !on;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 
 	return 0;
 }
@@ -696,12 +707,11 @@ static int bcm43xx_wx_get_swencryption(s
 				       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int on;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
 	on = bcm->ieee->host_encrypt;
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	mutex_unlock(&bcm->mutex);
 
 	if (on)
 		strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -764,11 +774,13 @@ static int bcm43xx_wx_sprom_read(struct 
 	if (!sprom)
 		goto out;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
 	err = -ENODEV;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_read(bcm, sprom);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 	if (!err)
 		data->data.length = sprom2hex(sprom, extra);
 	kfree(sprom);
@@ -809,11 +821,15 @@ static int bcm43xx_wx_sprom_write(struct
 	if (err)
 		goto out_kfree;
 
-	bcm43xx_lock_irqsafe(bcm, flags);
+	mutex_lock(&bcm->mutex);
+	spin_lock_irqsave(&bcm->irq_lock, flags);
+	spin_lock(&bcm->leds_lock);
 	err = -ENODEV;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_irqsafe(bcm, flags);
+	spin_unlock(&bcm->leds_lock);
+	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+	mutex_unlock(&bcm->mutex);
 out_kfree:
 	kfree(sprom);
 out:
@@ -827,6 +843,9 @@ static struct iw_statistics *bcm43xx_get
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
 	struct iw_statistics *wstats;
+	struct ieee80211_network *network = NULL;
+	static int tmp_level = 0;
+	unsigned long flags;
 
 	wstats = &bcm->stats.wstats;
 	if (!mac->associated) {
@@ -844,16 +863,25 @@ static struct iw_statistics *bcm43xx_get
 		wstats->qual.level = 0;
 		wstats->qual.noise = 0;
 		wstats->qual.updated = 7;
-		wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
-			IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+		wstats->qual.updated |= IW_QUAL_ALL_UPDATED;
 		return wstats;
 	}
 	/* fill in the real statistics when iface associated */
-	wstats->qual.qual = 100;     // TODO: get the real signal quality
-	wstats->qual.level = 3 - bcm->stats.link_quality;
+	spin_lock_irqsave(&mac->ieee->lock, flags);
+	list_for_each_entry(network, &mac->ieee->network_list, list) {
+		if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+			if (!tmp_level)		/* get initial value */
+				tmp_level = network->stats.rssi;
+			else			/* smooth results */
+				tmp_level = (7 * tmp_level + network->stats.rssi)/8;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&mac->ieee->lock, flags);
+	wstats->qual.level = tmp_level;
+	wstats->qual.qual = 100 + tmp_level - RX_POWER_MAX; // TODO: get the real signal quality
 	wstats->qual.noise = bcm->stats.noise;
-	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
-			IW_QUAL_NOISE_UPDATED;
+	wstats->qual.updated = IW_QUAL_ALL_UPDATED;
 	wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
 	wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
 	wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 72f9052..c68b9f8 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -39,9 +39,11 @@ static struct usb_device_id usb_ids[] = 
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{}
 };
 
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-28 17:32                               ` Larry Finger
@ 2006-06-28 18:02                                 ` Michael Buesch
  0 siblings, 0 replies; 108+ messages in thread
From: Michael Buesch @ 2006-06-28 18:02 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev

On Wednesday 28 June 2006 19:32, Larry Finger wrote:
> Michael Buesch wrote:
> > On Wednesday 28 June 2006 18:04, Larry Finger wrote:
> > 
> > Oh, well. Forget it all.
> > I remembered the code wrong.
> > At the moment I looked at the code and it has the opposite semantics.
> > It loops to wait for the READY bit to appear.
> > 
> > Well, I would say your old device simply takes this long
> > to disable and there is no bug.
> > 
> > Oh, well...
> 
> So the conclusion is that my card is really slow. As mine is likely to be the worst of the lot, I 
> propose the following structure for the loop in question:
> 
>                  for (i = 10000; i; i--) {
>                          tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
>                          if (tmp & BCM43xx_IRQ_READY) {
>                                  if (i < 9998)
>                                          printkl(KERN_INFO PFX "MAC suspend delay %d usec, IRQ_REASON "
>                                                  "0x%08x\n", 10000-i, tmp & ~BCM43xx_IRQ_READY);
>                                  goto out;
>                          }
>                          udelay(1);
>                  }
>                  printkl(KERN_ERR PFX "MAC suspend failed\n");
> 
> My maximum delay (so far) is 796 usec, thus this loop gives me a safety factor of more than 10, but 
> it should satisfy Jeff and let this patch in question be accepted.

Ok, I will send a patch to lower the limit to 10000 usec.
This won't do _any_ good (or bad), but well... If everybody likes
placebos, I will add it to the driver.

It's a bit complicated for me to say why your card takes 800usec
to suspend MAC. And additionally it is not really possible for
me to try to find a way making the card respond earlier (if possible)
remotely through you. ;)

How problematic might a 800usec delay with IRQs disabled be?

> Of course, the 'if (i < 9998)'  
> statement with the printkl is optional.

It is to be removed. ;)

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-28 16:32                             ` Michael Buesch
@ 2006-06-28 17:32                               ` Larry Finger
  2006-06-28 18:02                                 ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: Larry Finger @ 2006-06-28 17:32 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, netdev

Michael Buesch wrote:
> On Wednesday 28 June 2006 18:04, Larry Finger wrote:
> 
> Oh, well. Forget it all.
> I remembered the code wrong.
> At the moment I looked at the code and it has the opposite semantics.
> It loops to wait for the READY bit to appear.
> 
> Well, I would say your old device simply takes this long
> to disable and there is no bug.
> 
> Oh, well...

So the conclusion is that my card is really slow. As mine is likely to be the worst of the lot, I 
propose the following structure for the loop in question:

                 for (i = 10000; i; i--) {
                         tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
                         if (tmp & BCM43xx_IRQ_READY) {
                                 if (i < 9998)
                                         printkl(KERN_INFO PFX "MAC suspend delay %d usec, IRQ_REASON "
                                                 "0x%08x\n", 10000-i, tmp & ~BCM43xx_IRQ_READY);
                                 goto out;
                         }
                         udelay(1);
                 }
                 printkl(KERN_ERR PFX "MAC suspend failed\n");

My maximum delay (so far) is 796 usec, thus this loop gives me a safety factor of more than 10, but 
it should satisfy Jeff and let this patch in question be accepted. Of course, the 'if (i < 9998)' 
statement with the printkl is optional. BTW, as you suspected, the IRQ_REASON value is still at 
0x580 when the READY bit is set.

Thanks for the help,

Larry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-28 16:04                           ` Larry Finger
@ 2006-06-28 16:32                             ` Michael Buesch
  2006-06-28 17:32                               ` Larry Finger
  0 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-28 16:32 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev

On Wednesday 28 June 2006 18:04, Larry Finger wrote:
> Michael Buesch wrote:
> > 
> > It appears to be an older card. There are quite some
> > special codepaths for this, I think.
> 
> Yes, I bought this card before the G specifications were finalized.

Oh, very interresting. I did not know that these old cards
were pre-standard.

> For the past 12 hours, I have been printing the delay time for the cases where it took more  
> than 2 passes through the loop. There have been single instances of 3 and 4 usec; otherwise the 
> delay is much longer, with the largest delay at 750 usec. The long delays are always found during 
> scanning, associating, and authenticating. I use WPA with wpa_supplicant.

Oh, well. Forget it all.
I remembered the code wrong.
At the moment I looked at the code and it has the opposite semantics.
It loops to wait for the READY bit to appear.

Well, I would say your old device simply takes this long
to disable and there is no bug.

Oh, well...

> One other little problem. If I do an ifdown/ifup sequence without unloading the bcm43xx module, I 
> get a failure of the assert(bcm->mac_suspended >= 0) at the beginning of bcm43xx_mac_suspend.

Unrelated known bug.
I will do a patch, soon.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-28 14:34                         ` Michael Buesch
@ 2006-06-28 16:04                           ` Larry Finger
  2006-06-28 16:32                             ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: Larry Finger @ 2006-06-28 16:04 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, netdev

Michael Buesch wrote:
> 
> It appears to be an older card. There are quite some
> special codepaths for this, I think.

Yes, I bought this card before the G specifications were finalized.

> Well, we did not want to have the card, because at this point
> it did not make sense. We all have 4306 cards.
> But now it appears that this card seems to have some special
> things (because it is older than ours).
> 
> Well, how to debug.
> We are waiting for the IRQ Reason register there.
> Actually, we are waiting for the "no IRQ pending, but READY signal"
> state. Your card does not completely (?) clear the bits after MAC
> shutdown. So very helpful would be to print out in the loop the
> value. We know, that the card generates silly IRQs, that we did
> not ask for. That may happen here, too. So it _may_ help to
> mask out unwanted IRQs before the if-check. But I would first
> like to see a log of the reason-value on each iteration until it succeeds.

First of all, I have a udelay(1) in the wait loop. I have also moved the udelay to the top of the 
loop. For the past 12 hours, I have been printing the delay time for the cases where it took more 
than 2 passes through the loop. There have been single instances of 3 and 4 usec; otherwise the 
delay is much longer, with the largest delay at 750 usec. The long delays are always found during 
scanning, associating, and authenticating. I use WPA with wpa_supplicant.

Since adding the dump of IRQ reason, every case that took more than 1 pass through the loop has had 
an IRQ reason of 0x0580 for every pass in the loop. Your idea about the silly IRQ's seems to be 
right. I'll let you know if I get any results that are different.

One other little problem. If I do an ifdown/ifup sequence without unloading the bcm43xx module, I 
get a failure of the assert(bcm->mac_suspended >= 0) at the beginning of bcm43xx_mac_suspend.

Larry




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 20:37                       ` Larry Finger
@ 2006-06-28 14:34                         ` Michael Buesch
  2006-06-28 16:04                           ` Larry Finger
  0 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-28 14:34 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev

On Tuesday 27 June 2006 22:37, Larry Finger wrote:
> Michael Buesch wrote:
> > On Tuesday 27 June 2006 22:06, Larry Finger wrote:
> >> John,
> >>
> >> I would like to find a diplomatic solution to this impasse between Michael and Jeff, which is why 
> >> I'm writing to you privately. Michael is correct in that the loop in question will not usually delay 
> > 
> > private?
> 
> I meant it to be private, but screwed up.
> 
> >> long; however, on some hardware it takes longer than on his. On mine, I have seen delays as long as 
> >> 550 usec.
> > 
> > What's the chip?
> 
> bcm43xx: Chip ID 0x4306, rev 0x2
> bcm43xx: Number of cores: 6
> bcm43xx: Core 0: ID 0x800, rev 0x2, vendor 0x4243, enabled
> bcm43xx: Core 1: ID 0x812, rev 0x4, vendor 0x4243, disabled
> bcm43xx: Core 2: ID 0x80d, rev 0x1, vendor 0x4243, enabled
> bcm43xx: Core 3: ID 0x807, rev 0x1, vendor 0x4243, disabled
> bcm43xx: Core 4: ID 0x804, rev 0x7, vendor 0x4243, enabled
> bcm43xx: Core 5: ID 0x812, rev 0x4, vendor 0x4243, disabled
> bcm43xx: Ignoring additional 802.11 core.
> bcm43xx: Detected PHY: Version: 1, Type 2, Revision 1
> bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)

It appears to be an older card. There are quite some
special codepaths for this, I think.

> >> This would make the worst-case delay be 5 msec, but would provide a cushion of 10X the longest I 
> >> have seen and should be safe.
> >>
> >> Do you have any suggestions on what should be done next?
> > 
> > Leave it as is and find out why it takes so long for your strange card. ;)
> 
> I once offered you my second, duplicate card for testing, but never heard back. Do you have any 
> ideas regarding diagnostics to see why it takes so long? Remember, this card used to time-out on the 
> 1 second delay before the periodic work was restructured.

Well, we did not want to have the card, because at this point
it did not make sense. We all have 4306 cards.
But now it appears that this card seems to have some special
things (because it is older than ours).

Well, how to debug.
We are waiting for the IRQ Reason register there.
Actually, we are waiting for the "no IRQ pending, but READY signal"
state. Your card does not completely (?) clear the bits after MAC
shutdown. So very helpful would be to print out in the loop the
value. We know, that the card generates silly IRQs, that we did
not ask for. That may happen here, too. So it _may_ help to
mask out unwanted IRQs before the if-check. But I would first
like to see a log of the reason-value on each iteration until it succeeds.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 20:23                     ` Michael Buesch
@ 2006-06-27 20:37                       ` Larry Finger
  2006-06-28 14:34                         ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: Larry Finger @ 2006-06-27 20:37 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, netdev

Michael Buesch wrote:
> On Tuesday 27 June 2006 22:06, Larry Finger wrote:
>> John,
>>
>> I would like to find a diplomatic solution to this impasse between Michael and Jeff, which is why 
>> I'm writing to you privately. Michael is correct in that the loop in question will not usually delay 
> 
> private?

I meant it to be private, but screwed up.

>> long; however, on some hardware it takes longer than on his. On mine, I have seen delays as long as 
>> 550 usec.
> 
> What's the chip?

bcm43xx: Chip ID 0x4306, rev 0x2
bcm43xx: Number of cores: 6
bcm43xx: Core 0: ID 0x800, rev 0x2, vendor 0x4243, enabled
bcm43xx: Core 1: ID 0x812, rev 0x4, vendor 0x4243, disabled
bcm43xx: Core 2: ID 0x80d, rev 0x1, vendor 0x4243, enabled
bcm43xx: Core 3: ID 0x807, rev 0x1, vendor 0x4243, disabled
bcm43xx: Core 4: ID 0x804, rev 0x7, vendor 0x4243, enabled
bcm43xx: Core 5: ID 0x812, rev 0x4, vendor 0x4243, disabled
bcm43xx: Ignoring additional 802.11 core.
bcm43xx: Detected PHY: Version: 1, Type 2, Revision 1
bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)

>> In any case, I think that the following code fragment would work and pass Jeff's criticism: 
>>
>> for (i=5000; i; i--) {
>> 	..........
>> 	usleep(1);
> 
> usleep? Can't find that in my kernel tree.
> In fact, I think the lowest possible sleep time
> depends on HZ and is 1msec on 1000HZ.

I meant udelay, of course.

> Additionally, we are holding a spinlock at this time, so it is
> not as easy as simply replacing udelay() by some sleeping function.

I know that.

>> This would make the worst-case delay be 5 msec, but would provide a cushion of 10X the longest I 
>> have seen and should be safe.
>>
>> Do you have any suggestions on what should be done next?
> 
> Leave it as is and find out why it takes so long for your strange card. ;)

I once offered you my second, duplicate card for testing, but never heard back. Do you have any 
ideas regarding diagnostics to see why it takes so long? Remember, this card used to time-out on the 
1 second delay before the periodic work was restructured.

Larry




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 20:06                   ` Larry Finger
@ 2006-06-27 20:23                     ` Michael Buesch
  2006-06-27 20:37                       ` Larry Finger
  0 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 20:23 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev

On Tuesday 27 June 2006 22:06, Larry Finger wrote:
> John,
> 
> I would like to find a diplomatic solution to this impasse between Michael and Jeff, which is why 
> I'm writing to you privately. Michael is correct in that the loop in question will not usually delay 

private?

> long; however, on some hardware it takes longer than on his. On mine, I have seen delays as long as 
> 550 usec.

What's the chip?

> In any case, I think that the following code fragment would work and pass Jeff's criticism: 
> 
> for (i=5000; i; i--) {
> 	..........
> 	usleep(1);

usleep? Can't find that in my kernel tree.
In fact, I think the lowest possible sleep time
depends on HZ and is 1msec on 1000HZ.

Additionally, we are holding a spinlock at this time, so it is
not as easy as simply replacing udelay() by some sleeping function.

> This would make the worst-case delay be 5 msec, but would provide a cushion of 10X the longest I 
> have seen and should be safe.
> 
> Do you have any suggestions on what should be done next?

Leave it as is and find out why it takes so long for your strange card. ;)

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 19:47                 ` Michael Buesch
@ 2006-06-27 20:06                   ` Larry Finger
  2006-06-27 20:23                     ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: Larry Finger @ 2006-06-27 20:06 UTC (permalink / raw)
  Cc: John W. Linville, netdev

Michael Buesch wrote:
> On Tuesday 27 June 2006 21:33, John W. Linville wrote:
>> On Tue, Jun 27, 2006 at 06:31:01PM +0200, Michael Buesch wrote:
>>> On Tuesday 27 June 2006 18:12, Jeff Garzik wrote:
>>>> Michael Buesch wrote:
>>>>> So, I will submit a patch to lower the udelay(10) to udelay(1)
>>>>> and we can close the discussion? ;)
>>>> No, that totally avoids my point.  Your "otherwise idle machine" test is 
>>>> probably nowhere near worst case in the field, for loops that can 
>>>> potentially lock the CPU for a long time upon hardware fault.  And then 
>>>> there are the huge delays in specific functions that I pointed out...
>>> wtf are you requesting from me?
>>> 1) I proved you that the loop does only spin _once_ or even _less_.
>>> 2) If the hardware is faulty, the user must replace it.
>>>    Because, if the hardware is faulty, it can crash the whole
>>>    machine anyway, obviously.
>>>
>>> 3) There is no "huge delay". I proved it with my logs.
>>>    -> No CPU hog => Nothing to fix.
>> Michael,
>>
>> I think Jeff's concern is that by using udelay you are busy-waiting.
>> And, the for loop limit of 100000 means you could freeze the kernel
>> for up to a whole second.  Granted that this won't happen very often
> 
> s/very often/ever/
> 
> It won't happen, as long as the driver is not buggy, or the device
> is hardware broken. So, if it happens, something has to be fixed.
> In fact, it did happen _never_ for me.
> If it triggers, the device does not work _at all_ anyway.
> 
>> and in the grand scheme of things a second isn't all _that_ long,
>> but still it would be better to avoid a delay like that -- a second
>> could be the time it takes to avoid a meltdown at the nuclear power
>> plant. :-)
>>
>> Could you not use msleep instead of udelay (and scale the for loop
>> appropriately)?  What would be the problem with that?  It would get
>> rid of the busy waiting.
> 
> Becauses it horribly _increases_ the delay.
> We "spin" for _at most_ 10 usecs here. Please always remember that.
> We are talking about a 10 usec delay here. And I already sent a
> patch to even reduce this to under 10 usec.
> 
>> To be fair, this code was already in the driver and was only being
>> moved by this patch.  Still, what better time to fix it than now? :-)
> 
> If it ain't broken, don't fix it.
> 
>> I'll go ahead and reshuffle wireless-2.6 to drop this patch.  A new
>> patch that passes muster w/ Jeff will be most welcome! :-)
> 
> A new patch won't appear, as there is no problem with this
> delay.
> Please don't drop anything and apply the following patch on top
> of it:

John,

I would like to find a diplomatic solution to this impasse between Michael and Jeff, which is why 
I'm writing to you privately. Michael is correct in that the loop in question will not usually delay 
long; however, on some hardware it takes longer than on his. On mine, I have seen delays as long as 
550 usec. In any case, I think that the following code fragment would work and pass Jeff's criticism:

for (i=5000; i; i--) {
	..........
	usleep(1);
}

This would make the worst-case delay be 5 msec, but would provide a cushion of 10X the longest I 
have seen and should be safe.

Do you have any suggestions on what should be done next?

Larry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 19:33               ` John W. Linville
@ 2006-06-27 19:47                 ` Michael Buesch
  2006-06-27 20:06                   ` Larry Finger
  0 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 19:47 UTC (permalink / raw)
  To: John W. Linville; +Cc: Jeff Garzik, bcm43xx-dev, Larry Finger, netdev

On Tuesday 27 June 2006 21:33, John W. Linville wrote:
> On Tue, Jun 27, 2006 at 06:31:01PM +0200, Michael Buesch wrote:
> > On Tuesday 27 June 2006 18:12, Jeff Garzik wrote:
> > > Michael Buesch wrote:
> > > > So, I will submit a patch to lower the udelay(10) to udelay(1)
> > > > and we can close the discussion? ;)
> > > 
> > > No, that totally avoids my point.  Your "otherwise idle machine" test is 
> > > probably nowhere near worst case in the field, for loops that can 
> > > potentially lock the CPU for a long time upon hardware fault.  And then 
> > > there are the huge delays in specific functions that I pointed out...
> > 
> > wtf are you requesting from me?
> > 1) I proved you that the loop does only spin _once_ or even _less_.
> > 2) If the hardware is faulty, the user must replace it.
> >    Because, if the hardware is faulty, it can crash the whole
> >    machine anyway, obviously.
> > 
> > 3) There is no "huge delay". I proved it with my logs.
> >    -> No CPU hog => Nothing to fix.
> 
> Michael,
> 
> I think Jeff's concern is that by using udelay you are busy-waiting.
> And, the for loop limit of 100000 means you could freeze the kernel
> for up to a whole second.  Granted that this won't happen very often

s/very often/ever/

It won't happen, as long as the driver is not buggy, or the device
is hardware broken. So, if it happens, something has to be fixed.
In fact, it did happen _never_ for me.
If it triggers, the device does not work _at all_ anyway.

> and in the grand scheme of things a second isn't all _that_ long,
> but still it would be better to avoid a delay like that -- a second
> could be the time it takes to avoid a meltdown at the nuclear power
> plant. :-)
> 
> Could you not use msleep instead of udelay (and scale the for loop
> appropriately)?  What would be the problem with that?  It would get
> rid of the busy waiting.

Becauses it horribly _increases_ the delay.
We "spin" for _at most_ 10 usecs here. Please always remember that.
We are talking about a 10 usec delay here. And I already sent a
patch to even reduce this to under 10 usec.

> To be fair, this code was already in the driver and was only being
> moved by this patch.  Still, what better time to fix it than now? :-)

If it ain't broken, don't fix it.

> I'll go ahead and reshuffle wireless-2.6 to drop this patch.  A new
> patch that passes muster w/ Jeff will be most welcome! :-)

A new patch won't appear, as there is no problem with this
delay.
Please don't drop anything and apply the following patch on top
of it:

--

Microoptimization:
This reduces the udelay in bcm43xx_mac_suspend.

Signed-off-by: Michael Buesch <mb@bu3sch.de>

Index: wireless-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-2.6.orig/drivers/net/wireless/bcm43xx/bcm43xx_main.c	2006-06-27 17:47:24.000000000 +0200
+++ wireless-2.6/drivers/net/wireless/bcm43xx/bcm43xx_main.c	2006-06-27 17:53:29.000000000 +0200
@@ -2328,7 +2328,7 @@
 			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 			if (tmp & BCM43xx_IRQ_READY)
 				goto out;
-			udelay(10);
+			udelay(1);
 		}
 		printkl(KERN_ERR PFX "MAC suspend failed\n");
 	}


-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 16:31             ` Michael Buesch
@ 2006-06-27 19:33               ` John W. Linville
  2006-06-27 19:47                 ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-06-27 19:33 UTC (permalink / raw)
  To: Michael Buesch; +Cc: Jeff Garzik, bcm43xx-dev, Larry Finger, netdev

On Tue, Jun 27, 2006 at 06:31:01PM +0200, Michael Buesch wrote:
> On Tuesday 27 June 2006 18:12, Jeff Garzik wrote:
> > Michael Buesch wrote:
> > > So, I will submit a patch to lower the udelay(10) to udelay(1)
> > > and we can close the discussion? ;)
> > 
> > No, that totally avoids my point.  Your "otherwise idle machine" test is 
> > probably nowhere near worst case in the field, for loops that can 
> > potentially lock the CPU for a long time upon hardware fault.  And then 
> > there are the huge delays in specific functions that I pointed out...
> 
> wtf are you requesting from me?
> 1) I proved you that the loop does only spin _once_ or even _less_.
> 2) If the hardware is faulty, the user must replace it.
>    Because, if the hardware is faulty, it can crash the whole
>    machine anyway, obviously.
> 
> 3) There is no "huge delay". I proved it with my logs.
>    -> No CPU hog => Nothing to fix.

Michael,

I think Jeff's concern is that by using udelay you are busy-waiting.
And, the for loop limit of 100000 means you could freeze the kernel
for up to a whole second.  Granted that this won't happen very often
and in the grand scheme of things a second isn't all _that_ long,
but still it would be better to avoid a delay like that -- a second
could be the time it takes to avoid a meltdown at the nuclear power
plant. :-)

Could you not use msleep instead of udelay (and scale the for loop
appropriately)?  What would be the problem with that?  It would get
rid of the busy waiting.

To be fair, this code was already in the driver and was only being
moved by this patch.  Still, what better time to fix it than now? :-)

I'll go ahead and reshuffle wireless-2.6 to drop this patch.  A new
patch that passes muster w/ Jeff will be most welcome! :-)

Thanks,

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 16:12           ` Jeff Garzik
  2006-06-27 16:31             ` Michael Buesch
@ 2006-06-27 16:52             ` Joseph Jezak
  1 sibling, 0 replies; 108+ messages in thread
From: Joseph Jezak @ 2006-06-27 16:52 UTC (permalink / raw)
  To: NetDev

> No, that totally avoids my point.  Your "otherwise idle machine" test is
> probably nowhere near worst case in the field, for loops that can
> potentially lock the CPU for a long time upon hardware fault.  And then
> there are the huge delays in specific functions that I pointed out...
> 
>     Jeff

The problem is that these are the delays used in the original driver
that we've been writing the specs from.  We don't know what they're
for or why they're so long.  We don't know if reducing the delay
will cause issues on some hardware and work fine on others.  Without
the actual specs from Broadcom, it's hard to say what's excessive
and what's not and whether changing it will break the driver.

-Joe

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 16:12           ` Jeff Garzik
@ 2006-06-27 16:31             ` Michael Buesch
  2006-06-27 19:33               ` John W. Linville
  2006-06-27 16:52             ` Joseph Jezak
  1 sibling, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 16:31 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

On Tuesday 27 June 2006 18:12, Jeff Garzik wrote:
> Michael Buesch wrote:
> > So, I will submit a patch to lower the udelay(10) to udelay(1)
> > and we can close the discussion? ;)
> 
> No, that totally avoids my point.  Your "otherwise idle machine" test is 
> probably nowhere near worst case in the field, for loops that can 
> potentially lock the CPU for a long time upon hardware fault.  And then 
> there are the huge delays in specific functions that I pointed out...

wtf are you requesting from me?
1) I proved you that the loop does only spin _once_ or even _less_.
2) If the hardware is faulty, the user must replace it.
   Because, if the hardware is faulty, it can crash the whole
   machine anyway, obviously.

3) There is no "huge delay". I proved it with my logs.
   -> No CPU hog => Nothing to fix.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 16:10           ` Jeff Garzik
@ 2006-06-27 16:23             ` Michael Buesch
  0 siblings, 0 replies; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 16:23 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

On Tuesday 27 June 2006 18:10, Jeff Garzik wrote:
> Michael Buesch wrote:
> > On Tuesday 27 June 2006 16:11, Jeff Garzik wrote:
> >> Overall, bcm43xx is _really really bad_ about this sort of thing.  Just 
> >> grepping for udelay in bcm43xx_radio.c shows some of the worst 
> >> offenders.  bcm43xx_radio_init2060() and bcm43xx_radio_selectchannel() 
> >> both look like candidates for using msleep() rather than udelay().
> > 
> > This is _all_ at initialization time.
> > select_channel.... How often do you select a channel?
> 
> That question is irrelevant, because you have no idea what -else- is 
> going on in the system, at the point when bcm43xx chooses to spin the 
> CPU heavily.
> 
> Initialization time means you are definitely not in a hot path, and can 
> therefore sleep.

Ok, again:
If you are running a preemptible kernel (I am doing a patch for the
non-preemptible case), everything is _already_ fine.
We are not spinning long times with locks held or IRQs disabled.
I already fixed that.

And no, I don't really care for initialization time.
I am not going to potentially break the driver to remove
1ms of wasted CPU on ifconfig up.
In fact, initialization is and always was done lockless.
So we should be fine there, too, actually.

We don't know why these delays are there all. And we never will.
But as this are all some measuring an calibration routines,
they surely have some purpose. We don't know if longer delays
in some places may have ill effects. Making the whole thing
preemptible (as I am doing / have done) surely has its potential
to break the driver.

I prefer correct operation over an unnoticable 1ms CPU hog.

> > I recently reworked the periodically exectuted workhandlers,
> > so that they are preemptible.
> 
> Major classes of users run their kernels without preempt.  Please don't 
> depend on that to avoid bad behavior.

I am doing a patch atm.
I will add voluntary preemption points, if the kernel is not preemptible.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 15:25         ` Michael Buesch
@ 2006-06-27 16:12           ` Jeff Garzik
  2006-06-27 16:31             ` Michael Buesch
  2006-06-27 16:52             ` Joseph Jezak
  0 siblings, 2 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-06-27 16:12 UTC (permalink / raw)
  To: Michael Buesch; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

Michael Buesch wrote:
> So, I will submit a patch to lower the udelay(10) to udelay(1)
> and we can close the discussion? ;)

No, that totally avoids my point.  Your "otherwise idle machine" test is 
probably nowhere near worst case in the field, for loops that can 
potentially lock the CPU for a long time upon hardware fault.  And then 
there are the huge delays in specific functions that I pointed out...

	Jeff



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 14:36         ` Michael Buesch
@ 2006-06-27 16:10           ` Jeff Garzik
  2006-06-27 16:23             ` Michael Buesch
  0 siblings, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2006-06-27 16:10 UTC (permalink / raw)
  To: Michael Buesch; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

Michael Buesch wrote:
> On Tuesday 27 June 2006 16:11, Jeff Garzik wrote:
>> Overall, bcm43xx is _really really bad_ about this sort of thing.  Just 
>> grepping for udelay in bcm43xx_radio.c shows some of the worst 
>> offenders.  bcm43xx_radio_init2060() and bcm43xx_radio_selectchannel() 
>> both look like candidates for using msleep() rather than udelay().
> 
> This is _all_ at initialization time.
> select_channel.... How often do you select a channel?

That question is irrelevant, because you have no idea what -else- is 
going on in the system, at the point when bcm43xx chooses to spin the 
CPU heavily.

Initialization time means you are definitely not in a hot path, and can 
therefore sleep.


> I recently reworked the periodically exectuted workhandlers,
> so that they are preemptible.

Major classes of users run their kernels without preempt.  Please don't 
depend on that to avoid bad behavior.


> mac_suspend():
> It is always called in atomic context with IRQs disabled.
> We need to wait for the device here to signal "OK, MAC is down
> now and you can count on it". This takes a few usecs. I guess
> it sends out all queued packets, or whatever. We don't know
> really.
> I can actually measure how long it takes, if you really desire
> it.
> We _need_ to wait there. It is something like synchronize_irq(), or
> whatever. It is a synchronizing function and we need it to be
> synchronizing.
> And I don't think it is worth the pain to insert a preemption
> point there (or doing even fancier things with workqueues and
> completions).
> 
> Overall, I don't think bcm43xx is still so bad at
> wasting CPU. Maybe we should still insert some voluntary
> preemption points, if the bcm43xx user does not run a fully
> preemptible kernel. But if a fully preemptible kernel is run,
> I think it is all OK.

Never assume a preemptible kernel will clean up problems for you :)

	Jeff




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 14:11       ` Jeff Garzik
  2006-06-27 14:34         ` Larry Finger
  2006-06-27 14:36         ` Michael Buesch
@ 2006-06-27 15:25         ` Michael Buesch
  2006-06-27 16:12           ` Jeff Garzik
  2 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 15:25 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

On Tuesday 27 June 2006 16:11, Jeff Garzik wrote:
> Michael Buesch wrote:
> > On Tuesday 27 June 2006 04:27, Larry Finger wrote:
> >> Jeff Garzik wrote:
> >>> John W. Linville wrote:
> >>>> +    assert(bcm->mac_suspended >= 0);
> >>>> +    if (bcm->mac_suspended == 0) {
> >>>> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
> >>>> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> >>>> +                        bcm43xx_read32(bcm, 
> >>>> BCM43xx_MMIO_STATUS_BITFIELD)
> >>>> +                & ~BCM43xx_SBF_MAC_ENABLED);
> >>>> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
> >>>> read */
> >>>> +        for (i = 100000; i; i--) {
> >>>> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
> >>>> +            if (tmp & BCM43xx_IRQ_READY)
> >>>> +                goto out;
> >>>> +            udelay(10);
> >>>> +        }
> >>>> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
> >>>>      }
> >>>
> >>> NAK this super-long delay...  should be done in a workqueue, looks like?
> >>>
> >>> ACK everything else.
> >>>
> >> That delay was set to try to accommodate my interface when it refused to suspend the MAC, which 
> >> resulted in transmit errors. That problem has since been cured by reworking the periodic work 
> >> handlers - thus such a long delay should not be needed. The original spec from the clean-room group 
> >> was a delay loop of 1000. I'm currently testing that value now. If it passes the test, would a for 
> >> (i=1000; i; i--) be acceptable?
> > 
> > Short: Don't touch it. Fullstop.
> > 
> > Long: The delay will _never_ be exhausted. Actually the for-counter
> > is only there to not lock up the machine, if there is a Bug in the
> > driver. (__much__ easier debugging).
> > The loop will only iterate a few times, typically.
> > Actually, _if_ we want to change something, we should do this:
> > 
> > for (i = 1000000; i; i--) {
> > 	...
> > 	udelay(1);
> > }
> > 
> > (max loop multiplied by 10, delay value divided by 10).
> > This will shorten the whole delay by a few usecs (up to 10).
> > I will send a patch for this, if it is desired.
> > 
> > But lowering the loop counter value is NACKed by me,
> > because it simply does not make sense.
> 
> 
> My overriding concern was that this type of loop spins the CPU at 100% 
> until the hardware condition is satisfied, which starves all other 
> kernel work on that CPU, and is very unfriendly to power consumption 
> (though I believe monitor/mwait/cpu_relax helps on x86).

Ok, I did a testrun. Here's the result:

[   68.711243] bcm43xx_d80211: Chip ID 0x4306, rev 0x3
[   68.712662] bcm43xx_d80211: Number of cores: 5
[   68.714023] bcm43xx_d80211: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
[   68.715536] bcm43xx_d80211: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
[   68.717062] bcm43xx_d80211: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
[   68.718575] bcm43xx_d80211: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
[   68.720089] bcm43xx_d80211: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
[   68.724897] bcm43xx_d80211: PHY connected
[   68.726154] bcm43xx_d80211: Detected PHY: Version: 2, Type 2, Revision 2
[   68.727638] bcm43xx_d80211: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
[   68.729232] bcm43xx_d80211: Radio turned off
[   68.730512] bcm43xx_d80211: Radio turned off
[   68.745153] wmaster0: Selected rate control algorithm 'simple'
[   69.853876] bcm43xx_d80211: Virtual interface added (type: 0x00000002, ID: 7, MAC: 00:11:24:a0:de:8b)
[   69.861872] bcm43xx_d80211: PHY connected
[   70.000713] bcm43xx_d80211: Radio turned on
[   70.190153] bcm43xx_d80211: Chip initialized
[   70.192051] bcm43xx_d80211: DMA initialized
[   70.193987] bcm43xx_d80211: 80211 cores initialized
[   70.195550] bcm43xx_d80211: Keys cleared
[   70.212565] wmaster0: Does not support passive scan, disabled
[   70.252321] bcm43xx_d80211: mac_suspend() took 1 loops == 10 usec
[   70.542160] NET: Registered protocol family 17
[   70.692256] sta0: starting scan
[   70.702234] HW CONFIG: channel=1 freq=2412 phymode=3
[   70.762225] HW CONFIG: channel=2 freq=2417 phymode=3
[   70.822227] HW CONFIG: channel=3 freq=2422 phymode=3
[   70.882225] HW CONFIG: channel=4 freq=2427 phymode=3
[   70.942225] HW CONFIG: channel=5 freq=2432 phymode=3
[   71.002285] HW CONFIG: channel=6 freq=2437 phymode=3
[   71.062229] HW CONFIG: channel=7 freq=2442 phymode=3
[   71.122230] HW CONFIG: channel=8 freq=2447 phymode=3
[   71.182239] HW CONFIG: channel=9 freq=2452 phymode=3
[   71.242226] HW CONFIG: channel=10 freq=2457 phymode=3
[   71.302226] HW CONFIG: channel=11 freq=2462 phymode=3
[   71.512225] HW CONFIG: channel=1 freq=2412 phymode=3
[   71.520066] sta0: scan completed
[   71.523437] HW CONFIG: channel=6 freq=2437 phymode=3
[   71.531600] sta0: Initial auth_alg=0
[   71.531806] sta0: authenticate with AP 00:90:4c:60:04:00
[   71.533279] sta0: RX authentication from 00:90:4c:60:04:00 (alg=0 transaction=2 status=0)
[   71.533292] sta0: authenticated
[   71.533301] sta0: associate with AP 00:90:4c:60:04:00
[   71.536264] sta0: RX AssocResp from 00:90:4c:60:04:00 (capab=0x411 status=0 aid=1)
[   71.536276] sta0: associated
[   71.536352] wmaster0: Added STA 00:90:4c:60:04:00
[  130.292251] bcm43xx_d80211: mac_suspend() took 1 loops == 10 usec
[  190.322251] bcm43xx_d80211: mac_suspend() took 1 loops == 10 usec
[  250.362252] bcm43xx_d80211: mac_suspend() took 0 loops == 0 usec
[  310.392278] bcm43xx_d80211: mac_suspend() took 1 loops == 10 usec

So, I will submit a patch to lower the udelay(10) to udelay(1)
and we can close the discussion? ;)

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 14:11       ` Jeff Garzik
  2006-06-27 14:34         ` Larry Finger
@ 2006-06-27 14:36         ` Michael Buesch
  2006-06-27 16:10           ` Jeff Garzik
  2006-06-27 15:25         ` Michael Buesch
  2 siblings, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 14:36 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

On Tuesday 27 June 2006 16:11, Jeff Garzik wrote:
> Michael Buesch wrote:
> > On Tuesday 27 June 2006 04:27, Larry Finger wrote:
> >> Jeff Garzik wrote:
> >>> John W. Linville wrote:
> >>>> +    assert(bcm->mac_suspended >= 0);
> >>>> +    if (bcm->mac_suspended == 0) {
> >>>> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
> >>>> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> >>>> +                        bcm43xx_read32(bcm, 
> >>>> BCM43xx_MMIO_STATUS_BITFIELD)
> >>>> +                & ~BCM43xx_SBF_MAC_ENABLED);
> >>>> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
> >>>> read */
> >>>> +        for (i = 100000; i; i--) {
> >>>> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
> >>>> +            if (tmp & BCM43xx_IRQ_READY)
> >>>> +                goto out;
> >>>> +            udelay(10);
> >>>> +        }
> >>>> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
> >>>>      }
> >>>
> >>> NAK this super-long delay...  should be done in a workqueue, looks like?
> >>>
> >>> ACK everything else.
> >>>
> >> That delay was set to try to accommodate my interface when it refused to suspend the MAC, which 
> >> resulted in transmit errors. That problem has since been cured by reworking the periodic work 
> >> handlers - thus such a long delay should not be needed. The original spec from the clean-room group 
> >> was a delay loop of 1000. I'm currently testing that value now. If it passes the test, would a for 
> >> (i=1000; i; i--) be acceptable?
> > 
> > Short: Don't touch it. Fullstop.
> > 
> > Long: The delay will _never_ be exhausted. Actually the for-counter
> > is only there to not lock up the machine, if there is a Bug in the
> > driver. (__much__ easier debugging).
> > The loop will only iterate a few times, typically.
> > Actually, _if_ we want to change something, we should do this:
> > 
> > for (i = 1000000; i; i--) {
> > 	...
> > 	udelay(1);
> > }
> > 
> > (max loop multiplied by 10, delay value divided by 10).
> > This will shorten the whole delay by a few usecs (up to 10).
> > I will send a patch for this, if it is desired.
> > 
> > But lowering the loop counter value is NACKed by me,
> > because it simply does not make sense.
> 
> 
> My overriding concern was that this type of loop spins the CPU at 100% 
> until the hardware condition is satisfied, which starves all other 
> kernel work on that CPU, and is very unfriendly to power consumption 
> (though I believe monitor/mwait/cpu_relax helps on x86).
> 
> Overall, bcm43xx is _really really bad_ about this sort of thing.  Just 
> grepping for udelay in bcm43xx_radio.c shows some of the worst 
> offenders.  bcm43xx_radio_init2060() and bcm43xx_radio_selectchannel() 
> both look like candidates for using msleep() rather than udelay().

This is _all_ at initialization time.
select_channel.... How often do you select a channel?

I recently reworked the periodically exectuted workhandlers,
so that they are preemptible.

mac_suspend():
It is always called in atomic context with IRQs disabled.
We need to wait for the device here to signal "OK, MAC is down
now and you can count on it". This takes a few usecs. I guess
it sends out all queued packets, or whatever. We don't know
really.
I can actually measure how long it takes, if you really desire
it.
We _need_ to wait there. It is something like synchronize_irq(), or
whatever. It is a synchronizing function and we need it to be
synchronizing.
And I don't think it is worth the pain to insert a preemption
point there (or doing even fancier things with workqueues and
completions).

Overall, I don't think bcm43xx is still so bad at
wasting CPU. Maybe we should still insert some voluntary
preemption points, if the bcm43xx user does not run a fully
preemptible kernel. But if a fully preemptible kernel is run,
I think it is all OK.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 14:11       ` Jeff Garzik
@ 2006-06-27 14:34         ` Larry Finger
  2006-06-27 14:36         ` Michael Buesch
  2006-06-27 15:25         ` Michael Buesch
  2 siblings, 0 replies; 108+ messages in thread
From: Larry Finger @ 2006-06-27 14:34 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Michael Buesch, bcm43xx-dev, John W. Linville, netdev

Jeff Garzik wrote:
> Michael Buesch wrote:
>>
>> Short: Don't touch it. Fullstop.
>>
>> Long: The delay will _never_ be exhausted. Actually the for-counter
>> is only there to not lock up the machine, if there is a Bug in the
>> driver. (__much__ easier debugging).
>> The loop will only iterate a few times, typically.
>> Actually, _if_ we want to change something, we should do this:
>>
>> for (i = 1000000; i; i--) {
>>     ...
>>     udelay(1);
>> }
>>
>> (max loop multiplied by 10, delay value divided by 10).
>> This will shorten the whole delay by a few usecs (up to 10).
>> I will send a patch for this, if it is desired.
>>
>> But lowering the loop counter value is NACKed by me,
>> because it simply does not make sense.
> 
> 
> My overriding concern was that this type of loop spins the CPU at 100% 
> until the hardware condition is satisfied, which starves all other 
> kernel work on that CPU, and is very unfriendly to power consumption 
> (though I believe monitor/mwait/cpu_relax helps on x86).
> 
> Overall, bcm43xx is _really really bad_ about this sort of thing.  Just 
> grepping for udelay in bcm43xx_radio.c shows some of the worst 
> offenders.  bcm43xx_radio_init2060() and bcm43xx_radio_selectchannel() 
> both look like candidates for using msleep() rather than udelay().

It is not my place to get into the middle of this discussion; however, my interface has been pinging 
my AP for over 12 hours with the loop counter starting at 1000. I get the usual log entries for the 
hourly TKIP changes, but no MAC suspend failures.

Larry


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27 13:30     ` Michael Buesch
@ 2006-06-27 14:11       ` Jeff Garzik
  2006-06-27 14:34         ` Larry Finger
                           ` (2 more replies)
  0 siblings, 3 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-06-27 14:11 UTC (permalink / raw)
  To: Michael Buesch; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

Michael Buesch wrote:
> On Tuesday 27 June 2006 04:27, Larry Finger wrote:
>> Jeff Garzik wrote:
>>> John W. Linville wrote:
>>>> +    assert(bcm->mac_suspended >= 0);
>>>> +    if (bcm->mac_suspended == 0) {
>>>> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
>>>> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
>>>> +                        bcm43xx_read32(bcm, 
>>>> BCM43xx_MMIO_STATUS_BITFIELD)
>>>> +                & ~BCM43xx_SBF_MAC_ENABLED);
>>>> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
>>>> read */
>>>> +        for (i = 100000; i; i--) {
>>>> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
>>>> +            if (tmp & BCM43xx_IRQ_READY)
>>>> +                goto out;
>>>> +            udelay(10);
>>>> +        }
>>>> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
>>>>      }
>>>
>>> NAK this super-long delay...  should be done in a workqueue, looks like?
>>>
>>> ACK everything else.
>>>
>> That delay was set to try to accommodate my interface when it refused to suspend the MAC, which 
>> resulted in transmit errors. That problem has since been cured by reworking the periodic work 
>> handlers - thus such a long delay should not be needed. The original spec from the clean-room group 
>> was a delay loop of 1000. I'm currently testing that value now. If it passes the test, would a for 
>> (i=1000; i; i--) be acceptable?
> 
> Short: Don't touch it. Fullstop.
> 
> Long: The delay will _never_ be exhausted. Actually the for-counter
> is only there to not lock up the machine, if there is a Bug in the
> driver. (__much__ easier debugging).
> The loop will only iterate a few times, typically.
> Actually, _if_ we want to change something, we should do this:
> 
> for (i = 1000000; i; i--) {
> 	...
> 	udelay(1);
> }
> 
> (max loop multiplied by 10, delay value divided by 10).
> This will shorten the whole delay by a few usecs (up to 10).
> I will send a patch for this, if it is desired.
> 
> But lowering the loop counter value is NACKed by me,
> because it simply does not make sense.


My overriding concern was that this type of loop spins the CPU at 100% 
until the hardware condition is satisfied, which starves all other 
kernel work on that CPU, and is very unfriendly to power consumption 
(though I believe monitor/mwait/cpu_relax helps on x86).

Overall, bcm43xx is _really really bad_ about this sort of thing.  Just 
grepping for udelay in bcm43xx_radio.c shows some of the worst 
offenders.  bcm43xx_radio_init2060() and bcm43xx_radio_selectchannel() 
both look like candidates for using msleep() rather than udelay().

	Jeff



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27  2:27   ` Larry Finger
  2006-06-27  3:50     ` Jeff Garzik
@ 2006-06-27 13:30     ` Michael Buesch
  2006-06-27 14:11       ` Jeff Garzik
  1 sibling, 1 reply; 108+ messages in thread
From: Michael Buesch @ 2006-06-27 13:30 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: bcm43xx-dev, Larry Finger, John W. Linville, netdev

On Tuesday 27 June 2006 04:27, Larry Finger wrote:
> Jeff Garzik wrote:
> > John W. Linville wrote:
> >> +    assert(bcm->mac_suspended >= 0);
> >> +    if (bcm->mac_suspended == 0) {
> >> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
> >> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> >> +                        bcm43xx_read32(bcm, 
> >> BCM43xx_MMIO_STATUS_BITFIELD)
> >> +                & ~BCM43xx_SBF_MAC_ENABLED);
> >> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
> >> read */
> >> +        for (i = 100000; i; i--) {
> >> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
> >> +            if (tmp & BCM43xx_IRQ_READY)
> >> +                goto out;
> >> +            udelay(10);
> >> +        }
> >> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
> >>      }
> > 
> > 
> > NAK this super-long delay...  should be done in a workqueue, looks like?
> > 
> > ACK everything else.
> > 
> 
> That delay was set to try to accommodate my interface when it refused to suspend the MAC, which 
> resulted in transmit errors. That problem has since been cured by reworking the periodic work 
> handlers - thus such a long delay should not be needed. The original spec from the clean-room group 
> was a delay loop of 1000. I'm currently testing that value now. If it passes the test, would a for 
> (i=1000; i; i--) be acceptable?

Short: Don't touch it. Fullstop.

Long: The delay will _never_ be exhausted. Actually the for-counter
is only there to not lock up the machine, if there is a Bug in the
driver. (__much__ easier debugging).
The loop will only iterate a few times, typically.
Actually, _if_ we want to change something, we should do this:

for (i = 1000000; i; i--) {
	...
	udelay(1);
}

(max loop multiplied by 10, delay value divided by 10).
This will shorten the whole delay by a few usecs (up to 10).
I will send a patch for this, if it is desired.

But lowering the loop counter value is NACKed by me,
because it simply does not make sense.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27  2:27   ` Larry Finger
@ 2006-06-27  3:50     ` Jeff Garzik
  2006-06-27 13:30     ` Michael Buesch
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-06-27  3:50 UTC (permalink / raw)
  To: Larry Finger; +Cc: John W. Linville, netdev, Bcm43xx-dev

Larry Finger wrote:
> Jeff Garzik wrote:
>> John W. Linville wrote:
>>> +    assert(bcm->mac_suspended >= 0);
>>> +    if (bcm->mac_suspended == 0) {
>>> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
>>> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
>>> +                        bcm43xx_read32(bcm, 
>>> BCM43xx_MMIO_STATUS_BITFIELD)
>>> +                & ~BCM43xx_SBF_MAC_ENABLED);
>>> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
>>> read */
>>> +        for (i = 100000; i; i--) {
>>> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
>>> +            if (tmp & BCM43xx_IRQ_READY)
>>> +                goto out;
>>> +            udelay(10);
>>> +        }
>>> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
>>>      }
>>
>>
>> NAK this super-long delay...  should be done in a workqueue, looks like?
>>
>> ACK everything else.
>>
> 
> That delay was set to try to accommodate my interface when it refused to 
> suspend the MAC, which resulted in transmit errors. That problem has 
> since been cured by reworking the periodic work handlers - thus such a 
> long delay should not be needed. The original spec from the clean-room 
> group was a delay loop of 1000. I'm currently testing that value now. If 
> it passes the test, would a for (i=1000; i; i--) be acceptable?

That's acceptable, yes, but it sounds like the problem has since been cured?

	Jeff




^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-27  2:06 ` Jeff Garzik
@ 2006-06-27  2:27   ` Larry Finger
  2006-06-27  3:50     ` Jeff Garzik
  2006-06-27 13:30     ` Michael Buesch
  0 siblings, 2 replies; 108+ messages in thread
From: Larry Finger @ 2006-06-27  2:27 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: John W. Linville, netdev, Bcm43xx-dev

Jeff Garzik wrote:
> John W. Linville wrote:
>> +    assert(bcm->mac_suspended >= 0);
>> +    if (bcm->mac_suspended == 0) {
>> +        bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
>> +        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
>> +                        bcm43xx_read32(bcm, 
>> BCM43xx_MMIO_STATUS_BITFIELD)
>> +                & ~BCM43xx_SBF_MAC_ENABLED);
>> +        bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy 
>> read */
>> +        for (i = 100000; i; i--) {
>> +            tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
>> +            if (tmp & BCM43xx_IRQ_READY)
>> +                goto out;
>> +            udelay(10);
>> +        }
>> +        printkl(KERN_ERR PFX "MAC suspend failed\n");
>>      }
> 
> 
> NAK this super-long delay...  should be done in a workqueue, looks like?
> 
> ACK everything else.
> 

That delay was set to try to accommodate my interface when it refused to suspend the MAC, which 
resulted in transmit errors. That problem has since been cured by reworking the periodic work 
handlers - thus such a long delay should not be needed. The original spec from the clean-room group 
was a delay loop of 1000. I'm currently testing that value now. If it passes the test, would a for 
(i=1000; i; i--) be acceptable?

Larry

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-26 21:25 John W. Linville
@ 2006-06-27  2:06 ` Jeff Garzik
  2006-06-27  2:27   ` Larry Finger
  0 siblings, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2006-06-27  2:06 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> +	assert(bcm->mac_suspended >= 0);
> +	if (bcm->mac_suspended == 0) {
> +		bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
> +		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
> +		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
> +				& ~BCM43xx_SBF_MAC_ENABLED);
> +		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
> +		for (i = 100000; i; i--) {
> +			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
> +			if (tmp & BCM43xx_IRQ_READY)
> +				goto out;
> +			udelay(10);
> +		}
> +		printkl(KERN_ERR PFX "MAC suspend failed\n");
>  	}


NAK this super-long delay...  should be done in a workqueue, looks like?

ACK everything else.

	Jeff



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-06-26 21:25 John W. Linville
  2006-06-27  2:06 ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-06-26 21:25 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit fcc18e83e1f6fd9fa6b333735bf0fcd530655511:
  Malcolm Parsons:
        uclinux: use PER_LINUX_32BIT in binfmt_flat

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      bcm43xx: use softmac-suggested TX rate
      bcm43xx: enable shared key authentication

Eric Sesterhenn:
      skb used after passing to netif_rx in net/ieee80211/ieee80211_rx.c

Faidon Liambotis:
      Add two PLX device IDs

Hong Liu:
      ieee80211: fix not allocating IV+ICV space when usingencryption in ieee80211_tx_frame

Horms:
      CONFIG_WIRELESS_EXT is neccessary after all

John W. Linville:
      softmac: fix build-break from 881ee6999d66c8fc903b429b73bbe6045b38c549

Joseph Jezak:
      SoftMAC: Prevent multiple authentication attempts on the same network
      SoftMAC: Add network to ieee80211softmac_call_events when associate times out

Larry Finger:
      Convert bcm43xx-softmac to use the ieee80211_is_valid_channel routine
      2.6.17 missing a call to ieee80211softmac_capabilities from ieee80211softmac_assoc_req

Michael Buesch:
      bcm43xx: suspend MAC while executing long pwork
      bcm43xx: workaround init_board vs. IRQ race

 drivers/net/wireless/bcm43xx/bcm43xx.h         |    2 +
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   82 +++++++++++++++---------
 drivers/net/wireless/bcm43xx/bcm43xx_main.h    |   24 -------
 drivers/net/wireless/bcm43xx/bcm43xx_radio.c   |    7 +-
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |    2 -
 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c    |    5 +
 drivers/net/wireless/hostap/hostap_plx.c       |    2 +
 include/net/ieee80211softmac.h                 |    1 
 net/ieee80211/ieee80211_rx.c                   |    4 +
 net/ieee80211/ieee80211_tx.c                   |   15 +++-
 net/ieee80211/softmac/ieee80211softmac_assoc.c |   31 +++++++--
 net/ieee80211/softmac/ieee80211softmac_auth.c  |    4 +
 net/ieee80211/softmac/ieee80211softmac_io.c    |    3 +
 net/ieee80211/softmac/ieee80211softmac_wx.c    |   36 ++++++++++-
 14 files changed, 139 insertions(+), 79 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index d8f917c..d5e10e2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -722,6 +722,8 @@ #endif
 	u32 irq_savedstate;
 	/* Link Quality calculation context. */
 	struct bcm43xx_noise_calculation noisecalc;
+	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+	int mac_suspended;
 
 	/* Threshold values. */
 	//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 085d785..af97755 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_han
 
 	spin_lock(&bcm->irq_lock);
 
+	/* Only accept IRQs, if we are initialized properly.
+	 * This avoids an RX race while initializing.
+	 * We should probably not enable IRQs before we are initialized
+	 * completely, but some careful work is needed to fix this. I think it
+	 * is best to stay with this cheap workaround for now... .
+	 */
+	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+		goto out;
+
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
 		/* irq not for us (shared irq) */
@@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_han
 
 	bcm43xx_interrupt_ack(bcm, reason);
 
-	/* Only accept IRQs, if we are initialized properly.
-	 * This avoids an RX race while initializing.
-	 * We should probably not enable IRQs before we are initialized
-	 * completely, but some careful work is needed to fix this. I think it
-	 * is best to stay with this cheap workaround for now... .
-	 */
-	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
-		/* disable all IRQs. They are enabled again in the bottom half. */
-		bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-		/* save the reason code and call our bottom half. */
-		bcm->irq_reason = reason;
-		tasklet_schedule(&bcm->isr_tasklet);
-	}
+	/* disable all IRQs. They are enabled again in the bottom half. */
+	bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+	/* save the reason code and call our bottom half. */
+	bcm->irq_reason = reason;
+	tasklet_schedule(&bcm->isr_tasklet);
 
 out:
 	mmiowb();
@@ -2297,13 +2298,17 @@ static int bcm43xx_gpio_cleanup(struct b
 /* http://bcm-specs.sipsolutions.net/EnableMac */
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
 {
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			| BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	bcm->mac_suspended--;
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+	}
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2312,18 +2317,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_
 	int i;
 	u32 tmp;
 
-	bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
-	                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
-			& ~BCM43xx_SBF_MAC_ENABLED);
-	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
-	for (i = 100000; i; i--) {
-		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
-		if (tmp & BCM43xx_IRQ_READY)
-			return;
-		udelay(10);
+	assert(bcm->mac_suspended >= 0);
+	if (bcm->mac_suspended == 0) {
+		bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~BCM43xx_SBF_MAC_ENABLED);
+		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+		for (i = 100000; i; i--) {
+			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+			if (tmp & BCM43xx_IRQ_READY)
+				goto out;
+			udelay(10);
+		}
+		printkl(KERN_ERR PFX "MAC suspend failed\n");
 	}
-	printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+	bcm->mac_suspended++;
 }
 
 void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -3181,8 +3191,10 @@ static void bcm43xx_periodic_work_handle
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
 		 */
-		bcm43xx_lock_irqonly(bcm, flags);
 		netif_stop_queue(bcm->net_dev);
+		synchronize_net();
+		bcm43xx_lock_irqonly(bcm, flags);
+		bcm43xx_mac_suspend(bcm);
 		if (bcm43xx_using_pio(bcm))
 			bcm43xx_pio_freeze_txqueues(bcm);
 		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
@@ -3205,6 +3217,7 @@ static void bcm43xx_periodic_work_handle
 			bcm43xx_interrupt_enable(bcm, savedirqs);
 			if (bcm43xx_using_pio(bcm))
 				bcm43xx_pio_thaw_txqueues(bcm);
+			bcm43xx_mac_enable(bcm);
 		}
 		netif_wake_queue(bcm->net_dev);
 		mmiowb();
@@ -3661,6 +3674,10 @@ static void bcm43xx_ieee80211_set_securi
 		secinfo->encrypt = sec->encrypt;
 		dprintk(", .encrypt = %d", sec->encrypt);
 	}
+	if (sec->flags & SEC_AUTH_MODE) {
+		secinfo->auth_mode = sec->auth_mode;
+		dprintk(", .auth_mode = %d\n", sec->auth_mode);
+	}
 	dprintk("\n");
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
 	    !bcm->ieee->host_encrypt) {
@@ -3776,6 +3793,7 @@ static int bcm43xx_init_private(struct b
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
 
 	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+	bcm->mac_suspended = 1;
 	bcm->pci_dev = pci_dev;
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 30a202b..1164936 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43
 	return bcm43xx_channel_to_freq_bg(channel);
 }
 
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
-	return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
-	       && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
-	return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
-	       && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
-			     u8 channel)
-{
-	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
-		return bcm43xx_is_valid_channel_a(channel);
-	return bcm43xx_is_valid_channel_bg(channel);
-}
-
 void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af5c0bf..bb9c484 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct b
 	u16 r8, tmp;
 	u16 freq;
 
+	if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+		return -EINVAL;
 	if ((radio->manufact == 0x17F) &&
 	    (radio->version == 0x2060) &&
 	    (radio->revision == 1)) {
-		if (channel > 200)
-			return -EINVAL;
 		freq = channel2freq_a(channel);
 
 		r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct b
 		TODO();	//TODO:	TSSI2dbm workaround
 		bcm43xx_phy_xmitpower(bcm);//FIXME correct?
 	} else {
-		if ((channel < 1) || (channel > 14))
-			return -EINVAL;
-
 		if (synthetic_pu_workaround)
 			bcm43xx_synth_pu_workaround(bcm, channel);
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index c35cb3a..5c36e29 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(st
 		channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
 		freq = data->freq.m;
 	}
-	if (!bcm43xx_is_valid_channel(bcm, channel))
+	if (!ieee80211_is_valid_channel(bcm->ieee, channel))
 		goto out_unlock;
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		//ieee80211softmac_disassoc(softmac, $REASON);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index d8ece28..6dbd855 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43
 	u16 control = 0;
 	u16 wsec_rate = 0;
 	u16 encrypt_frame;
+	const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+	const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
 
 	/* Now construct the TX header. */
 	memset(txhdr, 0, sizeof(*txhdr));
 
-	bitrate = bcm->softmac->txrates.default_rate;
+	bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+		is_multicast_ether_addr(wireless_header->addr1), is_mgt);
 	ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
 	fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
 	fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index edaaa94..39c545e 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -67,10 +67,12 @@ static struct pci_device_id prism2_plx_i
 	PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
 	PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
 	PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+	PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
 	PLXDEV(0x1385, 0x4100, "Netgear MA301"),
 	PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
 	PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
 	PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+	PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
 	PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
 	PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
 	PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 7a483ab..00ad810 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
 	 */
 	u8 static_essid:1,
 	   associating:1,
+	   assoc_wait:1,
 	   bssvalid:1,
 	   bssfixed:1;
 
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 2bf567f..b2fabbb 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -369,6 +369,7 @@ #endif
 
 	/* Put this code here so that we avoid duplicating it in all
 	 * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
 	/* If spy monitoring on */
 	if (ieee->spy_data.spy_number > 0) {
@@ -397,15 +398,16 @@ #ifdef IW_WIRELESS_SPY		/* defined in iw
 		wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
 	}
 #endif				/* IW_WIRELESS_SPY */
+#endif				/* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
 	hostap_update_rx_stats(local->ap, hdr, rx_stats);
 #endif
 
 	if (ieee->iw_mode == IW_MODE_MONITOR) {
-		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		stats->rx_packets++;
 		stats->rx_bytes += skb->len;
+		ieee80211_monitor_rx(ieee, skb, rx_stats);
 		return 1;
 	}
 
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index 6a5de1b..e63bf77 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -563,10 +563,13 @@ int ieee80211_tx_frame(struct ieee80211_
 	struct net_device_stats *stats = &ieee->stats;
 	struct sk_buff *skb_frag;
 	int priority = -1;
+	int fraglen = total_len;
+	int headroom = ieee->tx_headroom;
+	struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
 
 	spin_lock_irqsave(&ieee->lock, flags);
 
-	if (encrypt_mpdu && !ieee->sec.encrypt)
+	if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
 		encrypt_mpdu = 0;
 
 	/* If there is no driver handler to take the TXB, dont' bother
@@ -582,20 +585,24 @@ int ieee80211_tx_frame(struct ieee80211_
 		goto success;
 	}
 
-	if (encrypt_mpdu)
+	if (encrypt_mpdu) {
 		frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		fraglen += crypt->ops->extra_mpdu_prefix_len +
+			   crypt->ops->extra_mpdu_postfix_len;
+		headroom += crypt->ops->extra_mpdu_prefix_len;
+	}
 
 	/* When we allocate the TXB we allocate enough space for the reserve
 	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
 	 * postfix, header, FCS, etc.) */
-	txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC);
+	txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
 	if (unlikely(!txb)) {
 		printk(KERN_WARNING "%s: Could not allocate TXB\n",
 		       ieee->dev->name);
 		goto failed;
 	}
 	txb->encrypted = 0;
-	txb->payload_size = total_len;
+	txb->payload_size = fraglen;
 
 	skb_frag = txb->fragments[0];
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 5e9a906..44215ce 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211s
 	
 	dprintk(KERN_INFO PFX "sent association request!\n");
 
-	/* Change the state to associating */
 	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.associating = 1;
 	mac->associated = 0; /* just to make sure */
 
 	/* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
 ieee80211softmac_assoc_timeout(void *d)
 {
 	struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+	struct ieee80211softmac_network *n;
 	unsigned long flags;
 
 	spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
 	mac->associnfo.associating = 0;
 	mac->associnfo.bssvalid = 0;
 	mac->associated = 0;
+
+	n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
 	spin_unlock_irqrestore(&mac->lock, flags);
 
 	dprintk(KERN_INFO PFX "assoc request timed out!\n");
-	/* FIXME: we need to know the network here. that requires a bit of restructuring */
-	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
+	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
 }
 
 void
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
 	if (mac->associated)
 		ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
 
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->associnfo.associating = 1;
+	spin_unlock_irqrestore(&mac->lock, flags);
+
 	/* try to find the requested network in our list, if we found one already */
 	if (bssvalid || mac->associnfo.bssfixed)
 		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);	
@@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
 	memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
 	
 	/* we found a network! authenticate (if necessary) and associate to it. */
-	if (!found->authenticated) {
+	if (found->authenticating) {
+		dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+		if(!mac->associnfo.assoc_wait) {
+			mac->associnfo.assoc_wait = 1;
+			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+		}
+		return;
+	}
+	if (!found->authenticated && !found->authenticating) {
 		/* This relies on the fact that _auth_req only queues the work,
 		 * otherwise adding the notification would be racy. */
 		if (!ieee80211softmac_auth_req(mac, found)) {
-			dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
-			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+			if(!mac->associnfo.assoc_wait) {
+				dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
+				mac->associnfo.assoc_wait = 1;
+				ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+			}
 		} else {
 			printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
+			mac->associnfo.assoc_wait = 0;
 			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
 		}
 		return;
 	}
 	/* finally! now we can start associating */
+	mac->associnfo.assoc_wait = 0;
 	ieee80211softmac_assoc(mac, found);
 }
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 90b8484..ebc33ca 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee802
 	struct ieee80211softmac_auth_queue_item *auth;
 	unsigned long flags;
 	
-	if (net->authenticating)
+	if (net->authenticating || net->authenticated)
 		return 0;
+	net->authenticating = 1;
 
 	/* Add the network if it's not already added */
 	ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
 			return;
 		}
 		net->authenticated = 0;
-		net->authenticating = 1;
 		/* add a timeout call so we eventually give up waiting for an auth reply */
 		schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
 		auth->retry--;
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 0954161..8cc8b20 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80
 		return 0;
 	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
 
+	/* Fill in the capabilities */
+	(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
+
 	/* Fill in Listen Interval (?) */
 	(*pkt)->listen_interval = cpu_to_le16(10);
 	
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 0e65ff4..75320b6 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net
 			      char *extra)
 {
 	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+	struct ieee80211softmac_network *n;
+	struct ieee80211softmac_auth_queue_item *authptr;
 	int length = 0;
 	unsigned long flags;
-	
+
+	/* Check if we're already associating to this or another network
+	 * If it's another network, cancel and start over with our new network
+	 * If it's our network, ignore the change, we're already doing it!
+	 */
+	if((sm->associnfo.associating || sm->associated) &&
+	   (data->essid.flags && data->essid.length && extra)) {
+		/* Get the associating network */
+		n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+		if(n && n->essid.len == (data->essid.length - 1) &&
+		   !memcmp(n->essid.data, extra, n->essid.len)) {
+			dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+				MAC_ARG(sm->associnfo.bssid));
+			return 0;
+		} else {
+			dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+			spin_lock_irqsave(&sm->lock,flags);
+			/* Cancel assoc work */
+			cancel_delayed_work(&sm->associnfo.work);
+			/* We don't have to do this, but it's a little cleaner */
+			list_for_each_entry(authptr, &sm->auth_queue, list)
+				cancel_delayed_work(&authptr->work);
+			sm->associnfo.bssvalid = 0;
+			sm->associnfo.bssfixed = 0;
+			spin_unlock_irqrestore(&sm->lock,flags);
+			flush_scheduled_work();
+		}
+	}
+
+
 	spin_lock_irqsave(&sm->lock, flags);
-	
+
 	sm->associnfo.static_essid = 0;
+	sm->associnfo.assoc_wait = 0;
 
 	if (data->essid.flags && data->essid.length && extra /*required?*/) {
 		length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-15 20:03 John W. Linville
@ 2006-06-20  8:46 ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-06-20  8:46 UTC (permalink / raw)
  To: John W. Linville; +Cc: netdev

John W. Linville wrote:
> The following changes since commit 76df73ff90e99681a99e457aec4cfe0a240b7982:
>   John W. Linville:
>         Merge branch 'from-linus' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Jiri Slaby:
>       pci: bcm43xx avoid pci_find_device
> 
> Larry Finger:
>       wireless: Changes to ieee80211.h for user space regulatory daemon
>       wireless: correct dump of WPA IE
> 
> Michael Buesch:
>       bcm43xx: redesign locking
>       bcm43xx: preemptible periodic work
> 
> Zhu Yi:
>       ipw2200 locking fix

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
@ 2006-06-15 20:03 John W. Linville
  2006-06-20  8:46 ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-06-15 20:03 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 76df73ff90e99681a99e457aec4cfe0a240b7982:
  John W. Linville:
        Merge branch 'from-linus' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Jiri Slaby:
      pci: bcm43xx avoid pci_find_device

Larry Finger:
      wireless: Changes to ieee80211.h for user space regulatory daemon
      wireless: correct dump of WPA IE

Michael Buesch:
      bcm43xx: redesign locking
      bcm43xx: preemptible periodic work

Zhu Yi:
      ipw2200 locking fix

 drivers/net/wireless/bcm43xx/bcm43xx.h         |  100 +++++++----
 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |   33 ++--
 drivers/net/wireless/bcm43xx/bcm43xx_leds.c    |    4 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |  221 ++++++++++++++++--------
 drivers/net/wireless/bcm43xx/bcm43xx_phy.c     |    9 +
 drivers/net/wireless/bcm43xx/bcm43xx_pio.c     |   44 ++++-
 drivers/net/wireless/bcm43xx/bcm43xx_pio.h     |   13 +
 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c   |   38 ++--
 drivers/net/wireless/bcm43xx/bcm43xx_wx.c      |  107 ++++++------
 drivers/net/wireless/ipw2200.c                 |   41 +++-
 drivers/net/wireless/ipw2200.h                 |    1 
 include/net/ieee80211.h                        |    5 -
 net/ieee80211/softmac/ieee80211softmac_wx.c    |    2 
 13 files changed, 402 insertions(+), 216 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index e66fdb1..d8f917c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -636,6 +636,17 @@ struct bcm43xx_key {
 	u8 algorithm;
 };
 
+/* Driver initialization status. */
+enum {
+	BCM43xx_STAT_UNINIT,		/* Uninitialized. */
+	BCM43xx_STAT_INITIALIZING,	/* init_board() in progress. */
+	BCM43xx_STAT_INITIALIZED,	/* Fully operational. */
+	BCM43xx_STAT_SHUTTINGDOWN,	/* free_board() in progress. */
+	BCM43xx_STAT_RESTARTING,	/* controller_restart() called. */
+};
+#define bcm43xx_status(bcm)		atomic_read(&(bcm)->init_status)
+#define bcm43xx_set_status(bcm, stat)	atomic_set(&(bcm)->init_status, (stat))
+
 struct bcm43xx_private {
 	struct ieee80211_device *ieee;
 	struct ieee80211softmac_device *softmac;
@@ -646,18 +657,17 @@ struct bcm43xx_private {
 
 	void __iomem *mmio_addr;
 
-	/* Do not use the lock directly. Use the bcm43xx_lock* helper
-	 * functions, to be MMIO-safe. */
-	spinlock_t _lock;
+	/* Locking, see "theory of locking" text below. */
+	spinlock_t irq_lock;
+	struct mutex mutex;
 
-	/* Driver status flags. */
-	u32 initialized:1,		/* init_board() succeed */
-	    was_initialized:1,		/* for PCI suspend/resume. */
-	    shutting_down:1,		/* free_board() in progress */
+	/* Driver initialization status BCM43xx_STAT_*** */
+	atomic_t init_status;
+
+	u16 was_initialized:1,		/* for PCI suspend/resume. */
 	    __using_pio:1,		/* Internal, use bcm43xx_using_pio(). */
 	    bad_frames_preempt:1,	/* Use "Bad Frames Preemption" (default off) */
 	    reg124_set_0x4:1,		/* Some variable to keep track of IRQ stuff. */
-	    powersaving:1,		/* TRUE if we are in PowerSaving mode. FALSE otherwise. */
 	    short_preamble:1,		/* TRUE, if short preamble is enabled. */
 	    firmware_norelease:1;	/* Do not release the firmware. Used on suspend. */
 
@@ -721,7 +731,7 @@ #endif
 	struct tasklet_struct isr_tasklet;
 
 	/* Periodic tasks */
-	struct timer_list periodic_tasks;
+	struct work_struct periodic_work;
 	unsigned int periodic_state;
 
 	struct work_struct restart_work;
@@ -746,21 +756,55 @@ #ifdef CONFIG_BCM43XX_DEBUG
 #endif
 };
 
-/* bcm43xx_(un)lock() protect struct bcm43xx_private.
- * Note that _NO_ MMIO writes are allowed. If you want to
- * write to the device through MMIO in the critical section, use
- * the *_mmio lock functions.
- * MMIO read-access is allowed, though.
- */
-#define bcm43xx_lock(bcm, flags)	spin_lock_irqsave(&(bcm)->_lock, flags)
-#define bcm43xx_unlock(bcm, flags)	spin_unlock_irqrestore(&(bcm)->_lock, flags)
-/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO.
- * MMIO write-access to the device is allowed.
- * All MMIO writes are flushed on unlock, so it is guaranteed to not
- * interfere with other threads writing MMIO registers.
+
+/*    *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex:    General sleeping mutex. Protects struct bcm43xx_private
+ *                   and the device registers.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * We have three types of helper function pairs to utilize these locks.
+ *     (Always use the helper functions.)
+ * 1) bcm43xx_{un}lock_noirq():
+ *     Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
+ *     so it is almost always unsafe, if device IRQs are enabled.
+ *     So only use this, if device IRQs are masked.
+ *     Locking may sleep.
+ *     You can sleep within the critical section.
+ * 2) bcm43xx_{un}lock_irqonly():
+ *     Takes bcm->irq_lock. Does _not_ protect against
+ *     bcm43xx_lock_noirq() critical sections.
+ *     Does only protect against the IRQ handler path and other
+ *     irqonly() critical sections.
+ *     Locking does not sleep.
+ *     You must not sleep within the critical section.
+ * 3) bcm43xx_{un}lock_irqsafe():
+ *     This is the cummulative lock and takes both, mutex and irq_lock.
+ *     Protects against noirq() and irqonly() critical sections (and
+ *     the IRQ handler path).
+ *     Locking may sleep.
+ *     You must not sleep within the critical section.
  */
-#define bcm43xx_lock_mmio(bcm, flags)	bcm43xx_lock(bcm, flags)
-#define bcm43xx_unlock_mmio(bcm, flags)	do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0)
+
+/* Lock type 1 */
+#define bcm43xx_lock_noirq(bcm)		mutex_lock(&(bcm)->mutex)
+#define bcm43xx_unlock_noirq(bcm)	mutex_unlock(&(bcm)->mutex)
+/* Lock type 2 */
+#define bcm43xx_lock_irqonly(bcm, flags)	\
+	spin_lock_irqsave(&(bcm)->irq_lock, flags)
+#define bcm43xx_unlock_irqonly(bcm, flags)	\
+	spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
+/* Lock type 3 */
+#define bcm43xx_lock_irqsafe(bcm, flags) do {	\
+	bcm43xx_lock_noirq(bcm);		\
+	bcm43xx_lock_irqonly(bcm, flags);	\
+		} while (0)
+#define bcm43xx_unlock_irqsafe(bcm, flags) do {	\
+	bcm43xx_unlock_irqonly(bcm, flags);	\
+	bcm43xx_unlock_noirq(bcm);		\
+		} while (0)
+
 
 static inline
 struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
@@ -843,16 +887,6 @@ struct bcm43xx_radioinfo * bcm43xx_curre
 	return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
 }
 
-/* Are we running in init_board() context? */
-static inline
-int bcm43xx_is_initializing(struct bcm43xx_private *bcm)
-{
-	if (bcm->initialized)
-		return 0;
-	if (bcm->shutting_down)
-		return 0;
-	return 1;
-}
 
 static inline
 struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 7497fb1..ce2e40b 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -77,8 +77,8 @@ static ssize_t devinfo_read_file(struct 
 
 	down(&big_buffer_sem);
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -121,7 +121,7 @@ #undef fappend_core
 	fappend("\n");
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -159,8 +159,8 @@ static ssize_t spromdump_read_file(struc
 	unsigned long flags;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -169,7 +169,7 @@ static ssize_t spromdump_read_file(struc
 	fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -188,8 +188,8 @@ static ssize_t tsf_read_file(struct file
 	u64 tsf;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		fappend("Board not initialized.\n");
 		goto out;
 	}
@@ -199,7 +199,7 @@ static ssize_t tsf_read_file(struct file
 		(unsigned int)(tsf & 0xFFFFFFFFULL));
 
 out:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	up(&big_buffer_sem);
 	return res;
@@ -221,8 +221,8 @@ static ssize_t tsf_write_file(struct fil
 	        res = -EFAULT;
 		goto out_up;
 	}
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
 		printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
 		res = -EFAULT;
 		goto out_unlock;
@@ -233,10 +233,11 @@ static ssize_t tsf_write_file(struct fil
 		goto out_unlock;
 	}
 	bcm43xx_tsf_write(bcm, tsf);
+	mmiowb();
 	res = buf_size;
 	
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_up:
 	up(&big_buffer_sem);
 	return res;
@@ -257,7 +258,7 @@ static ssize_t txstat_read_file(struct f
 	int i, cnt, j = 0;
 
 	down(&big_buffer_sem);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
 		BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -293,14 +294,14 @@ static ssize_t txstat_read_file(struct f
 			i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
 	}
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (*ppos == pos) {
 		/* Done. Drop the copied data. */
 		e->xmitstatus_printing = 0;
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	up(&big_buffer_sem);
 	return res;
 }
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 4b2c02c..ec80692 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned l
 	struct bcm43xx_private *bcm = led->bcm;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	if (led->blink_interval) {
 		bcm43xx_led_changestate(led);
 		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 736dde9..085d785 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -498,20 +498,31 @@ static inline u32 bcm43xx_interrupt_disa
 	return old_mask;
 }
 
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
+{
+	synchronize_irq(bcm->irq);
+	tasklet_disable(&bcm->isr_tasklet);
+}
+
 /* Make sure we don't receive more data from the device. */
 static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
 {
-	u32 old;
 	unsigned long flags;
+	u32 old;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {
-		bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
+	if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
+		bcm43xx_unlock_irqonly(bcm, flags);
 		return -EBUSY;
 	}
 	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-	tasklet_disable(&bcm->isr_tasklet);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
+	bcm43xx_synchronize_irq(bcm);
+
 	if (oldstate)
 		*oldstate = old;
 
@@ -1389,7 +1400,7 @@ #ifndef CONFIG_BCM947XX
 			bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
 #endif
 	}
-	if (bcm->shutting_down) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
 		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
 				& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
@@ -1709,7 +1720,7 @@ #else
 # define bcmirq_handled(irq)	do { /* nothing */ } while (0)
 #endif /* CONFIG_BCM43XX_DEBUG*/
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	reason = bcm->irq_reason;
 	dma_reason[0] = bcm->dma_reason[0];
 	dma_reason[1] = bcm->dma_reason[1];
@@ -1734,7 +1745,8 @@ #endif /* CONFIG_BCM43XX_DEBUG*/
 		        dma_reason[0], dma_reason[1],
 			dma_reason[2], dma_reason[3]);
 		bcm43xx_controller_restart(bcm, "DMA error");
-		bcm43xx_unlock_mmio(bcm, flags);
+		mmiowb();
+		bcm43xx_unlock_irqonly(bcm, flags);
 		return;
 	}
 	if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
@@ -1821,7 +1833,8 @@ #undef bcmirq_handled
 	if (!modparam_noleds)
 		bcm43xx_leds_update(bcm, activity);
 	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1870,7 +1883,7 @@ static irqreturn_t bcm43xx_interrupt_han
 	if (!bcm)
 		return IRQ_NONE;
 
-	spin_lock(&bcm->_lock);
+	spin_lock(&bcm->irq_lock);
 
 	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
 	if (reason == 0xffffffff) {
@@ -1899,7 +1912,7 @@ static irqreturn_t bcm43xx_interrupt_han
 	 * completely, but some careful work is needed to fix this. I think it
 	 * is best to stay with this cheap workaround for now... .
 	 */
-	if (likely(bcm->initialized)) {
+	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
 		/* disable all IRQs. They are enabled again in the bottom half. */
 		bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 		/* save the reason code and call our bottom half. */
@@ -1909,7 +1922,7 @@ static irqreturn_t bcm43xx_interrupt_han
 
 out:
 	mmiowb();
-	spin_unlock(&bcm->_lock);
+	spin_unlock(&bcm->irq_lock);
 
 	return ret;
 }
@@ -2133,6 +2146,13 @@ out:
 	return err;
 }
 
+#ifdef CONFIG_BCM947XX
+static struct pci_device_id bcm43xx_47xx_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+	{ 0 }
+};
+#endif
+
 static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
 {
 	int res;
@@ -2142,11 +2162,15 @@ static int bcm43xx_initialize_irq(struct
 	bcm->irq = bcm->pci_dev->irq;
 #ifdef CONFIG_BCM947XX
 	if (bcm->pci_dev->bus->number == 0) {
-		struct pci_dev *d = NULL;
-		/* FIXME: we will probably need more device IDs here... */
-		d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);
-		if (d != NULL) {
-			bcm->irq = d->irq;
+		struct pci_dev *d;
+		struct pci_device_id *id;
+		for (id = bcm43xx_47xx_ids; id->vendor; id++) {
+			d = pci_get_device(id->vendor, id->device, NULL);
+			if (d != NULL) {
+				bcm->irq = d->irq;
+				pci_dev_put(d);
+				break;
+			}
 		}
 	}
 #endif
@@ -3106,15 +3130,10 @@ static void bcm43xx_periodic_every15sec(
 	//TODO for APHY (temperature?)
 }
 
-static void bcm43xx_periodic_task_handler(unsigned long d)
+static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-	struct bcm43xx_private *bcm = (struct bcm43xx_private *)d;
-	unsigned long flags;
 	unsigned int state;
 
-	bcm43xx_lock_mmio(bcm, flags);
-
-	assert(bcm->initialized);
 	state = bcm->periodic_state;
 	if (state % 8 == 0)
 		bcm43xx_periodic_every120sec(bcm);
@@ -3122,29 +3141,93 @@ static void bcm43xx_periodic_task_handle
 		bcm43xx_periodic_every60sec(bcm);
 	if (state % 2 == 0)
 		bcm43xx_periodic_every30sec(bcm);
-	bcm43xx_periodic_every15sec(bcm);
+	if (state % 1 == 0)
+		bcm43xx_periodic_every15sec(bcm);
 	bcm->periodic_state = state + 1;
 
-	mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15));
+	schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+	int badness = 0;
+
+	if (state % 8 == 0) /* every 120 sec */
+		badness += 10;
+	if (state % 4 == 0) /* every 60 sec */
+		badness += 5;
+	if (state % 2 == 0) /* every 30 sec */
+		badness += 1;
+	if (state % 1 == 0) /* every 15 sec */
+		badness += 1;
 
-	bcm43xx_unlock_mmio(bcm, flags);
+#define BADNESS_LIMIT	4
+	return badness;
+}
+
+static void bcm43xx_periodic_work_handler(void *d)
+{
+	struct bcm43xx_private *bcm = d;
+	unsigned long flags;
+	u32 savedirqs = 0;
+	int badness;
+
+	badness = estimate_periodic_work_badness(bcm->periodic_state);
+	if (badness > BADNESS_LIMIT) {
+		/* Periodic work will take a long time, so we want it to
+		 * be preemtible.
+		 */
+		bcm43xx_lock_irqonly(bcm, flags);
+		netif_stop_queue(bcm->net_dev);
+		if (bcm43xx_using_pio(bcm))
+			bcm43xx_pio_freeze_txqueues(bcm);
+		savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+		bcm43xx_unlock_irqonly(bcm, flags);
+		bcm43xx_lock_noirq(bcm);
+		bcm43xx_synchronize_irq(bcm);
+	} else {
+		/* Periodic work should take short time, so we want low
+		 * locking overhead.
+		 */
+		bcm43xx_lock_irqsafe(bcm, flags);
+	}
+
+	do_periodic_work(bcm);
+
+	if (badness > BADNESS_LIMIT) {
+		bcm43xx_lock_irqonly(bcm, flags);
+		if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
+			tasklet_enable(&bcm->isr_tasklet);
+			bcm43xx_interrupt_enable(bcm, savedirqs);
+			if (bcm43xx_using_pio(bcm))
+				bcm43xx_pio_thaw_txqueues(bcm);
+		}
+		netif_wake_queue(bcm->net_dev);
+		mmiowb();
+		bcm43xx_unlock_irqonly(bcm, flags);
+		bcm43xx_unlock_noirq(bcm);
+	} else {
+		mmiowb();
+		bcm43xx_unlock_irqsafe(bcm, flags);
+	}
 }
 
 static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
 {
-	del_timer_sync(&bcm->periodic_tasks);
+	cancel_rearming_delayed_work(&bcm->periodic_work);
 }
 
 static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
-	struct timer_list *timer = &(bcm->periodic_tasks);
+	struct work_struct *work = &(bcm->periodic_work);
 
-	assert(bcm->initialized);
-	setup_timer(timer,
-		    bcm43xx_periodic_task_handler,
-		    (unsigned long)bcm);
-	timer->expires = jiffies;
-	add_timer(timer);
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+	INIT_WORK(work, bcm43xx_periodic_work_handler, bcm);
+	schedule_work(work);
 }
 
 static void bcm43xx_security_init(struct bcm43xx_private *bcm)
@@ -3158,16 +3241,12 @@ static void bcm43xx_security_init(struct
 static void bcm43xx_free_board(struct bcm43xx_private *bcm)
 {
 	int i, err;
-	unsigned long flags;
 
+	bcm43xx_lock_noirq(bcm);
 	bcm43xx_sysfs_unregister(bcm);
-
 	bcm43xx_periodic_tasks_delete(bcm);
 
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 0;
-	bcm->shutting_down = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
 
 	for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
 		if (!bcm->core_80211[i].available)
@@ -3182,23 +3261,19 @@ static void bcm43xx_free_board(struct bc
 
 	bcm43xx_pctl_set_crystal(bcm, 0);
 
-	bcm43xx_lock(bcm, flags);
-	bcm->shutting_down = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+	bcm43xx_unlock_noirq(bcm);
 }
 
 static int bcm43xx_init_board(struct bcm43xx_private *bcm)
 {
 	int i, err;
 	int connect_phy;
-	unsigned long flags;
 
 	might_sleep();
 
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 0;
-	bcm->shutting_down = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
 
 	err = bcm43xx_pctl_set_crystal(bcm, 1);
 	if (err)
@@ -3265,9 +3340,7 @@ static int bcm43xx_init_board(struct bcm
 	}
 
 	/* Initialization of the board is done. Flag it as such. */
-	bcm43xx_lock(bcm, flags);
-	bcm->initialized = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
 
 	bcm43xx_periodic_tasks_setup(bcm);
 	bcm43xx_sysfs_register(bcm);
@@ -3278,6 +3351,8 @@ static int bcm43xx_init_board(struct bcm
 
 	assert(err == 0);
 out:
+	bcm43xx_unlock_noirq(bcm);
+
 	return err;
 
 err_80211_unwind:
@@ -3534,8 +3609,8 @@ static void bcm43xx_ieee80211_set_chan(s
 	struct bcm43xx_radioinfo *radio;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		bcm43xx_mac_suspend(bcm);
 		bcm43xx_radio_selectchannel(bcm, channel, 0);
 		bcm43xx_mac_enable(bcm);
@@ -3543,7 +3618,7 @@ static void bcm43xx_ieee80211_set_chan(s
 		radio = bcm43xx_current_radio(bcm);
 		radio->initial_channel = channel;
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* set_security() callback in struct ieee80211_device */
@@ -3557,7 +3632,7 @@ static void bcm43xx_ieee80211_set_securi
 	
 	dprintk(KERN_INFO PFX "set security called");
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
 		if (sec->flags & (1<<keyidx)) {
@@ -3587,7 +3662,8 @@ static void bcm43xx_ieee80211_set_securi
 		dprintk(", .encrypt = %d", sec->encrypt);
 	}
 	dprintk("\n");
-	if (bcm->initialized && !bcm->ieee->host_encrypt) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
+	    !bcm->ieee->host_encrypt) {
 		if (secinfo->enabled) {
 			/* upload WEP keys to hardware */
 			char null_address[6] = { 0 };
@@ -3621,7 +3697,7 @@ static void bcm43xx_ieee80211_set_securi
 		} else
 				bcm43xx_clear_keys(bcm);
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 }
 
 /* hard_start_xmit() callback in struct ieee80211_device */
@@ -3633,10 +3709,10 @@ static int bcm43xx_ieee80211_hard_start_
 	int err = -ENODEV;
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (likely(bcm->initialized))
+	bcm43xx_lock_irqonly(bcm, flags);
+	if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
 		err = bcm43xx_tx(bcm, txb);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 
 	return err;
 }
@@ -3651,9 +3727,9 @@ static void bcm43xx_net_tx_timeout(struc
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 	bcm43xx_controller_restart(bcm, "TX timeout");
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3678,9 +3754,11 @@ static int bcm43xx_net_open(struct net_d
 static int bcm43xx_net_stop(struct net_device *net_dev)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+	int err;
 
 	ieee80211softmac_stop(net_dev);
-	bcm43xx_disable_interrupts_sync(bcm, NULL);
+	err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+	assert(!err);
 	bcm43xx_free_board(bcm);
 
 	return 0;
@@ -3692,6 +3770,7 @@ static int bcm43xx_init_private(struct b
 {
 	int err;
 
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
 	bcm->ieee = netdev_priv(net_dev);
 	bcm->softmac = ieee80211_priv(net_dev);
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
@@ -3700,7 +3779,8 @@ static int bcm43xx_init_private(struct b
 	bcm->pci_dev = pci_dev;
 	bcm->net_dev = net_dev;
 	bcm->bad_frames_preempt = modparam_bad_frames_preempt;
-	spin_lock_init(&bcm->_lock);
+	spin_lock_init(&bcm->irq_lock);
+	mutex_init(&bcm->mutex);
 	tasklet_init(&bcm->isr_tasklet,
 		     (void (*)(unsigned long))bcm43xx_interrupt_tasklet,
 		     (unsigned long)bcm);
@@ -3831,7 +3911,7 @@ static void bcm43xx_chip_reset(void *_bc
 	struct net_device *net_dev = bcm->net_dev;
 	struct pci_dev *pci_dev = bcm->pci_dev;
 	int err;
-	int was_initialized = bcm->initialized;
+	int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
 	netif_stop_queue(bcm->net_dev);
 	tasklet_disable(&bcm->isr_tasklet);
@@ -3866,6 +3946,7 @@ failure:
 */
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
 {
+	bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
 	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
 	bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
 	printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
@@ -3884,11 +3965,11 @@ static int bcm43xx_suspend(struct pci_de
 
 	dprintk(KERN_INFO PFX "Suspending...\n");
 
-	bcm43xx_lock(bcm, flags);
-	bcm->was_initialized = bcm->initialized;
-	if (bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+	if (bcm->was_initialized)
 		try_to_shutdown = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	netif_device_detach(net_dev);
 	if (try_to_shutdown) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b0abac5..f8200de 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1410,7 +1410,10 @@ static inline
 u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+	u16 ret;
+	unsigned long flags;
 
+	local_irq_save(flags);
 	if (phy->connected) {
 		bcm43xx_phy_write(bcm, 0x15, 0xE300);
 		control <<= 8;
@@ -1430,8 +1433,10 @@ u16 bcm43xx_phy_lo_g_deviation_subval(st
 		bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0);
 		udelay(8);
 	}
+	ret = bcm43xx_phy_read(bcm, 0x002D);
+	local_irq_restore(flags);
 
-	return bcm43xx_phy_read(bcm, 0x002D);
+	return ret;
 }
 
 static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control)
@@ -1648,7 +1653,7 @@ void bcm43xx_phy_set_baseband_attenuatio
 void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
 {
 	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
-	const int is_initializing = bcm43xx_is_initializing(bcm);
+	const int is_initializing = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZING);
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
 	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
 	u16 h, i, oldi = 0, j;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 0aa1bd2..574085c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,8 +262,10 @@ static void tx_tasklet(unsigned long d)
 	int err;
 	u16 txctl;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqonly(bcm, flags);
 
+	if (queue->tx_frozen)
+		goto out_unlock;
 	txctl = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL);
 	if (txctl & BCM43xx_PIO_TXCTL_SUSPEND)
 		goto out_unlock;
@@ -298,7 +300,7 @@ static void tx_tasklet(unsigned long d)
 		continue;
 	}
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqonly(bcm, flags);
 }
 
 static void setup_txqueues(struct bcm43xx_pioqueue *queue)
@@ -374,7 +376,6 @@ static void cancel_transfers(struct bcm4
 	struct bcm43xx_pio_txpacket *packet, *tmp_packet;
 
 	netif_tx_disable(queue->bcm->net_dev);
-	assert(queue->bcm->shutting_down);
 	tasklet_disable(&queue->txtask);
 
 	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
@@ -634,5 +635,40 @@ void bcm43xx_pio_tx_resume(struct bcm43x
 			  bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL)
 			  & ~BCM43xx_PIO_TXCTL_SUSPEND);
 	bcm43xx_power_saving_ctl_bits(queue->bcm, -1, -1);
-	tasklet_schedule(&queue->txtask);
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	assert(bcm43xx_using_pio(bcm));
+	pio = bcm43xx_current_pio(bcm);
+	pio->queue0->tx_frozen = 1;
+	pio->queue1->tx_frozen = 1;
+	pio->queue2->tx_frozen = 1;
+	pio->queue3->tx_frozen = 1;
 }
+
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+	struct bcm43xx_pio *pio;
+
+	assert(bcm43xx_using_pio(bcm));
+	pio = bcm43xx_current_pio(bcm);
+	pio->queue0->tx_frozen = 0;
+	pio->queue1->tx_frozen = 0;
+	pio->queue2->tx_frozen = 0;
+	pio->queue3->tx_frozen = 0;
+	if (!list_empty(&pio->queue0->txqueue))
+		tasklet_schedule(&pio->queue0->txtask);
+	if (!list_empty(&pio->queue1->txqueue))
+		tasklet_schedule(&pio->queue1->txtask);
+	if (!list_empty(&pio->queue2->txqueue))
+		tasklet_schedule(&pio->queue2->txtask);
+	if (!list_empty(&pio->queue3->txqueue))
+		tasklet_schedule(&pio->queue3->txtask);
+}
+
+
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
index dfc7820..bc78a3c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h
@@ -54,6 +54,7 @@ struct bcm43xx_pioqueue {
 	u16 mmio_base;
 
 	u8 tx_suspended:1,
+	   tx_frozen:1,
 	   need_workarounds:1; /* Workarounds needed for core.rev < 3 */
 
 	/* Adjusted size of the device internal TX buffer. */
@@ -108,8 +109,12 @@ void bcm43xx_pio_handle_xmitstatus(struc
 				   struct bcm43xx_xmitstatus *status);
 void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue);
 
+/* Suspend a TX queue on hardware level. */
 void bcm43xx_pio_tx_suspend(struct bcm43xx_pioqueue *queue);
 void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm);
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm);
 
 #else /* CONFIG_BCM43XX_PIO */
 
@@ -145,6 +150,14 @@ static inline
 void bcm43xx_pio_tx_resume(struct bcm43xx_pioqueue *queue)
 {
 }
+static inline
+void bcm43xx_pio_freeze_txqueues(struct bcm43xx_private *bcm)
+{
+}
+static inline
+void bcm43xx_pio_thaw_txqueues(struct bcm43xx_private *bcm)
+{
+}
 
 #endif /* CONFIG_BCM43XX_PIO */
 #endif /* BCM43xx_PIO_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index b438f48..6a23bdc 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,12 @@ static ssize_t bcm43xx_attr_sprom_show(s
 			GFP_KERNEL);
 	if (!sprom)
 		return -ENOMEM;
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = bcm43xx_sprom_read(bcm, sprom);
 	if (!err)
 		err = sprom2hex(sprom, buf, PAGE_SIZE);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	kfree(sprom);
 
 	return err;
@@ -150,10 +150,10 @@ static ssize_t bcm43xx_attr_sprom_store(
 	err = hex2sprom(sprom, buf, count);
 	if (err)
 		goto out_kfree;
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
 	kfree(sprom);
 
@@ -170,15 +170,13 @@ static ssize_t bcm43xx_attr_interfmode_s
 					    char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	unsigned long flags;
 	int err;
 	ssize_t count = 0;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_noirq(bcm);
 
 	switch (bcm43xx_current_radio(bcm)->interfmode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -195,7 +193,7 @@ static ssize_t bcm43xx_attr_interfmode_s
 	}
 	err = 0;
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return err ? err : count;
 
@@ -231,16 +229,15 @@ static ssize_t bcm43xx_attr_interfmode_s
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 	if (err) {
 		printk(KERN_ERR PFX "Interference Mitigation not "
 				    "supported by device\n");
 	}
-
-	bcm43xx_unlock_mmio(bcm, flags);
+	mmiowb();
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err ? err : count;
 }
@@ -254,15 +251,13 @@ static ssize_t bcm43xx_attr_preamble_sho
 					  char *buf)
 {
 	struct bcm43xx_private *bcm = dev_to_bcm(dev);
-	unsigned long flags;
 	int err;
 	ssize_t count;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_noirq(bcm);
 
 	if (bcm->short_preamble)
 		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
@@ -270,7 +265,7 @@ static ssize_t bcm43xx_attr_preamble_sho
 		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
 
 	err = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return err ? err : count;
 }
@@ -290,13 +285,12 @@ static ssize_t bcm43xx_attr_preamble_sto
 	value = get_boolean(buf, count);
 	if (value < 0)
 		return value;
-	bcm43xx_lock(bcm, flags);
-	assert(bcm->initialized);
+	bcm43xx_lock_irqsafe(bcm, flags);
 
 	bcm->short_preamble = !!value;
 
 	err = 0;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err ? err : count;
 }
@@ -310,7 +304,7 @@ int bcm43xx_sysfs_register(struct bcm43x
 	struct device *dev = &bcm->pci_dev->dev;
 	int err;
 
-	assert(bcm->initialized);
+	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
 
 	err = device_create_file(dev, &dev_attr_sprom);
 	if (err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index b450639..c35cb3a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -55,13 +55,13 @@ static int bcm43xx_wx_get_name(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	int i;
+	unsigned long flags;
 	struct bcm43xx_phyinfo *phy;
 	char suffix[7] = { 0 };
 	int have_a = 0, have_b = 0, have_g = 0;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	for (i = 0; i < bcm->nr_80211_available; i++) {
 		phy = &(bcm->core_80211_ext[i].phy);
 		switch (phy->type) {
@@ -77,7 +77,7 @@ static int bcm43xx_wx_get_name(struct ne
 			assert(0);
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	i = 0;
 	if (have_a) {
@@ -111,7 +111,7 @@ static int bcm43xx_wx_set_channelfreq(st
 	int freq;
 	int err = -EINVAL;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
 		channel = data->freq.m;
 		freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -121,7 +121,7 @@ static int bcm43xx_wx_set_channelfreq(st
 	}
 	if (!bcm43xx_is_valid_channel(bcm, channel))
 		goto out_unlock;
-	if (bcm->initialized) {
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		//ieee80211softmac_disassoc(softmac, $REASON);
 		bcm43xx_mac_suspend(bcm);
 		err = bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -131,7 +131,7 @@ static int bcm43xx_wx_set_channelfreq(st
 		err = 0;
 	}
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -147,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(st
 	int err = -ENODEV;
 	u16 channel;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	radio = bcm43xx_current_radio(bcm);
 	channel = radio->channel;
 	if (channel == 0xFF) {
-		assert(!bcm->initialized);
 		channel = radio->initial_channel;
 		if (channel == 0xFF)
 			goto out_unlock;
@@ -163,7 +162,7 @@ static int bcm43xx_wx_get_channelfreq(st
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -181,13 +180,13 @@ static int bcm43xx_wx_set_mode(struct ne
 	if (mode == IW_MODE_AUTO)
 		mode = BCM43xx_INITIAL_IWMODE;
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		if (bcm->ieee->iw_mode != mode)
 			bcm43xx_set_iwmode(bcm, mode);
 	} else
 		bcm->ieee->iw_mode = mode;
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -200,9 +199,9 @@ static int bcm43xx_wx_get_mode(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->mode = bcm->ieee->iw_mode;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -255,7 +254,7 @@ static int bcm43xx_wx_get_rangeparams(st
 			  IW_ENC_CAPA_CIPHER_TKIP |
 			  IW_ENC_CAPA_CIPHER_CCMP;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	phy = bcm43xx_current_phy(bcm);
 
 	range->num_bitrates = 0;
@@ -302,7 +301,7 @@ static int bcm43xx_wx_get_rangeparams(st
 	}
 	range->num_frequency = j;
 
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -313,14 +312,13 @@ static int bcm43xx_wx_set_nick(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	size_t len;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
 	len =  min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
 	memcpy(bcm->nick, extra, len);
 	bcm->nick[len] = '\0';
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return 0;
 }
@@ -331,15 +329,14 @@ static int bcm43xx_wx_get_nick(struct ne
 			       char *extra)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
-	unsigned long flags;
 	size_t len;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_noirq(bcm);
 	len = strlen(bcm->nick) + 1;
 	memcpy(extra, bcm->nick, len);
 	data->data.length = (__u16)len;
 	data->data.flags = 1;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_noirq(bcm);
 
 	return 0;
 }
@@ -353,7 +350,7 @@ static int bcm43xx_wx_set_rts(struct net
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (data->rts.disabled) {
 		bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
 		err = 0;
@@ -364,7 +361,7 @@ static int bcm43xx_wx_set_rts(struct net
 			err = 0;
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -377,11 +374,11 @@ static int bcm43xx_wx_get_rts(struct net
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->rts.value = bcm->rts_threshold;
 	data->rts.fixed = 0;
 	data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -395,7 +392,7 @@ static int bcm43xx_wx_set_frag(struct ne
 	unsigned long flags;
 	int err = -EINVAL;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	if (data->frag.disabled) {
 		bcm->ieee->fts = MAX_FRAG_THRESHOLD;
 		err = 0;
@@ -406,7 +403,7 @@ static int bcm43xx_wx_set_frag(struct ne
 			err = 0;
 		}
 	}
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -419,11 +416,11 @@ static int bcm43xx_wx_get_frag(struct ne
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	unsigned long flags;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	data->frag.value = bcm->ieee->fts;
 	data->frag.fixed = 0;
 	data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -445,8 +442,8 @@ static int bcm43xx_wx_set_xmitpower(stru
 		return -EOPNOTSUPP;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (!bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
 	phy = bcm43xx_current_phy(bcm);
@@ -469,7 +466,7 @@ static int bcm43xx_wx_set_xmitpower(stru
 	err = 0;
 
 out_unlock:
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -484,8 +481,8 @@ static int bcm43xx_wx_get_xmitpower(stru
 	unsigned long flags;
 	int err = -ENODEV;
 
-	bcm43xx_lock(bcm, flags);
-	if (!bcm->initialized)
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
 		goto out_unlock;
 	radio = bcm43xx_current_radio(bcm);
 	/* desired dBm value is in Q5.2 */
@@ -496,7 +493,7 @@ static int bcm43xx_wx_get_xmitpower(stru
 
 	err = 0;
 out_unlock:
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -583,8 +580,8 @@ static int bcm43xx_wx_set_interfmode(str
 		return -EINVAL;
 	}
 
-	bcm43xx_lock_mmio(bcm, flags);
-	if (bcm->initialized) {
+	bcm43xx_lock_irqsafe(bcm, flags);
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
 		if (err) {
 			printk(KERN_ERR PFX "Interference Mitigation not "
@@ -598,7 +595,7 @@ static int bcm43xx_wx_set_interfmode(str
 		} else
 			bcm43xx_current_radio(bcm)->interfmode = mode;
 	}
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return err;
 }
@@ -612,9 +609,9 @@ static int bcm43xx_wx_get_interfmode(str
 	unsigned long flags;
 	int mode;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	mode = bcm43xx_current_radio(bcm)->interfmode;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	switch (mode) {
 	case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -644,9 +641,9 @@ static int bcm43xx_wx_set_shortpreamble(
 	int on;
 
 	on = *((int *)extra);
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	bcm->short_preamble = !!on;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -660,9 +657,9 @@ static int bcm43xx_wx_get_shortpreamble(
 	unsigned long flags;
 	int on;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	on = bcm->short_preamble;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	if (on)
 		strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -684,11 +681,11 @@ static int bcm43xx_wx_set_swencryption(s
 	
 	on = *((int *)extra);
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	bcm->ieee->host_encrypt = !!on;
 	bcm->ieee->host_decrypt = !!on;
 	bcm->ieee->host_build_iv = !on;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	return 0;
 }
@@ -702,9 +699,9 @@ static int bcm43xx_wx_get_swencryption(s
 	unsigned long flags;
 	int on;
 
-	bcm43xx_lock(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	on = bcm->ieee->host_encrypt;
-	bcm43xx_unlock(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 
 	if (on)
 		strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -767,11 +764,11 @@ static int bcm43xx_wx_sprom_read(struct 
 	if (!sprom)
 		goto out;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = -ENODEV;
-	if (bcm->initialized)
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_read(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 	if (!err)
 		data->data.length = sprom2hex(sprom, extra);
 	kfree(sprom);
@@ -812,11 +809,11 @@ static int bcm43xx_wx_sprom_write(struct
 	if (err)
 		goto out_kfree;
 
-	bcm43xx_lock_mmio(bcm, flags);
+	bcm43xx_lock_irqsafe(bcm, flags);
 	err = -ENODEV;
-	if (bcm->initialized)
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
 		err = bcm43xx_sprom_write(bcm, sprom);
-	bcm43xx_unlock_mmio(bcm, flags);
+	bcm43xx_unlock_irqsafe(bcm, flags);
 out_kfree:
 	kfree(sprom);
 out:
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 39f82f2..081a899 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -533,7 +533,7 @@ static inline void ipw_clear_bit(struct 
 	ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
 }
 
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
 {
 	if (priv->status & STATUS_INT_ENABLED)
 		return;
@@ -541,7 +541,7 @@ static inline void ipw_enable_interrupts
 	ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
 }
 
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
 {
 	if (!(priv->status & STATUS_INT_ENABLED))
 		return;
@@ -549,6 +549,24 @@ static inline void ipw_disable_interrupt
 	ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
 }
 
+static inline void ipw_enable_interrupts(struct ipw_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->irq_lock, flags);
+	__ipw_enable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static inline void ipw_disable_interrupts(struct ipw_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->irq_lock, flags);
+	__ipw_disable_interrupts(priv);
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
 #ifdef CONFIG_IPW2200_DEBUG
 static char *ipw_error_desc(u32 val)
 {
@@ -1856,7 +1874,7 @@ static void ipw_irq_tasklet(struct ipw_p
 	unsigned long flags;
 	int rc = 0;
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irqsave(&priv->irq_lock, flags);
 
 	inta = ipw_read32(priv, IPW_INTA_RW);
 	inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
@@ -1865,6 +1883,10 @@ static void ipw_irq_tasklet(struct ipw_p
 	/* Add any cached INTA values that need to be handled */
 	inta |= priv->isr_inta;
 
+	spin_unlock_irqrestore(&priv->irq_lock, flags);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
 	/* handle all the justifications for the interrupt */
 	if (inta & IPW_INTA_BIT_RX_TRANSFER) {
 		ipw_rx(priv);
@@ -1993,10 +2015,10 @@ #endif
 		IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
 	}
 
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	/* enable all interrupts */
 	ipw_enable_interrupts(priv);
-
-	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 #define IPW_CMD(x) case IPW_CMD_ ## x : return #x
@@ -10460,7 +10482,7 @@ static irqreturn_t ipw_isr(int irq, void
 	if (!priv)
 		return IRQ_NONE;
 
-	spin_lock(&priv->lock);
+	spin_lock(&priv->irq_lock);
 
 	if (!(priv->status & STATUS_INT_ENABLED)) {
 		/* Shared IRQ */
@@ -10482,7 +10504,7 @@ static irqreturn_t ipw_isr(int irq, void
 	}
 
 	/* tell the device to stop sending interrupts */
-	ipw_disable_interrupts(priv);
+	__ipw_disable_interrupts(priv);
 
 	/* ack current interrupts */
 	inta &= (IPW_INTA_MASK_ALL & inta_mask);
@@ -10493,11 +10515,11 @@ static irqreturn_t ipw_isr(int irq, void
 
 	tasklet_schedule(&priv->irq_tasklet);
 
-	spin_unlock(&priv->lock);
+	spin_unlock(&priv->irq_lock);
 
 	return IRQ_HANDLED;
       none:
-	spin_unlock(&priv->lock);
+	spin_unlock(&priv->irq_lock);
 	return IRQ_NONE;
 }
 
@@ -11477,6 +11499,7 @@ static int ipw_pci_probe(struct pci_dev 
 #ifdef CONFIG_IPW2200_DEBUG
 	ipw_debug_level = debug;
 #endif
+	spin_lock_init(&priv->irq_lock);
 	spin_lock_init(&priv->lock);
 	for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 6044c0b..ea12ad6 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1173,6 +1173,7 @@ struct ipw_priv {
 	struct ieee80211_device *ieee;
 
 	spinlock_t lock;
+	spinlock_t irq_lock;
 	struct mutex mutex;
 
 	/* basic pci-network driver stuff */
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index d514777..ecc4286 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -968,6 +968,7 @@ #define IEEE80211_52GHZ_CHANNELS (IEEE80
 
 enum {
 	IEEE80211_CH_PASSIVE_ONLY = (1 << 0),
+	IEEE80211_CH_80211H_RULES = (1 << 1),
 	IEEE80211_CH_B_ONLY = (1 << 2),
 	IEEE80211_CH_NO_IBSS = (1 << 3),
 	IEEE80211_CH_UNIFORM_SPREADING = (1 << 4),
@@ -976,10 +977,10 @@ enum {
 };
 
 struct ieee80211_channel {
-	u32 freq;
+	u32 freq;	/* in MHz */
 	u8 channel;
 	u8 flags;
-	u8 max_power;
+	u8 max_power;	/* in dBm */
 };
 
 struct ieee80211_geo {
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 22aa619..0e65ff4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -388,7 +388,7 @@ ieee80211softmac_wx_set_genie(struct net
 		memcpy(mac->wpa.IE, extra, wrqu->data.length);
 		dprintk(KERN_INFO PFX "generic IE set to ");
 		for (i=0;i<wrqu->data.length;i++)
-			dprintk("%.2x", mac->wpa.IE[i]);
+			dprintk("%.2x", (u8)mac->wpa.IE[i]);
 		dprintk("\n");
 		mac->wpa.IElen = wrqu->data.length;
 	} else {
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-06-05 21:55 ` Please pull 'upstream' " John W. Linville
@ 2006-06-08 19:48   ` Jeff Garzik
  0 siblings, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-06-08 19:48 UTC (permalink / raw)
  To: John W. Linville, netdev

John W. Linville wrote:
> This pull is intended for 2.6.18.
> 
> Thanks,
> 
> John
> 
> ---
> 
> The following changes since commit f6882a0688ea83db5fc2f3491ac9fcdce0834cc7:
>   John W. Linville:
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

applied


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-06-05 21:53 Please pull 'upstream-fixes' " John W. Linville
@ 2006-06-05 21:55 ` John W. Linville
  2006-06-08 19:48   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-06-05 21:55 UTC (permalink / raw)
  To: jeff; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 1920 bytes --]

This pull is intended for 2.6.18.

Thanks,

John

---

The following changes since commit f6882a0688ea83db5fc2f3491ac9fcdce0834cc7:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Daniel Drake:
      softmac: complete shared key authentication
      softmac: Fix handling of authentication failure

Jason Lunz:
      bcm43xx: quiet down log spam from set_security

Joseph Jezak:
      softmac: unified capabilities computation

Pavel Machek:
      usb wifi: zd1201 cleanups
      wireless: move zd1201 where it belongs

Toralf Förster:
      ieee80211softmac_io.c: fix warning "defined but not used"

 drivers/net/wireless/Kconfig                   |   17 ++
 drivers/net/wireless/Makefile                  |    2 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   13 +-
 drivers/net/wireless/zd1201.c                  |   67 ++++------
 drivers/net/wireless/zd1201.h                  |    0 
 drivers/usb/net/Kconfig                        |   17 --
 drivers/usb/net/Makefile                       |    1 
 include/net/ieee80211.h                        |    3 
 include/net/ieee80211softmac.h                 |    2 
 net/ieee80211/ieee80211_tx.c                   |   25 +++-
 net/ieee80211/softmac/Kconfig                  |    1 
 net/ieee80211/softmac/ieee80211softmac_assoc.c |   22 +++
 net/ieee80211/softmac/ieee80211softmac_auth.c  |   12 +-
 net/ieee80211/softmac/ieee80211softmac_event.c |    5 +
 net/ieee80211/softmac/ieee80211softmac_io.c    |  169 +++++++++++-------------
 15 files changed, 180 insertions(+), 176 deletions(-)
 rename drivers/{usb/net/zd1201.c => net/wireless/zd1201.c} (98%)
 rename drivers/{usb/net/zd1201.h => net/wireless/zd1201.h} (100%)

Patch included as attachment "upstream.patch.bz2"
-- 
John W. Linville
linville@tuxdriver.com

[-- Attachment #2: upstream.patch.bz2 --]
[-- Type: application/x-bzip2, Size: 23158 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-05-24  4:35   ` Jeff Garzik
@ 2006-05-24 12:42     ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-05-24 12:42 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

On Wed, May 24, 2006 at 12:35:20AM -0400, Jeff Garzik wrote:
> John W. Linville wrote:
> >The following changes since commit 
> >01d654d25d23fb73deb7904ce1c0b3a0f5fc2908:
> >  John W. Linville:
> >        Merge branch 'upstream-fixes' into upstream
> >
> >are found in the git repository at:
> >
> >  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git 
> >  upstream
> >
> >Marcin Juszkiewicz:
> >      hostap: new pcmcia IDs
> >
> > drivers/net/wireless/hostap/hostap_cs.c |    6 ++++++
> > 1 files changed, 6 insertions(+), 0 deletions(-)
> 
> WTF???  I pull, and see diffstat:
> 
> Merge db21e578e551421d76641d72cb3f8296ed3f9e61, made by recursive.
>  drivers/net/wireless/airo.c                     |    2
...

> This is vastly different from any 'pull upstream' email I've received 
> from you.  It is extremely uncool for me to pull, and receive something 
> other than what your email specified.

Jeff, I am terribly sorry.  I sent a request for this on 24 April,
but it does not appear in the archives.  It must have been dropped
(probably due to size) by the netdev list filters, and I neglected
to notice.

/me wishes the list would send me a note when it drops stuff due
to size...

> Nonetheless, I looked over the changes and they look OK, so I took the 
> lazy route and kept them.
 
I greatly appreciate that!

> For the future, I would perhaps recommend creating an upstream-jeff 
> branch at the time of submission, if you insist upon continuing to push 

The point is well taken.  It probably does make sense either to have an
upstream-jeff branch or to make a new branch if you haven't yet pulled.
I'll keep that in mind.

Thanks,

John
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-05-22 19:19 ` Please pull 'upstream' " John W. Linville
@ 2006-05-24  4:35   ` Jeff Garzik
  2006-05-24 12:42     ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: Jeff Garzik @ 2006-05-24  4:35 UTC (permalink / raw)
  To: John W. Linville, netdev

John W. Linville wrote:
> The following changes since commit 01d654d25d23fb73deb7904ce1c0b3a0f5fc2908:
>   John W. Linville:
>         Merge branch 'upstream-fixes' into upstream
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Marcin Juszkiewicz:
>       hostap: new pcmcia IDs
> 
>  drivers/net/wireless/hostap/hostap_cs.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)

WTF???  I pull, and see diffstat:

Merge db21e578e551421d76641d72cb3f8296ed3f9e61, made by recursive.
  drivers/net/wireless/airo.c                     |    2
  drivers/net/wireless/bcm43xx/bcm43xx_main.c     |    8 +-
  drivers/net/wireless/hostap/hostap_80211_tx.c   |    1
  drivers/net/wireless/hostap/hostap_ap.c         |   11 --
  drivers/net/wireless/hostap/hostap_cs.c         |    6 +
  drivers/net/wireless/hostap/hostap_main.c       |    2
  drivers/net/wireless/orinoco_cs.c               |   33 ++----
  drivers/net/wireless/orinoco_nortel.c           |    5 +
  drivers/net/wireless/orinoco_pci.c              |    5 +
  drivers/net/wireless/orinoco_pci.h              |   31 +-----
  drivers/net/wireless/orinoco_plx.c              |    5 +
  drivers/net/wireless/orinoco_tmd.c              |    5 +
  drivers/net/wireless/spectrum_cs.c              |   33 ++----
  include/net/ieee80211softmac.h                  |   38 ++++++-
  net/ieee80211/ieee80211_wx.c                    |    2
  net/ieee80211/softmac/ieee80211softmac_assoc.c  |   72 +++++++-------
  net/ieee80211/softmac/ieee80211softmac_auth.c   |    3 +
  net/ieee80211/softmac/ieee80211softmac_module.c |  117 
+++++++++++++++++++----
  net/ieee80211/softmac/ieee80211softmac_priv.h   |    6 +
  net/ieee80211/softmac/ieee80211softmac_wx.c     |    6 +
  20 files changed, 228 insertions(+), 163 deletions(-)

This is vastly different from any 'pull upstream' email I've received 
from you.  It is extremely uncool for me to pull, and receive something 
other than what your email specified.

Nonetheless, I looked over the changes and they look OK, so I took the 
lazy route and kept them.

For the future, I would perhaps recommend creating an upstream-jeff 
branch at the time of submission, if you insist upon continuing to push 
stuff into the upstream branch in the window between submission and 
pull.  I do this with Linus:  I create an 'upstream-linus' branch, 
branched off of 'upstream', at the time of submission.  After Linus 
pulls, I delete the branch.

	Jeff


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-05-22 19:18 Please pull 'upstream-fixes' " John W. Linville
@ 2006-05-22 19:19 ` John W. Linville
  2006-05-24  4:35   ` Jeff Garzik
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-05-22 19:19 UTC (permalink / raw)
  To: jeff; +Cc: netdev

The following changes since commit 01d654d25d23fb73deb7904ce1c0b3a0f5fc2908:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Marcin Juszkiewicz:
      hostap: new pcmcia IDs

 drivers/net/wireless/hostap/hostap_cs.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 55bed92..db03dc2 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -881,6 +881,12 @@ static struct pcmcia_device_id hostap_cs
 	PCMCIA_DEVICE_PROD_ID12(
 		"ZoomAir 11Mbps High", "Rate wireless Networking",
 		0x273fe3db, 0x32a1eaee),
+	PCMCIA_DEVICE_PROD_ID123(
+		"Pretec", "CompactWLAN Card 802.11b", "2.5",
+		0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
+	PCMCIA_DEVICE_PROD_ID123(
+		"U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
+		0xc7b8df9d, 0x1700d087, 0x4b74baa0),
 	PCMCIA_DEVICE_NULL
 };
 MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-05-18 17:28     ` John W. Linville
@ 2006-05-18 18:26       ` Daniel Drake
  0 siblings, 0 replies; 108+ messages in thread
From: Daniel Drake @ 2006-05-18 18:26 UTC (permalink / raw)
  To: Daniel Drake, jeff, netdev, arjan

John W. Linville wrote:
> On Wed, May 17, 2006 at 10:23:34PM +0100, Daniel Drake wrote:
>> John W. Linville wrote:
>>> Daniel Drake:
>>>      set_security implementation inside softmac
>> If it's not too late, can you drop this one?
> 
> Well, it's your patch.  If you want to withdraw it, I'll comply.

Please do. I didn't sign off or send it to you directly as I wasn't 
asking for inclusion, but I'll make that clearer next time.

Thanks,
Daniel


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-05-17 21:23   ` Daniel Drake
@ 2006-05-18 17:28     ` John W. Linville
  2006-05-18 18:26       ` Daniel Drake
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-05-18 17:28 UTC (permalink / raw)
  To: Daniel Drake; +Cc: jeff, netdev, arjan

On Wed, May 17, 2006 at 10:23:34PM +0100, Daniel Drake wrote:
> John W. Linville wrote:
> >Daniel Drake:
> >      set_security implementation inside softmac
> 
> If it's not too late, can you drop this one?

Well, it's your patch.  If you want to withdraw it, I'll comply.

---

The following changes since commit 59d4b684fbe74b25ac8593f39d2aaa86aa485b1f:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Arjan van de Ven:
      unused exports in wireless drivers

 drivers/net/wireless/hostap/hostap_80211_tx.c |    1 -
 drivers/net/wireless/hostap/hostap_ap.c       |   11 -----------
 drivers/net/wireless/hostap/hostap_main.c     |    2 --
 3 files changed, 0 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 06a5214..4a5be70 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -534,5 +534,4 @@ int hostap_master_start_xmit(struct sk_b
 }
 
 
-EXPORT_SYMBOL(hostap_dump_tx_80211);
 EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 06c3fa3..ba13125 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -3276,17 +3276,6 @@ EXPORT_SYMBOL(hostap_init_data);
 EXPORT_SYMBOL(hostap_init_ap_proc);
 EXPORT_SYMBOL(hostap_free_data);
 EXPORT_SYMBOL(hostap_check_sta_fw_version);
-EXPORT_SYMBOL(hostap_handle_sta_tx);
-EXPORT_SYMBOL(hostap_handle_sta_release);
 EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
-EXPORT_SYMBOL(hostap_update_sta_ps);
-EXPORT_SYMBOL(hostap_handle_sta_rx);
-EXPORT_SYMBOL(hostap_is_sta_assoc);
-EXPORT_SYMBOL(hostap_is_sta_authorized);
-EXPORT_SYMBOL(hostap_add_sta);
-EXPORT_SYMBOL(hostap_update_rates);
-EXPORT_SYMBOL(hostap_add_wds_links);
-EXPORT_SYMBOL(hostap_wds_link_oper);
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-EXPORT_SYMBOL(hostap_deauth_all_stas);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 8dd4c44..93786f4 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -1125,11 +1125,9 @@ EXPORT_SYMBOL(hostap_set_auth_algs);
 EXPORT_SYMBOL(hostap_dump_rx_header);
 EXPORT_SYMBOL(hostap_dump_tx_header);
 EXPORT_SYMBOL(hostap_80211_header_parse);
-EXPORT_SYMBOL(hostap_80211_prism_header_parse);
 EXPORT_SYMBOL(hostap_80211_get_hdrlen);
 EXPORT_SYMBOL(hostap_get_stats);
 EXPORT_SYMBOL(hostap_setup_dev);
-EXPORT_SYMBOL(hostap_proc);
 EXPORT_SYMBOL(hostap_set_multicast_list_queue);
 EXPORT_SYMBOL(hostap_set_hostapd);
 EXPORT_SYMBOL(hostap_set_hostapd_sta);
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-05-17 19:38 ` Please pull 'upstream' " John W. Linville
@ 2006-05-17 21:23   ` Daniel Drake
  2006-05-18 17:28     ` John W. Linville
  0 siblings, 1 reply; 108+ messages in thread
From: Daniel Drake @ 2006-05-17 21:23 UTC (permalink / raw)
  To: jeff, netdev, arjan, dsd

John W. Linville wrote:
> Daniel Drake:
>       set_security implementation inside softmac

If it's not too late, can you drop this one?

I didn't receive any feedback on it, and I decided it's not the right 
approach. The interface isn't great, but when done at the driver level 
it allows drivers to reject various security settings that they don't 
support by not copying them into secinfo.

So, even though this code block will be almost duplicated over bcm43xx, 
zd1211, and more, I think that level is the right place to put it.

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-05-17 19:34 Please pull 'upstream-fixes' " John W. Linville
@ 2006-05-17 19:38 ` John W. Linville
  2006-05-17 21:23   ` Daniel Drake
  0 siblings, 1 reply; 108+ messages in thread
From: John W. Linville @ 2006-05-17 19:38 UTC (permalink / raw)
  To: jeff; +Cc: netdev, arjan, dsd

The following changes since commit 59d4b684fbe74b25ac8593f39d2aaa86aa485b1f:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Arjan van de Ven:
      unused exports in wireless drivers

Daniel Drake:
      set_security implementation inside softmac

 drivers/net/wireless/bcm43xx/bcm43xx_main.c     |   38 +++----------------
 drivers/net/wireless/hostap/hostap_80211_tx.c   |    1 -
 drivers/net/wireless/hostap/hostap_ap.c         |   11 ------
 drivers/net/wireless/hostap/hostap_main.c       |    2 -
 include/net/ieee80211softmac.h                  |    4 ++
 net/ieee80211/softmac/ieee80211softmac_module.c |   46 +++++++++++++++++++++++
 6 files changed, 55 insertions(+), 47 deletions(-)

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index c050290..17b59ef 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3547,8 +3547,7 @@ static void bcm43xx_ieee80211_set_chan(s
 }
 
 /* set_security() callback in struct ieee80211_device */
-static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
-					   struct ieee80211_security *sec)
+static void bcm43xx_ieee80211_set_security(struct net_device *net_dev)
 {
 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
 	struct ieee80211_security *secinfo = &bcm->ieee->sec;
@@ -3559,42 +3558,15 @@ static void bcm43xx_ieee80211_set_securi
 
 	bcm43xx_lock_mmio(bcm, flags);
 
-	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
-		if (sec->flags & (1<<keyidx)) {
-			secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
-			secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
-			memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN);
-		}
-	
-	if (sec->flags & SEC_ACTIVE_KEY) {
-		secinfo->active_key = sec->active_key;
-		dprintk(KERN_INFO PFX "   .active_key = %d\n", sec->active_key);
-	}
-	if (sec->flags & SEC_UNICAST_GROUP) {
-		secinfo->unicast_uses_group = sec->unicast_uses_group;
-		dprintk(KERN_INFO PFX "   .unicast_uses_group = %d\n", sec->unicast_uses_group);
-	}
-	if (sec->flags & SEC_LEVEL) {
-		secinfo->level = sec->level;
-		dprintk(KERN_INFO PFX "   .level = %d\n", sec->level);
-	}
-	if (sec->flags & SEC_ENABLED) {
-		secinfo->enabled = sec->enabled;
-		dprintk(KERN_INFO PFX "   .enabled = %d\n", sec->enabled);
-	}
-	if (sec->flags & SEC_ENCRYPT) {
-		secinfo->encrypt = sec->encrypt;
-		dprintk(KERN_INFO PFX "   .encrypt = %d\n", sec->encrypt);
-	}
 	if (bcm->initialized && !bcm->ieee->host_encrypt) {
 		if (secinfo->enabled) {
 			/* upload WEP keys to hardware */
 			char null_address[6] = { 0 };
 			u8 algorithm = 0;
 			for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) {
-				if (!(sec->flags & (1<<keyidx)))
+				if (!(secinfo->flags & (1<<keyidx)))
 					continue;
-				switch (sec->encode_alg[keyidx]) {
+				switch (secinfo->encode_alg[keyidx]) {
 					case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break;
 					case SEC_ALG_WEP:
 						algorithm = BCM43xx_SEC_ALGO_WEP;
@@ -3613,7 +3585,7 @@ static void bcm43xx_ieee80211_set_securi
 						assert(0);
 						break;
 				}
-				bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
+				bcm43xx_key_write(bcm, keyidx, algorithm, secinfo->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]);
 				bcm->key[keyidx].enabled = 1;
 				bcm->key[keyidx].algorithm = algorithm;
 			}
@@ -3694,6 +3666,7 @@ static int bcm43xx_init_private(struct b
 	bcm->ieee = netdev_priv(net_dev);
 	bcm->softmac = ieee80211_priv(net_dev);
 	bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
+	bcm->softmac->set_security = bcm43xx_ieee80211_set_security;
 
 	bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
 	bcm->pci_dev = pci_dev;
@@ -3729,7 +3702,6 @@ #endif /* CONFIG_BCM43XX_PIO */
 	
 	bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE;
 	bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr);
-	bcm->ieee->set_security = bcm43xx_ieee80211_set_security;
 	bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit;
 
 	return 0;
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 06a5214..4a5be70 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -534,5 +534,4 @@ int hostap_master_start_xmit(struct sk_b
 }
 
 
-EXPORT_SYMBOL(hostap_dump_tx_80211);
 EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 06c3fa3..ba13125 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -3276,17 +3276,6 @@ EXPORT_SYMBOL(hostap_init_data);
 EXPORT_SYMBOL(hostap_init_ap_proc);
 EXPORT_SYMBOL(hostap_free_data);
 EXPORT_SYMBOL(hostap_check_sta_fw_version);
-EXPORT_SYMBOL(hostap_handle_sta_tx);
-EXPORT_SYMBOL(hostap_handle_sta_release);
 EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
-EXPORT_SYMBOL(hostap_update_sta_ps);
-EXPORT_SYMBOL(hostap_handle_sta_rx);
-EXPORT_SYMBOL(hostap_is_sta_assoc);
-EXPORT_SYMBOL(hostap_is_sta_authorized);
-EXPORT_SYMBOL(hostap_add_sta);
-EXPORT_SYMBOL(hostap_update_rates);
-EXPORT_SYMBOL(hostap_add_wds_links);
-EXPORT_SYMBOL(hostap_wds_link_oper);
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-EXPORT_SYMBOL(hostap_deauth_all_stas);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 8dd4c44..93786f4 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -1125,11 +1125,9 @@ EXPORT_SYMBOL(hostap_set_auth_algs);
 EXPORT_SYMBOL(hostap_dump_rx_header);
 EXPORT_SYMBOL(hostap_dump_tx_header);
 EXPORT_SYMBOL(hostap_80211_header_parse);
-EXPORT_SYMBOL(hostap_80211_prism_header_parse);
 EXPORT_SYMBOL(hostap_80211_get_hdrlen);
 EXPORT_SYMBOL(hostap_get_stats);
 EXPORT_SYMBOL(hostap_setup_dev);
-EXPORT_SYMBOL(hostap_proc);
 EXPORT_SYMBOL(hostap_set_multicast_list_queue);
 EXPORT_SYMBOL(hostap_set_hostapd);
 EXPORT_SYMBOL(hostap_set_hostapd_sta);
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 703463a..1729842 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -172,6 +172,10 @@ struct ieee80211softmac_device {
 	void (*set_bssid_filter)(struct net_device *dev, const u8 *bssid);
 	void (*set_channel)(struct net_device *dev, u8 channel);
 
+	/* implement this if you need to configure hardware encryption
+	 * when the user changes security settings */
+	void (*set_security)(struct net_device *dev);
+
 	/* assign if you need it, informational only */
 	void (*link_change)(struct net_device *dev);
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 4b2e57d..03cd26c 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -27,6 +27,51 @@
 #include "ieee80211softmac_priv.h"
 #include <linux/sort.h>
 #include <linux/etherdevice.h>
+#include <net/ieee80211.h>
+
+static void set_security(struct net_device *dev,
+	struct ieee80211_security *sec)
+{
+	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+	struct ieee80211_device *ieee = mac->ieee;
+	struct ieee80211_security *secinfo = &ieee->sec;
+	int keyidx;
+
+	dprintk(KERN_NOTICE PFX "set_security:\n");
+	secinfo->flags = sec->flags;
+
+	for (keyidx = 0; keyidx < WEP_KEYS; keyidx++)
+		if (sec->flags & (1 << keyidx)) {
+			secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+			secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+			memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
+			       SCM_KEY_LEN);
+		}
+
+	if (sec->flags & SEC_ACTIVE_KEY) {
+		secinfo->active_key = sec->active_key;
+		dprintk("   .active_key = %d\n", sec->active_key);
+	}
+	if (sec->flags & SEC_UNICAST_GROUP) {
+		secinfo->unicast_uses_group = sec->unicast_uses_group;
+		dprintk("   .unicast_uses_group = %d\n", sec->unicast_uses_group);
+	}
+	if (sec->flags & SEC_LEVEL) {
+		secinfo->level = sec->level;
+		dprintk("   .level = %d\n", sec->level);
+	}
+	if (sec->flags & SEC_ENABLED) {
+		secinfo->enabled = sec->enabled;
+		dprintk("   .enabled = %d\n", sec->enabled);
+	}
+	if (sec->flags & SEC_ENCRYPT) {
+		secinfo->encrypt = sec->encrypt;
+		dprintk("   .encrypt = %d\n", sec->encrypt);
+	}
+
+	if (mac->set_security)
+		mac->set_security(dev);
+}
 
 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
 {
@@ -44,6 +89,7 @@ struct net_device *alloc_ieee80211softma
 	softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
 	softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
 	softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
+	softmac->ieee->set_security = set_security;
 	softmac->scaninfo = NULL;
 
 	softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Please pull upstream branch of wireless-2.6
  2006-05-06  1:06 Please pull upstream-fixes " John W. Linville
@ 2006-05-06  1:09 ` John W. Linville
  0 siblings, 0 replies; 108+ messages in thread
From: John W. Linville @ 2006-05-06  1:09 UTC (permalink / raw)
  To: netdev; +Cc: jeff, shemminger, akpm

These are patches intended for the next release (i.e. 2.6.18)...thanks!

---

The following changes since commit fd5226a72694d1c0abe1cc39711a86f1754e637d:
  John W. Linville:
        Merge branch 'upstream-fixes' into upstream

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Adrian Bunk:
      ieee80211_wx.c: remove dead code

Daniel Drake:
      softmac: deauthentication implies deassociation
      softmac: suggest per-frame-type TX rate

Michal Schmidt:
      wireless/airo: minimal WPA awareness

Pavel Roskin:
      orinoco: unregister network device before releasing PCMCIA resources
      orinoco: report more relevant data on startup
      orinoco: simplify locking, fix error handling in PCMCIA resume
      orinoco: eliminate the suspend/resume functions if CONFIG_PM is unset
      orinoco: don't put PCI resource data to the network device

Stefano Brivio:
      bcm43xx: fix whitespace
      bcm43xx: add PCI ID for bcm4319

 drivers/net/wireless/airo.c                     |    2 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c     |    8 +-
 drivers/net/wireless/orinoco_cs.c               |   33 ++----
 drivers/net/wireless/orinoco_nortel.c           |    5 +
 drivers/net/wireless/orinoco_pci.c              |    5 +
 drivers/net/wireless/orinoco_pci.h              |   31 +-----
 drivers/net/wireless/orinoco_plx.c              |    5 +
 drivers/net/wireless/orinoco_tmd.c              |    5 +
 drivers/net/wireless/spectrum_cs.c              |   33 ++----
 include/net/ieee80211softmac.h                  |   38 ++++++-
 net/ieee80211/ieee80211_wx.c                    |    2 
 net/ieee80211/softmac/ieee80211softmac_assoc.c  |   72 +++++++-------
 net/ieee80211/softmac/ieee80211softmac_auth.c   |    3 +
 net/ieee80211/softmac/ieee80211softmac_module.c |  117 +++++++++++++++++++----
 net/ieee80211/softmac/ieee80211softmac_priv.h   |    6 +
 net/ieee80211/softmac/ieee80211softmac_wx.c     |    6 +
 16 files changed, 222 insertions(+), 149 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 7f2dacf..4069b79 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2768,7 +2768,7 @@ static int airo_test_wpa_capable(struct 
 
 	/* Only firmware versions 5.30.17 or better can do WPA */
 	if ((cap_rid.softVer > 0x530)
-	  || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 0x17))) {
+	  || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
 		airo_print_info(name, "WPA is supported.");
 		return 1;
 	}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 8d0f618..e69e8b5 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -128,13 +128,15 @@ #endif /* CONFIG_BCM43XX_DEBUG*/
 	static struct pci_device_id bcm43xx_pci_tbl[] = {
 	/* Broadcom 4303 802.11b */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-		/* Broadcom 4307 802.11b */
+	/* Broadcom 4307 802.11b */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-		/* Broadcom 4318 802.11b/g */
+	/* Broadcom 4318 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	/* Broadcom 4319 802.11a/b/g */
+	{ PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 4306 802.11b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-		/* Broadcom 4306 802.11a */
+	/* Broadcom 4306 802.11a */
 //	{ PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	/* Broadcom 4309 802.11a/b/g */
 	{ PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d2c48ac..b2aec4d 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -147,14 +147,11 @@ static void orinoco_cs_detach(struct pcm
 {
 	struct net_device *dev = link->priv;
 
+	if (link->dev_node)
+		unregister_netdev(dev);
+
 	orinoco_cs_release(link);
 
-	DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
-	if (link->dev_node) {
-		DEBUG(0, PFX "About to unregister net device %p\n",
-		      dev);
-		unregister_netdev(dev);
-	}
 	free_orinocodev(dev);
 }				/* orinoco_cs_detach */
 
@@ -346,19 +343,10 @@ orinoco_cs_config(struct pcmcia_device *
                                     net_device has been registered */
 
 	/* Finally, report what we've done */
-	printk(KERN_DEBUG "%s: index 0x%02x: ",
-	       dev->name, link->conf.ConfigIndex);
-	if (link->conf.Vpp)
-		printk(", Vpp %d.%d", link->conf.Vpp / 10,
-		       link->conf.Vpp % 10);
-	printk(", irq %d", link->irq.AssignedIRQ);
-	if (link->io.NumPorts1)
-		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-		       link->io.BasePort1 + link->io.NumPorts1 - 1);
-	if (link->io.NumPorts2)
-		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-		       link->io.BasePort2 + link->io.NumPorts2 - 1);
-	printk("\n");
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+	       "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+	       link->irq.AssignedIRQ, link->io.BasePort1,
+	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 
 	return 0;
 
@@ -427,7 +415,6 @@ static int orinoco_cs_resume(struct pcmc
 	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pccard *card = priv->card;
 	int err = 0;
-	unsigned long flags;
 
 	if (! test_bit(0, &card->hard_reset_in_progress)) {
 		err = orinoco_reinit_firmware(dev);
@@ -437,7 +424,7 @@ static int orinoco_cs_resume(struct pcmc
 			return -EIO;
 		}
 
-		spin_lock_irqsave(&priv->lock, flags);
+		spin_lock(&priv->lock);
 
 		netif_device_attach(dev);
 		priv->hw_unavailable--;
@@ -449,10 +436,10 @@ static int orinoco_cs_resume(struct pcmc
 				       dev->name, err);
 		}
 
-		spin_unlock_irqrestore(&priv->lock, flags);
+		spin_unlock(&priv->lock);
 	}
 
-	return 0;
+	return err;
 }
 
 
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index 1596182..74b9d5b 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -206,7 +206,6 @@ static int orinoco_nortel_init_one(struc
 		err = -EBUSY;
 		goto fail_irq;
 	}
-	orinoco_pci_setup_netdev(dev, pdev, 2);
 
 	err = orinoco_nortel_hw_init(card);
 	if (err) {
@@ -227,6 +226,8 @@ static int orinoco_nortel_init_one(struc
 	}
 
 	pci_set_drvdata(pdev, dev);
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+	       pci_name(pdev));
 
 	return 0;
 
@@ -265,7 +266,7 @@ static void __devexit orinoco_nortel_rem
 	iowrite16(0, card->bridge_io + 10);
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
 	free_orinocodev(dev);
 	pci_iounmap(pdev, priv->hw.iobase);
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index df37b95..1c105f4 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -161,7 +161,6 @@ static int orinoco_pci_init_one(struct p
 		err = -EBUSY;
 		goto fail_irq;
 	}
-	orinoco_pci_setup_netdev(dev, pdev, 0);
 
 	err = orinoco_pci_cor_reset(priv);
 	if (err) {
@@ -176,6 +175,8 @@ static int orinoco_pci_init_one(struct p
 	}
 
 	pci_set_drvdata(pdev, dev);
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+	       pci_name(pdev));
 
 	return 0;
 
@@ -204,7 +205,7 @@ static void __devexit orinoco_pci_remove
 	struct orinoco_private *priv = netdev_priv(dev);
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
 	free_orinocodev(dev);
 	pci_iounmap(pdev, priv->hw.iobase);
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h
index b05a9a5..7eb1e08 100644
--- a/drivers/net/wireless/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco_pci.h
@@ -18,32 +18,7 @@ struct orinoco_pci_card {
 	void __iomem *attr_io;
 };
 
-/* Set base address or memory range of the network device based on
- * the PCI device it's using.  Specify BAR of the "main" resource.
- * To be used after request_irq().  */
-static inline void orinoco_pci_setup_netdev(struct net_device *dev,
-					    struct pci_dev *pdev, int bar)
-{
-	char *range_type;
-	unsigned long start = pci_resource_start(pdev, bar);
-	unsigned long len = pci_resource_len(pdev, bar);
-	unsigned long flags = pci_resource_flags(pdev, bar);
-	unsigned long end = start + len - 1;
-
-	dev->irq = pdev->irq;
-	if (flags & IORESOURCE_IO) {
-		dev->base_addr = start;
-		range_type = "ports";
-	} else {
-		dev->mem_start = start;
-		dev->mem_end = end;
-		range_type = "memory";
-	}
-
-	printk(KERN_DEBUG PFX "%s: irq %d, %s 0x%lx-0x%lx\n",
-	       pci_name(pdev), pdev->irq, range_type, start, end);
-}
-
+#ifdef CONFIG_PM
 static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
@@ -121,5 +96,9 @@ static int orinoco_pci_resume(struct pci
 
 	return 0;
 }
+#else
+#define orinoco_pci_suspend NULL
+#define orinoco_pci_resume NULL
+#endif
 
 #endif /* _ORINOCO_PCI_H */
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 7b94050..84f696c 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -245,7 +245,6 @@ static int orinoco_plx_init_one(struct p
 		err = -EBUSY;
 		goto fail_irq;
 	}
-	orinoco_pci_setup_netdev(dev, pdev, 2);
 
 	err = orinoco_plx_hw_init(card);
 	if (err) {
@@ -266,6 +265,8 @@ static int orinoco_plx_init_one(struct p
 	}
 
 	pci_set_drvdata(pdev, dev);
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+	       pci_name(pdev));
 
 	return 0;
 
@@ -301,7 +302,7 @@ static void __devexit orinoco_plx_remove
 	struct orinoco_pci_card *card = priv->card;
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
 	free_orinocodev(dev);
 	pci_iounmap(pdev, priv->hw.iobase);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 0496663..d2b4dec 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -147,7 +147,6 @@ static int orinoco_tmd_init_one(struct p
 		err = -EBUSY;
 		goto fail_irq;
 	}
-	orinoco_pci_setup_netdev(dev, pdev, 2);
 
 	err = orinoco_tmd_cor_reset(priv);
 	if (err) {
@@ -162,6 +161,8 @@ static int orinoco_tmd_init_one(struct p
 	}
 
 	pci_set_drvdata(pdev, dev);
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+	       pci_name(pdev));
 
 	return 0;
 
@@ -194,7 +195,7 @@ static void __devexit orinoco_tmd_remove
 	struct orinoco_pci_card *card = priv->card;
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
+	free_irq(pdev->irq, dev);
 	pci_set_drvdata(pdev, NULL);
 	free_orinocodev(dev);
 	pci_iounmap(pdev, priv->hw.iobase);
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index aeb38d9..7f9aa13 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -625,14 +625,11 @@ static void spectrum_cs_detach(struct pc
 {
 	struct net_device *dev = link->priv;
 
+	if (link->dev_node)
+		unregister_netdev(dev);
+
 	spectrum_cs_release(link);
 
-	DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
-	if (link->dev_node) {
-		DEBUG(0, PFX "About to unregister net device %p\n",
-		      dev);
-		unregister_netdev(dev);
-	}
 	free_orinocodev(dev);
 }				/* spectrum_cs_detach */
 
@@ -825,19 +822,10 @@ spectrum_cs_config(struct pcmcia_device 
                                     net_device has been registered */
 
 	/* Finally, report what we've done */
-	printk(KERN_DEBUG "%s: index 0x%02x: ",
-	       dev->name, link->conf.ConfigIndex);
-	if (link->conf.Vpp)
-		printk(", Vpp %d.%d", link->conf.Vpp / 10,
-		       link->conf.Vpp % 10);
-	printk(", irq %d", link->irq.AssignedIRQ);
-	if (link->io.NumPorts1)
-		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-		       link->io.BasePort1 + link->io.NumPorts1 - 1);
-	if (link->io.NumPorts2)
-		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-		       link->io.BasePort2 + link->io.NumPorts2 - 1);
-	printk("\n");
+	printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+	       "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+	       link->irq.AssignedIRQ, link->io.BasePort1,
+	       link->io.BasePort1 + link->io.NumPorts1 - 1);
 
 	return 0;
 
@@ -878,11 +866,10 @@ spectrum_cs_suspend(struct pcmcia_device
 {
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = netdev_priv(dev);
-	unsigned long flags;
 	int err = 0;
 
 	/* Mark the device as stopped, to block IO until later */
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock(&priv->lock);
 
 	err = __orinoco_down(dev);
 	if (err)
@@ -892,9 +879,9 @@ spectrum_cs_suspend(struct pcmcia_device
 	netif_device_detach(dev);
 	priv->hw_unavailable++;
 
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock(&priv->lock);
 
-	return 0;
+	return err;
 }
 
 static int
diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h
index 052ed59..703463a 100644
--- a/include/net/ieee80211softmac.h
+++ b/include/net/ieee80211softmac.h
@@ -86,6 +86,9 @@ struct ieee80211softmac_assoc_info {
 	
 	/* BSSID we're trying to associate to */
 	char bssid[ETH_ALEN];
+
+	/* Rates supported by the network */
+	struct ieee80211softmac_ratesinfo supported_rates;
 	
 	/* some flags.
 	 * static_essid is valid if the essid is constant,
@@ -132,23 +135,26 @@ #define IEEE80211SOFTMAC_ASSOC_SCAN_RETR
 struct ieee80211softmac_txrates {
 	/* The Bit-Rate to be used for multicast frames. */
 	u8 mcast_rate;
-	/* The Bit-Rate to be used for multicast fallback
-	 * (If the device supports fallback and hardware-retry)
-	 */
-	u8 mcast_fallback;
+
+	/* The Bit-Rate to be used for multicast management frames. */
+	u8 mgt_mcast_rate;
+
 	/* The Bit-Rate to be used for any other (normal) data packet. */
 	u8 default_rate;
 	/* The Bit-Rate to be used for default fallback
 	 * (If the device supports fallback and hardware-retry)
 	 */
 	u8 default_fallback;
+
+	/* This is the rate that the user asked for */
+	u8 user_rate;
 };
 
 /* Bits for txrates_change callback. */
 #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT		(1 << 0) /* default_rate */
 #define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK	(1 << 1) /* default_fallback */
 #define IEEE80211SOFTMAC_TXRATECHG_MCAST		(1 << 2) /* mcast_rate */
-#define IEEE80211SOFTMAC_TXRATECHG_MCAST_FBACK		(1 << 3) /* mcast_fallback */
+#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST		(1 << 3) /* mgt_mcast_rate */
 
 struct ieee80211softmac_device {
 	/* 802.11 structure for data stuff */
@@ -250,6 +256,28 @@ extern void ieee80211softmac_fragment_lo
  * Note that the rates need to be sorted. */
 extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates);
 
+/* Helper function which advises you the rate at which a frame should be
+ * transmitted at. */
+static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac,
+						 int is_multicast,
+						 int is_mgt)
+{
+	struct ieee80211softmac_txrates *txrates = &mac->txrates;
+
+	if (!mac->associated)
+		return txrates->mgt_mcast_rate;
+
+	/* We are associated, sending unicast frame */
+	if (!is_multicast)
+		return txrates->default_rate;
+
+	/* We are associated, sending multicast frame */
+	if (is_mgt)
+		return txrates->mgt_mcast_rate;
+	else
+		return txrates->mcast_rate;
+}
+
 /* Start the SoftMAC. Call this after you initialized the device
  * and it is ready to run.
  */
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 0ea55cb..a78c4f8 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -503,7 +503,7 @@ int ieee80211_wx_get_encode(struct ieee8
 	len = sec->key_sizes[key];
 	memcpy(keybuf, sec->keys[key], len);
 
-	erq->length = (len >= 0 ? len : 0);
+	erq->length = len;
 	erq->flags |= IW_ENCODE_ENABLED;
 
 	if (ieee->open_wep)
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index d4c79ce..5d90b9a 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -82,51 +82,52 @@ ieee80211softmac_assoc_timeout(void *d)
 	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
 }
 
-/* Sends out a disassociation request to the desired AP */
 void
-ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
+ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
 {
 	unsigned long flags;
+
+	spin_lock_irqsave(&mac->lock, flags);
+	if (mac->associnfo.associating)
+		cancel_delayed_work(&mac->associnfo.timeout);
+
+	netif_carrier_off(mac->dev);
+
+	mac->associated = 0;
+	mac->associnfo.bssvalid = 0;
+	mac->associnfo.associating = 0;
+	ieee80211softmac_init_txrates(mac);
+	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
+	spin_unlock_irqrestore(&mac->lock, flags);
+}
+
+/* Sends out a disassociation request to the desired AP */
+void
+ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
+{
 	struct ieee80211softmac_network *found;
 
 	if (mac->associnfo.bssvalid && mac->associated) {
 		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
 		if (found)
 			ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
-	} else if (mac->associnfo.associating) {
-		cancel_delayed_work(&mac->associnfo.timeout);
 	}
 
-	/* Change our state */
-	spin_lock_irqsave(&mac->lock, flags);
-	/* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
-	mac->associated = 0;
-	mac->associnfo.associating = 0;
-	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
-	spin_unlock_irqrestore(&mac->lock, flags);
+	ieee80211softmac_disassoc(mac);
 }
 
 static inline int
 we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
 {
-	int idx, search, found;
-	u8 rate, search_rate;
+	int idx;
+	u8 rate;
 
 	for (idx = 0; idx < (from_len); idx++) {
 		rate = (from)[idx];
 		if (!(rate & IEEE80211_BASIC_RATE_MASK))
 			continue;
-		found = 0;
 		rate &= ~IEEE80211_BASIC_RATE_MASK;
-		for (search = 0; search < mac->ratesinfo.count; search++) {
-			search_rate = mac->ratesinfo.rates[search];
-			search_rate &= ~IEEE80211_BASIC_RATE_MASK;
-			if (rate == search_rate) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
+		if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
 			return 0;
 	}
 	return 1;
@@ -176,14 +177,18 @@ ieee80211softmac_assoc_work(void *d)
 	struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
 	struct ieee80211softmac_network *found = NULL;
 	struct ieee80211_network *net = NULL, *best = NULL;
+	int bssvalid;
 	unsigned long flags;
-	
+
+	/* ieee80211_disassoc might clear this */
+	bssvalid = mac->associnfo.bssvalid;
+
 	/* meh */
 	if (mac->associated)
-		ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+		ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
 
 	/* try to find the requested network in our list, if we found one already */
-	if (mac->associnfo.bssvalid || mac->associnfo.bssfixed)
+	if (bssvalid || mac->associnfo.bssfixed)
 		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);	
 	
 	/* Search the ieee80211 networks for this network if we didn't find it by bssid,
@@ -297,6 +302,9 @@ ieee80211softmac_associated(struct ieee8
 	struct ieee80211softmac_network *net)
 {
 	mac->associnfo.associating = 0;
+	mac->associnfo.supported_rates = net->supported_rates;
+	ieee80211softmac_recalc_txrates(mac);
+
 	mac->associated = 1;
 	if (mac->set_bssid_filter)
 		mac->set_bssid_filter(mac->dev, net->bssid);
@@ -380,7 +388,6 @@ ieee80211softmac_handle_disassoc(struct 
 				 struct ieee80211_disassoc *disassoc)
 {
 	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	unsigned long flags;
 
 	if (unlikely(!mac->running))
 		return -ENODEV;
@@ -392,14 +399,11 @@ ieee80211softmac_handle_disassoc(struct 
 		return 0;
 
 	dprintk(KERN_INFO PFX "got disassoc frame\n");
-	netif_carrier_off(dev);
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.bssvalid = 0;
-	mac->associated = 0;
-	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
+	ieee80211softmac_disassoc(mac);
+
+	/* try to reassociate */
 	schedule_work(&mac->associnfo.work);
-	spin_unlock_irqrestore(&mac->lock, flags);
-	
+
 	return 0;
 }
 
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 06e3326..084b621 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -279,6 +279,9 @@ ieee80211softmac_deauth_from_net(struct 
 	struct list_head *list_ptr;
 	unsigned long flags;
 
+	/* deauthentication implies disassociation */
+	ieee80211softmac_disassoc(mac);
+
 	/* Lock and reset status flags */
 	spin_lock_irqsave(&mac->lock, flags);
 	net->authenticating = 0;
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 6252be2..4b2e57d 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -26,6 +26,7 @@
 
 #include "ieee80211softmac_priv.h"
 #include <linux/sort.h>
+#include <linux/etherdevice.h>
 
 struct net_device *alloc_ieee80211softmac(int sizeof_priv)
 {
@@ -61,14 +62,6 @@ struct net_device *alloc_ieee80211softma
 	softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
 	softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
 
-	//TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
-	//      It has to be set to the highest rate all stations in the current network can handle.
-	softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
-	softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
-	/* This is reassigned in ieee80211softmac_start to sane values. */
-	softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
-	softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
-
 	/* to start with, we can't send anything ... */
 	netif_carrier_off(dev);
 	
@@ -170,15 +163,82 @@ static void ieee80211softmac_start_check
 	}
 }
 
-void ieee80211softmac_start(struct net_device *dev)
+int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
+{
+	int search;
+	u8 search_rate;
+
+	for (search = 0; search < ri->count; search++) {
+		search_rate = ri->rates[search];
+		search_rate &= ~IEEE80211_BASIC_RATE_MASK;
+		if (rate == search_rate)
+			return 1;
+	}
+
+	return 0;
+}
+
+/* Finds the highest rate which is:
+ *  1. Present in ri (optionally a basic rate)
+ *  2. Supported by the device
+ *  3. Less than or equal to the user-defined rate
+ */
+static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
+	struct ieee80211softmac_ratesinfo *ri, int basic_only)
+{
+	u8 user_rate = mac->txrates.user_rate;
+	int i;
+
+	if (ri->count == 0) {
+		dprintk(KERN_ERR PFX "empty ratesinfo?\n");
+		return IEEE80211_CCK_RATE_1MB;
+	}
+
+	for (i = ri->count - 1; i >= 0; i--) {
+		u8 rate = ri->rates[i];
+		if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
+			continue;
+		rate &= ~IEEE80211_BASIC_RATE_MASK;
+		if (rate > user_rate)
+			continue;
+		if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
+			return rate;
+	}
+
+	/* If we haven't found a suitable rate by now, just trust the user */
+	return user_rate;
+}
+
+void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
+{
+	struct ieee80211softmac_txrates *txrates = &mac->txrates;
+	struct ieee80211softmac_txrates oldrates;
+	u32 change = 0;
+
+	if (mac->txrates_change)
+		oldrates = mac->txrates;
+
+	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+	txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
+
+	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+	txrates->default_fallback = lower_rate(mac, txrates->default_rate);
+
+	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
+	txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
+
+	if (mac->txrates_change)
+		mac->txrates_change(mac->dev, change, &oldrates);
+
+}
+
+void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
 {
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
 	struct ieee80211_device *ieee = mac->ieee;
 	u32 change = 0;
+	struct ieee80211softmac_txrates *txrates = &mac->txrates;
 	struct ieee80211softmac_txrates oldrates;
 
-	ieee80211softmac_start_check_rates(mac);
-
 	/* TODO: We need some kind of state machine to lower the default rates
 	 *       if we loose too many packets.
 	 */
@@ -193,22 +253,37 @@ void ieee80211softmac_start(struct net_d
 	   more reliable. Note similar logic in
 	   ieee80211softmac_wx_set_rate() */	 
 	if (ieee->modulation & IEEE80211_CCK_MODULATION) {
-		mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-		mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+		txrates->user_rate = IEEE80211_CCK_RATE_11MB;
 	} else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
-		mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-		mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
-		change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+		txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
 	} else
 		assert(0);
+
+	txrates->default_rate = IEEE80211_CCK_RATE_1MB;
+	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
+
+	txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
+	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
+
+	txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
+	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
+
+	txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
+	change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
+
 	if (mac->txrates_change)
-		mac->txrates_change(dev, change, &oldrates);
+		mac->txrates_change(mac->dev, change, &oldrates);
 
 	mac->running = 1;
 }
+
+void ieee80211softmac_start(struct net_device *dev)
+{
+	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+	ieee80211softmac_start_check_rates(mac);
+	ieee80211softmac_init_txrates(mac);
+}
 EXPORT_SYMBOL_GPL(ieee80211softmac_start);
 
 void ieee80211softmac_stop(struct net_device *dev)
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index 8c95b3a..fa1f8e3 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(st
 	struct ieee80211softmac_essid *essid);
 
 /* Rates related */
+int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
 u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
+void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
+void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
 static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
 	return ieee80211softmac_lower_rate_delta(mac, rate, 1);
 }
@@ -150,7 +153,8 @@ int ieee80211softmac_handle_disassoc(str
 int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
 				        struct ieee80211_reassoc_request * reassoc);
 void ieee80211softmac_assoc_timeout(void *d);
-void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason);
+void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
+void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
 
 /* some helper functions */
 static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 8d0c226..22aa619 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -211,8 +211,8 @@ ieee80211softmac_wx_set_rate(struct net_
 	if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
 		goto out_unlock;
 
-	mac->txrates.default_rate = rate;
-	mac->txrates.default_fallback = lower_rate(mac, rate);
+	mac->txrates.user_rate = rate;
+	ieee80211softmac_recalc_txrates(mac);
 	err = 0;
 
 out_unlock:	
@@ -456,7 +456,7 @@ ieee80211softmac_wx_set_mlme(struct net_
 		}
 		return ieee80211softmac_deauth_req(mac, net, reason);
 	case IW_MLME_DISASSOC:
-		ieee80211softmac_disassoc(mac, reason);
+		ieee80211softmac_send_disassoc_req(mac, reason);
 		return 0;
 	default:
 		return -EOPNOTSUPP;
-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply related	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-04-24 20:40 ` Please pull 'upstream' " John W. Linville
  2006-04-25  0:33   ` Dan Williams
@ 2006-04-26 10:18   ` Jeff Garzik
  1 sibling, 0 replies; 108+ messages in thread
From: Jeff Garzik @ 2006-04-26 10:18 UTC (permalink / raw)
  To: John W. Linville, netdev

John W. Linville wrote:
> The following changes since commit 7c241d37fe0e6442c5cf3b5d73f7f58f2dc66352:
>   Michael Buesch:
>         bcm43xx: make PIO mode usable
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

pulled



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-04-25 11:30     ` Johannes Berg
@ 2006-04-25 12:03       ` Dan Williams
  0 siblings, 0 replies; 108+ messages in thread
From: Dan Williams @ 2006-04-25 12:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: John W. Linville, jeff, netdev

On Tue, 2006-04-25 at 13:30 +0200, Johannes Berg wrote:
> On Mon, 2006-04-24 at 20:33 -0400, Dan Williams wrote:
> 
> > Any way to get the event handling cleanup patch into 2.6.17?  It's
> > pretty much a bugfix and bcm43xx is useless with wpa_supplicant and NM
> > without the patch...
> 
> No, that's not true, the cleanup patch is exactly that, code cleanup :)
> 
> Externally, softmac behaves the same without it since your patch and
> some other patches I did on top of that have already gone in.

Ah, sorry, mistook this patch for the one that actually sent the events.

Dan



^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-04-25  0:33   ` Dan Williams
@ 2006-04-25 11:30     ` Johannes Berg
  2006-04-25 12:03       ` Dan Williams
  0 siblings, 1 reply; 108+ messages in thread
From: Johannes Berg @ 2006-04-25 11:30 UTC (permalink / raw)
  To: Dan Williams; +Cc: John W. Linville, jeff, netdev

[-- Attachment #1: Type: text/plain, Size: 448 bytes --]

On Mon, 2006-04-24 at 20:33 -0400, Dan Williams wrote:

> Any way to get the event handling cleanup patch into 2.6.17?  It's
> pretty much a bugfix and bcm43xx is useless with wpa_supplicant and NM
> without the patch...

No, that's not true, the cleanup patch is exactly that, code cleanup :)

Externally, softmac behaves the same without it since your patch and
some other patches I did on top of that have already gone in.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

* Re: Please pull 'upstream' branch of wireless-2.6
  2006-04-24 20:40 ` Please pull 'upstream' " John W. Linville
@ 2006-04-25  0:33   ` Dan Williams
  2006-04-25 11:30     ` Johannes Berg
  2006-04-26 10:18   ` Jeff Garzik
  1 sibling, 1 reply; 108+ messages in thread
From: Dan Williams @ 2006-04-25  0:33 UTC (permalink / raw)
  To: John W. Linville; +Cc: jeff, netdev

On Mon, 2006-04-24 at 16:40 -0400, John W. Linville wrote:
> The following changes since commit 7c241d37fe0e6442c5cf3b5d73f7f58f2dc66352:
>   Michael Buesch:
>         bcm43xx: make PIO mode usable
> 
> are found in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
> 
> Dan Williams:
>       wireless/airo: minimal WPA awareness
> 
> Jiri Benc:
>       orinoco: fix BAP0 offset error after several days of operation
> 
> Johannes Berg:
>       softmac: add SIOCSIWMLME
>       softmac: clean up event handling code

Any way to get the event handling cleanup patch into 2.6.17?  It's
pretty much a bugfix and bcm43xx is useless with wpa_supplicant and NM
without the patch...

Dan

> Michael Buesch:
>       bcm43xx: use pci_iomap() for convenience.
> 
> Pavel Roskin:
>       orinoco: Remove useless CIS validation
>       orinoco: remove PCMCIA audio support, it's useless for wireless cards
>       orinoco: remove underscores from little-endian field names
>       orinoco: remove tracing code, it's unused
>       orinoco: remove debug buffer code and userspace include support
>       orinoco: Symbol card supported by spectrum_cs is LA4137, not LA4100
>       orinoco: optimize Tx exception handling in orinoco
>       orinoco: orinoco_xmit() should only return valid symbolic constants
>       orinoco replace hermes_write_words() with hermes_write_bytes()
>       orinoco: don't use any padding for Tx frames
>       orinoco: refactor and clean up Tx error handling
>       orinoco: simplify 802.3 encapsulation code
>       orinoco: delay FID allocation after firmware initialization
>       orinoco_pci: disable device and free IRQ when suspending
>       orinoco_pci: use pci_iomap() for resources
>       orinoco: support PCI suspend/resume for Nortel, PLX and TMD adaptors
>       orinoco: reduce differences between PCI drivers, create orinoco_pci.h
>       orinoco: further comment cleanup in the PCI drivers
>       orinoco: bump version to 0.15
> 
> Zhu Yi:
>       ieee80211: Fix TKIP MIC calculation for QoS frames
>       ieee80211: Fix TX code doesn't enable QoS when using WPA + QoS
>       ieee80211: export list of bit rates with standard WEXT procddures
>       ieee80211: remove unnecessary CONFIG_WIRELESS_EXT checking
>       ieee80211: replace debug IEEE80211_WARNING with each own debug macro
>       ieee80211: update version stamp to 1.1.13
>       ipw2200: Exponential averaging for signal and noise Level
>       ipw2200: Fix TX QoS enabled frames problem
>       ipw2200: generates a scan event after a scan has completed
>       ipw2200: add module_param support for antenna selection
>       ipw2200: fix compile warning when !CONFIG_IPW2200_DEBUG
>       ipw2200: Do not continue loading the firmware if kmalloc fails
>       ipw2200: turn off signal debug log
>       ipw2200: Set the 'fixed' flags in wext get_rate
>       ipw2200: Fix endian issues with v3.0 fw image format
>       README.ipw2200: rename CONFIG_IPW_DEBUG to CONFIG_IPW2200_DEBUG
>       ipw2200: Enable rtap interface for RF promiscuous mode while associated
>       ipw2200: version string rework
>       ipw2200: update version stamp to 1.1.2
>       ipw2200: rename CONFIG_IPW_QOS to CONFIG_IPW2200_QOS
>       wireless Kconfig add IPW2200_RADIOTAP
>       ipw2200: rename CONFIG_IEEE80211_RADIOTAP to CONFIG_IPW2200_RADIOTAP
>       ipw2200: remove priv->last_noise reference
>       ipw2200: Fix wpa_supplicant association problem
> 
>  Documentation/networking/README.ipw2200        |   10 
>  drivers/net/wireless/Kconfig                   |   30 +
>  drivers/net/wireless/airo.c                    |  271 +++++---
>  drivers/net/wireless/bcm43xx/bcm43xx.h         |    1 
>  drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |    2 
>  drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   27 -
>  drivers/net/wireless/hermes.c                  |   66 --
>  drivers/net/wireless/hermes.h                  |   43 -
>  drivers/net/wireless/ipw2200.c                 |  849 +++++++++++++++++++++---
>  drivers/net/wireless/ipw2200.h                 |   83 ++
>  drivers/net/wireless/orinoco.c                 |  251 ++-----
>  drivers/net/wireless/orinoco.h                 |   19 -
>  drivers/net/wireless/orinoco_cs.c              |    9 
>  drivers/net/wireless/orinoco_nortel.c          |  168 +++--
>  drivers/net/wireless/orinoco_pci.c             |  207 +-----
>  drivers/net/wireless/orinoco_pci.h             |  125 ++++
>  drivers/net/wireless/orinoco_plx.c             |  222 +++---
>  drivers/net/wireless/orinoco_tmd.c             |   96 +--
>  drivers/net/wireless/spectrum_cs.c             |   48 +
>  include/net/ieee80211.h                        |    6 
>  include/net/ieee80211softmac_wx.h              |    5 
>  net/ieee80211/ieee80211_crypt_tkip.c           |   11 
>  net/ieee80211/ieee80211_rx.c                   |   18 -
>  net/ieee80211/ieee80211_tx.c                   |   63 +-
>  net/ieee80211/ieee80211_wx.c                   |   44 +
>  net/ieee80211/softmac/ieee80211softmac_assoc.c |    2 
>  net/ieee80211/softmac/ieee80211softmac_event.c |   25 -
>  net/ieee80211/softmac/ieee80211softmac_priv.h  |    1 
>  net/ieee80211/softmac/ieee80211softmac_wx.c    |   32 +
>  29 files changed, 1673 insertions(+), 1061 deletions(-)
>  create mode 100644 drivers/net/wireless/orinoco_pci.h
> 
> Patch included as attachment due to size concerns.


^ permalink raw reply	[flat|nested] 108+ messages in thread

* Please pull 'upstream' branch of wireless-2.6
  2006-04-24 19:40 Please pull 'upstream-fixes' " John W. Linville
@ 2006-04-24 20:40 ` John W. Linville
  2006-04-25  0:33   ` Dan Williams
  2006-04-26 10:18   ` Jeff Garzik
  0 siblings, 2 replies; 108+ messages in thread
From: John W. Linville @ 2006-04-24 20:40 UTC (permalink / raw)
  To: jeff; +Cc: netdev

[-- Attachment #1: Type: text/plain, Size: 5062 bytes --]

The following changes since commit 7c241d37fe0e6442c5cf3b5d73f7f58f2dc66352:
  Michael Buesch:
        bcm43xx: make PIO mode usable

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream

Dan Williams:
      wireless/airo: minimal WPA awareness

Jiri Benc:
      orinoco: fix BAP0 offset error after several days of operation

Johannes Berg:
      softmac: add SIOCSIWMLME
      softmac: clean up event handling code

Michael Buesch:
      bcm43xx: use pci_iomap() for convenience.

Pavel Roskin:
      orinoco: Remove useless CIS validation
      orinoco: remove PCMCIA audio support, it's useless for wireless cards
      orinoco: remove underscores from little-endian field names
      orinoco: remove tracing code, it's unused
      orinoco: remove debug buffer code and userspace include support
      orinoco: Symbol card supported by spectrum_cs is LA4137, not LA4100
      orinoco: optimize Tx exception handling in orinoco
      orinoco: orinoco_xmit() should only return valid symbolic constants
      orinoco replace hermes_write_words() with hermes_write_bytes()
      orinoco: don't use any padding for Tx frames
      orinoco: refactor and clean up Tx error handling
      orinoco: simplify 802.3 encapsulation code
      orinoco: delay FID allocation after firmware initialization
      orinoco_pci: disable device and free IRQ when suspending
      orinoco_pci: use pci_iomap() for resources
      orinoco: support PCI suspend/resume for Nortel, PLX and TMD adaptors
      orinoco: reduce differences between PCI drivers, create orinoco_pci.h
      orinoco: further comment cleanup in the PCI drivers
      orinoco: bump version to 0.15

Zhu Yi:
      ieee80211: Fix TKIP MIC calculation for QoS frames
      ieee80211: Fix TX code doesn't enable QoS when using WPA + QoS
      ieee80211: export list of bit rates with standard WEXT procddures
      ieee80211: remove unnecessary CONFIG_WIRELESS_EXT checking
      ieee80211: replace debug IEEE80211_WARNING with each own debug macro
      ieee80211: update version stamp to 1.1.13
      ipw2200: Exponential averaging for signal and noise Level
      ipw2200: Fix TX QoS enabled frames problem
      ipw2200: generates a scan event after a scan has completed
      ipw2200: add module_param support for antenna selection
      ipw2200: fix compile warning when !CONFIG_IPW2200_DEBUG
      ipw2200: Do not continue loading the firmware if kmalloc fails
      ipw2200: turn off signal debug log
      ipw2200: Set the 'fixed' flags in wext get_rate
      ipw2200: Fix endian issues with v3.0 fw image format
      README.ipw2200: rename CONFIG_IPW_DEBUG to CONFIG_IPW2200_DEBUG
      ipw2200: Enable rtap interface for RF promiscuous mode while associated
      ipw2200: version string rework
      ipw2200: update version stamp to 1.1.2
      ipw2200: rename CONFIG_IPW_QOS to CONFIG_IPW2200_QOS
      wireless Kconfig add IPW2200_RADIOTAP
      ipw2200: rename CONFIG_IEEE80211_RADIOTAP to CONFIG_IPW2200_RADIOTAP
      ipw2200: remove priv->last_noise reference
      ipw2200: Fix wpa_supplicant association problem

 Documentation/networking/README.ipw2200        |   10 
 drivers/net/wireless/Kconfig                   |   30 +
 drivers/net/wireless/airo.c                    |  271 +++++---
 drivers/net/wireless/bcm43xx/bcm43xx.h         |    1 
 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c |    2 
 drivers/net/wireless/bcm43xx/bcm43xx_main.c    |   27 -
 drivers/net/wireless/hermes.c                  |   66 --
 drivers/net/wireless/hermes.h                  |   43 -
 drivers/net/wireless/ipw2200.c                 |  849 +++++++++++++++++++++---
 drivers/net/wireless/ipw2200.h                 |   83 ++
 drivers/net/wireless/orinoco.c                 |  251 ++-----
 drivers/net/wireless/orinoco.h                 |   19 -
 drivers/net/wireless/orinoco_cs.c              |    9 
 drivers/net/wireless/orinoco_nortel.c          |  168 +++--
 drivers/net/wireless/orinoco_pci.c             |  207 +-----
 drivers/net/wireless/orinoco_pci.h             |  125 ++++
 drivers/net/wireless/orinoco_plx.c             |  222 +++---
 drivers/net/wireless/orinoco_tmd.c             |   96 +--
 drivers/net/wireless/spectrum_cs.c             |   48 +
 include/net/ieee80211.h                        |    6 
 include/net/ieee80211softmac_wx.h              |    5 
 net/ieee80211/ieee80211_crypt_tkip.c           |   11 
 net/ieee80211/ieee80211_rx.c                   |   18 -
 net/ieee80211/ieee80211_tx.c                   |   63 +-
 net/ieee80211/ieee80211_wx.c                   |   44 +
 net/ieee80211/softmac/ieee80211softmac_assoc.c |    2 
 net/ieee80211/softmac/ieee80211softmac_event.c |   25 -
 net/ieee80211/softmac/ieee80211softmac_priv.h  |    1 
 net/ieee80211/softmac/ieee80211softmac_wx.c    |   32 +
 29 files changed, 1673 insertions(+), 1061 deletions(-)
 create mode 100644 drivers/net/wireless/orinoco_pci.h

Patch included as attachment due to size concerns.
-- 
John W. Linville
linville@tuxdriver.com

[-- Attachment #2: upstream.patch.gz --]
[-- Type: application/x-gzip, Size: 41864 bytes --]

^ permalink raw reply	[flat|nested] 108+ messages in thread

end of thread, other threads:[~2007-05-30 14:03 UTC | newest]

Thread overview: 108+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-16 21:31 Please pull 'upstream-fixes' branch of wireless-2.6 John W. Linville
2007-03-16 21:34 ` Please pull 'upstream' " John W. Linville
2007-03-23  5:55   ` Jeff Garzik
2007-03-23 12:02     ` Dan Williams
  -- strict thread matches above, loose matches on Subject: below --
2007-05-29 18:30 Please pull 'upstream-fixes' " John W. Linville
2007-05-29 18:31 ` Please pull 'upstream' " John W. Linville
2007-05-30 14:03   ` Jeff Garzik
2007-05-08 17:39 John W. Linville
2007-05-09 22:54 ` Jeff Garzik
2007-05-07 17:51 John W. Linville
2007-05-07 21:15 ` Dan Williams
2007-05-07 21:15   ` Dan Williams
2007-05-07 22:51   ` John W. Linville
2007-05-07 22:51     ` John W. Linville
2007-05-08  8:49   ` Johannes Berg
2007-05-08  8:49     ` Johannes Berg
2007-05-07 23:09 ` Jeff Garzik
2007-05-07 23:09   ` Jeff Garzik
2007-05-07 23:30   ` Michael Wu
2007-05-07 23:30     ` Michael Wu
2007-05-07 23:38   ` John W. Linville
2007-05-08 17:38 ` John W. Linville
2007-05-08 17:38   ` John W. Linville
2007-03-27 18:26 Please pull 'upstream-fixes' " John W. Linville
2007-03-27 18:26 ` Please pull 'upstream' " John W. Linville
2007-03-29 12:31   ` Jeff Garzik
2007-03-08  3:30 Please pull 'upstream-fixes' " John W. Linville
2007-03-08  3:32 ` Please pull 'upstream' " John W. Linville
2007-03-09 16:59   ` Jeff Garzik
2007-02-27 20:50 Please pull 'upstream-fixes' " John W. Linville
2007-02-27 20:51 ` Please pull 'upstream' " John W. Linville
2007-03-03  0:42   ` Jeff Garzik
2007-02-02 21:27 Please pull "upstream-fixes" " John W. Linville
2007-02-02 21:28 ` Please pull "upstream" " John W. Linville
2007-02-07  0:06 ` Please pull "upstream-fixes" " Jeff Garzik
2007-02-07 21:11   ` Please pull "upstream" " John W. Linville
2007-02-07 21:11     ` John W. Linville
2007-02-09 20:13     ` John W. Linville
2007-02-09 20:13       ` John W. Linville
2007-02-09 21:12       ` Jeff Garzik
2007-02-09 21:12         ` Jeff Garzik
2007-01-18 15:48 Please pull 'upstream-fixes' " John W. Linville
2007-01-18 15:49 ` Please pull 'upstream' " John W. Linville
2007-01-19  3:10   ` Jeff Garzik
2007-01-19  8:42     ` John W. Linville
2007-01-23  5:36   ` Jeff Garzik
2007-01-03  2:41 Please pull 'upstream-fixes' " John W. Linville
2007-01-03  2:42 ` Please pull 'upstream' " John W. Linville
2007-01-18 12:16   ` John W. Linville
2006-12-21  3:03 Please pull 'upstream-fixes' " John W. Linville
2006-12-21  3:05 ` Please pull 'upstream' " John W. Linville
2006-12-26 21:39   ` Jeff Garzik
2006-12-28  0:10     ` John W. Linville
2007-01-03  2:04       ` John W. Linville
2006-12-12  0:21 John W. Linville
2006-12-06  1:42 John W. Linville
2006-12-07 10:03 ` Jeff Garzik
2006-11-15  1:29 Please pull 'upstream-fixes' " John W. Linville
2006-11-15  1:31 ` Please pull 'upstream' " John W. Linville
2006-11-28 19:13   ` John W. Linville
2006-11-08  4:58 Please pull 'upstream-fixes' " John W. Linville
2006-11-08  4:59 ` Please pull 'upstream' " John W. Linville
2006-11-08 19:48   ` John W. Linville
2006-11-14 15:29   ` Jeff Garzik
2006-10-17 21:34 Please pull 'upstream-fixes' " John W. Linville
2006-10-17 21:35 ` Please pull 'upstream' " John W. Linville
2006-10-21 18:22   ` Jeff Garzik
2006-09-11 23:58 Please pull 'upstream-fixes' " John W. Linville
2006-09-11 23:59 ` Please pull 'upstream' " John W. Linville
2006-09-12 15:43   ` Jeff Garzik
2006-09-12 19:49   ` Michael Buesch
2006-08-30 15:05 John W. Linville
2006-09-06 15:02 ` Jeff Garzik
2006-08-14 20:50 John W. Linville
2006-07-28  0:22 Please pull 'upstream-fixes' " John W. Linville
2006-07-28  0:23 ` Please pull 'upstream' " John W. Linville
2006-07-29  4:33   ` Jeff Garzik
2006-07-10 21:29 Please pull 'upstream-fixes' " John W. Linville
2006-07-10 21:31 ` Please pull 'upstream' " John W. Linville
2006-07-10 21:38   ` Michael Buesch
2006-07-10 21:58     ` Larry Finger
2006-07-19 17:51   ` Jeff Garzik
2006-06-26 21:25 John W. Linville
2006-06-27  2:06 ` Jeff Garzik
2006-06-27  2:27   ` Larry Finger
2006-06-27  3:50     ` Jeff Garzik
2006-06-27 13:30     ` Michael Buesch
2006-06-27 14:11       ` Jeff Garzik
2006-06-27 14:34         ` Larry Finger
2006-06-27 14:36         ` Michael Buesch
2006-06-27 16:10           ` Jeff Garzik
2006-06-27 16:23             ` Michael Buesch
2006-06-27 15:25         ` Michael Buesch
2006-06-27 16:12           ` Jeff Garzik
2006-06-27 16:31             ` Michael Buesch
2006-06-27 19:33               ` John W. Linville
2006-06-27 19:47                 ` Michael Buesch
2006-06-27 20:06                   ` Larry Finger
2006-06-27 20:23                     ` Michael Buesch
2006-06-27 20:37                       ` Larry Finger
2006-06-28 14:34                         ` Michael Buesch
2006-06-28 16:04                           ` Larry Finger
2006-06-28 16:32                             ` Michael Buesch
2006-06-28 17:32                               ` Larry Finger
2006-06-28 18:02                                 ` Michael Buesch
2006-06-27 16:52             ` Joseph Jezak
2006-06-15 20:03 John W. Linville
2006-06-20  8:46 ` Jeff Garzik
2006-06-05 21:53 Please pull 'upstream-fixes' " John W. Linville
2006-06-05 21:55 ` Please pull 'upstream' " John W. Linville
2006-06-08 19:48   ` Jeff Garzik
2006-05-22 19:18 Please pull 'upstream-fixes' " John W. Linville
2006-05-22 19:19 ` Please pull 'upstream' " John W. Linville
2006-05-24  4:35   ` Jeff Garzik
2006-05-24 12:42     ` John W. Linville
2006-05-17 19:34 Please pull 'upstream-fixes' " John W. Linville
2006-05-17 19:38 ` Please pull 'upstream' " John W. Linville
2006-05-17 21:23   ` Daniel Drake
2006-05-18 17:28     ` John W. Linville
2006-05-18 18:26       ` Daniel Drake
2006-05-06  1:06 Please pull upstream-fixes " John W. Linville
2006-05-06  1:09 ` Please pull upstream " John W. Linville
2006-04-24 19:40 Please pull 'upstream-fixes' " John W. Linville
2006-04-24 20:40 ` Please pull 'upstream' " John W. Linville
2006-04-25  0:33   ` Dan Williams
2006-04-25 11:30     ` Johannes Berg
2006-04-25 12:03       ` Dan Williams
2006-04-26 10:18   ` Jeff Garzik

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.