Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorDavid S. Miller <davem@davemloft.net>
Mon, 10 Nov 2008 21:24:44 +0000 (13:24 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 10 Nov 2008 21:24:44 +0000 (13:24 -0800)
134 files changed:
drivers/net/ps3_gelic_wireless.c
drivers/net/ps3_gelic_wireless.h
drivers/net/wireless/Makefile
drivers/net/wireless/adm8211.c
drivers/net/wireless/adm8211.h
drivers/net/wireless/airo.c
drivers/net/wireless/airport.c [deleted file]
drivers/net/wireless/ath5k/ath5k.h
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/pcu.c
drivers/net/wireless/ath5k/reg.h
drivers/net/wireless/ath9k/Makefile
drivers/net/wireless/ath9k/ani.c [new file with mode: 0644]
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/beacon.c
drivers/net/wireless/ath9k/calib.c [new file with mode: 0644]
drivers/net/wireless/ath9k/core.c
drivers/net/wireless/ath9k/core.h
drivers/net/wireless/ath9k/eeprom.c [new file with mode: 0644]
drivers/net/wireless/ath9k/hw.c
drivers/net/wireless/ath9k/hw.h
drivers/net/wireless/ath9k/mac.c [new file with mode: 0644]
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/phy.c
drivers/net/wireless/ath9k/rc.c
drivers/net/wireless/ath9k/recv.c
drivers/net/wireless/ath9k/xmit.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/hermes.c [deleted file]
drivers/net/wireless/hermes.h [deleted file]
drivers/net/wireless/hermes_dld.c [deleted file]
drivers/net/wireless/hermes_dld.h [deleted file]
drivers/net/wireless/hermes_rid.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/persistcfg.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/scan.h
drivers/net/wireless/libertas/types.h
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/libertas_tf/if_usb.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/orinoco.c [deleted file]
drivers/net/wireless/orinoco.h [deleted file]
drivers/net/wireless/orinoco/Makefile [new file with mode: 0644]
drivers/net/wireless/orinoco/airport.c [new file with mode: 0644]
drivers/net/wireless/orinoco/hermes.c [new file with mode: 0644]
drivers/net/wireless/orinoco/hermes.h [new file with mode: 0644]
drivers/net/wireless/orinoco/hermes_dld.c [new file with mode: 0644]
drivers/net/wireless/orinoco/hermes_dld.h [new file with mode: 0644]
drivers/net/wireless/orinoco/hermes_rid.h [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco.c [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco.h [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_cs.c [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_nortel.c [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_pci.c [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_pci.h [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_plx.c [new file with mode: 0644]
drivers/net/wireless/orinoco/orinoco_tmd.c [new file with mode: 0644]
drivers/net/wireless/orinoco/spectrum_cs.c [new file with mode: 0644]
drivers/net/wireless/orinoco_cs.c [deleted file]
drivers/net/wireless/orinoco_nortel.c [deleted file]
drivers/net/wireless/orinoco_pci.c [deleted file]
drivers/net/wireless/orinoco_pci.h [deleted file]
drivers/net/wireless/orinoco_plx.c [deleted file]
drivers/net/wireless/orinoco_tmd.c [deleted file]
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54common.h
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2400pci.h
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500pci.h
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2500usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00debug.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt61pci.h
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rt2x00/rt73usb.h
drivers/net/wireless/rtl8187_dev.c
drivers/net/wireless/rtl8187_rtl8225.c
drivers/net/wireless/spectrum_cs.c [deleted file]
drivers/net/wireless/wl3501.h
drivers/net/wireless/zd1201.c
include/linux/ieee80211.h
include/linux/nl80211.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/wireless.h
net/ieee80211/ieee80211_wx.c
net/mac80211/cfg.c
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/scan.c
net/mac80211/tx.c
net/mac80211/wext.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/util.c

index d10dc3ea9c79814ca36765aa798d57a8731a4a80..ec2314246682af0946bbe97475b3947670401383 100644 (file)
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include <linux/dma-mapping.h>
 #include <net/checksum.h>
@@ -449,9 +450,9 @@ static size_t gelic_wl_synthesize_ie(u8 *buf,
 
        /* element id */
        if (rsn)
-               *buf++ = MFIE_TYPE_RSN;
+               *buf++ = WLAN_EID_RSN;
        else
-               *buf++ = MFIE_TYPE_GENERIC;
+               *buf++ = WLAN_EID_GENERIC;
 
        /* length filed; set later */
        buf++;
@@ -539,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
                        break;
 
                switch (item_id) {
-               case MFIE_TYPE_GENERIC:
+               case WLAN_EID_GENERIC:
                        if ((OUI_LEN + 1 <= item_len) &&
                            !memcmp(pos, wpa_oui, OUI_LEN) &&
                            pos[OUI_LEN] == 0x01) {
@@ -547,7 +548,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
                                ie_info->wpa.len = item_len + 2;
                        }
                        break;
-               case MFIE_TYPE_RSN:
+               case WLAN_EID_RSN:
                        ie_info->rsn.data = pos - 2;
                        /* length includes the header */
                        ie_info->rsn.len = item_len + 2;
@@ -581,7 +582,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev,
        char *tmp;
        u8 rate;
        unsigned int i, j, len;
-       u8 buf[MAX_WPA_IE_LEN];
+       u8 buf[64]; /* arbitrary size large enough */
 
        pr_debug("%s: <-\n", __func__);
 
@@ -1734,14 +1735,14 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
                target->essid_len = strnlen(scan_info->essid,
                                            sizeof(scan_info->essid));
                target->rate_len = 0;
-               for (r = 0; r < MAX_RATES_LENGTH; r++)
+               for (r = 0; r < 12; r++)
                        if (scan_info->rate[r])
                                target->rate_len++;
                if (8 < target->rate_len)
                        pr_info("%s: AP returns %d rates\n", __func__,
                                target->rate_len);
                target->rate_ext_len = 0;
-               for (r = 0; r < MAX_RATES_EX_LENGTH; r++)
+               for (r = 0; r < 16; r++)
                        if (scan_info->ext_rate[r])
                                target->rate_ext_len++;
                list_move_tail(&target->list, &wl->network_list);
index 5339e0078d180a885f53a622dddac4c4743c50ee..5b631c6c97759ec36f4d2296549f10b979a89158 100644 (file)
@@ -164,8 +164,8 @@ struct gelic_eurus_scan_info {
        __be16 security;
        u8  bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */
        u8  essid[32]; /* IW_ESSID_MAX_SIZE */
-       u8  rate[16]; /* first MAX_RATES_LENGTH(12) are valid */
-       u8  ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */
+       u8  rate[16]; /* first 12 are valid */
+       u8  ext_rate[16]; /* first 16 are valid */
        __be32 reserved1;
        __be32 reserved2;
        __be32 reserved3;
index 59d2d805f60b4591b1332944b51ac7cf380b5006..78820840fe21285b54d5d9ca5ed03e8168b0071a 100644 (file)
@@ -16,14 +16,7 @@ obj-$(CONFIG_WAVELAN)                += wavelan.o
 obj-$(CONFIG_PCMCIA_NETWAVE)   += netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)   += wavelan_cs.o
 
-obj-$(CONFIG_HERMES)           += orinoco.o hermes.o hermes_dld.o
-obj-$(CONFIG_PCMCIA_HERMES)    += orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT)    += airport.o
-obj-$(CONFIG_PLX_HERMES)       += orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES)       += orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES)       += orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES)    += orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM)  += spectrum_cs.o
+obj-$(CONFIG_HERMES)           += orinoco/
 
 obj-$(CONFIG_AIRO)             += airo.o
 obj-$(CONFIG_AIRO_CS)          += airo_cs.o airo.o
index b96ebfe4ef3e8aae192366806ea93f69c4743c13..fc0897fb22390c87d908ceefdc0a4ea05193e383 100644 (file)
@@ -1297,22 +1297,6 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
        ADM8211_CSR_WRITE(ABDA1, reg);
 }
 
-static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
-{
-       struct adm8211_priv *priv = dev->priv;
-       u8 buf[36];
-
-       if (ssid_len > 32)
-               return -EINVAL;
-
-       memset(buf, 0, sizeof(buf));
-       buf[0] = ssid_len;
-       memcpy(buf + 1, ssid, ssid_len);
-       adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
-       /* TODO: configure beacon for adhoc? */
-       return 0;
-}
-
 static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
 {
        struct adm8211_priv *priv = dev->priv;
@@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev,
                memcpy(priv->bssid, conf->bssid, ETH_ALEN);
        }
 
-       if (conf->ssid_len != priv->ssid_len ||
-           memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
-               adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
-               priv->ssid_len = conf->ssid_len;
-               memcpy(priv->ssid, conf->ssid, conf->ssid_len);
-       }
-
        return 0;
 }
 
index 9b190ee26e903c291fa54aaa0c51e5153ace4d67..4f6ab1322189805660e99b0e5b3bc3acf2fba9d8 100644 (file)
@@ -553,8 +553,6 @@ struct adm8211_priv {
 
        int channel;
        u8 bssid[ETH_ALEN];
-       u8 ssid[32];
-       size_t ssid_len;
 
        u8 soft_rx_crc;
        u8 retry_limit;
index c8dc6568cec9e60f602dc2eb890ceb430f0c8ad6..67d504e32290da0519ed527f8d31ae5b2f07e133 100644 (file)
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
-#include <net/ieee80211.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
+#include <linux/ieee80211.h>
+
 #include "airo.h"
 
 #define DRV_NAME "airo"
@@ -7265,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev,
        if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
                unsigned int num_null_ies = 0;
                u16 length = sizeof (bss->extra.iep);
-               struct ieee80211_info_element *info_element =
-                       (struct ieee80211_info_element *) &bss->extra.iep;
+               u8 *ie = (void *)&bss->extra.iep;
 
-               while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
-                       if (sizeof(*info_element) + info_element->len > length) {
+               while ((length >= 2) && (num_null_ies < 2)) {
+                       if (2 + ie[1] > length) {
                                /* Invalid element, don't continue parsing IE */
                                break;
                        }
 
-                       switch (info_element->id) {
-                       case MFIE_TYPE_SSID:
+                       switch (ie[0]) {
+                       case WLAN_EID_SSID:
                                /* Two zero-length SSID elements
                                 * mean we're done parsing elements */
-                               if (!info_element->len)
+                               if (!ie[1])
                                        num_null_ies++;
                                break;
 
-                       case MFIE_TYPE_GENERIC:
-                               if (info_element->len >= 4 &&
-                                   info_element->data[0] == 0x00 &&
-                                   info_element->data[1] == 0x50 &&
-                                   info_element->data[2] == 0xf2 &&
-                                   info_element->data[3] == 0x01) {
+                       case WLAN_EID_GENERIC:
+                               if (ie[1] >= 4 &&
+                                   ie[2] == 0x00 &&
+                                   ie[3] == 0x50 &&
+                                   ie[4] == 0xf2 &&
+                                   ie[5] == 0x01) {
                                        iwe.cmd = IWEVGENIE;
-                                       iwe.u.data.length = min(info_element->len + 2,
-                                                                 MAX_WPA_IE_LEN);
+                                       /* 64 is an arbitrary cut-off */
+                                       iwe.u.data.length = min(ie[1] + 2,
+                                                               64);
                                        current_ev = iwe_stream_add_point(
                                                        info, current_ev,
-                                                       end_buf, &iwe,
-                                                       (char *) info_element);
+                                                       end_buf, &iwe, ie);
                                }
                                break;
 
-                       case MFIE_TYPE_RSN:
+                       case WLAN_EID_RSN:
                                iwe.cmd = IWEVGENIE;
-                               iwe.u.data.length = min(info_element->len + 2,
-                                                         MAX_WPA_IE_LEN);
+                               /* 64 is an arbitrary cut-off */
+                               iwe.u.data.length = min(ie[1] + 2, 64);
                                current_ev = iwe_stream_add_point(
                                        info, current_ev, end_buf,
-                                       &iwe, (char *) info_element);
+                                       &iwe, ie);
                                break;
 
                        default:
                                break;
                        }
 
-                       length -= sizeof(*info_element) + info_element->len;
-                       info_element =
-                           (struct ieee80211_info_element *)&info_element->
-                           data[info_element->len];
+                       length -= 2 + ie[1];
+                       ie += 2 + ie[1];
                }
        }
        return current_ev;
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
deleted file mode 100644 (file)
index ce03a2e..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/* airport.c
- *
- * A driver for "Hermes" chipset based Apple Airport wireless
- * card.
- *
- * Copyright notice & release notes in file orinoco.c
- * 
- * Note specific to airport stub:
- * 
- *  0.05 : first version of the new split driver
- *  0.06 : fix possible hang on powerup, add sleep support
- */
-
-#define DRIVER_NAME "airport"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/pmac_feature.h>
-
-#include "orinoco.h"
-
-#define AIRPORT_IO_LEN (0x1000)        /* one page */
-
-struct airport {
-       struct macio_dev *mdev;
-       void __iomem *vaddr;
-       int irq_requested;
-       int ndev_registered;
-};
-
-static int
-airport_suspend(struct macio_dev *mdev, pm_message_t state)
-{
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
-
-       err = orinoco_lock(priv, &flags);
-       if (err) {
-               printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
-                      dev->name);
-               return 0;
-       }
-
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
-                      dev->name, err);
-
-       netif_device_detach(dev);
-
-       priv->hw_unavailable++;
-
-       orinoco_unlock(priv, &flags);
-
-       disable_irq(dev->irq);
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
-
-       return 0;
-}
-
-static int
-airport_resume(struct macio_dev *mdev)
-{
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
-
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
-       msleep(200);
-
-       enable_irq(dev->irq);
-
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
-                      dev->name, err);
-               return 0;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       netif_device_attach(dev);
-
-       priv->hw_unavailable--;
-
-       if (priv->open && (! priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
-                              dev->name, err);
-       }
-
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-static int
-airport_detach(struct macio_dev *mdev)
-{
-       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct airport *card = priv->card;
-
-       if (card->ndev_registered)
-               unregister_netdev(dev);
-       card->ndev_registered = 0;
-
-       if (card->irq_requested)
-               free_irq(dev->irq, dev);
-       card->irq_requested = 0;
-
-       if (card->vaddr)
-               iounmap(card->vaddr);
-       card->vaddr = NULL;
-
-       macio_release_resource(mdev, 0);
-
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
-       ssleep(1);
-
-       macio_set_drvdata(mdev, NULL);
-       free_orinocodev(dev);
-
-       return 0;
-}
-
-static int airport_hard_reset(struct orinoco_private *priv)
-{
-       /* It would be nice to power cycle the Airport for a real hard
-        * reset, but for some reason although it appears to
-        * re-initialize properly, it falls in a screaming heap
-        * shortly afterwards. */
-#if 0
-       struct net_device *dev = priv->ndev;
-       struct airport *card = priv->card;
-
-       /* Vitally important.  If we don't do this it seems we get an
-        * interrupt somewhere during the power cycle, since
-        * hw_unavailable is already set it doesn't get ACKed, we get
-        * into an interrupt loop and the PMU decides to turn us
-        * off. */
-       disable_irq(dev->irq);
-
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
-       ssleep(1);
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
-       ssleep(1);
-
-       enable_irq(dev->irq);
-       ssleep(1);
-#endif
-
-       return 0;
-}
-
-static int
-airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
-{
-       struct orinoco_private *priv;
-       struct net_device *dev;
-       struct airport *card;
-       unsigned long phys_addr;
-       hermes_t *hw;
-
-       if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
-               printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
-               return -ENODEV;
-       }
-
-       /* Allocate space for private device-specific data */
-       dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
-                              airport_hard_reset, NULL);
-       if (! dev) {
-               printk(KERN_ERR PFX "Cannot allocate network device\n");
-               return -ENODEV;
-       }
-       priv = netdev_priv(dev);
-       card = priv->card;
-
-       hw = &priv->hw;
-       card->mdev = mdev;
-
-       if (macio_request_resource(mdev, 0, "airport")) {
-               printk(KERN_ERR PFX "can't request IO resource !\n");
-               free_orinocodev(dev);
-               return -EBUSY;
-       }
-
-       SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
-       macio_set_drvdata(mdev, dev);
-
-       /* Setup interrupts & base address */
-       dev->irq = macio_irq(mdev, 0);
-       phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
-       printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
-       dev->base_addr = phys_addr;
-       card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
-       if (!card->vaddr) {
-               printk(KERN_ERR PFX "ioremap() failed\n");
-               goto failed;
-       }
-
-       hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
-               
-       /* Power up card */
-       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
-       ssleep(1);
-
-       /* Reset it before we get the interrupt */
-       hermes_init(hw);
-
-       if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
-               printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
-               goto failed;
-       }
-       card->irq_requested = 1;
-
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
-               goto failed;
-       }
-       printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
-       card->ndev_registered = 1;
-       return 0;
- failed:
-       airport_detach(mdev);
-       return -ENODEV;
-}                              /* airport_attach */
-
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static struct of_device_id airport_match[] = 
-{
-       {
-       .name           = "radio",
-       },
-       {},
-};
-
-MODULE_DEVICE_TABLE (of, airport_match);
-
-static struct macio_driver airport_driver = 
-{
-       .name           = DRIVER_NAME,
-       .match_table    = airport_match,
-       .probe          = airport_attach,
-       .remove         = airport_detach,
-       .suspend        = airport_suspend,
-       .resume         = airport_resume,
-};
-
-static int __init
-init_airport(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-
-       return macio_register_driver(&airport_driver);
-}
-
-static void __exit
-exit_airport(void)
-{
-       return macio_unregister_driver(&airport_driver);
-}
-
-module_init(init_airport);
-module_exit(exit_airport);
index b11792039911a2738d36c55d2b65eeb3de1e2027..a725bb94a52d51f4118a58d58f01445e06370b59 100644 (file)
@@ -1093,10 +1093,11 @@ struct ath5k_hw {
 
        u8                      ah_sta_id[ETH_ALEN];
 
-       /* Current BSSID we are trying to assoc to / creating.
+       /* Current BSSID we are trying to assoc to / create.
         * This is passed by mac80211 on config_interface() and cached here for
         * use in resets */
        u8                      ah_bssid[ETH_ALEN];
+       u8                      ah_bssid_mask[ETH_ALEN];
 
        u32                     ah_gpio[AR5K_MAX_GPIO];
        int                     ah_gpio_npins;
index 6f368e8cdf17766bf5fee052a6070157dad27c56..c7ffcbb9062deb1ab80976866477e7abad69f1b1 100644 (file)
@@ -60,6 +60,9 @@
 #include "debug.h"
 
 static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
 
 /******************\
@@ -2975,12 +2978,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        struct ath5k_softc *sc = hw->priv;
        int ret = 0;
 
+       if (modparam_nohwcrypt)
+               return -EOPNOTSUPP;
+
        switch (key->alg) {
        case ALG_WEP:
-       /* XXX: fix hardware encryption, its not working. For now
-        * allow software encryption */
-               /* break; */
        case ALG_TKIP:
+               break;
        case ALG_CCMP:
                return -EOPNOTSUPP;
        default:
@@ -2999,6 +3003,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                }
                __set_bit(key->keyidx, sc->keymap);
                key->hw_key_idx = key->keyidx;
+               key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV |
+                              IEEE80211_KEY_FLAG_GENERATE_MMIC);
                break;
        case DISABLE_KEY:
                ath5k_hw_reset_key(sc->ah, key->keyidx);
index a47df9a24aa126783497eeb296edad22aa150d0e..d7f0c1017bda55a86a18acbb1384ebee34377eb5 100644 (file)
@@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
 {
        u32 pcu_reg, beacon_reg, low_id, high_id;
 
-       pcu_reg = 0;
+
+       /* Preserve rest settings */
+       pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+       pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+                       | AR5K_STA_ID1_KEYSRCH_MODE
+                       | (ah->ah_version == AR5K_AR5210 ?
+                       (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
        beacon_reg = 0;
 
        ATH5K_TRACE(ah->ah_sc);
 
        switch (ah->ah_op_mode) {
        case NL80211_IFTYPE_ADHOC:
-               pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
-                       (ah->ah_version == AR5K_AR5210 ?
-                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
                beacon_reg |= AR5K_BCR_ADHOC;
+               if (ah->ah_version == AR5K_AR5210)
+                       pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+               else
+                       AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
                break;
 
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
-               pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
-                       (ah->ah_version == AR5K_AR5210 ?
-                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE;
                beacon_reg |= AR5K_BCR_AP;
+               if (ah->ah_version == AR5K_AR5210)
+                       pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
+               else
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
                break;
 
        case NL80211_IFTYPE_STATION:
-               pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-                       (ah->ah_version == AR5K_AR5210 ?
+               pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+                       (ah->ah_version == AR5K_AR5210 ?
                                AR5K_STA_ID1_PWR_SV : 0);
        case NL80211_IFTYPE_MONITOR:
-               pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
-                       (ah->ah_version == AR5K_AR5210 ?
+               pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+                       (ah->ah_version == AR5K_AR5210 ?
                                AR5K_STA_ID1_NO_PSPOLL : 0);
                break;
 
@@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
                ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
                ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
        }
+
+       /* TODO: Handle ANI stats */
 }
 
 /**
@@ -254,6 +267,10 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
  * @mac: The card's mac address
  *
  * Set station id on hw using the provided mac address
+ *
+ * NOTE: This is only called during attach, don't call it
+ * on reset because it overwrites all AR5K_STA_ID1 settings.
+ * We have set_opmode (above) for reset.
  */
 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
 {
@@ -290,8 +307,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
         * Set simple BSSID mask on 5212
         */
        if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0);
-               ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1);
+               ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+                                                       AR5K_BSS_IDM0);
+               ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+                                                       AR5K_BSS_IDM1);
        }
 
        /*
@@ -415,6 +434,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
        u32 low_id, high_id;
        ATH5K_TRACE(ah->ah_sc);
 
+       /* Cache bssid mask so that we can restore it
+        * on reset */
+       memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
        if (ah->ah_version == AR5K_AR5212) {
                low_id = AR5K_LOW_ID(mask);
                high_id = AR5K_HIGH_ID(mask);
@@ -576,7 +598,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
                filter |= AR5K_RX_FILTER_PROM;
        }
 
-       /*Zero length DMA*/
+       /*Zero length DMA (phy error reporting) */
        if (data)
                AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
        else
@@ -661,7 +683,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
         * Set the additional timers by mode
         */
        switch (ah->ah_op_mode) {
+       case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_STATION:
+               /* In STA mode timer1 is used as next wakeup
+                * timer and timer2 as next CFP duration start
+                * timer. Both in 1/8TUs. */
+               /* TODO: PCF handling */
                if (ah->ah_version == AR5K_AR5210) {
                        timer1 = 0xffffffff;
                        timer2 = 0xffffffff;
@@ -669,27 +696,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
                        timer1 = 0x0000ffff;
                        timer2 = 0x0007ffff;
                }
+               /* Mark associated AP as PCF incapable for now */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF);
                break;
-
+       case NL80211_IFTYPE_ADHOC:
+               AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM);
        default:
+               /* On non-STA modes timer1 is used as next DMA
+                * beacon alert (DBA) timer and timer2 as next
+                * software beacon alert. Both in 1/8TUs. */
                timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
                timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+               break;
        }
 
+       /* Timer3 marks the end of our ATIM window
+        * a zero length window is not allowed because
+        * we 'll get no beacons */
        timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
 
        /*
         * Set the beacon register and enable all timers.
-        * (next beacon, DMA beacon, software beacon, ATIM window time)
         */
-       ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+       /* When in AP mode zero timer0 to start TSF */
+       if (ah->ah_op_mode == NL80211_IFTYPE_AP)
+               ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+       else
+               ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
        ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
        ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
        ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
 
+       /* Force a TSF reset if requested and enable beacons */
+       if (interval & AR5K_BEACON_RESET_TSF)
+               ath5k_hw_reset_tsf(ah);
+
        ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
-                       AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
-               AR5K_BEACON);
+                                       AR5K_BEACON_ENABLE),
+                                               AR5K_BEACON);
+
+       /* Flush any pending BMISS interrupts on ISR by
+        * performing a clear-on-write operation on PISR
+        * register for the BMISS bit (writing a bit on
+        * ISR togles a reset for that bit and leaves
+        * the rest bits intact) */
+       if (ah->ah_version == AR5K_AR5210)
+               ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR);
+       else
+               ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR);
+
+       /* TODO: Set enchanced sleep registers on AR5212
+        * based on vif->bss_conf params, until then
+        * disable power save reporting.*/
+       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV);
+
 }
 
 #if 0
@@ -899,14 +959,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
  */
 int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
 {
-       unsigned int i;
+       unsigned int i, type;
+       u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
 
        ATH5K_TRACE(ah->ah_sc);
        AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
 
+       type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
        for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
                ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
 
+       /* Reset associated MIC entry if TKIP
+        * is enabled located at offset (entry + 64) */
+       if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+               AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE);
+               for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+                       ath5k_hw_reg_write(ah, 0,
+                               AR5K_KEYTABLE_OFF(micentry, i));
+       }
+
        /*
         * Set NULL encryption on AR5212+
         *
@@ -916,10 +988,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
         * Note2: Windows driver (ndiswrapper) sets this to
         *        0x00000714 instead of 0x00000007
         */
-       if (ah->ah_version > AR5K_AR5211)
+       if (ah->ah_version > AR5K_AR5211) {
                ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
                                AR5K_KEYTABLE_TYPE(entry));
 
+               if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+                       ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+                               AR5K_KEYTABLE_TYPE(micentry));
+               }
+       }
+
        return 0;
 }
 
@@ -943,17 +1021,29 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
                const struct ieee80211_key_conf *key, const u8 *mac)
 {
        unsigned int i;
+       int keylen;
        __le32 key_v[5] = {};
+       __le32 key0 = 0, key1 = 0;
+       __le32 *rxmic, *txmic;
        u32 keytype;
+       u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+       bool is_tkip;
 
        ATH5K_TRACE(ah->ah_sc);
 
-       /* key->keylen comes in from mac80211 in bytes */
+       is_tkip = (key->alg == ALG_TKIP);
+
+       /*
+        * key->keylen comes in from mac80211 in bytes.
+        * TKIP is 128 bit + 128 bit mic
+        */
+       keylen = (is_tkip) ? (128 / 8) : key->keylen;
 
-       if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+       if (entry > AR5K_KEYTABLE_SIZE ||
+               (is_tkip && micentry > AR5K_KEYTABLE_SIZE))
                return -EOPNOTSUPP;
 
-       switch (key->keylen) {
+       switch (keylen) {
        /* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
        case 40 / 8:
                memcpy(&key_v[0], key->key, 5);
@@ -967,24 +1057,66 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
                memcpy(&key_v[4], &key->key[12], 1);
                keytype = AR5K_KEYTABLE_TYPE_104;
                break;
-       /* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
+       /* WEP/TKIP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
        case 128 / 8:
                memcpy(&key_v[0], &key->key[0], 6);
                memcpy(&key_v[2], &key->key[6], 6);
                memcpy(&key_v[4], &key->key[12], 4);
-               keytype = AR5K_KEYTABLE_TYPE_128;
+               keytype = is_tkip ?
+                       AR5K_KEYTABLE_TYPE_TKIP :
+                       AR5K_KEYTABLE_TYPE_128;
                break;
 
        default:
                return -EINVAL; /* shouldn't happen */
        }
 
+       /* intentionally corrupt key until mic is installed */
+       if (is_tkip) {
+               key0 = key_v[0] = ~key_v[0];
+               key1 = key_v[1] = ~key_v[1];
+       }
+
        for (i = 0; i < ARRAY_SIZE(key_v); i++)
                ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
                                AR5K_KEYTABLE_OFF(entry, i));
 
        ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
 
+       if (is_tkip) {
+               /* Install rx/tx MIC */
+               rxmic = (__le32 *) &key->key[16];
+               txmic = (__le32 *) &key->key[24];
+#if 0
+               /* MISC_MODE register & 0x04 - for mac srev >= griffin */
+               key_v[0] = rxmic[0];
+               key_v[1] = (txmic[0] >> 16) & 0xffff;
+               key_v[2] = rxmic[1];
+               key_v[3] = txmic[0] & 0xffff;
+               key_v[4] = txmic[1];
+#else
+               key_v[0] = rxmic[0];
+               key_v[1] = 0;
+               key_v[2] = rxmic[1];
+               key_v[3] = 0;
+               key_v[4] = 0;
+#endif
+               for (i = 0; i < ARRAY_SIZE(key_v); i++)
+                       ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+                               AR5K_KEYTABLE_OFF(micentry, i));
+
+               ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+                       AR5K_KEYTABLE_TYPE(micentry));
+               ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry));
+               ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry));
+
+               /* restore first 2 words of key */
+               ath5k_hw_reg_write(ah, le32_to_cpu(~key0),
+                       AR5K_KEYTABLE_OFF(entry, 0));
+               ath5k_hw_reg_write(ah, le32_to_cpu(~key1),
+                       AR5K_KEYTABLE_OFF(entry, 1));
+       }
+
        return ath5k_hw_set_key_lladdr(ah, entry, mac);
 }
 
index 0dae54d00f03bc85bbe06686475041f568d251b2..69755fc2f9bee78ab78489bec6cd1ceb782ef914 100644 (file)
 #define AR5K_PCU_MAX   0x8fff
 
 /*
- * First station id register (MAC address in lower 32 bits)
+ * First station id register (Lower 32 bits of MAC address)
  */
-#define AR5K_STA_ID0   0x8000
+#define AR5K_STA_ID0           0x8000
+#define        AR5K_STA_ID0_ARRD_L32   0xffffffff
 
 /*
- * Second station id register (MAC address in upper 16 bits)
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
  */
 #define AR5K_STA_ID1                   0x8004                  /* Register Address */
+#define        AR5K_STA_ID1_ADDR_U16           0x0000ffff      /* Upper 16 bits of MAC addres */
 #define AR5K_STA_ID1_AP                        0x00010000      /* Set AP mode */
 #define AR5K_STA_ID1_ADHOC             0x00020000      /* Set Ad-Hoc mode */
 #define AR5K_STA_ID1_PWR_SV            0x00040000      /* Power save reporting */
 #define AR5K_KEYTABLE_MAC1(_n)         AR5K_KEYTABLE_OFF(_n, 7)
 #define AR5K_KEYTABLE_VALID            0x00008000
 
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define        AR5K_KEYTABLE_MIC_OFFSET        64
+
 /* WEP 40-bit  = 40-bit  entered key + 24 bit IV = 64-bit
  * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit
  * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit
index a6411517e5f849f79c9e49180783ca11264ba4e5..c58cfdeb49c9ac65d74ac7f8306b480b25628e89 100644 (file)
@@ -1,4 +1,8 @@
 ath9k-y +=     hw.o \
+               eeprom.o \
+               mac.o \
+               calib.o \
+               ani.o \
                phy.o \
                regd.o \
                beacon.o \
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c
new file mode 100644 (file)
index 0000000..ada12e9
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+                                       struct ath9k_channel *chan)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+               if (ahp->ah_ani[i].c.channel == chan->channel)
+                       return i;
+               if (ahp->ah_ani[i].c.channel == 0) {
+                       ahp->ah_ani[i].c.channel = chan->channel;
+                       ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+                       return i;
+               }
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+               "No more channel states left. Using channel 0\n");
+
+       return 0;
+}
+
+static bool ath9k_hw_ani_control(struct ath_hal *ah,
+                                enum ath9k_ani_cmd cmd, int param)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState = ahp->ah_curani;
+
+       switch (cmd & ahp->ah_ani_function) {
+       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                               "%s: level out of range (%u > %u)\n",
+                               __func__, level,
+                               (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired));
+                       return false;
+               }
+
+               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+                             AR_PHY_DESIRED_SZ_TOT_DES,
+                             ahp->ah_totalSizeDesired[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+                             AR_PHY_AGC_CTL1_COARSE_LOW,
+                             ahp->ah_coarseLow[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+                             AR_PHY_AGC_CTL1_COARSE_HIGH,
+                             ahp->ah_coarseHigh[level]);
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRPWR,
+                             ahp->ah_firpwr[level]);
+
+               if (level > aniState->noiseImmunityLevel)
+                       ahp->ah_stats.ast_ani_niup++;
+               else if (level < aniState->noiseImmunityLevel)
+                       ahp->ah_stats.ast_ani_nidown++;
+               aniState->noiseImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+               const int m1ThreshLow[] = { 127, 50 };
+               const int m2ThreshLow[] = { 127, 40 };
+               const int m1Thresh[] = { 127, 0x4d };
+               const int m2Thresh[] = { 127, 0x40 };
+               const int m2CountThr[] = { 31, 16 };
+               const int m2CountThrLow[] = { 63, 48 };
+               u32 on = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+                             m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+                             m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M1_THRESH,
+                             m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2_THRESH,
+                             m2Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2COUNT_THR,
+                             m2CountThr[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+                             m2CountThrLow[on]);
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+                             m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+                             m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH,
+                             m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH,
+                             m2Thresh[on]);
+
+               if (on)
+                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+               else
+                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+               if (!on != aniState->ofdmWeakSigDetectOff) {
+                       if (on)
+                               ahp->ah_stats.ast_ani_ofdmon++;
+                       else
+                               ahp->ah_stats.ast_ani_ofdmoff++;
+                       aniState->ofdmWeakSigDetectOff = !on;
+               }
+               break;
+       }
+       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+               const int weakSigThrCck[] = { 8, 6 };
+               u32 high = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+                             weakSigThrCck[high]);
+               if (high != aniState->cckWeakSigThreshold) {
+                       if (high)
+                               ahp->ah_stats.ast_ani_cckhigh++;
+                       else
+                               ahp->ah_stats.ast_ani_ccklow++;
+                       aniState->cckWeakSigThreshold = high;
+               }
+               break;
+       }
+       case ATH9K_ANI_FIRSTEP_LEVEL:{
+               const int firstep[] = { 0, 4, 8 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(firstep)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                               "%s: level out of range (%u > %u)\n",
+                               __func__, level,
+                               (unsigned) ARRAY_SIZE(firstep));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRSTEP,
+                             firstep[level]);
+               if (level > aniState->firstepLevel)
+                       ahp->ah_stats.ast_ani_stepup++;
+               else if (level < aniState->firstepLevel)
+                       ahp->ah_stats.ast_ani_stepdown++;
+               aniState->firstepLevel = level;
+               break;
+       }
+       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+               const int cycpwrThr1[] =
+                       { 2, 4, 6, 8, 10, 12, 14, 16 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(cycpwrThr1)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                               "%s: level out of range (%u > %u)\n",
+                               __func__, level,
+                               (unsigned)
+                               ARRAY_SIZE(cycpwrThr1));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+                             AR_PHY_TIMING5_CYCPWR_THR1,
+                             cycpwrThr1[level]);
+               if (level > aniState->spurImmunityLevel)
+                       ahp->ah_stats.ast_ani_spurup++;
+               else if (level < aniState->spurImmunityLevel)
+                       ahp->ah_stats.ast_ani_spurdown++;
+               aniState->spurImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_PRESENT:
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                       "%s: invalid cmd %u\n", __func__, cmd);
+               return false;
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+               "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+               "ofdmWeakSigDetectOff=%d\n",
+               aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
+               !aniState->ofdmWeakSigDetectOff);
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+               "cckWeakSigThreshold=%d, "
+               "firstepLevel=%d, listenTime=%d\n",
+               aniState->cckWeakSigThreshold, aniState->firstepLevel,
+               aniState->listenTime);
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+               aniState->cycleCount, aniState->ofdmPhyErrCount,
+               aniState->cckPhyErrCount);
+
+       return true;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+                                    struct ath9k_mib_stats *stats)
+{
+       stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+       stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+       stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+       stats->rts_good += REG_READ(ah, AR_RTS_OK);
+       stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_ani_restart(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState;
+
+       if (!DO_ANI(ah))
+               return;
+
+       aniState = ahp->ah_curani;
+
+       aniState->listenTime = 0;
+       if (ahp->ah_hasHwPhyCounters) {
+               if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+                       aniState->ofdmPhyErrBase = 0;
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                               "OFDM Trigger is too high for hw counters\n");
+               } else {
+                       aniState->ofdmPhyErrBase =
+                               AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+               }
+               if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+                       aniState->cckPhyErrBase = 0;
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                               "CCK Trigger is too high for hw counters\n");
+               } else {
+                       aniState->cckPhyErrBase =
+                               AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+               }
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                       "%s: Writing ofdmbase=%u   cckbase=%u\n",
+                       __func__, aniState->ofdmPhyErrBase,
+                       aniState->cckPhyErrBase);
+               REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+               REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+               REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+               REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+               ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+       }
+       aniState->ofdmPhyErrCount = 0;
+       aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_channel *chan = ah->ah_curchan;
+       struct ar5416AniState *aniState;
+       enum wireless_mode mode;
+       int32_t rssi;
+
+       if (!DO_ANI(ah))
+               return;
+
+       aniState = ahp->ah_curani;
+
+       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+                                        aniState->noiseImmunityLevel + 1)) {
+                       return;
+               }
+       }
+
+       if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
+               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+                                        aniState->spurImmunityLevel + 1)) {
+                       return;
+               }
+       }
+
+       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                            aniState->firstepLevel + 1);
+               }
+               return;
+       }
+       rssi = BEACON_RSSI(ahp);
+       if (rssi > aniState->rssiThrHigh) {
+               if (!aniState->ofdmWeakSigDetectOff) {
+                       if (ath9k_hw_ani_control(ah,
+                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                        false)) {
+                               ath9k_hw_ani_control(ah,
+                                       ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+                               return;
+                       }
+               }
+               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                            aniState->firstepLevel + 1);
+                       return;
+               }
+       } else if (rssi > aniState->rssiThrLow) {
+               if (aniState->ofdmWeakSigDetectOff)
+                       ath9k_hw_ani_control(ah,
+                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    true);
+               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                            aniState->firstepLevel + 1);
+               return;
+       } else {
+               mode = ath9k_hw_chan2wmode(ah, chan);
+               if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+                       if (!aniState->ofdmWeakSigDetectOff)
+                               ath9k_hw_ani_control(ah,
+                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    false);
+                       if (aniState->firstepLevel > 0)
+                               ath9k_hw_ani_control(ah,
+                                            ATH9K_ANI_FIRSTEP_LEVEL, 0);
+                       return;
+               }
+       }
+}
+
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_channel *chan = ah->ah_curchan;
+       struct ar5416AniState *aniState;
+       enum wireless_mode mode;
+       int32_t rssi;
+
+       if (!DO_ANI(ah))
+               return;
+
+       aniState = ahp->ah_curani;
+       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+                                        aniState->noiseImmunityLevel + 1)) {
+                       return;
+               }
+       }
+       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                            aniState->firstepLevel + 1);
+               }
+               return;
+       }
+       rssi = BEACON_RSSI(ahp);
+       if (rssi > aniState->rssiThrLow) {
+               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                            aniState->firstepLevel + 1);
+       } else {
+               mode = ath9k_hw_chan2wmode(ah, chan);
+               if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+                       if (aniState->firstepLevel > 0)
+                               ath9k_hw_ani_control(ah,
+                                            ATH9K_ANI_FIRSTEP_LEVEL, 0);
+               }
+       }
+}
+
+static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState;
+       int32_t rssi;
+
+       aniState = ahp->ah_curani;
+
+       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+               if (aniState->firstepLevel > 0) {
+                       if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                                aniState->firstepLevel - 1))
+                               return;
+               }
+       } else {
+               rssi = BEACON_RSSI(ahp);
+               if (rssi > aniState->rssiThrHigh) {
+                       /* XXX: Handle me */
+               } else if (rssi > aniState->rssiThrLow) {
+                       if (aniState->ofdmWeakSigDetectOff) {
+                               if (ath9k_hw_ani_control(ah,
+                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                        true) == true)
+                                       return;
+                       }
+                       if (aniState->firstepLevel > 0) {
+                               if (ath9k_hw_ani_control(ah,
+                                        ATH9K_ANI_FIRSTEP_LEVEL,
+                                        aniState->firstepLevel - 1) == true)
+                                       return;
+                       }
+               } else {
+                       if (aniState->firstepLevel > 0) {
+                               if (ath9k_hw_ani_control(ah,
+                                        ATH9K_ANI_FIRSTEP_LEVEL,
+                                        aniState->firstepLevel - 1) == true)
+                                       return;
+                       }
+               }
+       }
+
+       if (aniState->spurImmunityLevel > 0) {
+               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+                                        aniState->spurImmunityLevel - 1))
+                       return;
+       }
+
+       if (aniState->noiseImmunityLevel > 0) {
+               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+                                    aniState->noiseImmunityLevel - 1);
+               return;
+       }
+}
+
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState;
+       u32 txFrameCount, rxFrameCount, cycleCount;
+       int32_t listenTime;
+
+       txFrameCount = REG_READ(ah, AR_TFCNT);
+       rxFrameCount = REG_READ(ah, AR_RFCNT);
+       cycleCount = REG_READ(ah, AR_CCCNT);
+
+       aniState = ahp->ah_curani;
+       if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+
+               listenTime = 0;
+               ahp->ah_stats.ast_ani_lzero++;
+       } else {
+               int32_t ccdelta = cycleCount - aniState->cycleCount;
+               int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
+               int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+               listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+       }
+       aniState->cycleCount = cycleCount;
+       aniState->txFrameCount = txFrameCount;
+       aniState->rxFrameCount = rxFrameCount;
+
+       return listenTime;
+}
+
+void ath9k_ani_reset(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState;
+       struct ath9k_channel *chan = ah->ah_curchan;
+       int index;
+
+       if (!DO_ANI(ah))
+               return;
+
+       index = ath9k_hw_get_ani_channel_idx(ah, chan);
+       aniState = &ahp->ah_ani[index];
+       ahp->ah_curani = aniState;
+
+       if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
+           && ah->ah_opmode != ATH9K_M_IBSS) {
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                       "%s: Reset ANI state opmode %u\n", __func__,
+                       ah->ah_opmode);
+               ahp->ah_stats.ast_ani_reset++;
+
+               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
+               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
+               ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    !ATH9K_ANI_USE_OFDM_WEAK_SIG);
+               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+                                    ATH9K_ANI_CCK_WEAK_SIG_THR);
+
+               ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+                                    ATH9K_RX_FILTER_PHYERR);
+
+               if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+                       ahp->ah_curani->ofdmTrigHigh =
+                               ah->ah_config.ofdm_trig_high;
+                       ahp->ah_curani->ofdmTrigLow =
+                               ah->ah_config.ofdm_trig_low;
+                       ahp->ah_curani->cckTrigHigh =
+                               ah->ah_config.cck_trig_high;
+                       ahp->ah_curani->cckTrigLow =
+                               ah->ah_config.cck_trig_low;
+               }
+               ath9k_ani_restart(ah);
+               return;
+       }
+
+       if (aniState->noiseImmunityLevel != 0)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+                                    aniState->noiseImmunityLevel);
+       if (aniState->spurImmunityLevel != 0)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+                                    aniState->spurImmunityLevel);
+       if (aniState->ofdmWeakSigDetectOff)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    !aniState->ofdmWeakSigDetectOff);
+       if (aniState->cckWeakSigThreshold)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+                                    aniState->cckWeakSigThreshold);
+       if (aniState->firstepLevel != 0)
+               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+                                    aniState->firstepLevel);
+       if (ahp->ah_hasHwPhyCounters) {
+               ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+                                    ~ATH9K_RX_FILTER_PHYERR);
+               ath9k_ani_restart(ah);
+               REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+               REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+       } else {
+               ath9k_ani_restart(ah);
+               ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
+                                    ATH9K_RX_FILTER_PHYERR);
+       }
+}
+
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+                         const struct ath9k_node_stats *stats,
+                         struct ath9k_channel *chan)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416AniState *aniState;
+       int32_t listenTime;
+
+       aniState = ahp->ah_curani;
+       ahp->ah_stats.ast_nodestats = *stats;
+
+       listenTime = ath9k_hw_ani_get_listen_time(ah);
+       if (listenTime < 0) {
+               ahp->ah_stats.ast_ani_lneg++;
+               ath9k_ani_restart(ah);
+               return;
+       }
+
+       aniState->listenTime += listenTime;
+
+       if (ahp->ah_hasHwPhyCounters) {
+               u32 phyCnt1, phyCnt2;
+               u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+               ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+               phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+               phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+               if (phyCnt1 < aniState->ofdmPhyErrBase ||
+                   phyCnt2 < aniState->cckPhyErrBase) {
+                       if (phyCnt1 < aniState->ofdmPhyErrBase) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                                       "%s: phyCnt1 0x%x, resetting "
+                                       "counter value to 0x%x\n",
+                                       __func__, phyCnt1,
+                                       aniState->ofdmPhyErrBase);
+                               REG_WRITE(ah, AR_PHY_ERR_1,
+                                         aniState->ofdmPhyErrBase);
+                               REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+                                         AR_PHY_ERR_OFDM_TIMING);
+                       }
+                       if (phyCnt2 < aniState->cckPhyErrBase) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                                       "%s: phyCnt2 0x%x, resetting "
+                                       "counter value to 0x%x\n",
+                                       __func__, phyCnt2,
+                                       aniState->cckPhyErrBase);
+                               REG_WRITE(ah, AR_PHY_ERR_2,
+                                         aniState->cckPhyErrBase);
+                               REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+                                         AR_PHY_ERR_CCK_TIMING);
+                       }
+                       return;
+               }
+
+               ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+               ahp->ah_stats.ast_ani_ofdmerrs +=
+                       ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+               aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+               cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+               ahp->ah_stats.ast_ani_cckerrs +=
+                       cckPhyErrCnt - aniState->cckPhyErrCount;
+               aniState->cckPhyErrCount = cckPhyErrCnt;
+       }
+
+       if (!DO_ANI(ah))
+               return;
+
+       if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+               if (aniState->ofdmPhyErrCount <= aniState->listenTime *
+                   aniState->ofdmTrigLow / 1000 &&
+                   aniState->cckPhyErrCount <= aniState->listenTime *
+                   aniState->cckTrigLow / 1000)
+                       ath9k_hw_ani_lower_immunity(ah);
+               ath9k_ani_restart(ah);
+       } else if (aniState->listenTime > ahp->ah_aniPeriod) {
+               if (aniState->ofdmPhyErrCount > aniState->listenTime *
+                   aniState->ofdmTrigHigh / 1000) {
+                       ath9k_hw_ani_ofdm_err_trigger(ah);
+                       ath9k_ani_restart(ah);
+               } else if (aniState->cckPhyErrCount >
+                          aniState->listenTime * aniState->cckTrigHigh /
+                          1000) {
+                       ath9k_hw_ani_cck_err_trigger(ah);
+                       ath9k_ani_restart(ah);
+               }
+       }
+}
+
+bool ath9k_hw_phycounters(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       return ahp->ah_hasHwPhyCounters ? true : false;
+}
+
+void ath9k_enable_mib_counters(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n");
+
+       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+       REG_WRITE(ah, AR_FILT_OFDM, 0);
+       REG_WRITE(ah, AR_FILT_CCK, 0);
+       REG_WRITE(ah, AR_MIBC,
+                 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
+                 & 0x0f);
+       REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+       REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+}
+
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
+
+       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
+
+       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+       REG_WRITE(ah, AR_FILT_OFDM, 0);
+       REG_WRITE(ah, AR_FILT_CCK, 0);
+}
+
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+                                 u32 *rxc_pcnt,
+                                 u32 *rxf_pcnt,
+                                 u32 *txf_pcnt)
+{
+       static u32 cycles, rx_clear, rx_frame, tx_frame;
+       u32 good = 1;
+
+       u32 rc = REG_READ(ah, AR_RCCNT);
+       u32 rf = REG_READ(ah, AR_RFCNT);
+       u32 tf = REG_READ(ah, AR_TFCNT);
+       u32 cc = REG_READ(ah, AR_CCCNT);
+
+       if (cycles == 0 || cycles > cc) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: cycle counter wrap. ExtBusy = 0\n",
+                       __func__);
+               good = 0;
+       } else {
+               u32 cc_d = cc - cycles;
+               u32 rc_d = rc - rx_clear;
+               u32 rf_d = rf - rx_frame;
+               u32 tf_d = tf - tx_frame;
+
+               if (cc_d != 0) {
+                       *rxc_pcnt = rc_d * 100 / cc_d;
+                       *rxf_pcnt = rf_d * 100 / cc_d;
+                       *txf_pcnt = tf_d * 100 / cc_d;
+               } else {
+                       good = 0;
+               }
+       }
+
+       cycles = cc;
+       rx_frame = rf;
+       rx_clear = rc;
+       tx_frame = tf;
+
+       return good;
+}
+
+/*
+ * Process a MIB interrupt.  We may potentially be invoked because
+ * any of the MIB counters overflow/trigger so don't assume we're
+ * here because a PHY error counter triggered.
+ */
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+                          const struct ath9k_node_stats *stats)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 phyCnt1, phyCnt2;
+
+       /* Reset these counters regardless */
+       REG_WRITE(ah, AR_FILT_OFDM, 0);
+       REG_WRITE(ah, AR_FILT_CCK, 0);
+       if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
+               REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+
+       /* Clear the mib counters and save them in the stats */
+       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+       ahp->ah_stats.ast_nodestats = *stats;
+
+       if (!DO_ANI(ah))
+               return;
+
+       /* NB: these are not reset-on-read */
+       phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+       phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+       if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
+               struct ar5416AniState *aniState = ahp->ah_curani;
+               u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+               /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
+               ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+               ahp->ah_stats.ast_ani_ofdmerrs +=
+                       ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+               aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+               cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+               ahp->ah_stats.ast_ani_cckerrs +=
+                       cckPhyErrCnt - aniState->cckPhyErrCount;
+               aniState->cckPhyErrCount = cckPhyErrCnt;
+
+               /*
+                * NB: figure out which counter triggered.  If both
+                * trigger we'll only deal with one as the processing
+                * clobbers the error counter so the trigger threshold
+                * check will never be true.
+                */
+               if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
+                       ath9k_hw_ani_ofdm_err_trigger(ah);
+               if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
+                       ath9k_hw_ani_cck_err_trigger(ah);
+               /* NB: always restart to insure the h/w counters are reset */
+               ath9k_ani_restart(ah);
+       }
+}
+
+void ath9k_hw_ani_setup(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+       const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+       const int coarseLow[] = { -64, -64, -64, -64, -70 };
+       const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+       for (i = 0; i < 5; i++) {
+               ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
+               ahp->ah_coarseHigh[i] = coarseHigh[i];
+               ahp->ah_coarseLow[i] = coarseLow[i];
+               ahp->ah_firpwr[i] = firpwr[i];
+       }
+}
+
+void ath9k_hw_ani_attach(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n");
+
+       ahp->ah_hasHwPhyCounters = 1;
+
+       memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
+       for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+               ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+               ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+               ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+               ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+               ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+               ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+               ahp->ah_ani[i].ofdmWeakSigDetectOff =
+                       !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+               ahp->ah_ani[i].cckWeakSigThreshold =
+                       ATH9K_ANI_CCK_WEAK_SIG_THR;
+               ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+               ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+               if (ahp->ah_hasHwPhyCounters) {
+                       ahp->ah_ani[i].ofdmPhyErrBase =
+                               AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+                       ahp->ah_ani[i].cckPhyErrBase =
+                               AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+               }
+       }
+       if (ahp->ah_hasHwPhyCounters) {
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                       "Setting OfdmErrBase = 0x%08x\n",
+                       ahp->ah_ani[0].ofdmPhyErrBase);
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+                       ahp->ah_ani[0].cckPhyErrBase);
+
+               REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
+               REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+               ath9k_enable_mib_counters(ah);
+       }
+       ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
+       if (ah->ah_config.enable_ani)
+               ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+}
+
+void ath9k_hw_ani_detach(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n");
+
+       if (ahp->ah_hasHwPhyCounters) {
+               ath9k_hw_disable_mib_counters(ah);
+               REG_WRITE(ah, AR_PHY_ERR_1, 0);
+               REG_WRITE(ah, AR_PHY_ERR_2, 0);
+       }
+}
index a6063dea0fa26bb8d2a1980f3a405c3c28022a70..3a180ce1770bb6174463ecd7a24c96a57e3fb14a 100644 (file)
@@ -828,195 +828,251 @@ struct chan_centers {
        u16 ext_center;
 };
 
-int ath_hal_getcapability(struct ath_hal *ah,
-                         enum ath9k_capability_type type,
-                         u32 capability,
-                         u32 *result);
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-                                                    u32 mode);
-void ath9k_hw_detach(struct ath_hal *ah);
-struct ath_hal *ath9k_hw_attach(u16 devid,
-                               struct ath_softc *sc,
-                               void __iomem *mem,
-                               int *error);
-bool ath9k_regd_init_channels(struct ath_hal *ah,
-                             u32 maxchans, u32 *nchans,
-                             u8 *regclassids,
-                             u32 maxregids, u32 *nregids,
-                             u16 cc,
-                             bool enableOutdoor,
-                             bool enableExtendedChannels);
+/* Helpers */
+
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+                              const struct ath9k_channel *chan);
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+                            u16 flags, u16 *low,
+                            u16 *high);
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+                          const struct ath9k_rate_table *rates,
+                          u32 frameLen, u16 rateix,
+                          bool shortPreamble);
 u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
-                                    enum ath9k_int ints);
-bool ath9k_hw_reset(struct ath_hal *ah,
-                   struct ath9k_channel *chan,
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+                                 struct ath9k_channel *chan,
+                                 struct chan_centers *centers);
+
+/* Attach, Detach */
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_detach(struct ath_hal *ah);
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+                               void __iomem *mem, int *error);
+void ath9k_hw_rfdetach(struct ath_hal *ah);
+
+
+/* HW Reset */
+
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
                    enum ath9k_ht_macmode macmode,
                    u8 txchainmask, u8 rxchainmask,
                    enum ath9k_ht_extprotspacing extprotspacing,
-                   bool bChannelChange,
-                   int *status);
-bool ath9k_hw_phy_disable(struct ath_hal *ah);
-void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
-                            bool *isCalDone);
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-                         const struct ath9k_node_stats *stats,
-                         struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hal *ah,
-                       struct ath9k_channel *chan,
-                       u8 rxchainmask,
-                       bool longcal,
-                       bool *isCalDone);
-s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
-                              struct ath9k_channel *chan);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-                           u16 assocId);
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
-void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-                           u16 assocId);
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
-void ath9k_hw_reset_tsf(struct ath_hal *ah);
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
-                       const u8 *mac);
-bool ath9k_hw_set_keycache_entry(struct ath_hal *ah,
-                                u16 entry,
-                                const struct ath9k_keyval *k,
-                                const u8 *mac,
-                                int xorKey);
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah,
-                           u32 setting);
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
-bool ath9k_hw_intrpend(struct ath_hal *ah);
-bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
-bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah,
-                               bool bIncTrigLevel);
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-                          const struct ath9k_node_stats *stats);
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
-bool ath9k_hw_phycounters(struct ath_hal *ah);
+                   bool bChannelChange, int *status);
+
+/* Key Cache Management */
+
 bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
-bool ath9k_hw_getcapability(struct ath_hal *ah,
-                           enum ath9k_capability_type type,
-                           u32 capability,
-                           u32 *result);
-bool ath9k_hw_setcapability(struct ath_hal *ah,
-                           enum ath9k_capability_type type,
-                           u32 capability,
-                           u32 setting,
-                           int *status);
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
-bool ath9k_hw_setbssidmask(struct ath_hal *ah,
-                          const u8 *mask);
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+                                const struct ath9k_keyval *k,
+                                const u8 *mac, int xorKey);
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
+
+/* Power Management */
+
 bool ath9k_hw_setpower(struct ath_hal *ah,
                       enum ath9k_power_mode mode);
-enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
-u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
+
+/* Beacon timers */
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+                                   const struct ath9k_beacon_state *bs);
+
+/* Rate table */
+
+const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
+                                                    u32 mode);
+
+/* HW Capabilities */
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah);
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+                           u32 capability, u32 *result);
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+                           u32 capability, u32 setting, int *status);
+
+/* GPIO / RFKILL / Antennae */
+
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+                        u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val);
+#ifdef CONFIG_RFKILL
+void ath9k_enable_rfkill(struct ath_hal *ah);
+#endif
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg);
 u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
 bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
                               enum ath9k_ant_setting settings,
                               struct ath9k_channel *chan,
                               u8 *tx_chainmask,
                               u8 *rx_chainmask,
                               u8 *antenna_cfgd);
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
-int ath9k_hw_select_antconfig(struct ath_hal *ah,
-                             u32 cfg);
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
-                      u32 txdp);
+
+/* General Operation */
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
+bool ath9k_hw_phy_disable(struct ath_hal *ah);
+bool ath9k_hw_disable(struct ath_hal *ah);
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
+void ath9k_hw_setopmode(struct ath_hal *ah);
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1);
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId);
+u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+void ath9k_hw_reset_tsf(struct ath_hal *ah);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+
+/* Regulatory */
+
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
+struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah,
+                        const struct ath9k_channel *c);
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
+u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+                                  struct ath9k_channel *chan);
+bool ath9k_regd_init_channels(struct ath_hal *ah,
+                             u32 maxchans, u32 *nchans, u8 *regclassids,
+                             u32 maxregids, u32 *nregids, u16 cc,
+                             bool enableOutdoor, bool enableExtendedChannels);
+
+/* ANI */
+
+void ath9k_ani_reset(struct ath_hal *ah);
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+                         const struct ath9k_node_stats *stats,
+                         struct ath9k_channel *chan);
+bool ath9k_hw_phycounters(struct ath_hal *ah);
+void ath9k_enable_mib_counters(struct ath_hal *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hal *ah);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+                                 u32 *rxc_pcnt,
+                                 u32 *rxf_pcnt,
+                                 u32 *txf_pcnt);
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+                          const struct ath9k_node_stats *stats);
+void ath9k_hw_ani_setup(struct ath_hal *ah);
+void ath9k_hw_ani_attach(struct ath_hal *ah);
+void ath9k_hw_ani_detach(struct ath_hal *ah);
+
+/* Calibration */
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+                            bool *isCalDone);
+void ath9k_hw_start_nfcal(struct ath_hal *ah);
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan);
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+                      struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah);
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+                       u8 rxchainmask, bool longcal,
+                       bool *isCalDone);
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+                      struct ath9k_channel *chan);
+
+
+/* EEPROM */
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+                        struct ath9k_channel *chan,
+                        u16 cfgCtl,
+                        u8 twiceAntennaReduction,
+                        u8 twiceMaxRegulatoryPower,
+                        u8 powerLimit);
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan);
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+                                      struct ath9k_channel *chan,
+                                      int16_t *ratesArray,
+                                      u16 cfgCtl,
+                                      u8 AntennaReduction,
+                                      u8 twiceMaxRegulatoryPower,
+                                      u8 powerLimit);
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+                                 struct ath9k_channel *chan,
+                                 int16_t *pTxPowerIndexOffset);
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+                                     struct ath9k_channel *chan);
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+                                   struct ath9k_channel *chan,
+                                   u8 index, u16 *config);
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+                              enum ieee80211_band freq_band);
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz);
+int ath9k_hw_eeprom_attach(struct ath_hal *ah);
+
+/* Interrupt Handling */
+
+bool ath9k_hw_intrpend(struct ath_hal *ah);
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints);
+
+/* MAC (PCU/QCU) */
+
+void ath9k_hw_dmaRegDump(struct ath_hal *ah);
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp);
 bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
-u16 ath9k_hw_computetxtime(struct ath_hal *ah,
-                                const struct ath9k_rate_table *rates,
-                                u32 frameLen, u16 rateix,
-                                bool shortPreamble);
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel);
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+                        u32 segLen, bool firstSeg,
+                        bool lastSeg, const struct ath_desc *ds0);
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+                           u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+                           u32 keyIx, enum ath9k_key_type keyType, u32 flags);
 void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
                                  struct ath_desc *lastds,
                                  u32 durUpdateEn, u32 rtsctsRate,
                                  u32 rtsctsDuration,
                                  struct ath9k_11n_rate_series series[],
                                  u32 nseries, u32 flags);
-void ath9k_hw_set11n_burstduration(struct ath_hal *ah,
-                                  struct ath_desc *ds,
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+                               u32 aggrLen);
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+                                u32 numDelims);
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
                                   u32 burstDuration);
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
-u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
-u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
-u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
-                                    struct ath9k_channel *chan);
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-                           struct ath9k_tx_queue_info *qinfo);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+                                    u32 vmf);
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
 bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
                            const struct ath9k_tx_queue_info *qinfo);
-struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah,
-                                             const struct ath9k_channel *c);
-void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-                           u32 pktLen, enum ath9k_pkt_type type,
-                           u32 txPower, u32 keyIx,
-                           enum ath9k_key_type keyType, u32 flags);
-bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-                        u32 segLen, bool firstSeg,
-                        bool lastSeg,
-                        const struct ath_desc *ds0);
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-                                       u32 *rxc_pcnt,
-                                       u32 *rxf_pcnt,
-                                       u32 *txf_pcnt);
-void ath9k_hw_dmaRegDump(struct ath_hal *ah);
-void ath9k_hw_beaconinit(struct ath_hal *ah,
-                        u32 next_beacon, u32 beacon_period);
-void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-                                   const struct ath9k_beacon_state *bs);
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+                           struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+                         const struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+                       u32 pa, struct ath_desc *nds, u64 tsf);
 bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
                          u32 size, u32 flags);
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
 void ath9k_hw_rxena(struct ath_hal *ah);
-void ath9k_hw_setopmode(struct ath_hal *ah);
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
-void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
-                            u32 filter1);
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
 void ath9k_hw_startpcureceive(struct ath_hal *ah);
 void ath9k_hw_stoppcurecv(struct ath_hal *ah);
 bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
-int ath9k_hw_rxprocdesc(struct ath_hal *ah,
-                       struct ath_desc *ds, u32 pa,
-                       struct ath_desc *nds, u64 tsf);
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
-int ath9k_hw_txprocdesc(struct ath_hal *ah,
-                       struct ath_desc *ds);
-void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-                                u32 numDelims);
-void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-                               u32 aggrLen);
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah,
-                                    struct ath_desc *ds, u32 vmf);
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
-bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
-int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-                         const struct ath9k_tx_queue_info *qinfo);
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
-const char *ath9k_hw_probe(u16 vendorid, u16 devid);
-bool ath9k_hw_disable(struct ath_hal *ah);
-void ath9k_hw_rfdetach(struct ath_hal *ah);
-void ath9k_hw_get_channel_centers(struct ath_hal *ah,
-                                 struct ath9k_channel *chan,
-                                 struct chan_centers *centers);
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-                            u16 flags, u16 *low,
-                            u16 *high);
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-                       u32 ah_signal_type);
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
+
 #endif
index 9e15c30bbc065bcb0326ffee6860efda07242f64..d186cd41c2352fa0946de62b829c57df0d3876a3 100644 (file)
@@ -114,7 +114,7 @@ static void ath_beacon_setup(struct ath_softc *sc,
        ath9k_hw_set11n_txdesc(ah, ds,
                               skb->len + FCS_LEN,     /* frame length */
                               ATH9K_PKT_TYPE_BEACON,  /* Atheros packet type */
-                              avp->av_btxctl.txpower, /* txpower XXX */
+                              MAX_RATE_POWER,         /* FIXME */
                               ATH9K_TXKEYIX_INVALID,  /* no encryption */
                               ATH9K_KEY_TYPE_CLEAR,   /* no encryption */
                               flags                   /* no ack,
@@ -152,12 +152,14 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
        struct ath_vap *avp;
        struct sk_buff *skb;
        struct ath_txq *cabq;
+       struct ieee80211_vif *vif;
        struct ieee80211_tx_info *info;
        int cabq_depth;
 
-       avp = sc->sc_vaps[if_id];
-       ASSERT(avp);
+       vif = sc->sc_vaps[if_id];
+       ASSERT(vif);
 
+       avp = (void *)vif->drv_priv;
        cabq = sc->sc_cabq;
 
        if (avp->av_bcbuf == NULL) {
@@ -174,7 +176,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
                                 PCI_DMA_TODEVICE);
        }
 
-       skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+       skb = ieee80211_beacon_get(sc->hw, vif);
        bf->bf_mpdu = skb;
        if (skb == NULL)
                return NULL;
@@ -196,7 +198,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
                               skb_end_pointer(skb) - skb->head,
                               PCI_DMA_TODEVICE);
 
-       skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+       skb = ieee80211_get_buffered_bc(sc->hw, vif);
 
        /*
         * if the CABQ traffic from previous DTIM is pending and the current
@@ -232,7 +234,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
         */
        while (skb) {
                ath_tx_cabq(sc, skb);
-               skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data);
+               skb = ieee80211_get_buffered_bc(sc->hw, vif);
        }
 
        return bf;
@@ -244,13 +246,16 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 */
 static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
 {
+       struct ieee80211_vif *vif;
        struct ath_hal *ah = sc->sc_ah;
        struct ath_buf *bf;
        struct ath_vap *avp;
        struct sk_buff *skb;
 
-       avp = sc->sc_vaps[if_id];
-       ASSERT(avp);
+       vif = sc->sc_vaps[if_id];
+       ASSERT(vif);
+
+       avp = (void *)vif->drv_priv;
 
        if (avp->av_bcbuf == NULL) {
                DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
@@ -300,14 +305,17 @@ int ath_beaconq_setup(struct ath_hal *ah)
 */
 int ath_beacon_alloc(struct ath_softc *sc, int if_id)
 {
+       struct ieee80211_vif *vif;
        struct ath_vap *avp;
        struct ieee80211_hdr *hdr;
        struct ath_buf *bf;
        struct sk_buff *skb;
        __le64 tstamp;
 
-       avp = sc->sc_vaps[if_id];
-       ASSERT(avp);
+       vif = sc->sc_vaps[if_id];
+       ASSERT(vif);
+
+       avp = (void *)vif->drv_priv;
 
        /* Allocate a beacon descriptor if we haven't done so. */
        if (!avp->av_bcbuf) {
@@ -363,7 +371,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
         * FIXME: Fill avp->av_btxctl.txpower and
         * avp->av_btxctl.shortPreamble
         */
-       skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+       skb = ieee80211_beacon_get(sc->hw, vif);
        if (skb == NULL) {
                DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n",
                        __func__);
@@ -652,15 +660,21 @@ void ath_bstuck_process(struct ath_softc *sc)
  */
 void ath_beacon_config(struct ath_softc *sc, int if_id)
 {
+       struct ieee80211_vif *vif;
        struct ath_hal *ah = sc->sc_ah;
        struct ath_beacon_config conf;
+       struct ath_vap *avp;
        enum ath9k_opmode av_opmode;
        u32 nexttbtt, intval;
 
-       if (if_id != ATH_IF_ID_ANY)
-               av_opmode = sc->sc_vaps[if_id]->av_opmode;
-       else
+       if (if_id != ATH_IF_ID_ANY) {
+               vif = sc->sc_vaps[if_id];
+               ASSERT(vif);
+               avp = (void *)vif->drv_priv;
+               av_opmode = avp->av_opmode;
+       } else {
                av_opmode = sc->sc_ah->ah_opmode;
+       }
 
        memset(&conf, 0, sizeof(struct ath_beacon_config));
 
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c
new file mode 100644 (file)
index 0000000..1690759
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
+
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW       -60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+       if (nf > ATH9K_NF_TOO_LOW) {
+               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+                       "%s: noise floor value detected (%d) is "
+                       "lower than what we think is a "
+                       "reasonable value (%d)\n",
+                       __func__, nf, ATH9K_NF_TOO_LOW);
+               return false;
+       }
+       return true;
+}
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+       int16_t nfval;
+       int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+       int i, j;
+
+       for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+               sort[i] = nfCalBuffer[i];
+
+       for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+               for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+                       if (sort[j] > sort[j - 1]) {
+                               nfval = sort[j];
+                               sort[j] = sort[j - 1];
+                               sort[j - 1] = nfval;
+                       }
+               }
+       }
+       nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+       return nfval;
+}
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+                                             int16_t *nfarray)
+{
+       int i;
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+               if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+                       h[i].currIndex = 0;
+
+               if (h[i].invalidNFcount > 0) {
+                       if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
+                           nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+                               h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+                       } else {
+                               h[i].invalidNFcount--;
+                               h[i].privNF = nfarray[i];
+                       }
+               } else {
+                       h[i].privNF =
+                               ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+               }
+       }
+       return;
+}
+
+static void ath9k_hw_do_getnf(struct ath_hal *ah,
+                             int16_t nfarray[NUM_NF_READINGS])
+{
+       int16_t nf;
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+       else
+               nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+               "NF calibrated [ctl] [chain 0] is %d\n", nf);
+       nfarray[0] = nf;
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+                       AR9280_PHY_CH1_MINCCA_PWR);
+       else
+               nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+                       AR_PHY_CH1_MINCCA_PWR);
+
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+               "NF calibrated [ctl] [chain 1] is %d\n", nf);
+       nfarray[1] = nf;
+
+       if (!AR_SREV_9280(ah)) {
+               nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
+                       AR_PHY_CH2_MINCCA_PWR);
+               if (nf & 0x100)
+                       nf = 0 - ((nf ^ 0x1ff) + 1);
+               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+                       "NF calibrated [ctl] [chain 2] is %d\n", nf);
+               nfarray[2] = nf;
+       }
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+                       AR9280_PHY_EXT_MINCCA_PWR);
+       else
+               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+                       AR_PHY_EXT_MINCCA_PWR);
+
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+               "NF calibrated [ext] [chain 0] is %d\n", nf);
+       nfarray[3] = nf;
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+                       AR9280_PHY_CH1_EXT_MINCCA_PWR);
+       else
+               nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+                       AR_PHY_CH1_EXT_MINCCA_PWR);
+
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+               "NF calibrated [ext] [chain 1] is %d\n", nf);
+       nfarray[4] = nf;
+
+       if (!AR_SREV_9280(ah)) {
+               nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
+                       AR_PHY_CH2_EXT_MINCCA_PWR);
+               if (nf & 0x100)
+                       nf = 0 - ((nf ^ 0x1ff) + 1);
+               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+                       "NF calibrated [ext] [chain 2] is %d\n", nf);
+               nfarray[5] = nf;
+       }
+}
+
+static bool getNoiseFloorThresh(struct ath_hal *ah,
+                               const struct ath9k_channel *chan,
+                               int16_t *nft)
+{
+       switch (chan->chanmode) {
+       case CHANNEL_A:
+       case CHANNEL_A_HT20:
+       case CHANNEL_A_HT40PLUS:
+       case CHANNEL_A_HT40MINUS:
+               *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
+               break;
+       case CHANNEL_B:
+       case CHANNEL_G:
+       case CHANNEL_G_HT20:
+       case CHANNEL_G_HT40PLUS:
+       case CHANNEL_G_HT40MINUS:
+               *nft = (int16_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: invalid channel flags 0x%x\n", __func__,
+                       chan->channelFlags);
+               return false;
+       }
+
+       return true;
+}
+
+static void ath9k_hw_setup_calibration(struct ath_hal *ah,
+                                      struct hal_cal_list *currCal)
+{
+       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+                     AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+                     currCal->calData->calCountMax);
+
+       switch (currCal->calData->calType) {
+       case IQ_MISMATCH_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: starting IQ Mismatch Calibration\n",
+                       __func__);
+               break;
+       case ADC_GAIN_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: starting ADC Gain Calibration\n", __func__);
+               break;
+       case ADC_DC_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: starting ADC DC Calibration\n", __func__);
+               break;
+       case ADC_DC_INIT_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: starting Init ADC DC Calibration\n",
+                       __func__);
+               break;
+       }
+
+       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+                   AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static void ath9k_hw_reset_calibration(struct ath_hal *ah,
+                                      struct hal_cal_list *currCal)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       ath9k_hw_setup_calibration(ah, currCal);
+
+       currCal->calState = CAL_RUNNING;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ahp->ah_Meas0.sign[i] = 0;
+               ahp->ah_Meas1.sign[i] = 0;
+               ahp->ah_Meas2.sign[i] = 0;
+               ahp->ah_Meas3.sign[i] = 0;
+       }
+
+       ahp->ah_CalSamples = 0;
+}
+
+static void ath9k_hw_per_calibration(struct ath_hal *ah,
+                                    struct ath9k_channel *ichan,
+                                    u8 rxchainmask,
+                                    struct hal_cal_list *currCal,
+                                    bool *isCalDone)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       *isCalDone = false;
+
+       if (currCal->calState == CAL_RUNNING) {
+               if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+                     AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+                       currCal->calData->calCollect(ah);
+                       ahp->ah_CalSamples++;
+
+                       if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) {
+                               int i, numChains = 0;
+                               for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+                                       if (rxchainmask & (1 << i))
+                                               numChains++;
+                               }
+
+                               currCal->calData->calPostProc(ah, numChains);
+                               ichan->CalValid |= currCal->calData->calType;
+                               currCal->calState = CAL_DONE;
+                               *isCalDone = true;
+                       } else {
+                               ath9k_hw_setup_calibration(ah, currCal);
+                       }
+               }
+       } else if (!(ichan->CalValid & currCal->calData->calType)) {
+               ath9k_hw_reset_calibration(ah, currCal);
+       }
+}
+
+static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+                                    struct ath9k_channel *chan,
+                                    enum hal_cal_types calType)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       bool retval = false;
+
+       switch (calType & ahp->ah_suppCals) {
+       case IQ_MISMATCH_CAL:
+               if (!IS_CHAN_B(chan))
+                       retval = true;
+               break;
+       case ADC_GAIN_CAL:
+       case ADC_DC_CAL:
+               if (!IS_CHAN_B(chan)
+                   && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+                       retval = true;
+               break;
+       }
+
+       return retval;
+}
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ahp->ah_totalPowerMeasI[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ahp->ah_totalPowerMeasQ[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ahp->ah_totalIqCorrMeas[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+                       ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
+                       ahp->ah_totalPowerMeasQ[i],
+                       ahp->ah_totalIqCorrMeas[i]);
+       }
+}
+
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ahp->ah_totalAdcIOddPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ahp->ah_totalAdcIEvenPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ahp->ah_totalAdcQOddPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ahp->ah_totalAdcQEvenPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+                       "oddq=0x%08x; evenq=0x%08x;\n",
+                       ahp->ah_CalSamples, i,
+                       ahp->ah_totalAdcIOddPhase[i],
+                       ahp->ah_totalAdcIEvenPhase[i],
+                       ahp->ah_totalAdcQOddPhase[i],
+                       ahp->ah_totalAdcQEvenPhase[i]);
+       }
+}
+
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+                       "oddq=0x%08x; evenq=0x%08x;\n",
+                       ahp->ah_CalSamples, i,
+                       ahp->ah_totalAdcDcOffsetIOddPhase[i],
+                       ahp->ah_totalAdcDcOffsetIEvenPhase[i],
+                       ahp->ah_totalAdcDcOffsetQOddPhase[i],
+                       ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+       }
+}
+
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 powerMeasQ, powerMeasI, iqCorrMeas;
+       u32 qCoffDenom, iCoffDenom;
+       int32_t qCoff, iCoff;
+       int iqCorrNeg, i;
+
+       for (i = 0; i < numChains; i++) {
+               powerMeasI = ahp->ah_totalPowerMeasI[i];
+               powerMeasQ = ahp->ah_totalPowerMeasQ[i];
+               iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Starting IQ Cal and Correction for Chain %d\n",
+                       i);
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+                       i, ahp->ah_totalIqCorrMeas[i]);
+
+               iqCorrNeg = 0;
+
+               if (iqCorrMeas > 0x80000000) {
+                       iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+                       iqCorrNeg = 1;
+               }
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+                       iqCorrNeg);
+
+               iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+               qCoffDenom = powerMeasQ / 64;
+
+               if (powerMeasQ != 0) {
+                       iCoff = iqCorrMeas / iCoffDenom;
+                       qCoff = powerMeasI / qCoffDenom - 64;
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "Chn %d iCoff = 0x%08x\n", i, iCoff);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+                       iCoff = iCoff & 0x3f;
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+                       if (iqCorrNeg == 0x0)
+                               iCoff = 0x40 - iCoff;
+
+                       if (qCoff > 15)
+                               qCoff = 15;
+                       else if (qCoff <= -16)
+                               qCoff = 16;
+
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+                               i, iCoff, qCoff);
+
+                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+                                     iCoff);
+                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+                                     qCoff);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "IQ Cal and Correction done for Chain %d\n",
+                               i);
+               }
+       }
+
+       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+                   AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+       u32 qGainMismatch, iGainMismatch, val, i;
+
+       for (i = 0; i < numChains; i++) {
+               iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
+               iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
+               qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
+               qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Starting ADC Gain Cal for Chain %d\n", i);
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+                       iOddMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+                       iEvenMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+                       qOddMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+                       qEvenMeasOffset);
+
+               if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+                       iGainMismatch =
+                               ((iEvenMeasOffset * 32) /
+                                iOddMeasOffset) & 0x3f;
+                       qGainMismatch =
+                               ((qOddMeasOffset * 32) /
+                                qEvenMeasOffset) & 0x3f;
+
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "Chn %d gain_mismatch_i = 0x%08x\n", i,
+                               iGainMismatch);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "Chn %d gain_mismatch_q = 0x%08x\n", i,
+                               qGainMismatch);
+
+                       val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+                       val &= 0xfffff000;
+                       val |= (qGainMismatch) | (iGainMismatch << 6);
+                       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "ADC Gain Cal done for Chain %d\n", i);
+               }
+       }
+
+       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+                 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+       int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+       const struct hal_percal_data *calData =
+               ahp->ah_cal_list_curr->calData;
+       u32 numSamples =
+               (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+       for (i = 0; i < numChains; i++) {
+               iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
+               iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
+               qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
+               qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_odd_i = %d\n", i,
+                       iOddMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_even_i = %d\n", i,
+                       iEvenMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_odd_q = %d\n", i,
+                       qOddMeasOffset);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d pwr_meas_even_q = %d\n", i,
+                       qEvenMeasOffset);
+
+               iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+                              numSamples) & 0x1ff;
+               qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+                              numSamples) & 0x1ff;
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+                       iDcMismatch);
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+                       qDcMismatch);
+
+               val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+               val &= 0xc0000fff;
+               val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+               REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "ADC DC Offset Cal done for Chain %d\n", i);
+       }
+
+       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+                 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+                            bool *isCalDone)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_channel *ichan =
+               ath9k_regd_check_channel(ah, chan);
+       struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+
+       *isCalDone = true;
+
+       if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+               return;
+
+       if (currCal == NULL)
+               return;
+
+       if (ichan == NULL) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: invalid channel %u/0x%x; no mapping\n",
+                       __func__, chan->channel, chan->channelFlags);
+               return;
+       }
+
+
+       if (currCal->calState != CAL_DONE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: Calibration state incorrect, %d\n",
+                       __func__, currCal->calState);
+               return;
+       }
+
+
+       if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
+               return;
+
+       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+               "%s: Resetting Cal %d state for channel %u/0x%x\n",
+               __func__, currCal->calData->calType, chan->channel,
+               chan->channelFlags);
+
+       ichan->CalValid &= ~currCal->calData->calType;
+       currCal->calState = CAL_WAITING;
+
+       *isCalDone = false;
+}
+
+void ath9k_hw_start_nfcal(struct ath_hal *ah)
+{
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_ENABLE_NF);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+       struct ath9k_nfcal_hist *h;
+       int i, j;
+       int32_t val;
+       const u32 ar5416_cca_regs[6] = {
+               AR_PHY_CCA,
+               AR_PHY_CH1_CCA,
+               AR_PHY_CH2_CCA,
+               AR_PHY_EXT_CCA,
+               AR_PHY_CH1_EXT_CCA,
+               AR_PHY_CH2_EXT_CCA
+       };
+       u8 chainmask;
+
+       if (AR_SREV_9280(ah))
+               chainmask = 0x1B;
+       else
+               chainmask = 0x3F;
+
+#ifdef ATH_NF_PER_CHAN
+       h = chan->nfCalHist;
+#else
+       h = ah->nfCalHist;
+#endif
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar5416_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar5416_cca_regs[i], val);
+               }
+       }
+
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_ENABLE_NF);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+       for (j = 0; j < 1000; j++) {
+               if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+                    AR_PHY_AGC_CONTROL_NF) == 0)
+                       break;
+               udelay(10);
+       }
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar5416_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (-50) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar5416_cca_regs[i], val);
+               }
+       }
+}
+
+int16_t ath9k_hw_getnf(struct ath_hal *ah,
+                      struct ath9k_channel *chan)
+{
+       int16_t nf, nfThresh;
+       int16_t nfarray[NUM_NF_READINGS] = { 0 };
+       struct ath9k_nfcal_hist *h;
+       u8 chainmask;
+
+       if (AR_SREV_9280(ah))
+               chainmask = 0x1B;
+       else
+               chainmask = 0x3F;
+
+       chan->channelFlags &= (~CHANNEL_CW_INT);
+       if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: NF did not complete in calibration window\n",
+                       __func__);
+               nf = 0;
+               chan->rawNoiseFloor = nf;
+               return chan->rawNoiseFloor;
+       } else {
+               ath9k_hw_do_getnf(ah, nfarray);
+               nf = nfarray[0];
+               if (getNoiseFloorThresh(ah, chan, &nfThresh)
+                   && nf > nfThresh) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "%s: noise floor failed detected; "
+                               "detected %d, threshold %d\n", __func__,
+                               nf, nfThresh);
+                       chan->channelFlags |= CHANNEL_CW_INT;
+               }
+       }
+
+#ifdef ATH_NF_PER_CHAN
+       h = chan->nfCalHist;
+#else
+       h = ah->nfCalHist;
+#endif
+
+       ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+       chan->rawNoiseFloor = h[0].privNF;
+
+       return chan->rawNoiseFloor;
+}
+
+void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+{
+       int i, j;
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               ah->nfCalHist[i].currIndex = 0;
+               ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+               ah->nfCalHist[i].invalidNFcount =
+                       AR_PHY_CCA_FILTERWINDOW_LENGTH;
+               for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+                       ah->nfCalHist[i].nfCalBuffer[j] =
+                               AR_PHY_CCA_MAX_GOOD_VALUE;
+               }
+       }
+       return;
+}
+
+s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+       struct ath9k_channel *ichan;
+       s16 nf;
+
+       ichan = ath9k_regd_check_channel(ah, chan);
+       if (ichan == NULL) {
+               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+                       "%s: invalid channel %u/0x%x; no mapping\n",
+                       __func__, chan->channel, chan->channelFlags);
+               return ATH_DEFAULT_NOISE_FLOOR;
+       }
+       if (ichan->rawNoiseFloor == 0) {
+               enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
+               nf = NOISE_FLOOR[mode];
+       } else
+               nf = ichan->rawNoiseFloor;
+
+       if (!ath9k_hw_nf_in_range(ah, nf))
+               nf = ATH_DEFAULT_NOISE_FLOOR;
+
+       return nf;
+}
+
+bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+                       u8 rxchainmask, bool longcal,
+                       bool *isCalDone)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+       struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+       *isCalDone = true;
+
+       if (ichan == NULL) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: invalid channel %u/0x%x; no mapping\n",
+                       __func__, chan->channel, chan->channelFlags);
+               return false;
+       }
+
+       if (currCal &&
+           (currCal->calState == CAL_RUNNING ||
+            currCal->calState == CAL_WAITING)) {
+               ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
+                                        isCalDone);
+               if (*isCalDone) {
+                       ahp->ah_cal_list_curr = currCal = currCal->calNext;
+
+                       if (currCal->calState == CAL_WAITING) {
+                               *isCalDone = false;
+                               ath9k_hw_reset_calibration(ah, currCal);
+                       }
+               }
+       }
+
+       if (longcal) {
+               ath9k_hw_getnf(ah, ichan);
+               ath9k_hw_loadnf(ah, ah->ah_curchan);
+               ath9k_hw_start_nfcal(ah);
+
+               if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+                       chan->channelFlags |= CHANNEL_CW_INT;
+                       ichan->channelFlags &= ~CHANNEL_CW_INT;
+               }
+       }
+
+       return true;
+}
+
+bool ath9k_hw_init_cal(struct ath_hal *ah,
+                      struct ath9k_channel *chan)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
+
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                 AR_PHY_AGC_CONTROL_CAL);
+
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                       "%s: offset calibration failed to complete in 1ms; "
+                       "noisy environment?\n", __func__);
+               return false;
+       }
+
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                 AR_PHY_AGC_CONTROL_NF);
+
+       ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+
+       if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+               if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
+                       INIT_CAL(&ahp->ah_adcGainCalData);
+                       INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "%s: enabling ADC Gain Calibration.\n",
+                               __func__);
+               }
+               if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
+                       INIT_CAL(&ahp->ah_adcDcCalData);
+                       INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "%s: enabling ADC DC Calibration.\n",
+                               __func__);
+               }
+               if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+                       INIT_CAL(&ahp->ah_iqCalData);
+                       INSERT_CAL(ahp, &ahp->ah_iqCalData);
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "%s: enabling IQ Calibration.\n",
+                               __func__);
+               }
+
+               ahp->ah_cal_list_curr = ahp->ah_cal_list;
+
+               if (ahp->ah_cal_list_curr)
+                       ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
+       }
+
+       ichan->CalValid = 0;
+
+       return true;
+}
+
+const struct hal_percal_data iq_cal_multi_sample = {
+       IQ_MISMATCH_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ath9k_hw_iqcal_collect,
+       ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data iq_cal_single_sample = {
+       IQ_MISMATCH_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ath9k_hw_iqcal_collect,
+       ath9k_hw_iqcalibrate
+};
+const struct hal_percal_data adc_gain_cal_multi_sample = {
+       ADC_GAIN_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ath9k_hw_adc_gaincal_collect,
+       ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_gain_cal_single_sample = {
+       ADC_GAIN_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ath9k_hw_adc_gaincal_collect,
+       ath9k_hw_adc_gaincal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_multi_sample = {
+       ADC_DC_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ath9k_hw_adc_dccal_collect,
+       ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_dc_cal_single_sample = {
+       ADC_DC_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ath9k_hw_adc_dccal_collect,
+       ath9k_hw_adc_dccal_calibrate
+};
+const struct hal_percal_data adc_init_dc_cal = {
+       ADC_DC_INIT_CAL,
+       MIN_CAL_SAMPLES,
+       INIT_LOG_COUNT,
+       ath9k_hw_adc_dccal_collect,
+       ath9k_hw_adc_dccal_calibrate
+};
index 0089e023c60940481afa854cfc6350937bf30242..5f5184acb2746de6a73b418f27a489e0c11397cf 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
- /* Implementation of the main "ATH" layer. */
-
 #include "core.h"
 #include "regd.h"
 
-static int ath_outdoor;                /* enable outdoor use */
-
 static u32 ath_chainmask_sel_up_rssi_thres =
        ATH_CHAINMASK_SEL_UP_RSSI_THRES;
 static u32 ath_chainmask_sel_down_rssi_thres =
@@ -47,6 +43,41 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
                *csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
 }
 
+static u8 parse_mpdudensity(u8 mpdudensity)
+{
+       /*
+        * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+        *   0 for no restriction
+        *   1 for 1/4 us
+        *   2 for 1/2 us
+        *   3 for 1 us
+        *   4 for 2 us
+        *   5 for 4 us
+        *   6 for 8 us
+        *   7 for 16 us
+        */
+       switch (mpdudensity) {
+       case 0:
+               return 0;
+       case 1:
+       case 2:
+       case 3:
+               /* Our lower layer calculations limit our precision to
+                  1 microsecond */
+               return 1;
+       case 4:
+               return 2;
+       case 5:
+               return 4;
+       case 6:
+               return 8;
+       case 7:
+               return 16;
+       default:
+               return 0;
+       }
+}
+
 /*
  *  Set current operating mode
  *
@@ -155,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc)
        struct ath9k_channel *c;
 
        /* Fill in ah->ah_channels */
-       if (!ath9k_regd_init_channels(ah,
-                                     ATH_CHAN_MAX,
-                                     (u32 *)&nchan,
-                                     regclassids,
-                                     ATH_REGCLASSIDS_MAX,
-                                     &nregclass,
-                                     CTRY_DEFAULT,
-                                     false,
-                                     1)) {
+       if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan,
+                                     regclassids, ATH_REGCLASSIDS_MAX,
+                                     &nregclass, CTRY_DEFAULT, false, 1)) {
                u32 rd = ah->ah_currentRD;
-
                DPRINTF(sc, ATH_DBG_FATAL,
                        "%s: unable to collect channel list; "
                        "regdomain likely %u country code %u\n",
@@ -186,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc)
                        chan_2ghz[a].max_power = c->maxTxPower;
 
                        if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-                               chan_2ghz[a].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                               chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS;
                        if (c->channelFlags & CHANNEL_PASSIVE)
-                               chan_2ghz[a].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                               chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
                        band_2ghz->n_channels = ++a;
 
                        DPRINTF(sc, ATH_DBG_CONFIG,
                                "%s: 2MHz channel: %d, "
                                "channelFlags: 0x%x\n",
-                               __func__,
-                               c->channel,
-                               c->channelFlags);
+                               __func__, c->channel, c->channelFlags);
                } else if (IS_CHAN_5GHZ(c)) {
                        chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
                        chan_5ghz[b].center_freq = c->channel;
                        chan_5ghz[b].max_power = c->maxTxPower;
 
                        if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
-                               chan_5ghz[b].flags |=
-                                       IEEE80211_CHAN_NO_IBSS;
+                               chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS;
                        if (c->channelFlags & CHANNEL_PASSIVE)
-                               chan_5ghz[b].flags |=
-                                       IEEE80211_CHAN_PASSIVE_SCAN;
+                               chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN;
 
                        band_5ghz->n_channels = ++b;
 
                        DPRINTF(sc, ATH_DBG_CONFIG,
                                "%s: 5MHz channel: %d, "
                                "channelFlags: 0x%x\n",
-                               __func__,
-                               c->channel,
-                               c->channelFlags);
+                               __func__, c->channel, c->channelFlags);
                }
        }
 
@@ -260,44 +276,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
        return ATH9K_MODE_11B;
 }
 
-/*
- * Stop the device, grabbing the top-level lock to protect
- * against concurrent entry through ath_init (which can happen
- * if another thread does a system call and the thread doing the
- * stop is preempted).
- */
-
-static int ath_stop(struct ath_softc *sc)
-{
-       struct ath_hal *ah = sc->sc_ah;
-
-       DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n",
-               __func__, sc->sc_flags & SC_OP_INVALID);
-
-       /*
-        * Shutdown the hardware and driver:
-        *    stop output from above
-        *    turn off timers
-        *    disable interrupts
-        *    clear transmit machinery
-        *    clear receive machinery
-        *    turn off the radio
-        *    reclaim beacon resources
-        *
-        * Note that some of this work is not possible if the
-        * hardware is gone (invalid).
-        */
-
-       ath_draintxq(sc, false);
-       if (!(sc->sc_flags & SC_OP_INVALID)) {
-               ath_stoprecv(sc);
-               ath9k_hw_phy_disable(ah);
-       } else
-               sc->sc_rxlink = NULL;
-
-       return 0;
-}
-
 /*
  * Set the current channel
  *
@@ -606,114 +584,6 @@ static void ath_ani_calibrate(unsigned long data)
        mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 }
 
-/******************/
-/* VAP management */
-/******************/
-
-int ath_vap_attach(struct ath_softc *sc,
-                  int if_id,
-                  struct ieee80211_vif *if_data,
-                  enum ath9k_opmode opmode)
-{
-       struct ath_vap *avp;
-
-       if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "%s: Invalid interface id = %u\n", __func__, if_id);
-               return -EINVAL;
-       }
-
-       switch (opmode) {
-       case ATH9K_M_STA:
-       case ATH9K_M_IBSS:
-       case ATH9K_M_MONITOR:
-               break;
-       case ATH9K_M_HOSTAP:
-               /* XXX not right, beacon buffer is allocated on RUN trans */
-               if (list_empty(&sc->sc_bbuf))
-                       return -ENOMEM;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* create ath_vap */
-       avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL);
-       if (avp == NULL)
-               return -ENOMEM;
-
-       memset(avp, 0, sizeof(struct ath_vap));
-       avp->av_if_data = if_data;
-       /* Set the VAP opmode */
-       avp->av_opmode = opmode;
-       avp->av_bslot = -1;
-
-       if (opmode == ATH9K_M_HOSTAP)
-               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
-
-       sc->sc_vaps[if_id] = avp;
-       sc->sc_nvaps++;
-       /* Set the device opmode */
-       sc->sc_ah->ah_opmode = opmode;
-
-       /* default VAP configuration */
-       avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
-       avp->av_config.av_fixed_retryset = 0x03030303;
-
-       return 0;
-}
-
-int ath_vap_detach(struct ath_softc *sc, int if_id)
-{
-       struct ath_hal *ah = sc->sc_ah;
-       struct ath_vap *avp;
-
-       avp = sc->sc_vaps[if_id];
-       if (avp == NULL) {
-               DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
-                       __func__, if_id);
-               return -EINVAL;
-       }
-
-       /*
-        * Quiesce the hardware while we remove the vap.  In
-        * particular we need to reclaim all references to the
-        * vap state by any frames pending on the tx queues.
-        *
-        * XXX can we do this w/o affecting other vap's?
-        */
-       ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
-       ath_draintxq(sc, false);        /* stop xmit side */
-       ath_stoprecv(sc);       /* stop recv side */
-       ath_flushrecv(sc);      /* flush recv queue */
-
-       kfree(avp);
-       sc->sc_vaps[if_id] = NULL;
-       sc->sc_nvaps--;
-
-       return 0;
-}
-
-int ath_vap_config(struct ath_softc *sc,
-       int if_id, struct ath_vap_config *if_config)
-{
-       struct ath_vap *avp;
-
-       if (if_id >= ATH_BCBUF) {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "%s: Invalid interface id = %u\n", __func__, if_id);
-               return -EINVAL;
-       }
-
-       avp = sc->sc_vaps[if_id];
-       ASSERT(avp != NULL);
-
-       if (avp)
-               memcpy(&avp->av_config, if_config, sizeof(avp->av_config));
-
-       return 0;
-}
-
 /********/
 /* Core */
 /********/
@@ -727,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
        DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n",
                __func__, sc->sc_ah->ah_opmode);
 
-       /*
-        * Stop anything previously setup.  This is safe
-        * whether this is the first time through or not.
-        */
-       ath_stop(sc);
-
-       /* Initialize chanmask selection */
-       sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
-       sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
-
        /* Reset SERDES registers */
        ath9k_hw_configpcipowersave(ah, 0);
 
@@ -762,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
                goto done;
        }
        spin_unlock_bh(&sc->sc_resetlock);
+
        /*
         * This is needed only to setup initial state
         * but it's best done after a reset.
@@ -781,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
                error = -EIO;
                goto done;
        }
+
        /* Setup our intr mask. */
        sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
                | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
@@ -810,30 +672,60 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
            (sc->sc_ah->ah_opmode == ATH9K_M_STA) &&
            !sc->sc_config.swBeaconProcess)
                sc->sc_imask |= ATH9K_INT_TIM;
-       /*
-        *  Don't enable interrupts here as we've not yet built our
-        *  vap and node data structures, which will be needed as soon
-        *  as we start receiving.
-        */
+
        ath_setcurmode(sc, ath_chan2mode(initial_chan));
 
-       /* XXX: we must make sure h/w is ready and clear invalid flag
-        * before turning on interrupt. */
        sc->sc_flags &= ~SC_OP_INVALID;
+
+       /* Disable BMISS interrupt when we're not associated */
+       sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+       ath9k_hw_set_interrupts(sc->sc_ah,sc->sc_imask);
+
+       ieee80211_wake_queues(sc->hw);
 done:
        return error;
 }
 
+void ath_stop(struct ath_softc *sc)
+{
+       struct ath_hal *ah = sc->sc_ah;
+
+       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__);
+
+       ieee80211_stop_queues(sc->hw);
+
+       /* make sure h/w will not generate any interrupt
+        * before setting the invalid flag. */
+       ath9k_hw_set_interrupts(ah, 0);
+
+       if (!(sc->sc_flags & SC_OP_INVALID)) {
+               ath_draintxq(sc, false);
+               ath_stoprecv(sc);
+               ath9k_hw_phy_disable(ah);
+       } else
+               sc->sc_rxlink = NULL;
+
+#ifdef CONFIG_RFKILL
+       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+               cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+       /* disable HAL and put h/w to sleep */
+       ath9k_hw_disable(sc->sc_ah);
+       ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+       sc->sc_flags |= SC_OP_INVALID;
+}
+
 int ath_reset(struct ath_softc *sc, bool retry_tx)
 {
        struct ath_hal *ah = sc->sc_ah;
        int status;
        int error = 0;
 
-       ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
-       ath_draintxq(sc, retry_tx);     /* stop xmit */
-       ath_stoprecv(sc);               /* stop recv */
-       ath_flushrecv(sc);              /* flush recv queue */
+       ath9k_hw_set_interrupts(ah, 0);
+       ath_draintxq(sc, retry_tx);
+       ath_stoprecv(sc);
+       ath_flushrecv(sc);
 
        /* Reset chip */
        spin_lock_bh(&sc->sc_resetlock);
@@ -848,7 +740,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        }
        spin_unlock_bh(&sc->sc_resetlock);
 
-       if (ath_startrecv(sc) != 0)     /* restart recv */
+       if (ath_startrecv(sc) != 0)
                DPRINTF(sc, ATH_DBG_FATAL,
                        "%s: unable to start recv logic\n", __func__);
 
@@ -881,29 +773,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        return error;
 }
 
-int ath_suspend(struct ath_softc *sc)
-{
-       struct ath_hal *ah = sc->sc_ah;
-
-       /* No I/O if device has been surprise removed */
-       if (sc->sc_flags & SC_OP_INVALID)
-               return -EIO;
-
-       /* Shut off the interrupt before setting sc->sc_invalid to '1' */
-       ath9k_hw_set_interrupts(ah, 0);
-
-       /* XXX: we must make sure h/w will not generate any interrupt
-        * before setting the invalid flag. */
-       sc->sc_flags |= SC_OP_INVALID;
-
-       /* disable HAL and put h/w to sleep */
-       ath9k_hw_disable(sc->sc_ah);
-
-       ath9k_hw_configpcipowersave(sc->sc_ah, 1);
-
-       return 0;
-}
-
 /* Interrupt handler.  Most of the actual processing is deferred.
  * It's the caller's responsibility to ensure the chip is awake. */
 
@@ -1071,11 +940,9 @@ int ath_init(u16 devid, struct ath_softc *sc)
 
        /* XXX: hardware will not be ready until ath_open() being called */
        sc->sc_flags |= SC_OP_INVALID;
-
        sc->sc_debug = DBG_DEFAULT;
-       DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
 
-       /* Initialize tasklet */
+       spin_lock_init(&sc->sc_resetlock);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
        tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
                     (unsigned long)sc);
@@ -1088,8 +955,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
        /* XXX assert csz is non-zero */
        sc->sc_cachelsz = csz << 2;     /* convert to bytes */
 
-       spin_lock_init(&sc->sc_resetlock);
-
        ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
        if (ah == NULL) {
                DPRINTF(sc, ATH_DBG_FATAL,
@@ -1100,10 +965,6 @@ int ath_init(u16 devid, struct ath_softc *sc)
        }
        sc->sc_ah = ah;
 
-       /* Initializes the noise floor to a reasonable default value.
-        * Later on this will be updated during ANI processing. */
-       sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
-
        /* Get the hardware key cache size. */
        sc->sc_keymax = ah->ah_caps.keycache_size;
        if (sc->sc_keymax > ATH_KEYMAX) {
@@ -1131,17 +992,14 @@ int ath_init(u16 devid, struct ath_softc *sc)
                set_bit(i + 64, sc->sc_keymap);
                set_bit(i + 32 + 64, sc->sc_keymap);
        }
-       /*
-        * Collect the channel list using the default country
-        * code and including outdoor channels.  The 802.11 layer
-        * is resposible for filtering this list based on settings
-        * like the phy mode.
-        */
+
+       /* Collect the channel list using the default country code */
+
        error = ath_setup_channels(sc);
        if (error)
                goto bad;
 
-       /* default to STA mode */
+       /* default to MONITOR mode */
        sc->sc_ah->ah_opmode = ATH9K_M_MONITOR;
 
        /* Setup rate tables */
@@ -1211,6 +1069,10 @@ int ath_init(u16 devid, struct ath_softc *sc)
                goto bad2;
        }
 
+       /* Initializes the noise floor to a reasonable default value.
+        * Later on this will be updated during ANI processing. */
+
+       sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR;
        setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
        sc->sc_rc = ath_rate_attach(ah);
@@ -1271,6 +1133,7 @@ int ath_init(u16 devid, struct ath_softc *sc)
                ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
                ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
        }
+
        sc->sc_slottime = ATH9K_SLOT_TIME_9;    /* default to short slot time */
 
        /* initialize beacon slots */
@@ -1285,6 +1148,22 @@ int ath_init(u16 devid, struct ath_softc *sc)
        ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
 #endif
 
+       /* setup channels and rates */
+
+       sc->sbands[IEEE80211_BAND_2GHZ].channels =
+               sc->channels[IEEE80211_BAND_2GHZ];
+       sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
+               sc->rates[IEEE80211_BAND_2GHZ];
+       sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+
+       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+               sc->sbands[IEEE80211_BAND_5GHZ].channels =
+                       sc->channels[IEEE80211_BAND_5GHZ];
+               sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+                       sc->rates[IEEE80211_BAND_5GHZ];
+               sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+       }
+
        return 0;
 bad2:
        /* cleanup tx queues */
@@ -1294,125 +1173,39 @@ bad2:
 bad:
        if (ah)
                ath9k_hw_detach(ah);
-       return error;
-}
-
-void ath_deinit(struct ath_softc *sc)
-{
-       struct ath_hal *ah = sc->sc_ah;
-       int i;
 
-       DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
-
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
-       ath_stop(sc);
-       if (!(sc->sc_flags & SC_OP_INVALID))
-               ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
-       ath_rate_detach(sc->sc_rc);
-       /* cleanup tx queues */
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i))
-                       ath_tx_cleanupq(sc, &sc->sc_txq[i]);
-       ath9k_hw_detach(ah);
+       return error;
 }
 
 /*******************/
 /* Node Management */
 /*******************/
 
-struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id)
+void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
-       struct ath_vap *avp;
        struct ath_node *an;
 
-       avp = sc->sc_vaps[if_id];
-       ASSERT(avp != NULL);
+       an = (struct ath_node *)sta->drv_priv;
 
-       /* mac80211 sta_notify callback is from an IRQ context, so no sleep */
-       an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
-       if (an == NULL)
-               return NULL;
-       memset(an, 0, sizeof(*an));
+       if (sc->sc_flags & SC_OP_TXAGGR)
+               ath_tx_node_init(sc, an);
 
-       an->an_sc = sc;
-       memcpy(an->an_addr, addr, ETH_ALEN);
-       atomic_set(&an->an_refcnt, 1);
-
-       /* set up per-node tx/rx state */
-       ath_tx_node_init(sc, an);
-       ath_rx_node_init(sc, an);
+       an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+                            sta->ht_cap.ampdu_factor);
+       an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
 
        ath_chainmask_sel_init(sc, an);
        ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
-       list_add(&an->list, &sc->node_list);
-
-       return an;
 }
 
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
+void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
-       unsigned long flags;
+       struct ath_node *an = (struct ath_node *)sta->drv_priv;
 
        ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
-       an->an_flags |= ATH_NODE_CLEAN;
-       ath_tx_node_cleanup(sc, an, bh_flag);
-       ath_rx_node_cleanup(sc, an);
-
-       ath_tx_node_free(sc, an);
-       ath_rx_node_free(sc, an);
-
-       spin_lock_irqsave(&sc->node_lock, flags);
-
-       list_del(&an->list);
-
-       spin_unlock_irqrestore(&sc->node_lock, flags);
 
-       kfree(an);
-}
-
-/* Finds a node and increases the refcnt if found */
-
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr)
-{
-       struct ath_node *an = NULL, *an_found = NULL;
-
-       if (list_empty(&sc->node_list)) /* FIXME */
-               goto out;
-       list_for_each_entry(an, &sc->node_list, list) {
-               if (!compare_ether_addr(an->an_addr, addr)) {
-                       atomic_inc(&an->an_refcnt);
-                       an_found = an;
-                       break;
-               }
-       }
-out:
-       return an_found;
-}
-
-/* Decrements the refcnt and if it drops to zero, detach the node */
-
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
-{
-       if (atomic_dec_and_test(&an->an_refcnt))
-               ath_node_detach(sc, an, bh_flag);
-}
-
-/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr)
-{
-       struct ath_node *an = NULL, *an_found = NULL;
-
-       if (list_empty(&sc->node_list))
-               return NULL;
-
-       list_for_each_entry(an, &sc->node_list, list)
-               if (!compare_ether_addr(an->an_addr, addr)) {
-                       an_found = an;
-                       break;
-               }
-
-       return an_found;
+       if (sc->sc_flags & SC_OP_TXAGGR)
+               ath_tx_node_cleanup(sc, an);
 }
 
 /*
@@ -1433,11 +1226,8 @@ void ath_newassoc(struct ath_softc *sc,
                for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
                        if (sc->sc_flags & SC_OP_TXAGGR)
                                ath_tx_aggr_teardown(sc, an, tidno);
-                       if (sc->sc_flags & SC_OP_RXAGGR)
-                               ath_rx_aggr_teardown(sc, an, tidno);
                }
        }
-       an->an_flags = 0;
 }
 
 /**************/
@@ -1488,27 +1278,6 @@ void ath_update_txpow(struct ath_softc *sc)
        }
 }
 
-/* Return the current country and domain information */
-void ath_get_currentCountry(struct ath_softc *sc,
-       struct ath9k_country_entry *ctry)
-{
-       ath9k_regd_get_current_country(sc->sc_ah, ctry);
-
-       /* If HAL not specific yet, since it is band dependent,
-        * use the one we passed in. */
-       if (ctry->countryCode == CTRY_DEFAULT) {
-               ctry->iso[0] = 0;
-               ctry->iso[1] = 0;
-       } else if (ctry->iso[0] && ctry->iso[1]) {
-               if (!ctry->iso[2]) {
-                       if (ath_outdoor)
-                               ctry->iso[2] = 'O';
-                       else
-                               ctry->iso[2] = 'I';
-               }
-       }
-}
-
 /**************************/
 /* Slow Antenna Diversity */
 /**************************/
index fbff9aa4c28fcd3c74de3e0b9e661efb2927c86b..69e8d3e4113113929963a75a2b04f95a8776f381 100644 (file)
@@ -84,9 +84,6 @@ struct ath_node;
 #define TSF_TO_TU(_h,_l) \
        ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
-#define ATH9K_BH_STATUS_INTACT         0
-#define ATH9K_BH_STATUS_CHANGE         1
-
 #define        ATH_TXQ_SETUP(sc, i)        ((sc)->sc_txqsetup & (1<<i))
 
 static inline unsigned long get_timestamp(void)
@@ -209,6 +206,7 @@ struct ath_buf_state {
        struct ath_rc_series bfs_rcs[4];        /* rate series */
        u32 bf_type;                            /* BUF_* (enum buffer_type) */
        /* key type use to encrypt this frame */
+       u32 bfs_keyix;
        enum ath9k_key_type bfs_keytype;
 };
 
@@ -219,6 +217,7 @@ struct ath_buf_state {
 #define bf_seqno               bf_state.bfs_seqno
 #define bf_tidno               bf_state.bfs_tidno
 #define bf_rcs                 bf_state.bfs_rcs
+#define bf_keyix                bf_state.bfs_keyix
 #define bf_keytype             bf_state.bfs_keytype
 #define bf_isdata(bf)          (bf->bf_state.bf_type & BUF_DATA)
 #define bf_isaggr(bf)          (bf->bf_state.bf_type & BUF_AGGR)
@@ -244,7 +243,6 @@ struct ath_buf {
        struct ath_buf *bf_next;        /* next subframe in the aggregate */
        struct ath_buf *bf_rifslast;    /* last buf for RIFS burst */
        void *bf_mpdu;                  /* enclosing frame structure */
-       void *bf_node;                  /* pointer to the node */
        struct ath_desc *bf_desc;       /* virtual addr of desc */
        dma_addr_t bf_daddr;            /* physical addr of desc */
        dma_addr_t bf_buf_addr;         /* physical addr of data buffer */
@@ -306,15 +304,7 @@ void ath_descdma_cleanup(struct ath_softc *sc,
 
 #define ATH_MAX_ANTENNA          3
 #define ATH_RXBUF                512
-#define ATH_RX_TIMEOUT           40      /* 40 milliseconds */
 #define WME_NUM_TID              16
-#define IEEE80211_BAR_CTL_TID_M  0xF000  /* tid mask */
-#define IEEE80211_BAR_CTL_TID_S  12      /* tid shift */
-
-enum ATH_RX_TYPE {
-       ATH_RX_NON_CONSUMED = 0,
-       ATH_RX_CONSUMED
-};
 
 /* per frame rx status block */
 struct ath_recv_status {
@@ -348,48 +338,18 @@ struct ath_rxbuf {
        struct ath_recv_status rx_status;       /* cached rx status */
 };
 
-/* Per-TID aggregate receiver state for a node */
-struct ath_arx_tid {
-       struct ath_node *an;
-       struct ath_rxbuf *rxbuf;        /* re-ordering buffer */
-       struct timer_list timer;
-       spinlock_t tidlock;
-       int baw_head;                   /* seq_next at head */
-       int baw_tail;                   /* tail of block-ack window */
-       int seq_reset;                  /* need to reset start sequence */
-       int addba_exchangecomplete;
-       u16 seq_next;                   /* next expected sequence */
-       u16 baw_size;                   /* block-ack window size */
-};
-
-/* Per-node receiver aggregate state */
-struct ath_arx {
-       struct ath_arx_tid tid[WME_NUM_TID];
-};
-
 int ath_startrecv(struct ath_softc *sc);
 bool ath_stoprecv(struct ath_softc *sc);
 void ath_flushrecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an);
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_handle_rx_intr(struct ath_softc *sc);
 int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
 int ath_rx_tasklet(struct ath_softc *sc, int flush);
-int ath_rx_input(struct ath_softc *sc,
-                struct ath_node *node,
-                struct sk_buff *skb,
-                struct ath_recv_status *rx_status,
-                enum ATH_RX_TYPE *status);
 int _ath_rx_indicate(struct ath_softc *sc,
                     struct sk_buff *skb,
                     struct ath_recv_status *status,
                     u16 keyix);
-int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
-                   struct ath_recv_status *status);
-
 /******/
 /* TX */
 /******/
@@ -418,12 +378,6 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
 #define WME_AC_VO               3 /* voice */
 #define WME_NUM_AC              4
 
-enum ATH_SM_PWRSAV{
-       ATH_SM_ENABLE,
-       ATH_SM_PWRSAV_STATIC,
-       ATH_SM_PWRSAV_DYNAMIC,
-};
-
 /*
  * Data transmit queue state.  One of these exists for each
  * hardware transmit queue.  Packets sent to us from above
@@ -456,6 +410,10 @@ struct ath_txq {
        struct list_head axq_acq;
 };
 
+#define AGGR_CLEANUP         BIT(1)
+#define AGGR_ADDBA_COMPLETE  BIT(2)
+#define AGGR_ADDBA_PROGRESS  BIT(3)
+
 /* per TID aggregate tx state for a destination */
 struct ath_atx_tid {
        struct list_head list;          /* round-robin tid entry */
@@ -471,9 +429,7 @@ struct ath_atx_tid {
        int baw_tail;                   /* next unused tx buffer slot */
        int sched;
        int paused;
-       int cleanup_inprogress;
-       u32 addba_exchangecomplete:1;
-       int32_t addba_exchangeinprogress;
+       u8 state;
        int addba_exchangeattempts;
 };
 
@@ -494,24 +450,8 @@ struct ath_atx {
 
 /* per-frame tx control block */
 struct ath_tx_control {
-       struct ath_node *an;
+       struct ath_txq *txq;
        int if_id;
-       int qnum;
-       u32 ht:1;
-       u32 ps:1;
-       u32 use_minrate:1;
-       enum ath9k_pkt_type atype;
-       enum ath9k_key_type keytype;
-       u32 flags;
-       u16 seqno;
-       u16 tidno;
-       u16 txpower;
-       u16 frmlen;
-       u32 keyix;
-       int min_rate;
-       int mcast_rate;
-       struct ath_softc *dev;
-       dma_addr_t dmacontext;
 };
 
 /* per frame tx status block */
@@ -546,33 +486,29 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx);
 void ath_tx_draintxq(struct ath_softc *sc,
                     struct ath_txq *txq, bool retry_tx);
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
-void ath_tx_node_cleanup(struct ath_softc *sc,
-                        struct ath_node *an, bool bh_flag);
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_init(struct ath_softc *sc, int nbufs);
 int ath_tx_cleanup(struct ath_softc *sc);
 int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
 int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+                struct ath_tx_control *txctl);
 void ath_tx_tasklet(struct ath_softc *sc);
 u32 ath_txq_depth(struct ath_softc *sc, int qnum);
 u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
 void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-                    struct ath_xmit_status *tx_status, struct ath_node *an);
+                    struct ath_xmit_status *tx_status);
 void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 
 /**********************/
 /* Node / Aggregation */
 /**********************/
 
-/* indicates the node is clened up */
-#define ATH_NODE_CLEAN          0x1
-/* indicates the node is 80211 power save */
-#define ATH_NODE_PWRSAVE        0x2
-
 #define ADDBA_EXCHANGE_ATTEMPTS    10
 #define ATH_AGGR_DELIM_SZ          4   /* delimiter size   */
 #define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
@@ -584,6 +520,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
 #define IEEE80211_SEQ_SEQ_SHIFT    4
 #define IEEE80211_SEQ_MAX          4096
 #define IEEE80211_MIN_AMPDU_BUF    0x8
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
 
 /* return whether a bit at index _n in bitmap _bm is set
  * _sz is the size of the bitmap  */
@@ -614,14 +551,6 @@ enum ATH_AGGR_STATUS {
        ATH_AGGR_8K_LIMITED,
 };
 
-enum ATH_AGGR_CHECK {
-       AGGR_NOT_REQUIRED,
-       AGGR_REQUIRED,
-       AGGR_CLEANUP_PROGRESS,
-       AGGR_EXCHANGE_PROGRESS,
-       AGGR_EXCHANGE_DONE
-};
-
 struct aggr_rifs_param {
        int param_max_frames;
        int param_max_len;
@@ -633,54 +562,30 @@ struct aggr_rifs_param {
 /* Per-node aggregation state */
 struct ath_node_aggr {
        struct ath_atx tx;      /* node transmit state */
-       struct ath_arx rx;      /* node receive state */
 };
 
 /* driver-specific node state */
 struct ath_node {
-       struct list_head list;
        struct ath_softc *an_sc;
-       atomic_t an_refcnt;
        struct ath_chainmask_sel an_chainmask_sel;
        struct ath_node_aggr an_aggr;
-       u8 an_smmode; /* SM Power save mode */
-       u8 an_flags;
-       u8 an_addr[ETH_ALEN];
-
        u16 maxampdu;
        u8 mpdudensity;
 };
 
 void ath_tx_resume_tid(struct ath_softc *sc,
        struct ath_atx_tid *tid);
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
-       struct ath_node *an, u8 tidno);
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
 void ath_tx_aggr_teardown(struct ath_softc *sc,
        struct ath_node *an, u8 tidno);
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-       struct ath_node *an, u8 tidno);
-int ath_rx_aggr_start(struct ath_softc *sc,
-                     const u8 *addr,
-                     u16 tid,
-                     u16 *ssn);
-int ath_rx_aggr_stop(struct ath_softc *sc,
-                    const u8 *addr,
-                    u16 tid);
-int ath_tx_aggr_start(struct ath_softc *sc,
-                     const u8 *addr,
-                     u16 tid,
-                     u16 *ssn);
-int ath_tx_aggr_stop(struct ath_softc *sc,
-                    const u8 *addr,
-                    u16 tid);
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+                     u16 tid, u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
 void ath_newassoc(struct ath_softc *sc,
        struct ath_node *node, int isnew, int isuapsd);
-struct ath_node *ath_node_attach(struct ath_softc *sc,
-       u8 addr[ETH_ALEN], int if_id);
-void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]);
-void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
-struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
+void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta);
+void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta);
 
 /*******************/
 /* Beacon Handling */
@@ -744,23 +649,14 @@ struct ath_vap_config {
 
 /* driver-specific vap state */
 struct ath_vap {
-       struct ieee80211_vif *av_if_data;
+       int av_bslot;                   /* beacon slot index */
        enum ath9k_opmode av_opmode;    /* VAP operational mode */
        struct ath_buf *av_bcbuf;       /* beacon buffer */
        struct ath_tx_control av_btxctl;  /* txctl information for beacon */
-       int av_bslot;                   /* beacon slot index */
        struct ath_vap_config av_config;/* vap configuration parameters*/
        struct ath_rate_node *rc_node;
 };
 
-int ath_vap_attach(struct ath_softc *sc,
-                  int if_id,
-                  struct ieee80211_vif *if_data,
-                  enum ath9k_opmode opmode);
-int ath_vap_detach(struct ath_softc *sc, int if_id);
-int ath_vap_config(struct ath_softc *sc,
-                  int if_id, struct ath_vap_config *if_config);
-
 /*********************/
 /* Antenna diversity */
 /*********************/
@@ -968,14 +864,13 @@ struct ath_softc {
 
        u8 sc_nbcnvaps;                 /* # of vaps sending beacons */
        u16 sc_nvaps;                   /* # of active virtual ap's */
-       struct ath_vap *sc_vaps[ATH_BCBUF];
+       struct ieee80211_vif *sc_vaps[ATH_BCBUF];
 
        u8 sc_mcastantenna;
        u8 sc_defant;                   /* current default antenna */
        u8 sc_rxotherant;               /* rx's on non-default antenna */
 
        struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
-       struct list_head node_list;
        struct ath_ht_info sc_ht_info;
        enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
 
@@ -1036,7 +931,6 @@ struct ath_softc {
        spinlock_t sc_rxbuflock;
        spinlock_t sc_txbuflock;
        spinlock_t sc_resetlock;
-       spinlock_t node_lock;
 
        /* LEDs */
        struct ath_led radio_led;
@@ -1052,9 +946,8 @@ struct ath_softc {
 };
 
 int ath_init(u16 devid, struct ath_softc *sc);
-void ath_deinit(struct ath_softc *sc);
 int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
-int ath_suspend(struct ath_softc *sc);
+void ath_stop(struct ath_softc *sc);
 irqreturn_t ath_isr(int irq, void *dev);
 int ath_reset(struct ath_softc *sc, bool retry_tx);
 int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
@@ -1073,8 +966,6 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
 void ath_setslottime(struct ath_softc *sc);
 void ath_update_txpow(struct ath_softc *sc);
 int ath_cabq_update(struct ath_softc *);
-void ath_get_currentCountry(struct ath_softc *sc,
-       struct ath9k_country_entry *ctry);
 u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
 
 #endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
new file mode 100644 (file)
index 0000000..f5fd03c
--- /dev/null
@@ -0,0 +1,1605 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+                                     u32 reg, u32 mask,
+                                     u32 shift, u32 val)
+{
+       u32 regVal;
+
+       regVal = REG_READ(ah, reg) & ~mask;
+       regVal |= (val << shift) & mask;
+
+       REG_WRITE(ah, reg, regVal);
+
+       if (ah->ah_config.analog_shiftreg)
+               udelay(100);
+
+       return;
+}
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
+{
+
+       if (fbin == AR5416_BCHAN_UNUSED)
+               return fbin;
+
+       return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static inline int16_t ath9k_hw_interpolate(u16 target,
+                                          u16 srcLeft, u16 srcRight,
+                                          int16_t targetLeft,
+                                          int16_t targetRight)
+{
+       int16_t rv;
+
+       if (srcRight == srcLeft) {
+               rv = targetLeft;
+       } else {
+               rv = (int16_t) (((target - srcLeft) * targetRight +
+                                (srcRight - target) * targetLeft) /
+                               (srcRight - srcLeft));
+       }
+       return rv;
+}
+
+static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
+                                                 u16 listSize, u16 *indexL,
+                                                 u16 *indexR)
+{
+       u16 i;
+
+       if (target <= pList[0]) {
+               *indexL = *indexR = 0;
+               return true;
+       }
+       if (target >= pList[listSize - 1]) {
+               *indexL = *indexR = (u16) (listSize - 1);
+               return true;
+       }
+
+       for (i = 0; i < listSize - 1; i++) {
+               if (pList[i] == target) {
+                       *indexL = *indexR = i;
+                       return true;
+               }
+               if (target < pList[i + 1]) {
+                       *indexL = i;
+                       *indexR = (u16) (i + 1);
+                       return false;
+               }
+       }
+       return false;
+}
+
+static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+       (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+       if (!ath9k_hw_wait(ah,
+                          AR_EEPROM_STATUS_DATA,
+                          AR_EEPROM_STATUS_DATA_BUSY |
+                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+               return false;
+       }
+
+       *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+                  AR_EEPROM_STATUS_DATA_VAL);
+
+       return true;
+}
+
+static int ath9k_hw_flash_map(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+
+       if (!ahp->ah_cal_mem) {
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "%s: cannot remap eeprom region \n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       *data = ioread16(ahp->ah_cal_mem + off);
+
+       return true;
+}
+
+static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+       if (ath9k_hw_use_flash(ah))
+               return ath9k_hw_flash_read(ah, off, data);
+       else
+               return ath9k_hw_eeprom_read(ah, off, data);
+}
+
+static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       u16 *eep_data;
+       int addr, ar5416_eep_start_loc = 0;
+
+       if (!ath9k_hw_use_flash(ah)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "%s: Reading from EEPROM, not flash\n", __func__);
+               ar5416_eep_start_loc = 256;
+       }
+
+       if (AR_SREV_9100(ah))
+               ar5416_eep_start_loc = 256;
+
+       eep_data = (u16 *)eep;
+
+       for (addr = 0; addr < sizeof(struct ar5416_eeprom) / sizeof(u16); addr++) {
+               if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+                                        eep_data)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                               "%s: Unable to read eeprom region \n",
+                               __func__);
+                       return false;
+               }
+               eep_data++;
+       }
+       return true;
+}
+
+static int ath9k_hw_check_eeprom(struct ath_hal *ah)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep =
+               (struct ar5416_eeprom *) &ahp->ah_eeprom;
+       u16 *eepdata, temp, magic, magic2;
+       u32 sum = 0, el;
+       bool need_swap = false;
+       int i, addr, size;
+
+       if (!ath9k_hw_use_flash(ah)) {
+               if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+                                        &magic)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                               "%s: Reading Magic # failed\n", __func__);
+                       return false;
+               }
+
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
+                        __func__, magic);
+
+               if (magic != AR5416_EEPROM_MAGIC) {
+                       magic2 = swab16(magic);
+
+                       if (magic2 == AR5416_EEPROM_MAGIC) {
+                               size = sizeof(struct ar5416_eeprom);
+                               need_swap = true;
+                               eepdata = (u16 *) (&ahp->ah_eeprom);
+
+                               for (addr = 0; addr < size / sizeof(u16); addr++) {
+                                       temp = swab16(*eepdata);
+                                       *eepdata = temp;
+                                       eepdata++;
+
+                                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                                               "0x%04X  ", *eepdata);
+
+                                       if (((addr + 1) % 6) == 0)
+                                               DPRINTF(ah->ah_sc,
+                                                       ATH_DBG_EEPROM, "\n");
+                               }
+                       } else {
+                               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                                       "Invalid EEPROM Magic. "
+                                       "endianness mismatch.\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+               need_swap ? "True" : "False");
+
+       if (need_swap)
+               el = swab16(ahp->ah_eeprom.baseEepHeader.length);
+       else
+               el = ahp->ah_eeprom.baseEepHeader.length;
+
+       if (el > sizeof(struct ar5416_eeprom))
+               el = sizeof(struct ar5416_eeprom) / sizeof(u16);
+       else
+               el = el / sizeof(u16);
+
+       eepdata = (u16 *)(&ahp->ah_eeprom);
+
+       for (i = 0; i < el; i++)
+               sum ^= *eepdata++;
+
+       if (need_swap) {
+               u32 integer, j;
+               u16 word;
+
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "EEPROM Endianness is not native.. Changing \n");
+
+               word = swab16(eep->baseEepHeader.length);
+               eep->baseEepHeader.length = word;
+
+               word = swab16(eep->baseEepHeader.checksum);
+               eep->baseEepHeader.checksum = word;
+
+               word = swab16(eep->baseEepHeader.version);
+               eep->baseEepHeader.version = word;
+
+               word = swab16(eep->baseEepHeader.regDmn[0]);
+               eep->baseEepHeader.regDmn[0] = word;
+
+               word = swab16(eep->baseEepHeader.regDmn[1]);
+               eep->baseEepHeader.regDmn[1] = word;
+
+               word = swab16(eep->baseEepHeader.rfSilent);
+               eep->baseEepHeader.rfSilent = word;
+
+               word = swab16(eep->baseEepHeader.blueToothOptions);
+               eep->baseEepHeader.blueToothOptions = word;
+
+               word = swab16(eep->baseEepHeader.deviceCap);
+               eep->baseEepHeader.deviceCap = word;
+
+               for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+                       struct modal_eep_header *pModal =
+                               &eep->modalHeader[j];
+                       integer = swab32(pModal->antCtrlCommon);
+                       pModal->antCtrlCommon = integer;
+
+                       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+                               integer = swab32(pModal->antCtrlChain[i]);
+                               pModal->antCtrlChain[i] = integer;
+                       }
+
+                       for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+                               word = swab16(pModal->spurChans[i].spurChan);
+                               pModal->spurChans[i].spurChan = word;
+                       }
+               }
+       }
+
+       if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
+           ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+                       sum, ar5416_get_eep_ver(ahp));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+                                          u8 *pVpdList, u16 numIntercepts,
+                                          u8 *pRetVpdList)
+{
+       u16 i, k;
+       u8 currPwr = pwrMin;
+       u16 idxL = 0, idxR = 0;
+
+       for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+               ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+                                              numIntercepts, &(idxL),
+                                              &(idxR));
+               if (idxR < 1)
+                       idxR = 1;
+               if (idxL == numIntercepts - 1)
+                       idxL = (u16) (numIntercepts - 2);
+               if (pPwrList[idxL] == pPwrList[idxR])
+                       k = pVpdList[idxL];
+               else
+                       k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+                                  (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+                                 (pPwrList[idxR] - pPwrList[idxL]));
+               pRetVpdList[i] = (u8) k;
+               currPwr += 2;
+       }
+
+       return true;
+}
+
+static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
+                               struct ath9k_channel *chan,
+                               struct cal_data_per_freq *pRawDataSet,
+                               u8 *bChans, u16 availPiers,
+                               u16 tPdGainOverlap, int16_t *pMinCalPower,
+                               u16 *pPdGainBoundaries, u8 *pPDADCValues,
+                               u16 numXpdGains)
+{
+       int i, j, k;
+       int16_t ss;
+       u16 idxL = 0, idxR = 0, numPiers;
+       static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+       static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+       static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+       u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+       u8 minPwrT4[AR5416_NUM_PD_GAINS];
+       u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+       int16_t vpdStep;
+       int16_t tmpVal;
+       u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+       bool match;
+       int16_t minDelta = 0;
+       struct chan_centers centers;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+       for (numPiers = 0; numPiers < availPiers; numPiers++) {
+               if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+                       break;
+       }
+
+       match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+                                                            IS_CHAN_2GHZ(chan)),
+                                              bChans, numPiers, &idxL, &idxR);
+
+       if (match) {
+               for (i = 0; i < numXpdGains; i++) {
+                       minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+                       maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+                                       pRawDataSet[idxL].pwrPdg[i],
+                                       pRawDataSet[idxL].vpdPdg[i],
+                                       AR5416_PD_GAIN_ICEPTS,
+                                       vpdTableI[i]);
+               }
+       } else {
+               for (i = 0; i < numXpdGains; i++) {
+                       pVpdL = pRawDataSet[idxL].vpdPdg[i];
+                       pPwrL = pRawDataSet[idxL].pwrPdg[i];
+                       pVpdR = pRawDataSet[idxR].vpdPdg[i];
+                       pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+                       minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+                       maxPwrT4[i] =
+                               min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+                                   pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+                                               pPwrL, pVpdL,
+                                               AR5416_PD_GAIN_ICEPTS,
+                                               vpdTableL[i]);
+                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+                                               pPwrR, pVpdR,
+                                               AR5416_PD_GAIN_ICEPTS,
+                                               vpdTableR[i]);
+
+                       for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+                               vpdTableI[i][j] =
+                                       (u8)(ath9k_hw_interpolate((u16)
+                                            FREQ2FBIN(centers.
+                                                      synth_center,
+                                                      IS_CHAN_2GHZ
+                                                      (chan)),
+                                            bChans[idxL], bChans[idxR],
+                                            vpdTableL[i][j], vpdTableR[i][j]));
+                       }
+               }
+       }
+
+       *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+
+       k = 0;
+
+       for (i = 0; i < numXpdGains; i++) {
+               if (i == (numXpdGains - 1))
+                       pPdGainBoundaries[i] =
+                               (u16)(maxPwrT4[i] / 2);
+               else
+                       pPdGainBoundaries[i] =
+                               (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+               pPdGainBoundaries[i] =
+                       min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+               if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+                       minDelta = pPdGainBoundaries[0] - 23;
+                       pPdGainBoundaries[0] = 23;
+               } else {
+                       minDelta = 0;
+               }
+
+               if (i == 0) {
+                       if (AR_SREV_9280_10_OR_LATER(ah))
+                               ss = (int16_t)(0 - (minPwrT4[i] / 2));
+                       else
+                               ss = 0;
+               } else {
+                       ss = (int16_t)((pPdGainBoundaries[i - 1] -
+                                       (minPwrT4[i] / 2)) -
+                                      tPdGainOverlap + 1 + minDelta);
+               }
+               vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+               vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+               while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+                       tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+                       pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+                       ss++;
+               }
+
+               sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+               tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+                               (minPwrT4[i] / 2));
+               maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+                       tgtIndex : sizeCurrVpdTable;
+
+               while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+                       pPDADCValues[k++] = vpdTableI[i][ss++];
+               }
+
+               vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+                                   vpdTableI[i][sizeCurrVpdTable - 2]);
+               vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+               if (tgtIndex > maxIndex) {
+                       while ((ss <= tgtIndex) &&
+                              (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+                               tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+                                                   (ss - maxIndex + 1) * vpdStep));
+                               pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+                                                        255 : tmpVal);
+                               ss++;
+                       }
+               }
+       }
+
+       while (i < AR5416_PD_GAINS_IN_MASK) {
+               pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+               i++;
+       }
+
+       while (k < AR5416_NUM_PDADC_VALUES) {
+               pPDADCValues[k] = pPDADCValues[k - 1];
+               k++;
+       }
+
+       return;
+}
+
+static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
+                                     struct ath9k_channel *chan,
+                                     struct cal_target_power_leg *powInfo,
+                                     u16 numChannels,
+                                     struct cal_target_power_leg *pNewPower,
+                                     u16 numRates, bool isExtTarget)
+{
+       struct chan_centers centers;
+       u16 clo, chi;
+       int i;
+       int matchIndex = -1, lowIndex = -1;
+       u16 freq;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+       if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+                                      IS_CHAN_2GHZ(chan))) {
+               matchIndex = 0;
+       } else {
+               for (i = 0; (i < numChannels) &&
+                            (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+                       if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+                                                      IS_CHAN_2GHZ(chan))) {
+                               matchIndex = i;
+                               break;
+                       } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+                                                     IS_CHAN_2GHZ(chan))) &&
+                                  (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+                                                     IS_CHAN_2GHZ(chan)))) {
+                               lowIndex = i - 1;
+                               break;
+                       }
+               }
+               if ((matchIndex == -1) && (lowIndex == -1))
+                       matchIndex = i - 1;
+       }
+
+       if (matchIndex != -1) {
+               *pNewPower = powInfo[matchIndex];
+       } else {
+               clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+                                        IS_CHAN_2GHZ(chan));
+               chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+                                        IS_CHAN_2GHZ(chan));
+
+               for (i = 0; i < numRates; i++) {
+                       pNewPower->tPow2x[i] =
+                               (u8)ath9k_hw_interpolate(freq, clo, chi,
+                                               powInfo[lowIndex].tPow2x[i],
+                                               powInfo[lowIndex + 1].tPow2x[i]);
+               }
+       }
+}
+
+static void ath9k_hw_get_target_powers(struct ath_hal *ah,
+                                      struct ath9k_channel *chan,
+                                      struct cal_target_power_ht *powInfo,
+                                      u16 numChannels,
+                                      struct cal_target_power_ht *pNewPower,
+                                      u16 numRates, bool isHt40Target)
+{
+       struct chan_centers centers;
+       u16 clo, chi;
+       int i;
+       int matchIndex = -1, lowIndex = -1;
+       u16 freq;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+       if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+               matchIndex = 0;
+       } else {
+               for (i = 0; (i < numChannels) &&
+                            (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+                       if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+                                                      IS_CHAN_2GHZ(chan))) {
+                               matchIndex = i;
+                               break;
+                       } else
+                               if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+                                                      IS_CHAN_2GHZ(chan))) &&
+                                   (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+                                                      IS_CHAN_2GHZ(chan)))) {
+                                       lowIndex = i - 1;
+                                       break;
+                               }
+               }
+               if ((matchIndex == -1) && (lowIndex == -1))
+                       matchIndex = i - 1;
+       }
+
+       if (matchIndex != -1) {
+               *pNewPower = powInfo[matchIndex];
+       } else {
+               clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+                                        IS_CHAN_2GHZ(chan));
+               chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+                                        IS_CHAN_2GHZ(chan));
+
+               for (i = 0; i < numRates; i++) {
+                       pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+                                               clo, chi,
+                                               powInfo[lowIndex].tPow2x[i],
+                                               powInfo[lowIndex + 1].tPow2x[i]);
+               }
+       }
+}
+
+static u16 ath9k_hw_get_max_edge_power(u16 freq,
+                                      struct cal_ctl_edges *pRdEdgesPower,
+                                      bool is2GHz)
+{
+       u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+       int i;
+
+       for (i = 0; (i < AR5416_NUM_BAND_EDGES) &&
+                    (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+               if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+                       twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+                       break;
+               } else if ((i > 0) &&
+                          (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+                                                     is2GHz))) {
+                       if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+                                              is2GHz) < freq &&
+                           pRdEdgesPower[i - 1].flag) {
+                               twiceMaxEdgePower =
+                                       pRdEdgesPower[i - 1].tPower;
+                       }
+                       break;
+               }
+       }
+
+       return twiceMaxEdgePower;
+}
+
+int ath9k_hw_set_txpower(struct ath_hal *ah,
+                        struct ath9k_channel *chan,
+                        u16 cfgCtl,
+                        u8 twiceAntennaReduction,
+                        u8 twiceMaxRegulatoryPower,
+                        u8 powerLimit)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+       struct modal_eep_header *pModal =
+               &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+       int16_t ratesArray[Ar5416RateSize];
+       int16_t txPowerIndexOffset = 0;
+       u8 ht40PowerIncForPdadc = 2;
+       int i;
+
+       memset(ratesArray, 0, sizeof(ratesArray));
+
+       if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+           AR5416_EEP_MINOR_VER_2) {
+               ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+       }
+
+       if (!ath9k_hw_set_power_per_rate_table(ah, chan,
+                                              &ratesArray[0], cfgCtl,
+                                              twiceAntennaReduction,
+                                              twiceMaxRegulatoryPower,
+                                              powerLimit)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "ath9k_hw_set_txpower: unable to set "
+                       "tx power per rate table\n");
+               return -EIO;
+       }
+
+       if (!ath9k_hw_set_power_cal_table(ah, chan, &txPowerIndexOffset)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                        "ath9k_hw_set_txpower: unable to set power table\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+               ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+               if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+                       ratesArray[i] = AR5416_MAX_RATE_POWER;
+       }
+
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               for (i = 0; i < Ar5416RateSize; i++)
+                       ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+       }
+
+       REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+                 ATH9K_POW_SM(ratesArray[rate18mb], 24)
+                 | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+                 | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+                 | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+       REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+                 ATH9K_POW_SM(ratesArray[rate54mb], 24)
+                 | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+                 | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+                 | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+       if (IS_CHAN_2GHZ(chan)) {
+               REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+                         ATH9K_POW_SM(ratesArray[rate2s], 24)
+                         | ATH9K_POW_SM(ratesArray[rate2l], 16)
+                         | ATH9K_POW_SM(ratesArray[rateXr], 8)
+                         | ATH9K_POW_SM(ratesArray[rate1l], 0));
+               REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+                         ATH9K_POW_SM(ratesArray[rate11s], 24)
+                         | ATH9K_POW_SM(ratesArray[rate11l], 16)
+                         | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+                         | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+       }
+
+       REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+                 ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+       REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+                 ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+                 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+       if (IS_CHAN_HT40(chan)) {
+               REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+                         ATH9K_POW_SM(ratesArray[rateHt40_3] +
+                                      ht40PowerIncForPdadc, 24)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+                                        ht40PowerIncForPdadc, 16)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+                                        ht40PowerIncForPdadc, 8)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+                                        ht40PowerIncForPdadc, 0));
+               REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+                         ATH9K_POW_SM(ratesArray[rateHt40_7] +
+                                      ht40PowerIncForPdadc, 24)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+                                        ht40PowerIncForPdadc, 16)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+                                        ht40PowerIncForPdadc, 8)
+                         | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+                                        ht40PowerIncForPdadc, 0));
+
+               REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+                         ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+                         | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+                         | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+                         | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+       }
+
+       REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+                 ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+                 | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+       i = rate6mb;
+
+       if (IS_CHAN_HT40(chan))
+               i = rateHt40_0;
+       else if (IS_CHAN_HT20(chan))
+               i = rateHt20_0;
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               ah->ah_maxPowerLevel =
+                       ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+       else
+               ah->ah_maxPowerLevel = ratesArray[i];
+
+       return 0;
+}
+
+void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+       struct modal_eep_header *pModal;
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       u8 biaslevel;
+
+       if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+               return;
+
+       if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+               return;
+
+       pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+       if (pModal->xpaBiasLvl != 0xff) {
+               biaslevel = pModal->xpaBiasLvl;
+       } else {
+               u16 resetFreqBin, freqBin, freqCount = 0;
+               struct chan_centers centers;
+
+               ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+               resetFreqBin = FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
+               freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
+               biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
+
+               freqCount++;
+
+               while (freqCount < 3) {
+                       if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
+                               break;
+
+                       freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
+                       if (resetFreqBin >= freqBin) {
+                               biaslevel = (u8)(pModal->xpaBiasLvlFreq[freqCount] >> 14);
+                       } else {
+                               break;
+                       }
+                       freqCount++;
+               }
+       }
+
+       if (IS_CHAN_2GHZ(chan)) {
+               INI_RA(&ahp->ah_iniAddac, 7, 1) =
+                       (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+       } else {
+               INI_RA(&ahp->ah_iniAddac, 6, 1) =
+                       (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel << 6;
+       }
+}
+
+bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+                                      struct ath9k_channel *chan,
+                                      int16_t *ratesArray,
+                                      u16 cfgCtl,
+                                      u8 AntennaReduction,
+                                      u8 twiceMaxRegulatoryPower,
+                                      u8 powerLimit)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+       u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+       static const u16 tpScaleReductionTable[5] =
+               { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+       int i;
+       int8_t twiceLargestAntenna;
+       struct cal_ctl_data *rep;
+       struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+               0, { 0, 0, 0, 0}
+       };
+       struct cal_target_power_leg targetPowerOfdmExt = {
+               0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+               0, { 0, 0, 0, 0 }
+       };
+       struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+               0, {0, 0, 0, 0}
+       };
+       u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+       u16 ctlModesFor11a[] =
+               { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+       u16 ctlModesFor11g[] =
+               { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+                 CTL_2GHT40
+               };
+       u16 numCtlModes, *pCtlMode, ctlMode, freq;
+       struct chan_centers centers;
+       int tx_chainmask;
+       u8 twiceMinEdgePower;
+
+       tx_chainmask = ahp->ah_txchainmask;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+       twiceLargestAntenna = max(
+               pEepData->modalHeader
+                       [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+               pEepData->modalHeader
+                       [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+       twiceLargestAntenna = max((u8)twiceLargestAntenna,
+                                 pEepData->modalHeader
+                                 [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+       twiceLargestAntenna = (int8_t)min(AntennaReduction - twiceLargestAntenna, 0);
+
+       maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+       if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+               maxRegAllowedPower -=
+                       (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+       }
+
+       scaledPower = min(powerLimit, maxRegAllowedPower);
+
+       switch (ar5416_get_ntxchains(tx_chainmask)) {
+       case 1:
+               break;
+       case 2:
+               scaledPower -=
+                       pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor2Chain;
+               break;
+       case 3:
+               scaledPower -=
+                       pEepData->modalHeader[IS_CHAN_2GHZ(chan)].pwrDecreaseFor3Chain;
+               break;
+       }
+
+       scaledPower = max(0, (int32_t) scaledPower);
+
+       if (IS_CHAN_2GHZ(chan)) {
+               numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+                       SUB_NUM_CTL_MODES_AT_2G_40;
+               pCtlMode = ctlModesFor11g;
+
+               ath9k_hw_get_legacy_target_powers(ah, chan,
+                       pEepData->calTargetPowerCck,
+                       AR5416_NUM_2G_CCK_TARGET_POWERS,
+                       &targetPowerCck, 4, false);
+               ath9k_hw_get_legacy_target_powers(ah, chan,
+                       pEepData->calTargetPower2G,
+                       AR5416_NUM_2G_20_TARGET_POWERS,
+                       &targetPowerOfdm, 4, false);
+               ath9k_hw_get_target_powers(ah, chan,
+                       pEepData->calTargetPower2GHT20,
+                       AR5416_NUM_2G_20_TARGET_POWERS,
+                       &targetPowerHt20, 8, false);
+
+               if (IS_CHAN_HT40(chan)) {
+                       numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+                       ath9k_hw_get_target_powers(ah, chan,
+                               pEepData->calTargetPower2GHT40,
+                               AR5416_NUM_2G_40_TARGET_POWERS,
+                               &targetPowerHt40, 8, true);
+                       ath9k_hw_get_legacy_target_powers(ah, chan,
+                               pEepData->calTargetPowerCck,
+                               AR5416_NUM_2G_CCK_TARGET_POWERS,
+                               &targetPowerCckExt, 4, true);
+                       ath9k_hw_get_legacy_target_powers(ah, chan,
+                               pEepData->calTargetPower2G,
+                               AR5416_NUM_2G_20_TARGET_POWERS,
+                               &targetPowerOfdmExt, 4, true);
+               }
+       } else {
+               numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+                       SUB_NUM_CTL_MODES_AT_5G_40;
+               pCtlMode = ctlModesFor11a;
+
+               ath9k_hw_get_legacy_target_powers(ah, chan,
+                       pEepData->calTargetPower5G,
+                       AR5416_NUM_5G_20_TARGET_POWERS,
+                       &targetPowerOfdm, 4, false);
+               ath9k_hw_get_target_powers(ah, chan,
+                       pEepData->calTargetPower5GHT20,
+                       AR5416_NUM_5G_20_TARGET_POWERS,
+                       &targetPowerHt20, 8, false);
+
+               if (IS_CHAN_HT40(chan)) {
+                       numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+                       ath9k_hw_get_target_powers(ah, chan,
+                               pEepData->calTargetPower5GHT40,
+                               AR5416_NUM_5G_40_TARGET_POWERS,
+                               &targetPowerHt40, 8, true);
+                       ath9k_hw_get_legacy_target_powers(ah, chan,
+                               pEepData->calTargetPower5G,
+                               AR5416_NUM_5G_20_TARGET_POWERS,
+                               &targetPowerOfdmExt, 4, true);
+               }
+       }
+
+       for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+               bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+                       (pCtlMode[ctlMode] == CTL_2GHT40);
+               if (isHt40CtlMode)
+                       freq = centers.synth_center;
+               else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+                       freq = centers.ext_center;
+               else
+                       freq = centers.ctl_center;
+
+               if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2)
+                       twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                       "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+                       "EXT_ADDITIVE %d\n",
+                       ctlMode, numCtlModes, isHt40CtlMode,
+                       (pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+               for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                               "  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+                               "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+                               "chan %d\n",
+                               i, cfgCtl, pCtlMode[ctlMode],
+                               pEepData->ctlIndex[i], chan->channel);
+
+                       if ((((cfgCtl & ~CTL_MODE_M) |
+                             (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+                            pEepData->ctlIndex[i]) ||
+                           (((cfgCtl & ~CTL_MODE_M) |
+                             (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+                            ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+                               rep = &(pEepData->ctlData[i]);
+
+                               twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+                               rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+                               IS_CHAN_2GHZ(chan));
+
+                               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                                       "    MATCH-EE_IDX %d: ch %d is2 %d "
+                                       "2xMinEdge %d chainmask %d chains %d\n",
+                                       i, freq, IS_CHAN_2GHZ(chan),
+                                       twiceMinEdgePower, tx_chainmask,
+                                       ar5416_get_ntxchains
+                                       (tx_chainmask));
+                               if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+                                       twiceMaxEdgePower = min(twiceMaxEdgePower,
+                                                               twiceMinEdgePower);
+                               } else {
+                                       twiceMaxEdgePower = twiceMinEdgePower;
+                                       break;
+                               }
+                       }
+               }
+
+               minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                       "    SEL-Min ctlMode %d pCtlMode %d "
+                       "2xMaxEdge %d sP %d minCtlPwr %d\n",
+                       ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+                       scaledPower, minCtlPower);
+
+               switch (pCtlMode[ctlMode]) {
+               case CTL_11B:
+                       for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+                               targetPowerCck.tPow2x[i] =
+                                       min(targetPowerCck.tPow2x[i],
+                                           minCtlPower);
+                       }
+                       break;
+               case CTL_11A:
+               case CTL_11G:
+                       for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+                               targetPowerOfdm.tPow2x[i] =
+                                       min(targetPowerOfdm.tPow2x[i],
+                                           minCtlPower);
+                       }
+                       break;
+               case CTL_5GHT20:
+               case CTL_2GHT20:
+                       for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+                               targetPowerHt20.tPow2x[i] =
+                                       min(targetPowerHt20.tPow2x[i],
+                                           minCtlPower);
+                       }
+                       break;
+               case CTL_11B_EXT:
+                       targetPowerCckExt.tPow2x[0] =
+                               min(targetPowerCckExt.tPow2x[0], minCtlPower);
+                       break;
+               case CTL_11A_EXT:
+               case CTL_11G_EXT:
+                       targetPowerOfdmExt.tPow2x[0] =
+                               min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
+                       break;
+               case CTL_5GHT40:
+               case CTL_2GHT40:
+                       for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+                               targetPowerHt40.tPow2x[i] =
+                                       min(targetPowerHt40.tPow2x[i],
+                                           minCtlPower);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+               ratesArray[rate18mb] = ratesArray[rate24mb] =
+               targetPowerOfdm.tPow2x[0];
+       ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+       ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+       ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+       ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+       for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+               ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+       if (IS_CHAN_2GHZ(chan)) {
+               ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+               ratesArray[rate2s] = ratesArray[rate2l] =
+                       targetPowerCck.tPow2x[1];
+               ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+                       targetPowerCck.tPow2x[2];
+               ;
+               ratesArray[rate11s] = ratesArray[rate11l] =
+                       targetPowerCck.tPow2x[3];
+               ;
+       }
+       if (IS_CHAN_HT40(chan)) {
+               for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+                       ratesArray[rateHt40_0 + i] =
+                               targetPowerHt40.tPow2x[i];
+               }
+               ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+               ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+               ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+               if (IS_CHAN_2GHZ(chan)) {
+                       ratesArray[rateExtCck] =
+                               targetPowerCckExt.tPow2x[0];
+               }
+       }
+       return true;
+}
+
+bool ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+                                 struct ath9k_channel *chan,
+                                 int16_t *pTxPowerIndexOffset)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *pEepData = &ahp->ah_eeprom;
+       struct cal_data_per_freq *pRawDataset;
+       u8 *pCalBChans = NULL;
+       u16 pdGainOverlap_t2;
+       static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+       u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+       u16 numPiers, i, j;
+       int16_t tMinCalPower;
+       u16 numXpdGain, xpdMask;
+       u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+       u32 reg32, regOffset, regChainOffset;
+       int16_t modalIdx;
+
+       modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+       xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+       if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+           AR5416_EEP_MINOR_VER_2) {
+               pdGainOverlap_t2 =
+                       pEepData->modalHeader[modalIdx].pdGainOverlap;
+       } else {
+               pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+                                           AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+       }
+
+       if (IS_CHAN_2GHZ(chan)) {
+               pCalBChans = pEepData->calFreqPier2G;
+               numPiers = AR5416_NUM_2G_CAL_PIERS;
+       } else {
+               pCalBChans = pEepData->calFreqPier5G;
+               numPiers = AR5416_NUM_5G_CAL_PIERS;
+       }
+
+       numXpdGain = 0;
+
+       for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+               if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+                       if (numXpdGain >= AR5416_NUM_PD_GAINS)
+                               break;
+                       xpdGainValues[numXpdGain] =
+                               (u16)(AR5416_PD_GAINS_IN_MASK - i);
+                       numXpdGain++;
+               }
+       }
+
+       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+                     (numXpdGain - 1) & 0x3);
+       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+                     xpdGainValues[0]);
+       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+                     xpdGainValues[1]);
+       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+                     xpdGainValues[2]);
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               if (AR_SREV_5416_V20_OR_LATER(ah) &&
+                   (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) &&
+                   (i != 0)) {
+                       regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+               } else
+                       regChainOffset = i * 0x1000;
+
+               if (pEepData->baseEepHeader.txMask & (1 << i)) {
+                       if (IS_CHAN_2GHZ(chan))
+                               pRawDataset = pEepData->calPierData2G[i];
+                       else
+                               pRawDataset = pEepData->calPierData5G[i];
+
+                       ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
+                                           pRawDataset, pCalBChans,
+                                           numPiers, pdGainOverlap_t2,
+                                           &tMinCalPower, gainBoundaries,
+                                           pdadcValues, numXpdGain);
+
+                       if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+                               REG_WRITE(ah,
+                                         AR_PHY_TPCRG5 + regChainOffset,
+                                         SM(pdGainOverlap_t2,
+                                            AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+                                         | SM(gainBoundaries[0],
+                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+                                         | SM(gainBoundaries[1],
+                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+                                         | SM(gainBoundaries[2],
+                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+                                         | SM(gainBoundaries[3],
+                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+                       }
+
+                       regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+                       for (j = 0; j < 32; j++) {
+                               reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+                                       ((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+                                       ((pdadcValues[4 * j + 2] & 0xFF) << 16) |
+                                       ((pdadcValues[4 * j + 3] & 0xFF) << 24);
+                               REG_WRITE(ah, regOffset, reg32);
+
+                               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+                                       "PDADC (%d,%4x): %4.4x %8.8x\n",
+                                       i, regChainOffset, regOffset,
+                                       reg32);
+                               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+                                       "PDADC: Chain %d | PDADC %3d Value %3d | "
+                                       "PDADC %3d Value %3d | PDADC %3d Value %3d | "
+                                       "PDADC %3d Value %3d |\n",
+                                       i, 4 * j, pdadcValues[4 * j],
+                                       4 * j + 1, pdadcValues[4 * j + 1],
+                                       4 * j + 2, pdadcValues[4 * j + 2],
+                                       4 * j + 3,
+                                       pdadcValues[4 * j + 3]);
+
+                               regOffset += 4;
+                       }
+               }
+       }
+
+       *pTxPowerIndexOffset = 0;
+
+       return true;
+}
+
+/* XXX: Clean me up, make me more legible */
+bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+                                     struct ath9k_channel *chan)
+{
+       struct modal_eep_header *pModal;
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       int i, regChainOffset;
+       u8 txRxAttenLocal;
+       u16 ant_config;
+
+       pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+       txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+       ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 1, &ant_config);
+       REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               if (AR_SREV_9280(ah)) {
+                       if (i >= 2)
+                               break;
+               }
+
+               if (AR_SREV_5416_V20_OR_LATER(ah) &&
+                   (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+                   && (i != 0))
+                       regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+               else
+                       regChainOffset = i * 0x1000;
+
+               REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+                         pModal->antCtrlChain[i]);
+
+               REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+                         (REG_READ(ah,
+                                   AR_PHY_TIMING_CTRL4(0) +
+                                   regChainOffset) &
+                          ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+                            AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+                         SM(pModal->iqCalICh[i],
+                            AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+                         SM(pModal->iqCalQCh[i],
+                            AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+               if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+                       if ((eep->baseEepHeader.version &
+                            AR5416_EEP_VER_MINOR_MASK) >=
+                           AR5416_EEP_MINOR_VER_3) {
+                               txRxAttenLocal = pModal->txRxAttenCh[i];
+                               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                                       REG_RMW_FIELD(ah,
+                                               AR_PHY_GAIN_2GHZ +
+                                               regChainOffset,
+                                               AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+                                               pModal->
+                                               bswMargin[i]);
+                                       REG_RMW_FIELD(ah,
+                                               AR_PHY_GAIN_2GHZ +
+                                               regChainOffset,
+                                               AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+                                               pModal->
+                                               bswAtten[i]);
+                                       REG_RMW_FIELD(ah,
+                                               AR_PHY_GAIN_2GHZ +
+                                               regChainOffset,
+                                               AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+                                               pModal->
+                                               xatten2Margin[i]);
+                                       REG_RMW_FIELD(ah,
+                                               AR_PHY_GAIN_2GHZ +
+                                               regChainOffset,
+                                               AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+                                               pModal->
+                                               xatten2Db[i]);
+                               } else {
+                                       REG_WRITE(ah,
+                                                 AR_PHY_GAIN_2GHZ +
+                                                 regChainOffset,
+                                                 (REG_READ(ah,
+                                                           AR_PHY_GAIN_2GHZ +
+                                                           regChainOffset) &
+                                                  ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+                                                 | SM(pModal->
+                                                 bswMargin[i],
+                                                 AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+                                       REG_WRITE(ah,
+                                                 AR_PHY_GAIN_2GHZ +
+                                                 regChainOffset,
+                                                 (REG_READ(ah,
+                                                           AR_PHY_GAIN_2GHZ +
+                                                           regChainOffset) &
+                                                  ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+                                                 | SM(pModal->bswAtten[i],
+                                                 AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+                               }
+                       }
+                       if (AR_SREV_9280_10_OR_LATER(ah)) {
+                               REG_RMW_FIELD(ah,
+                                             AR_PHY_RXGAIN +
+                                             regChainOffset,
+                                             AR9280_PHY_RXGAIN_TXRX_ATTEN,
+                                             txRxAttenLocal);
+                               REG_RMW_FIELD(ah,
+                                             AR_PHY_RXGAIN +
+                                             regChainOffset,
+                                             AR9280_PHY_RXGAIN_TXRX_MARGIN,
+                                             pModal->rxTxMarginCh[i]);
+                       } else {
+                               REG_WRITE(ah,
+                                         AR_PHY_RXGAIN + regChainOffset,
+                                         (REG_READ(ah,
+                                                   AR_PHY_RXGAIN +
+                                                   regChainOffset) &
+                                          ~AR_PHY_RXGAIN_TXRX_ATTEN) |
+                                         SM(txRxAttenLocal,
+                                            AR_PHY_RXGAIN_TXRX_ATTEN));
+                               REG_WRITE(ah,
+                                         AR_PHY_GAIN_2GHZ +
+                                         regChainOffset,
+                                         (REG_READ(ah,
+                                                   AR_PHY_GAIN_2GHZ +
+                                                   regChainOffset) &
+                                          ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+                                         SM(pModal->rxTxMarginCh[i],
+                                            AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+                       }
+               }
+       }
+
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               if (IS_CHAN_2GHZ(chan)) {
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+                                                 AR_AN_RF2G1_CH0_OB,
+                                                 AR_AN_RF2G1_CH0_OB_S,
+                                                 pModal->ob);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+                                                 AR_AN_RF2G1_CH0_DB,
+                                                 AR_AN_RF2G1_CH0_DB_S,
+                                                 pModal->db);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+                                                 AR_AN_RF2G1_CH1_OB,
+                                                 AR_AN_RF2G1_CH1_OB_S,
+                                                 pModal->ob_ch1);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+                                                 AR_AN_RF2G1_CH1_DB,
+                                                 AR_AN_RF2G1_CH1_DB_S,
+                                                 pModal->db_ch1);
+               } else {
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+                                                 AR_AN_RF5G1_CH0_OB5,
+                                                 AR_AN_RF5G1_CH0_OB5_S,
+                                                 pModal->ob);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+                                                 AR_AN_RF5G1_CH0_DB5,
+                                                 AR_AN_RF5G1_CH0_DB5_S,
+                                                 pModal->db);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+                                                 AR_AN_RF5G1_CH1_OB5,
+                                                 AR_AN_RF5G1_CH1_OB5_S,
+                                                 pModal->ob_ch1);
+                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+                                                 AR_AN_RF5G1_CH1_DB5,
+                                                 AR_AN_RF5G1_CH1_DB5_S,
+                                                 pModal->db_ch1);
+               }
+               ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+                                         AR_AN_TOP2_XPABIAS_LVL,
+                                         AR_AN_TOP2_XPABIAS_LVL_S,
+                                         pModal->xpaBiasLvl);
+               ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+                                         AR_AN_TOP2_LOCALBIAS,
+                                         AR_AN_TOP2_LOCALBIAS_S,
+                                         pModal->local_bias);
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n",
+                       pModal->force_xpaon);
+               REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+                             pModal->force_xpaon);
+       }
+
+       REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+                     pModal->switchSettling);
+       REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+                     pModal->adcDesiredSize);
+
+       if (!AR_SREV_9280_10_OR_LATER(ah))
+               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+                             AR_PHY_DESIRED_SZ_PGA,
+                             pModal->pgaDesiredSize);
+
+       REG_WRITE(ah, AR_PHY_RF_CTL4,
+                 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+                 | SM(pModal->txEndToXpaOff,
+                      AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+                 | SM(pModal->txFrameToXpaOn,
+                      AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+                 | SM(pModal->txFrameToXpaOn,
+                      AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+       REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+                     pModal->txEndToRxOn);
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+                             pModal->thresh62);
+               REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+                             AR_PHY_EXT_CCA0_THRESH62,
+                             pModal->thresh62);
+       } else {
+               REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+                             pModal->thresh62);
+               REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+                             AR_PHY_EXT_CCA_THRESH62,
+                             pModal->thresh62);
+       }
+
+       if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+           AR5416_EEP_MINOR_VER_2) {
+               REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+                             AR_PHY_TX_END_DATA_START,
+                             pModal->txFrameToDataStart);
+               REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+                             pModal->txFrameToPaOn);
+       }
+
+       if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+           AR5416_EEP_MINOR_VER_3) {
+               if (IS_CHAN_HT40(chan))
+                       REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+                                     AR_PHY_SETTLING_SWITCH,
+                                     pModal->swSettleHt40);
+       }
+
+       return true;
+}
+
+int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah,
+                                   struct ath9k_channel *chan,
+                                   u8 index, u16 *config)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       struct modal_eep_header *pModal =
+               &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+       struct base_eep_header *pBase = &eep->baseEepHeader;
+
+       switch (index) {
+       case 0:
+               *config = pModal->antCtrlCommon & 0xFFFF;
+               return 0;
+       case 1:
+               if (pBase->version >= 0x0E0D) {
+                       if (pModal->useAnt1) {
+                               *config =
+                               ((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
+                               return 0;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah,
+                              enum ieee80211_band freq_band)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       struct modal_eep_header *pModal =
+               &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
+       struct base_eep_header *pBase = &eep->baseEepHeader;
+       u8 num_ant_config;
+
+       num_ant_config = 1;
+
+       if (pBase->version >= 0x0E0D)
+               if (pModal->useAnt1)
+                       num_ant_config += 1;
+
+       return num_ant_config;
+}
+
+u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep =
+               (struct ar5416_eeprom *) &ahp->ah_eeprom;
+       u16 spur_val = AR_NO_SPUR;
+
+       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+               "Getting spur idx %d is2Ghz. %d val %x\n",
+               i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+
+       switch (ah->ah_config.spurmode) {
+       case SPUR_DISABLE:
+               break;
+       case SPUR_ENABLE_IOCTL:
+               spur_val = ah->ah_config.spurchans[i][is2GHz];
+               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+                       "Getting spur val from new loc. %d\n", spur_val);
+               break;
+       case SPUR_ENABLE_EEPROM:
+               spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
+               break;
+
+       }
+
+       return spur_val;
+}
+
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
+                       enum eeprom_param param)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+       struct modal_eep_header *pModal = eep->modalHeader;
+       struct base_eep_header *pBase = &eep->baseEepHeader;
+
+       switch (param) {
+       case EEP_NFTHRESH_5:
+               return -pModal[0].noiseFloorThreshCh[0];
+       case EEP_NFTHRESH_2:
+               return -pModal[1].noiseFloorThreshCh[0];
+       case AR_EEPROM_MAC(0):
+               return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+       case AR_EEPROM_MAC(1):
+               return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+       case AR_EEPROM_MAC(2):
+               return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+       case EEP_REG_0:
+               return pBase->regDmn[0];
+       case EEP_REG_1:
+               return pBase->regDmn[1];
+       case EEP_OP_CAP:
+               return pBase->deviceCap;
+       case EEP_OP_MODE:
+               return pBase->opCapFlags;
+       case EEP_RF_SILENT:
+               return pBase->rfSilent;
+       case EEP_OB_5:
+               return pModal[0].ob;
+       case EEP_DB_5:
+               return pModal[0].db;
+       case EEP_OB_2:
+               return pModal[1].ob;
+       case EEP_DB_2:
+               return pModal[1].db;
+       case EEP_MINOR_REV:
+               return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+       case EEP_TX_MASK:
+               return pBase->txMask;
+       case EEP_RX_MASK:
+               return pBase->rxMask;
+       default:
+               return 0;
+       }
+}
+
+int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+{
+       int status;
+
+       if (ath9k_hw_use_flash(ah))
+               ath9k_hw_flash_map(ah);
+
+       if (!ath9k_hw_fill_eeprom(ah))
+               return -EIO;
+
+       status = ath9k_hw_check_eeprom(ah);
+
+       return status;
+}
index 1417ba07523dafc7a328b6b9368e147be23ca495..e05c9ef55e471327fa1a213db3e74446ccfaf27e 100644 (file)
 #include "phy.h"
 #include "initvals.h"
 
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah);
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains);
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah,
-                                          u8 numChains);
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah);
-static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah,
-                                        u8 numChains);
-
 static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
-static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
-
-static const struct hal_percal_data iq_cal_multi_sample = {
-       IQ_MISMATCH_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_iqcal_collect,
-       ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data iq_cal_single_sample = {
-       IQ_MISMATCH_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_iqcal_collect,
-       ath9k_hw_iqcalibrate
-};
-static const struct hal_percal_data adc_gain_cal_multi_sample = {
-       ADC_GAIN_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_adc_gaincal_collect,
-       ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_gain_cal_single_sample = {
-       ADC_GAIN_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_adc_gaincal_collect,
-       ath9k_hw_adc_gaincal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_multi_sample = {
-       ADC_DC_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_dc_cal_single_sample = {
-       ADC_DC_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
-static const struct hal_percal_data adc_init_dc_cal = {
-       ADC_DC_INIT_CAL,
-       MIN_CAL_SAMPLES,
-       INIT_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
 
-static struct ath9k_rate_table ar5416_11a_table = {
-       8,
-       {0},
-       {
-               {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-               {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-               {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-               {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
-       },
-};
+extern struct hal_percal_data iq_cal_multi_sample;
+extern struct hal_percal_data iq_cal_single_sample;
+extern struct hal_percal_data adc_gain_cal_multi_sample;
+extern struct hal_percal_data adc_gain_cal_single_sample;
+extern struct hal_percal_data adc_dc_cal_multi_sample;
+extern struct hal_percal_data adc_dc_cal_single_sample;
+extern struct hal_percal_data adc_init_dc_cal;
 
-static struct ath9k_rate_table ar5416_11b_table = {
-       4,
-       {0},
-       {
-               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
-               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
-       },
-};
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+                             enum ath9k_ht_macmode macmode);
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+                             struct ar5416_eeprom *pEepData,
+                             u32 reg, u32 value);
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
 
-static struct ath9k_rate_table ar5416_11g_table = {
-       12,
-       {0},
-       {
-               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
+/********************/
+/* Helper Functions */
+/********************/
 
-               {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-               {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-               {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-               {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
-       },
-};
+static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
+{
+       if (ah->ah_curchan != NULL)
+               return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
+       else
+               return clks / CLOCK_RATE[ATH9K_MODE_11B];
+}
 
-static struct ath9k_rate_table ar5416_11ng_table = {
-       28,
-       {0},
-       {
-               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
-               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
-               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
-               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
+static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
+{
+       struct ath9k_channel *chan = ah->ah_curchan;
 
-               {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
-               {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
-               {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
-               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
-               {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
-               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
-               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
-               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
-               {true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
-               {true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
-               {true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
-               {true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
-               {true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
-               {true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
-               {true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
-               {true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
-               {true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
-               {true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
-               {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
-               {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
-               {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
-               {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
-               {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
-               {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
-       },
-};
+       if (chan && IS_CHAN_HT40(chan))
+               return ath9k_hw_mac_usec(ah, clks) / 2;
+       else
+               return ath9k_hw_mac_usec(ah, clks);
+}
 
-static struct ath9k_rate_table ar5416_11na_table = {
-       24,
-       {0},
-       {
-               {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
-               {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
-               {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
-               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
-               {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
-               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
-               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
-               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
-               {true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
-               {true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
-               {true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
-               {true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
-               {true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
-               {true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
-               {true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
-               {true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
-               {true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
-               {true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
-               {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
-               {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
-               {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
-               {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
-               {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
-               {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
-       },
-};
+static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
+{
+       if (ah->ah_curchan != NULL)
+               return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
+                       ah->ah_curchan)];
+       else
+               return usecs * CLOCK_RATE[ATH9K_MODE_11B];
+}
+
+static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
+{
+       struct ath9k_channel *chan = ah->ah_curchan;
+
+       if (chan && IS_CHAN_HT40(chan))
+               return ath9k_hw_mac_clks(ah, usecs) * 2;
+       else
+               return ath9k_hw_mac_clks(ah, usecs);
+}
 
-static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
-                                      const struct ath9k_channel *chan)
+enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+                              const struct ath9k_channel *chan)
 {
        if (IS_CHAN_CCK(chan))
                return ATH9K_MODE_11A;
@@ -208,10 +93,7 @@ static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
        return ATH9K_MODE_11A;
 }
 
-static bool ath9k_hw_wait(struct ath_hal *ah,
-                         u32 reg,
-                         u32 mask,
-                         u32 val)
+bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val)
 {
        int i;
 
@@ -222,78 +104,10 @@ static bool ath9k_hw_wait(struct ath_hal *ah,
                udelay(AH_TIME_QUANTUM);
        }
        DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-                "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
-                __func__, reg, REG_READ(ah, reg), mask, val);
-       return false;
-}
-
-static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off,
-                                u16 *data)
-{
-       (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
-       if (!ath9k_hw_wait(ah,
-                          AR_EEPROM_STATUS_DATA,
-                          AR_EEPROM_STATUS_DATA_BUSY |
-                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
-               return false;
-       }
-
-       *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
-                  AR_EEPROM_STATUS_DATA_VAL);
-
-       return true;
-}
-
-static int ath9k_hw_flash_map(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
-
-       if (!ahp->ah_cal_mem) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "%s: cannot remap eeprom region \n", __func__);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off,
-                               u16 *data)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       *data = ioread16(ahp->ah_cal_mem + off);
-       return true;
-}
-
-static void ath9k_hw_read_revisions(struct ath_hal *ah)
-{
-       u32 val;
-
-       val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
-
-       if (val == 0xFF) {
-               val = REG_READ(ah, AR_SREV);
-
-               ah->ah_macVersion =
-                       (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
-
-               ah->ah_macRev = MS(val, AR_SREV_REVISION2);
-               ah->ah_isPciExpress =
-                       (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
-
-       } else {
-               if (!AR_SREV_9100(ah))
-                       ah->ah_macVersion = MS(val, AR_SREV_VERSION);
-
-               ah->ah_macRev = val & AR_SREV_REVISION;
+               "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+               __func__, reg, REG_READ(ah, reg), mask, val);
 
-               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
-                       ah->ah_isPciExpress = true;
-       }
+       return false;
 }
 
 u32 ath9k_hw_reverse_bits(u32 val, u32 n)
@@ -308,850 +122,318 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n)
        return retval;
 }
 
-static void ath9k_hw_set_defaults(struct ath_hal *ah)
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+                            u16 flags, u16 *low,
+                            u16 *high)
 {
-       int i;
-
-       ah->ah_config.dma_beacon_response_time = 2;
-       ah->ah_config.sw_beacon_response_time = 10;
-       ah->ah_config.additional_swba_backoff = 0;
-       ah->ah_config.ack_6mb = 0x0;
-       ah->ah_config.cwm_ignore_extcca = 0;
-       ah->ah_config.pcie_powersave_enable = 0;
-       ah->ah_config.pcie_l1skp_enable = 0;
-       ah->ah_config.pcie_clock_req = 0;
-       ah->ah_config.pcie_power_reset = 0x100;
-       ah->ah_config.pcie_restore = 0;
-       ah->ah_config.pcie_waen = 0;
-       ah->ah_config.analog_shiftreg = 1;
-       ah->ah_config.ht_enable = 1;
-       ah->ah_config.ofdm_trig_low = 200;
-       ah->ah_config.ofdm_trig_high = 500;
-       ah->ah_config.cck_trig_high = 200;
-       ah->ah_config.cck_trig_low = 100;
-       ah->ah_config.enable_ani = 1;
-       ah->ah_config.noise_immunity_level = 4;
-       ah->ah_config.ofdm_weaksignal_det = 1;
-       ah->ah_config.cck_weaksignal_thr = 0;
-       ah->ah_config.spur_immunity_level = 2;
-       ah->ah_config.firstep_level = 0;
-       ah->ah_config.rssi_thr_high = 40;
-       ah->ah_config.rssi_thr_low = 7;
-       ah->ah_config.diversity_control = 0;
-       ah->ah_config.antenna_switch_swap = 0;
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
-               ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
+       if (flags & CHANNEL_5GHZ) {
+               *low = pCap->low_5ghz_chan;
+               *high = pCap->high_5ghz_chan;
+               return true;
        }
-
-       ah->ah_config.intr_mitigation = 1;
+       if ((flags & CHANNEL_2GHZ)) {
+               *low = pCap->low_2ghz_chan;
+               *high = pCap->high_2ghz_chan;
+               return true;
+       }
+       return false;
 }
 
-static void ath9k_hw_override_ini(struct ath_hal *ah,
-                                        struct ath9k_channel *chan)
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+                          const struct ath9k_rate_table *rates,
+                          u32 frameLen, u16 rateix,
+                          bool shortPreamble)
 {
-       if (!AR_SREV_5416_V20_OR_LATER(ah)
-           || AR_SREV_9280_10_OR_LATER(ah))
-               return;
+       u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
+       u32 kbps;
 
-       REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
-}
+       kbps = rates->info[rateix].rateKbps;
 
-static void ath9k_hw_init_bb(struct ath_hal *ah,
-                            struct ath9k_channel *chan)
-{
-       u32 synthDelay;
+       if (kbps == 0)
+               return 0;
 
-       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-       if (IS_CHAN_CCK(chan))
-               synthDelay = (4 * synthDelay) / 22;
-       else
-               synthDelay /= 10;
+       switch (rates->info[rateix].phy) {
+       case PHY_CCK:
+               phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
+               if (shortPreamble && rates->info[rateix].shortPreamble)
+                       phyTime >>= 1;
+               numBits = frameLen << 3;
+               txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
+               break;
+       case PHY_OFDM:
+               if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
+                       bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
+                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+                       txTime = OFDM_SIFS_TIME_QUARTER
+                               + OFDM_PREAMBLE_TIME_QUARTER
+                               + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
+               } else if (ah->ah_curchan &&
+                          IS_CHAN_HALF_RATE(ah->ah_curchan)) {
+                       bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
+                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+                       txTime = OFDM_SIFS_TIME_HALF +
+                               OFDM_PREAMBLE_TIME_HALF
+                               + (numSymbols * OFDM_SYMBOL_TIME_HALF);
+               } else {
+                       bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
+                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+                       txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+                               + (numSymbols * OFDM_SYMBOL_TIME);
+               }
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+                       "%s: unknown phy %u (rate ix %u)\n", __func__,
+                       rates->info[rateix].phy, rateix);
+               txTime = 0;
+               break;
+       }
 
-       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+       return txTime;
+}
 
-       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
+{
+       if (flags & CHANNEL_2GHZ) {
+               if (freq == 2484)
+                       return 14;
+               if (freq < 2484)
+                       return (freq - 2407) / 5;
+               else
+                       return 15 + ((freq - 2512) / 20);
+       } else if (flags & CHANNEL_5GHZ) {
+               if (ath9k_regd_is_public_safety_sku(ah) &&
+                   IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+                       return ((freq * 10) +
+                               (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
+               } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
+                       return (freq - 4000) / 5;
+               } else {
+                       return (freq - 5000) / 5;
+               }
+       } else {
+               if (freq == 2484)
+                       return 14;
+               if (freq < 2484)
+                       return (freq - 2407) / 5;
+               if (freq < 5000) {
+                       if (ath9k_regd_is_public_safety_sku(ah)
+                           && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+                               return ((freq * 10) +
+                                       (((freq % 5) ==
+                                         2) ? 5 : 0) - 49400) / 5;
+                       } else if (freq > 4900) {
+                               return (freq - 4000) / 5;
+                       } else {
+                               return 15 + ((freq - 2512) / 20);
+                       }
+               }
+               return (freq - 5000) / 5;
+       }
 }
 
-static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
-                                         enum ath9k_opmode opmode)
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+                                 struct ath9k_channel *chan,
+                                 struct chan_centers *centers)
 {
+       int8_t extoff;
        struct ath_hal_5416 *ahp = AH5416(ah);
 
-       ahp->ah_maskReg = AR_IMR_TXERR |
-               AR_IMR_TXURN |
-               AR_IMR_RXERR |
-               AR_IMR_RXORN |
-               AR_IMR_BCNMISC;
-
-       if (ahp->ah_intrMitigation)
-               ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
-       else
-               ahp->ah_maskReg |= AR_IMR_RXOK;
-
-       ahp->ah_maskReg |= AR_IMR_TXOK;
-
-       if (opmode == ATH9K_M_HOSTAP)
-               ahp->ah_maskReg |= AR_IMR_MIB;
-
-       REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
-       REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
-
-       if (!AR_SREV_9100(ah)) {
-               REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
-               REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
-               REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+       if (!IS_CHAN_HT40(chan)) {
+               centers->ctl_center = centers->ext_center =
+                       centers->synth_center = chan->channel;
+               return;
        }
-}
 
-static void ath9k_hw_init_qos(struct ath_hal *ah)
-{
-       REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
-       REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
+       if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+           (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+               centers->synth_center =
+                       chan->channel + HT40_CHANNEL_CENTER_SHIFT;
+               extoff = 1;
+       } else {
+               centers->synth_center =
+                       chan->channel - HT40_CHANNEL_CENTER_SHIFT;
+               extoff = -1;
+       }
 
-       REG_WRITE(ah, AR_QOS_NO_ACK,
-                 SM(2, AR_QOS_NO_ACK_TWO_BIT) |
-                 SM(5, AR_QOS_NO_ACK_BIT_OFF) |
-                 SM(0, AR_QOS_NO_ACK_BYTE_OFF));
+       centers->ctl_center =
+               centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+       centers->ext_center =
+               centers->synth_center + (extoff *
+                        ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ?
+                         HT40_CHANNEL_CENTER_SHIFT : 15));
 
-       REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
-       REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
-       REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
-       REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
-       REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
 }
 
-static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
-                                     u32 reg,
-                                     u32 mask,
-                                     u32 shift,
-                                     u32 val)
+/******************/
+/* Chip Revisions */
+/******************/
+
+static void ath9k_hw_read_revisions(struct ath_hal *ah)
 {
-       u32 regVal;
+       u32 val;
 
-       regVal = REG_READ(ah, reg) & ~mask;
-       regVal |= (val << shift) & mask;
+       val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
 
-       REG_WRITE(ah, reg, regVal);
+       if (val == 0xFF) {
+               val = REG_READ(ah, AR_SREV);
+               ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+               ah->ah_macRev = MS(val, AR_SREV_REVISION2);
+               ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+       } else {
+               if (!AR_SREV_9100(ah))
+                       ah->ah_macVersion = MS(val, AR_SREV_VERSION);
 
-       if (ah->ah_config.analog_shiftreg)
-               udelay(100);
+               ah->ah_macRev = val & AR_SREV_REVISION;
 
-       return;
+               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
+                       ah->ah_isPciExpress = true;
+       }
 }
 
-static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp,
-                                     enum ieee80211_band freq_band)
+static int ath9k_hw_get_radiorev(struct ath_hal *ah)
 {
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       struct modal_eep_header *pModal =
-               &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
-       struct base_eep_header *pBase = &eep->baseEepHeader;
-       u8 num_ant_config;
+       u32 val;
+       int i;
 
-       num_ant_config = 1;
+       REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
 
-       if (pBase->version >= 0x0E0D)
-               if (pModal->useAnt1)
-                       num_ant_config += 1;
+       for (i = 0; i < 8; i++)
+               REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+       val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+       val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
 
-       return num_ant_config;
+       return ath9k_hw_reverse_bits(val, 8);
 }
 
-static int
-ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp,
-                               struct ath9k_channel *chan,
-                               u8 index,
-                               u16 *config)
+/************************************/
+/* HW Attach, Detach, Init Routines */
+/************************************/
+
+static void ath9k_hw_disablepcie(struct ath_hal *ah)
 {
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       struct modal_eep_header *pModal =
-               &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-       struct base_eep_header *pBase = &eep->baseEepHeader;
+       if (!AR_SREV_9100(ah))
+               return;
 
-       switch (index) {
-       case 0:
-               *config = pModal->antCtrlCommon & 0xFFFF;
-               return 0;
-       case 1:
-               if (pBase->version >= 0x0E0D) {
-                       if (pModal->useAnt1) {
-                               *config =
-                               ((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
-                               return 0;
-                       }
-               }
-               break;
-       default:
-               break;
-       }
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+       REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
 
-       return -EINVAL;
+       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
 }
 
-static inline bool ath9k_hw_nvram_read(struct ath_hal *ah,
-                                      u32 off,
-                                      u16 *data)
+static bool ath9k_hw_chip_test(struct ath_hal *ah)
 {
-       if (ath9k_hw_use_flash(ah))
-               return ath9k_hw_flash_read(ah, off, data);
-       else
-               return ath9k_hw_eeprom_read(ah, off, data);
-}
+       u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
+       u32 regHold[2];
+       u32 patternData[4] = { 0x55555555,
+                              0xaaaaaaaa,
+                              0x66666666,
+                              0x99999999 };
+       int i, j;
 
-static bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       u16 *eep_data;
-       int addr, ar5416_eep_start_loc = 0;
+       for (i = 0; i < 2; i++) {
+               u32 addr = regAddr[i];
+               u32 wrData, rdData;
 
-       if (!ath9k_hw_use_flash(ah)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "%s: Reading from EEPROM, not flash\n", __func__);
-               ar5416_eep_start_loc = 256;
-       }
-       if (AR_SREV_9100(ah))
-               ar5416_eep_start_loc = 256;
-
-       eep_data = (u16 *) eep;
-       for (addr = 0;
-            addr < sizeof(struct ar5416_eeprom) / sizeof(u16);
-            addr++) {
-               if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
-                                        eep_data)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                                "%s: Unable to read eeprom region \n",
-                                __func__);
-                       return false;
+               regHold[i] = REG_READ(ah, addr);
+               for (j = 0; j < 0x100; j++) {
+                       wrData = (j << 16) | j;
+                       REG_WRITE(ah, addr, wrData);
+                       rdData = REG_READ(ah, addr);
+                       if (rdData != wrData) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+                                       "%s: address test failed "
+                                       "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+                                       __func__, addr, wrData, rdData);
+                               return false;
+                       }
+               }
+               for (j = 0; j < 4; j++) {
+                       wrData = patternData[j];
+                       REG_WRITE(ah, addr, wrData);
+                       rdData = REG_READ(ah, addr);
+                       if (wrData != rdData) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+                                       "%s: address test failed "
+                                       "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+                                       __func__, addr, wrData, rdData);
+                               return false;
+                       }
                }
-               eep_data++;
+               REG_WRITE(ah, regAddr[i], regHold[i]);
        }
+       udelay(100);
        return true;
 }
 
-/* XXX: Clean me up, make me more legible */
-static bool
-ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
-                                struct ath9k_channel *chan)
+static const char *ath9k_hw_devname(u16 devid)
 {
-       struct modal_eep_header *pModal;
-       int i, regChainOffset;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       u8 txRxAttenLocal;
-       u16 ant_config;
-
-       pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
-       txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
-
-       ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config);
-       REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               if (AR_SREV_9280(ah)) {
-                       if (i >= 2)
-                               break;
-               }
-
-               if (AR_SREV_5416_V20_OR_LATER(ah) &&
-                   (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
-                   && (i != 0))
-                       regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-               else
-                       regChainOffset = i * 0x1000;
-
-               REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
-                         pModal->antCtrlChain[i]);
-
-               REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
-                         (REG_READ(ah,
-                                   AR_PHY_TIMING_CTRL4(0) +
-                                   regChainOffset) &
-                          ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
-                            AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
-                         SM(pModal->iqCalICh[i],
-                            AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
-                         SM(pModal->iqCalQCh[i],
-                            AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
-
-               if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-                       if ((eep->baseEepHeader.version &
-                            AR5416_EEP_VER_MINOR_MASK) >=
-                           AR5416_EEP_MINOR_VER_3) {
-                               txRxAttenLocal = pModal->txRxAttenCh[i];
-                               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                                       REG_RMW_FIELD(ah,
-                                               AR_PHY_GAIN_2GHZ +
-                                               regChainOffset,
-                                               AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
-                                               pModal->
-                                               bswMargin[i]);
-                                       REG_RMW_FIELD(ah,
-                                               AR_PHY_GAIN_2GHZ +
-                                               regChainOffset,
-                                               AR_PHY_GAIN_2GHZ_XATTEN1_DB,
-                                               pModal->
-                                               bswAtten[i]);
-                                       REG_RMW_FIELD(ah,
-                                               AR_PHY_GAIN_2GHZ +
-                                               regChainOffset,
-                                               AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
-                                               pModal->
-                                               xatten2Margin[i]);
-                                       REG_RMW_FIELD(ah,
-                                               AR_PHY_GAIN_2GHZ +
-                                               regChainOffset,
-                                               AR_PHY_GAIN_2GHZ_XATTEN2_DB,
-                                               pModal->
-                                               xatten2Db[i]);
-                               } else {
-                                       REG_WRITE(ah,
-                                                 AR_PHY_GAIN_2GHZ +
-                                                 regChainOffset,
-                                                 (REG_READ(ah,
-                                                           AR_PHY_GAIN_2GHZ +
-                                                           regChainOffset) &
-                                                  ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
-                                                 | SM(pModal->
-                                                 bswMargin[i],
-                                                 AR_PHY_GAIN_2GHZ_BSW_MARGIN));
-                                       REG_WRITE(ah,
-                                                 AR_PHY_GAIN_2GHZ +
-                                                 regChainOffset,
-                                                 (REG_READ(ah,
-                                                           AR_PHY_GAIN_2GHZ +
-                                                           regChainOffset) &
-                                                  ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
-                                                 | SM(pModal->bswAtten[i],
-                                                 AR_PHY_GAIN_2GHZ_BSW_ATTEN));
-                               }
-                       }
-                       if (AR_SREV_9280_10_OR_LATER(ah)) {
-                               REG_RMW_FIELD(ah,
-                                             AR_PHY_RXGAIN +
-                                             regChainOffset,
-                                             AR9280_PHY_RXGAIN_TXRX_ATTEN,
-                                             txRxAttenLocal);
-                               REG_RMW_FIELD(ah,
-                                             AR_PHY_RXGAIN +
-                                             regChainOffset,
-                                             AR9280_PHY_RXGAIN_TXRX_MARGIN,
-                                             pModal->rxTxMarginCh[i]);
-                       } else {
-                               REG_WRITE(ah,
-                                         AR_PHY_RXGAIN + regChainOffset,
-                                         (REG_READ(ah,
-                                                   AR_PHY_RXGAIN +
-                                                   regChainOffset) &
-                                          ~AR_PHY_RXGAIN_TXRX_ATTEN) |
-                                         SM(txRxAttenLocal,
-                                            AR_PHY_RXGAIN_TXRX_ATTEN));
-                               REG_WRITE(ah,
-                                         AR_PHY_GAIN_2GHZ +
-                                         regChainOffset,
-                                         (REG_READ(ah,
-                                                   AR_PHY_GAIN_2GHZ +
-                                                   regChainOffset) &
-                                          ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
-                                         SM(pModal->rxTxMarginCh[i],
-                                            AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
-                       }
-               }
+       switch (devid) {
+       case AR5416_DEVID_PCI:
+       case AR5416_DEVID_PCIE:
+               return "Atheros 5416";
+       case AR9160_DEVID_PCI:
+               return "Atheros 9160";
+       case AR9280_DEVID_PCI:
+       case AR9280_DEVID_PCIE:
+               return "Atheros 9280";
        }
 
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               if (IS_CHAN_2GHZ(chan)) {
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
-                                                 AR_AN_RF2G1_CH0_OB,
-                                                 AR_AN_RF2G1_CH0_OB_S,
-                                                 pModal->ob);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
-                                                 AR_AN_RF2G1_CH0_DB,
-                                                 AR_AN_RF2G1_CH0_DB_S,
-                                                 pModal->db);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
-                                                 AR_AN_RF2G1_CH1_OB,
-                                                 AR_AN_RF2G1_CH1_OB_S,
-                                                 pModal->ob_ch1);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
-                                                 AR_AN_RF2G1_CH1_DB,
-                                                 AR_AN_RF2G1_CH1_DB_S,
-                                                 pModal->db_ch1);
-               } else {
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
-                                                 AR_AN_RF5G1_CH0_OB5,
-                                                 AR_AN_RF5G1_CH0_OB5_S,
-                                                 pModal->ob);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
-                                                 AR_AN_RF5G1_CH0_DB5,
-                                                 AR_AN_RF5G1_CH0_DB5_S,
-                                                 pModal->db);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
-                                                 AR_AN_RF5G1_CH1_OB5,
-                                                 AR_AN_RF5G1_CH1_OB5_S,
-                                                 pModal->ob_ch1);
-                       ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
-                                                 AR_AN_RF5G1_CH1_DB5,
-                                                 AR_AN_RF5G1_CH1_DB5_S,
-                                                 pModal->db_ch1);
-               }
-               ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
-                                         AR_AN_TOP2_XPABIAS_LVL,
-                                         AR_AN_TOP2_XPABIAS_LVL_S,
-                                         pModal->xpaBiasLvl);
-               ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
-                                         AR_AN_TOP2_LOCALBIAS,
-                                         AR_AN_TOP2_LOCALBIAS_S,
-                                         pModal->local_bias);
-               DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n",
-                       pModal->force_xpaon);
-               REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
-                             pModal->force_xpaon);
-       }
+       return NULL;
+}
 
-       REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
-                     pModal->switchSettling);
-       REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
-                     pModal->adcDesiredSize);
+static void ath9k_hw_set_defaults(struct ath_hal *ah)
+{
+       int i;
 
-       if (!AR_SREV_9280_10_OR_LATER(ah))
-               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-                             AR_PHY_DESIRED_SZ_PGA,
-                             pModal->pgaDesiredSize);
-
-       REG_WRITE(ah, AR_PHY_RF_CTL4,
-                 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
-                 | SM(pModal->txEndToXpaOff,
-                      AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
-                 | SM(pModal->txFrameToXpaOn,
-                      AR_PHY_RF_CTL4_FRAME_XPAA_ON)
-                 | SM(pModal->txFrameToXpaOn,
-                      AR_PHY_RF_CTL4_FRAME_XPAB_ON));
-
-       REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
-                     pModal->txEndToRxOn);
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
-                             pModal->thresh62);
-               REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
-                             AR_PHY_EXT_CCA0_THRESH62,
-                             pModal->thresh62);
-       } else {
-               REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
-                             pModal->thresh62);
-               REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
-                             AR_PHY_EXT_CCA_THRESH62,
-                             pModal->thresh62);
-       }
-
-       if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-           AR5416_EEP_MINOR_VER_2) {
-               REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
-                             AR_PHY_TX_END_DATA_START,
-                             pModal->txFrameToDataStart);
-               REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
-                             pModal->txFrameToPaOn);
-       }
-
-       if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
-           AR5416_EEP_MINOR_VER_3) {
-               if (IS_CHAN_HT40(chan))
-                       REG_RMW_FIELD(ah, AR_PHY_SETTLING,
-                                     AR_PHY_SETTLING_SWITCH,
-                                     pModal->swSettleHt40);
-       }
-
-       return true;
-}
-
-static int ath9k_hw_check_eeprom(struct ath_hal *ah)
-{
-       u32 sum = 0, el;
-       u16 *eepdata;
-       int i;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       bool need_swap = false;
-       struct ar5416_eeprom *eep =
-               (struct ar5416_eeprom *) &ahp->ah_eeprom;
-
-       if (!ath9k_hw_use_flash(ah)) {
-               u16 magic, magic2;
-               int addr;
-
-               if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
-                                       &magic)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                                "%s: Reading Magic # failed\n", __func__);
-                       return false;
-               }
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
-                        __func__, magic);
-
-               if (magic != AR5416_EEPROM_MAGIC) {
-                       magic2 = swab16(magic);
-
-                       if (magic2 == AR5416_EEPROM_MAGIC) {
-                               need_swap = true;
-                               eepdata = (u16 *) (&ahp->ah_eeprom);
-
-                               for (addr = 0;
-                                    addr <
-                                            sizeof(struct ar5416_eeprom) /
-                                            sizeof(u16); addr++) {
-                                       u16 temp;
-
-                                       temp = swab16(*eepdata);
-                                       *eepdata = temp;
-                                       eepdata++;
-
-                                       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                                                "0x%04X  ", *eepdata);
-                                       if (((addr + 1) % 6) == 0)
-                                               DPRINTF(ah->ah_sc,
-                                                        ATH_DBG_EEPROM,
-                                                        "\n");
-                               }
-                       } else {
-                               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                                        "Invalid EEPROM Magic. "
-                                       "endianness missmatch.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
-       DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
-                need_swap ? "True" : "False");
-
-       if (need_swap)
-               el = swab16(ahp->ah_eeprom.baseEepHeader.length);
-       else
-               el = ahp->ah_eeprom.baseEepHeader.length;
-
-       if (el > sizeof(struct ar5416_eeprom))
-               el = sizeof(struct ar5416_eeprom) / sizeof(u16);
-       else
-               el = el / sizeof(u16);
-
-       eepdata = (u16 *) (&ahp->ah_eeprom);
-
-       for (i = 0; i < el; i++)
-               sum ^= *eepdata++;
-
-       if (need_swap) {
-               u32 integer, j;
-               u16 word;
-
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "EEPROM Endianness is not native.. Changing \n");
-
-               word = swab16(eep->baseEepHeader.length);
-               eep->baseEepHeader.length = word;
-
-               word = swab16(eep->baseEepHeader.checksum);
-               eep->baseEepHeader.checksum = word;
-
-               word = swab16(eep->baseEepHeader.version);
-               eep->baseEepHeader.version = word;
-
-               word = swab16(eep->baseEepHeader.regDmn[0]);
-               eep->baseEepHeader.regDmn[0] = word;
-
-               word = swab16(eep->baseEepHeader.regDmn[1]);
-               eep->baseEepHeader.regDmn[1] = word;
-
-               word = swab16(eep->baseEepHeader.rfSilent);
-               eep->baseEepHeader.rfSilent = word;
-
-               word = swab16(eep->baseEepHeader.blueToothOptions);
-               eep->baseEepHeader.blueToothOptions = word;
-
-               word = swab16(eep->baseEepHeader.deviceCap);
-               eep->baseEepHeader.deviceCap = word;
-
-               for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
-                       struct modal_eep_header *pModal =
-                               &eep->modalHeader[j];
-                       integer = swab32(pModal->antCtrlCommon);
-                       pModal->antCtrlCommon = integer;
-
-                       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-                               integer = swab32(pModal->antCtrlChain[i]);
-                               pModal->antCtrlChain[i] = integer;
-                       }
-
-                       for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
-                               word = swab16(pModal->spurChans[i].spurChan);
-                               pModal->spurChans[i].spurChan = word;
-                       }
-               }
-       }
-
-       if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
-           ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-                        sum, ar5416_get_eep_ver(ahp));
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static bool ath9k_hw_chip_test(struct ath_hal *ah)
-{
-       u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
-       u32 regHold[2];
-       u32 patternData[4] = { 0x55555555,
-                                    0xaaaaaaaa,
-                                    0x66666666,
-                                    0x99999999 };
-       int i, j;
-
-       for (i = 0; i < 2; i++) {
-               u32 addr = regAddr[i];
-               u32 wrData, rdData;
-
-               regHold[i] = REG_READ(ah, addr);
-               for (j = 0; j < 0x100; j++) {
-                       wrData = (j << 16) | j;
-                       REG_WRITE(ah, addr, wrData);
-                       rdData = REG_READ(ah, addr);
-                       if (rdData != wrData) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                                "%s: address test failed "
-                               "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
-                                __func__, addr, wrData, rdData);
-                               return false;
-                       }
-               }
-               for (j = 0; j < 4; j++) {
-                       wrData = patternData[j];
-                       REG_WRITE(ah, addr, wrData);
-                       rdData = REG_READ(ah, addr);
-                       if (wrData != rdData) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                                "%s: address test failed "
-                               "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
-                                __func__, addr, wrData, rdData);
-                               return false;
-                       }
-               }
-               REG_WRITE(ah, regAddr[i], regHold[i]);
-       }
-       udelay(100);
-       return true;
-}
-
-u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
-{
-       u32 bits = REG_READ(ah, AR_RX_FILTER);
-       u32 phybits = REG_READ(ah, AR_PHY_ERR);
-
-       if (phybits & AR_PHY_ERR_RADAR)
-               bits |= ATH9K_RX_FILTER_PHYRADAR;
-       if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
-               bits |= ATH9K_RX_FILTER_PHYERR;
-       return bits;
-}
-
-void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
-{
-       u32 phybits;
-
-       REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
-       phybits = 0;
-       if (bits & ATH9K_RX_FILTER_PHYRADAR)
-               phybits |= AR_PHY_ERR_RADAR;
-       if (bits & ATH9K_RX_FILTER_PHYERR)
-               phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
-       REG_WRITE(ah, AR_PHY_ERR, phybits);
-
-       if (phybits)
-               REG_WRITE(ah, AR_RXCFG,
-                         REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
-       else
-               REG_WRITE(ah, AR_RXCFG,
-                         REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
-}
-
-bool ath9k_hw_setcapability(struct ath_hal *ah,
-                           enum ath9k_capability_type type,
-                           u32 capability,
-                           u32 setting,
-                           int *status)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 v;
-
-       switch (type) {
-       case ATH9K_CAP_TKIP_MIC:
-               if (setting)
-                       ahp->ah_staId1Defaults |=
-                               AR_STA_ID1_CRPT_MIC_ENABLE;
-               else
-                       ahp->ah_staId1Defaults &=
-                               ~AR_STA_ID1_CRPT_MIC_ENABLE;
-               return true;
-       case ATH9K_CAP_DIVERSITY:
-               v = REG_READ(ah, AR_PHY_CCK_DETECT);
-               if (setting)
-                       v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-               else
-                       v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-               REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-               return true;
-       case ATH9K_CAP_MCAST_KEYSRCH:
-               if (setting)
-                       ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
-               else
-                       ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
-               return true;
-       case ATH9K_CAP_TSF_ADJUST:
-               if (setting)
-                       ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
-               else
-                       ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
-               return true;
-       default:
-               return false;
-       }
-}
-
-void ath9k_hw_dmaRegDump(struct ath_hal *ah)
-{
-       u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
-       int qcuOffset = 0, dcuOffset = 0;
-       u32 *qcuBase = &val[0], *dcuBase = &val[4];
-       int i;
-
-       REG_WRITE(ah, AR_MACMISC,
-                 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
-                  (AR_MACMISC_MISC_OBS_BUS_1 <<
-                   AR_MACMISC_MISC_OBS_BUS_MSB_S)));
-
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
-       for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
-               if (i % 4 == 0)
-                       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
-
-               val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
-               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
-       }
-
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
-
-       for (i = 0; i < ATH9K_NUM_QUEUES;
-            i++, qcuOffset += 4, dcuOffset += 5) {
-               if (i == 8) {
-                       qcuOffset = 0;
-                       qcuBase++;
-               }
-
-               if (i == 6) {
-                       dcuOffset = 0;
-                       dcuBase++;
-               }
-
-               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                        "%2d          %2x      %1x     %2x           %2x\n",
-                        i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
-                        (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset +
-                                                            3),
-                        val[2] & (0x7 << (i * 3)) >> (i * 3),
-                        (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
-       }
-
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
-                (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "qcu_complete state: %2x    dcu_complete state:     %2x\n",
-                (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
-                (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
-                (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
-                (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
-                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
-
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
-               REG_READ(ah, AR_OBS_BUS_1));
-       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-               "AR_CR 0x%x \n", REG_READ(ah, AR_CR));
-}
-
-u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
-                                       u32 *rxc_pcnt,
-                                       u32 *rxf_pcnt,
-                                       u32 *txf_pcnt)
-{
-       static u32 cycles, rx_clear, rx_frame, tx_frame;
-       u32 good = 1;
-
-       u32 rc = REG_READ(ah, AR_RCCNT);
-       u32 rf = REG_READ(ah, AR_RFCNT);
-       u32 tf = REG_READ(ah, AR_TFCNT);
-       u32 cc = REG_READ(ah, AR_CCCNT);
+       ah->ah_config.dma_beacon_response_time = 2;
+       ah->ah_config.sw_beacon_response_time = 10;
+       ah->ah_config.additional_swba_backoff = 0;
+       ah->ah_config.ack_6mb = 0x0;
+       ah->ah_config.cwm_ignore_extcca = 0;
+       ah->ah_config.pcie_powersave_enable = 0;
+       ah->ah_config.pcie_l1skp_enable = 0;
+       ah->ah_config.pcie_clock_req = 0;
+       ah->ah_config.pcie_power_reset = 0x100;
+       ah->ah_config.pcie_restore = 0;
+       ah->ah_config.pcie_waen = 0;
+       ah->ah_config.analog_shiftreg = 1;
+       ah->ah_config.ht_enable = 1;
+       ah->ah_config.ofdm_trig_low = 200;
+       ah->ah_config.ofdm_trig_high = 500;
+       ah->ah_config.cck_trig_high = 200;
+       ah->ah_config.cck_trig_low = 100;
+       ah->ah_config.enable_ani = 1;
+       ah->ah_config.noise_immunity_level = 4;
+       ah->ah_config.ofdm_weaksignal_det = 1;
+       ah->ah_config.cck_weaksignal_thr = 0;
+       ah->ah_config.spur_immunity_level = 2;
+       ah->ah_config.firstep_level = 0;
+       ah->ah_config.rssi_thr_high = 40;
+       ah->ah_config.rssi_thr_low = 7;
+       ah->ah_config.diversity_control = 0;
+       ah->ah_config.antenna_switch_swap = 0;
 
-       if (cycles == 0 || cycles > cc) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: cycle counter wrap. ExtBusy = 0\n",
-                        __func__);
-               good = 0;
-       } else {
-               u32 cc_d = cc - cycles;
-               u32 rc_d = rc - rx_clear;
-               u32 rf_d = rf - rx_frame;
-               u32 tf_d = tf - tx_frame;
-
-               if (cc_d != 0) {
-                       *rxc_pcnt = rc_d * 100 / cc_d;
-                       *rxf_pcnt = rf_d * 100 / cc_d;
-                       *txf_pcnt = tf_d * 100 / cc_d;
-               } else {
-                       good = 0;
-               }
+       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+               ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
+               ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
        }
 
-       cycles = cc;
-       rx_frame = rf;
-       rx_clear = rc;
-       tx_frame = tf;
-
-       return good;
-}
-
-void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
-{
-       u32 macmode;
-
-       if (mode == ATH9K_HT_MACMODE_2040 &&
-           !ah->ah_config.cwm_ignore_extcca)
-               macmode = AR_2040_JOINED_RX_CLEAR;
-       else
-               macmode = 0;
-
-       REG_WRITE(ah, AR_2040_MODE, macmode);
-}
-
-static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
-{
-       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+       ah->ah_config.intr_mitigation = 1;
 }
 
-
 static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
                                              struct ath_softc *sc,
                                              void __iomem *mem,
@@ -1165,20 +447,17 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
        ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
        if (ahp == NULL) {
                DPRINTF(sc, ATH_DBG_FATAL,
-                        "%s: cannot allocate memory for state block\n",
-                        __func__);
+                       "%s: cannot allocate memory for state block\n",
+                       __func__);
                *status = -ENOMEM;
                return NULL;
        }
 
        ah = &ahp->ah;
-
        ah->ah_sc = sc;
        ah->ah_sh = mem;
-
        ah->ah_magic = AR5416_MAGIC;
        ah->ah_countryCode = CTRY_DEFAULT;
-
        ah->ah_devid = devid;
        ah->ah_subvendorid = 0;
 
@@ -1190,12 +469,10 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
 
        ah->ah_powerLimit = MAX_RATE_POWER;
        ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
-
        ahp->ah_atimWindow = 0;
        ahp->ah_diversityControl = ah->ah_config.diversity_control;
        ahp->ah_antennaSwitchSwap =
                ah->ah_config.antenna_switch_swap;
-
        ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
        ahp->ah_beaconInterval = 100;
        ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
@@ -1210,79 +487,49 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
        return ahp;
 }
 
-static int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+static int ath9k_hw_rfattach(struct ath_hal *ah)
 {
-       int status;
-
-       if (ath9k_hw_use_flash(ah))
-               ath9k_hw_flash_map(ah);
-
-       if (!ath9k_hw_fill_eeprom(ah))
-               return -EIO;
+       bool rfStatus = false;
+       int ecode = 0;
 
-       status = ath9k_hw_check_eeprom(ah);
+       rfStatus = ath9k_hw_init_rf(ah, &ecode);
+       if (!rfStatus) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "%s: RF setup failed, status %u\n", __func__,
+                       ecode);
+               return ecode;
+       }
 
-       return status;
+       return 0;
 }
 
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
-                             enum eeprom_param param)
+static int ath9k_hw_rf_claim(struct ath_hal *ah)
 {
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       struct modal_eep_header *pModal = eep->modalHeader;
-       struct base_eep_header *pBase = &eep->baseEepHeader;
-
-       switch (param) {
-       case EEP_NFTHRESH_5:
-               return -pModal[0].noiseFloorThreshCh[0];
-       case EEP_NFTHRESH_2:
-               return -pModal[1].noiseFloorThreshCh[0];
-       case AR_EEPROM_MAC(0):
-               return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-       case AR_EEPROM_MAC(1):
-               return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-       case AR_EEPROM_MAC(2):
-               return pBase->macAddr[4] << 8 | pBase->macAddr[5];
-       case EEP_REG_0:
-               return pBase->regDmn[0];
-       case EEP_REG_1:
-               return pBase->regDmn[1];
-       case EEP_OP_CAP:
-               return pBase->deviceCap;
-       case EEP_OP_MODE:
-               return pBase->opCapFlags;
-       case EEP_RF_SILENT:
-               return pBase->rfSilent;
-       case EEP_OB_5:
-               return pModal[0].ob;
-       case EEP_DB_5:
-               return pModal[0].db;
-       case EEP_OB_2:
-               return pModal[1].ob;
-       case EEP_DB_2:
-               return pModal[1].db;
-       case EEP_MINOR_REV:
-               return pBase->version & AR5416_EEP_VER_MINOR_MASK;
-       case EEP_TX_MASK:
-               return pBase->txMask;
-       case EEP_RX_MASK:
-               return pBase->rxMask;
+       u32 val;
+
+       REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+       val = ath9k_hw_get_radiorev(ah);
+       switch (val & AR_RADIO_SREV_MAJOR) {
+       case 0:
+               val = AR_RAD5133_SREV_MAJOR;
+               break;
+       case AR_RAD5133_SREV_MAJOR:
+       case AR_RAD5122_SREV_MAJOR:
+       case AR_RAD2133_SREV_MAJOR:
+       case AR_RAD2122_SREV_MAJOR:
+               break;
        default:
-               return 0;
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: 5G Radio Chip Rev 0x%02X is not "
+                       "supported by this driver\n",
+                       __func__, ah->ah_analog5GhzRev);
+               return -EOPNOTSUPP;
        }
-}
 
-static int ath9k_hw_get_radiorev(struct ath_hal *ah)
-{
-       u32 val;
-       int i;
+       ah->ah_analog5GhzRev = val;
 
-       REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
-       for (i = 0; i < 8; i++)
-               REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
-       val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
-       val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
-       return ath9k_hw_reverse_bits(val, 8);
+       return 0;
 }
 
 static int ath9k_hw_init_macaddr(struct ath_hal *ah)
@@ -1294,3829 +541,410 @@ static int ath9k_hw_init_macaddr(struct ath_hal *ah)
 
        sum = 0;
        for (i = 0; i < 3; i++) {
-               eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i));
+               eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i));
                sum += eeval;
                ahp->ah_macaddr[2 * i] = eeval >> 8;
                ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
        }
        if (sum == 0 || sum == 0xffff * 3) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "%s: mac address read failed: %pM\n", __func__,
-                        ahp->ah_macaddr);
+                       "%s: mac address read failed: %pM\n", __func__,
+                       ahp->ah_macaddr);
                return -EADDRNOTAVAIL;
        }
 
        return 0;
 }
 
-static inline int16_t ath9k_hw_interpolate(u16 target,
-                                          u16 srcLeft,
-                                          u16 srcRight,
-                                          int16_t targetLeft,
-                                          int16_t targetRight)
-{
-       int16_t rv;
-
-       if (srcRight == srcLeft) {
-               rv = targetLeft;
-       } else {
-               rv = (int16_t) (((target - srcLeft) * targetRight +
-                                (srcRight - target) * targetLeft) /
-                               (srcRight - srcLeft));
-       }
-       return rv;
-}
-
-static inline u16 ath9k_hw_fbin2freq(u8 fbin,
-                                          bool is2GHz)
-{
-
-       if (fbin == AR5416_BCHAN_UNUSED)
-               return fbin;
-
-       return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
-}
-
-static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah,
-                                              u16 i,
-                                              bool is2GHz)
+static int ath9k_hw_post_attach(struct ath_hal *ah)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416_eeprom *eep =
-               (struct ar5416_eeprom *) &ahp->ah_eeprom;
-       u16 spur_val = AR_NO_SPUR;
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                "Getting spur idx %d is2Ghz. %d val %x\n",
-                i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
-
-       switch (ah->ah_config.spurmode) {
-       case SPUR_DISABLE:
-               break;
-       case SPUR_ENABLE_IOCTL:
-               spur_val = ah->ah_config.spurchans[i][is2GHz];
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                        "Getting spur val from new loc. %d\n", spur_val);
-               break;
-       case SPUR_ENABLE_EEPROM:
-               spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
-               break;
+       int ecode;
 
+       if (!ath9k_hw_chip_test(ah)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+                       "%s: hardware self-test failed\n", __func__);
+               return -ENODEV;
        }
-       return spur_val;
-}
-
-static int ath9k_hw_rfattach(struct ath_hal *ah)
-{
-       bool rfStatus = false;
-       int ecode = 0;
 
-       rfStatus = ath9k_hw_init_rf(ah, &ecode);
-       if (!rfStatus) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                        "%s: RF setup failed, status %u\n", __func__,
-                        ecode);
+       ecode = ath9k_hw_rf_claim(ah);
+       if (ecode != 0)
                return ecode;
-       }
-
-       return 0;
-}
-
-static int ath9k_hw_rf_claim(struct ath_hal *ah)
-{
-       u32 val;
 
-       REG_WRITE(ah, AR_PHY(0), 0x00000007);
+       ecode = ath9k_hw_eeprom_attach(ah);
+       if (ecode != 0)
+               return ecode;
+       ecode = ath9k_hw_rfattach(ah);
+       if (ecode != 0)
+               return ecode;
 
-       val = ath9k_hw_get_radiorev(ah);
-       switch (val & AR_RADIO_SREV_MAJOR) {
-       case 0:
-               val = AR_RAD5133_SREV_MAJOR;
-               break;
-       case AR_RAD5133_SREV_MAJOR:
-       case AR_RAD5122_SREV_MAJOR:
-       case AR_RAD2133_SREV_MAJOR:
-       case AR_RAD2122_SREV_MAJOR:
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: 5G Radio Chip Rev 0x%02X is not "
-                       "supported by this driver\n",
-                        __func__, ah->ah_analog5GhzRev);
-               return -EOPNOTSUPP;
+       if (!AR_SREV_9100(ah)) {
+               ath9k_hw_ani_setup(ah);
+               ath9k_hw_ani_attach(ah);
        }
 
-       ah->ah_analog5GhzRev = val;
-
        return 0;
 }
 
-static void ath9k_hw_init_pll(struct ath_hal *ah,
-                             struct ath9k_channel *chan)
+static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
+                                         void __iomem *mem, int *status)
 {
-       u32 pll;
-
-       if (AR_SREV_9100(ah)) {
-               if (chan && IS_CHAN_5GHZ(chan))
-                       pll = 0x1450;
-               else
-                       pll = 0x1458;
-       } else {
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+       struct ath_hal_5416 *ahp;
+       struct ath_hal *ah;
+       int ecode;
+#ifndef CONFIG_SLOW_ANT_DIV
+       u32 i;
+       u32 j;
+#endif
 
-                       if (chan && IS_CHAN_5GHZ(chan)) {
-                               pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
+       ahp = ath9k_hw_newstate(devid, sc, mem, status);
+       if (ahp == NULL)
+               return NULL;
 
+       ah = &ahp->ah;
 
-                               if (AR_SREV_9280_20(ah)) {
-                                       if (((chan->channel % 20) == 0)
-                                           || ((chan->channel % 10) == 0))
-                                               pll = 0x2850;
-                                       else
-                                               pll = 0x142c;
-                               }
-                       } else {
-                               pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
-                       }
+       ath9k_hw_set_defaults(ah);
 
-               } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+       if (ah->ah_config.intr_mitigation != 0)
+               ahp->ah_intrMitigation = true;
 
-                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n",
+                        __func__);
+               ecode = -EIO;
+               goto bad;
+       }
 
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n",
+                        __func__);
+               ecode = -EIO;
+               goto bad;
+       }
 
-                       if (chan && IS_CHAN_5GHZ(chan))
-                               pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
-                       else
-                               pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+       if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
+               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) {
+                       ah->ah_config.serialize_regmode =
+                               SER_REG_MODE_ON;
                } else {
-                       pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
-
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
-
-                       if (chan && IS_CHAN_5GHZ(chan))
-                               pll |= SM(0xa, AR_RTC_PLL_DIV);
-                       else
-                               pll |= SM(0xb, AR_RTC_PLL_DIV);
+                       ah->ah_config.serialize_regmode =
+                               SER_REG_MODE_OFF;
                }
        }
-       REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
-
-       udelay(RTC_PLL_SETTLE_DELAY);
-
-       REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
-}
 
-static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
-                             enum ath9k_ht_macmode macmode)
-{
-       u32 phymode;
-       struct ath_hal_5416 *ahp = AH5416(ah);
+       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+               "%s: serialize_regmode is %d\n",
+               __func__, ah->ah_config.serialize_regmode);
 
-       phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
-               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
+       if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
+           (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
+           (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
+           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "%s: Mac Chip Rev 0x%02x.%x is not supported by "
+                       "this driver\n", __func__,
+                       ah->ah_macVersion, ah->ah_macRev);
+               ecode = -EOPNOTSUPP;
+               goto bad;
+       }
 
-       if (IS_CHAN_HT40(chan)) {
-               phymode |= AR_PHY_FC_DYN2040_EN;
+       if (AR_SREV_9100(ah)) {
+               ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
+               ahp->ah_suppCals = IQ_MISMATCH_CAL;
+               ah->ah_isPciExpress = false;
+       }
+       ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
 
-               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-                   (chan->chanmode == CHANNEL_G_HT40PLUS))
-                       phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+       if (AR_SREV_9160_10_OR_LATER(ah)) {
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       ahp->ah_iqCalData.calData = &iq_cal_single_sample;
+                       ahp->ah_adcGainCalData.calData =
+                               &adc_gain_cal_single_sample;
+                       ahp->ah_adcDcCalData.calData =
+                               &adc_dc_cal_single_sample;
+                       ahp->ah_adcDcCalInitData.calData =
+                               &adc_init_dc_cal;
+               } else {
+                       ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
+                       ahp->ah_adcGainCalData.calData =
+                               &adc_gain_cal_multi_sample;
+                       ahp->ah_adcDcCalData.calData =
+                               &adc_dc_cal_multi_sample;
+                       ahp->ah_adcDcCalInitData.calData =
+                               &adc_init_dc_cal;
+               }
+               ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+       }
 
-               if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
-                       phymode |= AR_PHY_FC_DYN2040_EXT_CH;
+       if (AR_SREV_9160(ah)) {
+               ah->ah_config.enable_ani = 1;
+               ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+                                       ATH9K_ANI_FIRSTEP_LEVEL);
+       } else {
+               ahp->ah_ani_function = ATH9K_ANI_ALL;
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+               }
        }
-       REG_WRITE(ah, AR_PHY_TURBO, phymode);
 
-       ath9k_hw_set11nmac2040(ah, macmode);
+       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+               "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__,
+               ah->ah_macVersion, ah->ah_macRev);
 
-       REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
-       REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
-}
+       if (AR_SREV_9280_20_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
+                              ARRAY_SIZE(ar9280Modes_9280_2), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
+                              ARRAY_SIZE(ar9280Common_9280_2), 2);
 
-static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
-{
-       u32 val;
-
-       val = REG_READ(ah, AR_STA_ID1);
-       val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
-       switch (opmode) {
-       case ATH9K_M_HOSTAP:
-               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
-                         | AR_STA_ID1_KSRCH_MODE);
-               REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-               break;
-       case ATH9K_M_IBSS:
-               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
-                         | AR_STA_ID1_KSRCH_MODE);
-               REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
-               break;
-       case ATH9K_M_STA:
-       case ATH9K_M_MONITOR:
-               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
-               break;
+               if (ah->ah_config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                              ar9280PciePhy_clkreq_off_L1_9280,
+                              ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
+               } else {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                              ar9280PciePhy_clkreq_always_on_L1_9280,
+                              ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
+               }
+               INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
+                              ar9280Modes_fast_clock_9280_2,
+                              ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
+       } else if (AR_SREV_9280_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
+                              ARRAY_SIZE(ar9280Modes_9280), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280,
+                              ARRAY_SIZE(ar9280Common_9280), 2);
+       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160,
+                              ARRAY_SIZE(ar5416Modes_9160), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160,
+                              ARRAY_SIZE(ar5416Common_9160), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160,
+                              ARRAY_SIZE(ar5416Bank0_9160), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160,
+                              ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160,
+                              ARRAY_SIZE(ar5416Bank1_9160), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160,
+                              ARRAY_SIZE(ar5416Bank2_9160), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160,
+                              ARRAY_SIZE(ar5416Bank3_9160), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160,
+                              ARRAY_SIZE(ar5416Bank6_9160), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160,
+                              ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160,
+                              ARRAY_SIZE(ar5416Bank7_9160), 2);
+               if (AR_SREV_9160_11(ah)) {
+                       INIT_INI_ARRAY(&ahp->ah_iniAddac,
+                                      ar5416Addac_91601_1,
+                                      ARRAY_SIZE(ar5416Addac_91601_1), 2);
+               } else {
+                       INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160,
+                                      ARRAY_SIZE(ar5416Addac_9160), 2);
+               }
+       } else if (AR_SREV_9100_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100,
+                              ARRAY_SIZE(ar5416Modes_9100), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100,
+                              ARRAY_SIZE(ar5416Common_9100), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100,
+                              ARRAY_SIZE(ar5416Bank0_9100), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100,
+                              ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100,
+                              ARRAY_SIZE(ar5416Bank1_9100), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100,
+                              ARRAY_SIZE(ar5416Bank2_9100), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100,
+                              ARRAY_SIZE(ar5416Bank3_9100), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100,
+                              ARRAY_SIZE(ar5416Bank6_9100), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100,
+                              ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100,
+                              ARRAY_SIZE(ar5416Bank7_9100), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100,
+                              ARRAY_SIZE(ar5416Addac_9100), 2);
+       } else {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes,
+                              ARRAY_SIZE(ar5416Modes), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common,
+                              ARRAY_SIZE(ar5416Common), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0,
+                              ARRAY_SIZE(ar5416Bank0), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain,
+                              ARRAY_SIZE(ar5416BB_RfGain), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1,
+                              ARRAY_SIZE(ar5416Bank1), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2,
+                              ARRAY_SIZE(ar5416Bank2), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3,
+                              ARRAY_SIZE(ar5416Bank3), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6,
+                              ARRAY_SIZE(ar5416Bank6), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC,
+                              ARRAY_SIZE(ar5416Bank6TPC), 3);
+               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7,
+                              ARRAY_SIZE(ar5416Bank7), 2);
+               INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac,
+                              ARRAY_SIZE(ar5416Addac), 2);
        }
-}
-
-static void
-ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
-{
-       u32 rfMode = 0;
-
-       if (chan == NULL)
-               return;
-
-       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
-               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
-
-       if (!AR_SREV_9280_10_OR_LATER(ah))
-               rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ :
-                       AR_PHY_MODE_RF2GHZ;
 
-       if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
-               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+       if (ah->ah_isPciExpress)
+               ath9k_hw_configpcipowersave(ah, 0);
+       else
+               ath9k_hw_disablepcie(ah);
 
-       REG_WRITE(ah, AR_PHY_MODE, rfMode);
-}
+       ecode = ath9k_hw_post_attach(ah);
+       if (ecode != 0)
+               goto bad;
 
-static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
-{
-       u32 rst_flags;
-       u32 tmpReg;
+#ifndef CONFIG_SLOW_ANT_DIV
+       if (ah->ah_devid == AR9280_DEVID_PCI) {
+               for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
+                       u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
 
-       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
-                 AR_RTC_FORCE_WAKE_ON_INT);
+                       for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) {
+                               u32 val = INI_RA(&ahp->ah_iniModes, i, j);
 
-       if (AR_SREV_9100(ah)) {
-               rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
-                       AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
-       } else {
-               tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
-               if (tmpReg &
-                   (AR_INTR_SYNC_LOCAL_TIMEOUT |
-                    AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
-                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
-                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-               } else {
-                       REG_WRITE(ah, AR_RC, AR_RC_AHB);
+                               INI_RA(&ahp->ah_iniModes, i, j) =
+                                       ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
+                                                          reg, val);
+                       }
                }
-
-               rst_flags = AR_RTC_RC_MAC_WARM;
-               if (type == ATH9K_RESET_COLD)
-                       rst_flags |= AR_RTC_RC_MAC_COLD;
+       }
+#endif
+       if (!ath9k_hw_fill_cap_info(ah)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "%s:failed ath9k_hw_fill_cap_info\n", __func__);
+               ecode = -EINVAL;
+               goto bad;
        }
 
-       REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
-       udelay(50);
-
-       REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
-       if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+       ecode = ath9k_hw_init_macaddr(ah);
+       if (ecode != 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                       "%s: RTC stuck in MAC reset\n",
+                       "%s: failed initializing mac address\n",
                        __func__);
-               return false;
+               goto bad;
        }
 
-       if (!AR_SREV_9100(ah))
-               REG_WRITE(ah, AR_RC, 0);
+       if (AR_SREV_9285(ah))
+               ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S);
+       else
+               ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
 
-       ath9k_hw_init_pll(ah, NULL);
+       ath9k_init_nfcal_hist_buffer(ah);
 
-       if (AR_SREV_9100(ah))
-               udelay(50);
+       return ah;
+bad:
+       if (ahp)
+               ath9k_hw_detach((struct ath_hal *) ahp);
+       if (status)
+               *status = ecode;
 
-       return true;
+       return NULL;
 }
 
-static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+static void ath9k_hw_init_bb(struct ath_hal *ah,
+                            struct ath9k_channel *chan)
 {
-       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
-                 AR_RTC_FORCE_WAKE_ON_INT);
-
-       REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
-       REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+       u32 synthDelay;
 
-       if (!ath9k_hw_wait(ah,
-                          AR_RTC_STATUS,
-                          AR_RTC_STATUS_M,
-                          AR_RTC_STATUS_ON)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n",
-                        __func__);
-               return false;
-       }
+       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+       if (IS_CHAN_CCK(chan))
+               synthDelay = (4 * synthDelay) / 22;
+       else
+               synthDelay /= 10;
 
-       ath9k_hw_read_revisions(ah);
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
 
-       return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+       udelay(synthDelay + BASE_ACTIVATE_DELAY);
 }
 
-static bool ath9k_hw_set_reset_reg(struct ath_hal *ah,
-                                  u32 type)
+static void ath9k_hw_init_qos(struct ath_hal *ah)
 {
-       REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-                 AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+       REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
+       REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
 
-       switch (type) {
-       case ATH9K_RESET_POWER_ON:
-               return ath9k_hw_set_reset_power_on(ah);
-               break;
-       case ATH9K_RESET_WARM:
-       case ATH9K_RESET_COLD:
-               return ath9k_hw_set_reset(ah, type);
-               break;
-       default:
-               return false;
-       }
+       REG_WRITE(ah, AR_QOS_NO_ACK,
+                 SM(2, AR_QOS_NO_ACK_TWO_BIT) |
+                 SM(5, AR_QOS_NO_ACK_BIT_OFF) |
+                 SM(0, AR_QOS_NO_ACK_BYTE_OFF));
+
+       REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
+       REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
+       REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
 }
 
-static
-struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
-                                         struct ath9k_channel *chan)
+static void ath9k_hw_init_pll(struct ath_hal *ah,
+                             struct ath9k_channel *chan)
 {
-       if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: invalid channel %u/0x%x; not marked as "
-                        "2GHz or 5GHz\n", __func__, chan->channel,
-                        chan->channelFlags);
-               return NULL;
-       }
+       u32 pll;
 
-       if (!IS_CHAN_OFDM(chan) &&
-             !IS_CHAN_CCK(chan) &&
-             !IS_CHAN_HT20(chan) &&
-             !IS_CHAN_HT40(chan)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                       "%s: invalid channel %u/0x%x; not marked as "
-                       "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
-                       __func__, chan->channel, chan->channelFlags);
-               return NULL;
-       }
-
-       return ath9k_regd_check_channel(ah, chan);
-}
-
-static inline bool
-ath9k_hw_get_lower_upper_index(u8 target,
-                              u8 *pList,
-                              u16 listSize,
-                              u16 *indexL,
-                              u16 *indexR)
-{
-       u16 i;
-
-       if (target <= pList[0]) {
-               *indexL = *indexR = 0;
-               return true;
-       }
-       if (target >= pList[listSize - 1]) {
-               *indexL = *indexR = (u16) (listSize - 1);
-               return true;
-       }
-
-       for (i = 0; i < listSize - 1; i++) {
-               if (pList[i] == target) {
-                       *indexL = *indexR = i;
-                       return true;
-               }
-               if (target < pList[i + 1]) {
-                       *indexL = i;
-                       *indexR = (u16) (i + 1);
-                       return false;
-               }
-       }
-       return false;
-}
-
-static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
-{
-       int16_t nfval;
-       int16_t sort[ATH9K_NF_CAL_HIST_MAX];
-       int i, j;
-
-       for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
-               sort[i] = nfCalBuffer[i];
-
-       for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
-               for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
-                       if (sort[j] > sort[j - 1]) {
-                               nfval = sort[j];
-                               sort[j] = sort[j - 1];
-                               sort[j - 1] = nfval;
-                       }
-               }
-       }
-       nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
-
-       return nfval;
-}
-
-static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
-                                             int16_t *nfarray)
-{
-       int i;
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
-
-               if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
-                       h[i].currIndex = 0;
-
-               if (h[i].invalidNFcount > 0) {
-                       if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE
-                           || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
-                               h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
-                       } else {
-                               h[i].invalidNFcount--;
-                               h[i].privNF = nfarray[i];
-                       }
-               } else {
-                       h[i].privNF =
-                               ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
-               }
-       }
-       return;
-}
-
-static void ar5416GetNoiseFloor(struct ath_hal *ah,
-                               int16_t nfarray[NUM_NF_READINGS])
-{
-       int16_t nf;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                "NF calibrated [ctl] [chain 0] is %d\n", nf);
-       nfarray[0] = nf;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-                       AR9280_PHY_CH1_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-                       AR_PHY_CH1_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                "NF calibrated [ctl] [chain 1] is %d\n", nf);
-       nfarray[1] = nf;
-
-       if (!AR_SREV_9280(ah)) {
-               nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
-                       AR_PHY_CH2_MINCCA_PWR);
-               if (nf & 0x100)
-                       nf = 0 - ((nf ^ 0x1ff) + 1);
-               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                        "NF calibrated [ctl] [chain 2] is %d\n", nf);
-               nfarray[2] = nf;
-       }
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-                       AR9280_PHY_EXT_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-                       AR_PHY_EXT_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                "NF calibrated [ext] [chain 0] is %d\n", nf);
-       nfarray[3] = nf;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-                       AR9280_PHY_CH1_EXT_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-                       AR_PHY_CH1_EXT_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                "NF calibrated [ext] [chain 1] is %d\n", nf);
-       nfarray[4] = nf;
-
-       if (!AR_SREV_9280(ah)) {
-               nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
-                       AR_PHY_CH2_EXT_MINCCA_PWR);
-               if (nf & 0x100)
-                       nf = 0 - ((nf ^ 0x1ff) + 1);
-               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                        "NF calibrated [ext] [chain 2] is %d\n", nf);
-               nfarray[5] = nf;
-       }
-}
-
-static bool
-getNoiseFloorThresh(struct ath_hal *ah,
-                   const struct ath9k_channel *chan,
-                   int16_t *nft)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5);
-               break;
-       case CHANNEL_B:
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2);
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: invalid channel flags 0x%x\n", __func__,
-                        chan->channelFlags);
-               return false;
-       }
-       return true;
-}
-
-static void ath9k_hw_start_nfcal(struct ath_hal *ah)
-{
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_ENABLE_NF);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-}
-
-static void
-ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
-{
-       struct ath9k_nfcal_hist *h;
-       int i, j;
-       int32_t val;
-       const u32 ar5416_cca_regs[6] = {
-               AR_PHY_CCA,
-               AR_PHY_CH1_CCA,
-               AR_PHY_CH2_CCA,
-               AR_PHY_EXT_CCA,
-               AR_PHY_CH1_EXT_CCA,
-               AR_PHY_CH2_EXT_CCA
-       };
-       u8 chainmask;
-
-       if (AR_SREV_9280(ah))
-               chainmask = 0x1B;
-       else
-               chainmask = 0x3F;
-
-#ifdef ATH_NF_PER_CHAN
-       h = chan->nfCalHist;
-#else
-       h = ah->nfCalHist;
-#endif
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               if (chainmask & (1 << i)) {
-                       val = REG_READ(ah, ar5416_cca_regs[i]);
-                       val &= 0xFFFFFE00;
-                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
-                       REG_WRITE(ah, ar5416_cca_regs[i], val);
-               }
-       }
-
-       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_ENABLE_NF);
-       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
-       for (j = 0; j < 1000; j++) {
-               if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-                    AR_PHY_AGC_CONTROL_NF) == 0)
-                       break;
-               udelay(10);
-       }
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               if (chainmask & (1 << i)) {
-                       val = REG_READ(ah, ar5416_cca_regs[i]);
-                       val &= 0xFFFFFE00;
-                       val |= (((u32) (-50) << 1) & 0x1ff);
-                       REG_WRITE(ah, ar5416_cca_regs[i], val);
-               }
-       }
-}
-
-static int16_t ath9k_hw_getnf(struct ath_hal *ah,
-                             struct ath9k_channel *chan)
-{
-       int16_t nf, nfThresh;
-       int16_t nfarray[NUM_NF_READINGS] = { 0 };
-       struct ath9k_nfcal_hist *h;
-       u8 chainmask;
-
-       if (AR_SREV_9280(ah))
-               chainmask = 0x1B;
-       else
-               chainmask = 0x3F;
-
-       chan->channelFlags &= (~CHANNEL_CW_INT);
-       if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: NF did not complete in calibration window\n",
-                        __func__);
-               nf = 0;
-               chan->rawNoiseFloor = nf;
-               return chan->rawNoiseFloor;
-       } else {
-               ar5416GetNoiseFloor(ah, nfarray);
-               nf = nfarray[0];
-               if (getNoiseFloorThresh(ah, chan, &nfThresh)
-                   && nf > nfThresh) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: noise floor failed detected; "
-                                "detected %d, threshold %d\n", __func__,
-                                nf, nfThresh);
-                       chan->channelFlags |= CHANNEL_CW_INT;
-               }
-       }
-
-#ifdef ATH_NF_PER_CHAN
-       h = chan->nfCalHist;
-#else
-       h = ah->nfCalHist;
-#endif
-
-       ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
-       chan->rawNoiseFloor = h[0].privNF;
-
-       return chan->rawNoiseFloor;
-}
-
-static void ath9k_hw_update_mibstats(struct ath_hal *ah,
-                             struct ath9k_mib_stats *stats)
-{
-       stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
-       stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
-       stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
-       stats->rts_good += REG_READ(ah, AR_RTS_OK);
-       stats->beacons += REG_READ(ah, AR_BEACON_CNT);
-}
-
-static void ath9k_enable_mib_counters(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n");
-
-       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-       REG_WRITE(ah, AR_FILT_OFDM, 0);
-       REG_WRITE(ah, AR_FILT_CCK, 0);
-       REG_WRITE(ah, AR_MIBC,
-                 ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
-                 & 0x0f);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-}
-
-static void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n");
-
-       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
-
-       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-       REG_WRITE(ah, AR_FILT_OFDM, 0);
-       REG_WRITE(ah, AR_FILT_CCK, 0);
-}
-
-static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
-                                       struct ath9k_channel *chan)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-               if (ahp->ah_ani[i].c.channel == chan->channel)
-                       return i;
-               if (ahp->ah_ani[i].c.channel == 0) {
-                       ahp->ah_ani[i].c.channel = chan->channel;
-                       ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
-                       return i;
-               }
-       }
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                "No more channel states left. Using channel 0\n");
-       return 0;
-}
-
-static void ath9k_hw_ani_attach(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       ahp->ah_hasHwPhyCounters = 1;
-
-       memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
-       for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
-               ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
-               ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
-               ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
-               ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
-               ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
-               ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
-               ahp->ah_ani[i].ofdmWeakSigDetectOff =
-                       !ATH9K_ANI_USE_OFDM_WEAK_SIG;
-               ahp->ah_ani[i].cckWeakSigThreshold =
-                       ATH9K_ANI_CCK_WEAK_SIG_THR;
-               ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-               ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-               if (ahp->ah_hasHwPhyCounters) {
-                       ahp->ah_ani[i].ofdmPhyErrBase =
-                               AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
-                       ahp->ah_ani[i].cckPhyErrBase =
-                               AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
-               }
-       }
-       if (ahp->ah_hasHwPhyCounters) {
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                       "Setting OfdmErrBase = 0x%08x\n",
-                       ahp->ah_ani[0].ofdmPhyErrBase);
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
-                       ahp->ah_ani[0].cckPhyErrBase);
-
-               REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
-               REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
-               ath9k_enable_mib_counters(ah);
-       }
-       ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
-       if (ah->ah_config.enable_ani)
-               ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
-}
-
-static void ath9k_hw_ani_setup(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
-       const int coarseHigh[] = { -14, -14, -14, -14, -12 };
-       const int coarseLow[] = { -64, -64, -64, -64, -70 };
-       const int firpwr[] = { -78, -78, -78, -78, -80 };
-
-       for (i = 0; i < 5; i++) {
-               ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
-               ahp->ah_coarseHigh[i] = coarseHigh[i];
-               ahp->ah_coarseLow[i] = coarseLow[i];
-               ahp->ah_firpwr[i] = firpwr[i];
-       }
-}
-
-static void ath9k_hw_ani_detach(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n");
-       if (ahp->ah_hasHwPhyCounters) {
-               ath9k_hw_disable_mib_counters(ah);
-               REG_WRITE(ah, AR_PHY_ERR_1, 0);
-               REG_WRITE(ah, AR_PHY_ERR_2, 0);
-       }
-}
-
-
-static bool ath9k_hw_ani_control(struct ath_hal *ah,
-                                enum ath9k_ani_cmd cmd, int param)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState = ahp->ah_curani;
-
-       switch (cmd & ahp->ah_ani_function) {
-       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                "%s: level out of range (%u > %u)\n",
-                                __func__, level,
-                                (unsigned) ARRAY_SIZE(ahp->
-                                                      ah_totalSizeDesired));
-                       return false;
-               }
-
-               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-                             AR_PHY_DESIRED_SZ_TOT_DES,
-                             ahp->ah_totalSizeDesired[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_LOW,
-                             ahp->ah_coarseLow[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_HIGH,
-                             ahp->ah_coarseHigh[level]);
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRPWR,
-                             ahp->ah_firpwr[level]);
-
-               if (level > aniState->noiseImmunityLevel)
-                       ahp->ah_stats.ast_ani_niup++;
-               else if (level < aniState->noiseImmunityLevel)
-                       ahp->ah_stats.ast_ani_nidown++;
-               aniState->noiseImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
-               const int m1ThreshLow[] = { 127, 50 };
-               const int m2ThreshLow[] = { 127, 40 };
-               const int m1Thresh[] = { 127, 0x4d };
-               const int m2Thresh[] = { 127, 0x40 };
-               const int m2CountThr[] = { 31, 16 };
-               const int m2CountThrLow[] = { 63, 48 };
-               u32 on = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2_THRESH,
-                             m2Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2COUNT_THR,
-                             m2CountThr[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
-                             m2CountThrLow[on]);
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH,
-                             m2Thresh[on]);
-
-               if (on)
-                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+       if (AR_SREV_9100(ah)) {
+               if (chan && IS_CHAN_5GHZ(chan))
+                       pll = 0x1450;
                else
-                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-               if (!on != aniState->ofdmWeakSigDetectOff) {
-                       if (on)
-                               ahp->ah_stats.ast_ani_ofdmon++;
-                       else
-                               ahp->ah_stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
-               }
-               break;
-       }
-       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-               const int weakSigThrCck[] = { 8, 6 };
-               u32 high = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
-                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
-                             weakSigThrCck[high]);
-               if (high != aniState->cckWeakSigThreshold) {
-                       if (high)
-                               ahp->ah_stats.ast_ani_cckhigh++;
-                       else
-                               ahp->ah_stats.ast_ani_ccklow++;
-                       aniState->cckWeakSigThreshold = high;
-               }
-               break;
-       }
-       case ATH9K_ANI_FIRSTEP_LEVEL:{
-               const int firstep[] = { 0, 4, 8 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(firstep)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                "%s: level out of range (%u > %u)\n",
-                                __func__, level,
-                               (unsigned) ARRAY_SIZE(firstep));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRSTEP,
-                             firstep[level]);
-               if (level > aniState->firstepLevel)
-                       ahp->ah_stats.ast_ani_stepup++;
-               else if (level < aniState->firstepLevel)
-                       ahp->ah_stats.ast_ani_stepdown++;
-               aniState->firstepLevel = level;
-               break;
-       }
-       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-               const int cycpwrThr1[] =
-                       { 2, 4, 6, 8, 10, 12, 14, 16 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(cycpwrThr1)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                "%s: level out of range (%u > %u)\n",
-                                __func__, level,
-                                (unsigned)
-                               ARRAY_SIZE(cycpwrThr1));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
-                             AR_PHY_TIMING5_CYCPWR_THR1,
-                             cycpwrThr1[level]);
-               if (level > aniState->spurImmunityLevel)
-                       ahp->ah_stats.ast_ani_spurup++;
-               else if (level < aniState->spurImmunityLevel)
-                       ahp->ah_stats.ast_ani_spurdown++;
-               aniState->spurImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_PRESENT:
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                       "%s: invalid cmd %u\n", __func__, cmd);
-               return false;
-       }
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-               "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
-               "ofdmWeakSigDetectOff=%d\n",
-                aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
-                !aniState->ofdmWeakSigDetectOff);
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-               "cckWeakSigThreshold=%d, "
-               "firstepLevel=%d, listenTime=%d\n",
-                aniState->cckWeakSigThreshold, aniState->firstepLevel,
-                aniState->listenTime);
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-                aniState->cycleCount, aniState->ofdmPhyErrCount,
-                aniState->cckPhyErrCount);
-       return true;
-}
-
-static void ath9k_ani_restart(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState;
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ahp->ah_curani;
-
-       aniState->listenTime = 0;
-       if (ahp->ah_hasHwPhyCounters) {
-               if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
-                       aniState->ofdmPhyErrBase = 0;
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                "OFDM Trigger is too high for hw counters\n");
-               } else {
-                       aniState->ofdmPhyErrBase =
-                               AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
-               }
-               if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
-                       aniState->cckPhyErrBase = 0;
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                "CCK Trigger is too high for hw counters\n");
-               } else {
-                       aniState->cckPhyErrBase =
-                               AR_PHY_COUNTMAX - aniState->cckTrigHigh;
-               }
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                        "%s: Writing ofdmbase=%u   cckbase=%u\n",
-                        __func__, aniState->ofdmPhyErrBase,
-                        aniState->cckPhyErrBase);
-               REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
-               REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
-               REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-               REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-               ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-       }
-       aniState->ofdmPhyErrCount = 0;
-       aniState->cckPhyErrCount = 0;
-}
-
-static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *chan = ah->ah_curchan;
-       struct ar5416AniState *aniState;
-       enum wireless_mode mode;
-       int32_t rssi;
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ahp->ah_curani;
+                       pll = 0x1458;
+       } else {
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
 
-       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                        aniState->noiseImmunityLevel + 1)) {
-                       return;
-               }
-       }
+                       if (chan && IS_CHAN_HALF_RATE(chan))
+                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
 
-       if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                        aniState->spurImmunityLevel + 1)) {
-                       return;
-               }
-       }
+                       if (chan && IS_CHAN_5GHZ(chan)) {
+                               pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
 
-       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               }
-               return;
-       }
-       rssi = BEACON_RSSI(ahp);
-       if (rssi > aniState->rssiThrHigh) {
-               if (!aniState->ofdmWeakSigDetectOff) {
-                       if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                        false)) {
-                               ath9k_hw_ani_control(ah,
-                                       ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                       0);
-                               return;
-                       }
-               }
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-                       return;
-               }
-       } else if (rssi > aniState->rssiThrLow) {
-               if (aniState->ofdmWeakSigDetectOff)
-                       ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    true);
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               return;
-       } else {
-               mode = ath9k_hw_chan2wmode(ah, chan);
-               if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
-                       if (!aniState->ofdmWeakSigDetectOff)
-                               ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    false);
-                       if (aniState->firstepLevel > 0)
-                               ath9k_hw_ani_control(ah,
-                                                    ATH9K_ANI_FIRSTEP_LEVEL,
-                                                    0);
-                       return;
-               }
-       }
-}
-
-static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *chan = ah->ah_curchan;
-       struct ar5416AniState *aniState;
-       enum wireless_mode mode;
-       int32_t rssi;
-
-       if (!DO_ANI(ah))
-               return;
-
-       aniState = ahp->ah_curani;
-       if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                        aniState->noiseImmunityLevel + 1)) {
-                       return;
-               }
-       }
-       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-               }
-               return;
-       }
-       rssi = BEACON_RSSI(ahp);
-       if (rssi > aniState->rssiThrLow) {
-               if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
-                       ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                            aniState->firstepLevel + 1);
-       } else {
-               mode = ath9k_hw_chan2wmode(ah, chan);
-               if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
-                       if (aniState->firstepLevel > 0)
-                               ath9k_hw_ani_control(ah,
-                                                    ATH9K_ANI_FIRSTEP_LEVEL,
-                                                    0);
-               }
-       }
-}
-
-static void ath9k_ani_reset(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState;
-       struct ath9k_channel *chan = ah->ah_curchan;
-       int index;
-
-       if (!DO_ANI(ah))
-               return;
-
-       index = ath9k_hw_get_ani_channel_idx(ah, chan);
-       aniState = &ahp->ah_ani[index];
-       ahp->ah_curani = aniState;
-
-       if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
-           && ah->ah_opmode != ATH9K_M_IBSS) {
-               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                        "%s: Reset ANI state opmode %u\n", __func__,
-                        ah->ah_opmode);
-               ahp->ah_stats.ast_ani_reset++;
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
-               ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    !ATH9K_ANI_USE_OFDM_WEAK_SIG);
-               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-                                    ATH9K_ANI_CCK_WEAK_SIG_THR);
-               ath9k_hw_setrxfilter(ah,
-                                    ath9k_hw_getrxfilter(ah) |
-                                    ATH9K_RX_FILTER_PHYERR);
-               if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-                       ahp->ah_curani->ofdmTrigHigh =
-                               ah->ah_config.ofdm_trig_high;
-                       ahp->ah_curani->ofdmTrigLow =
-                               ah->ah_config.ofdm_trig_low;
-                       ahp->ah_curani->cckTrigHigh =
-                               ah->ah_config.cck_trig_high;
-                       ahp->ah_curani->cckTrigLow =
-                               ah->ah_config.cck_trig_low;
-               }
-               ath9k_ani_restart(ah);
-               return;
-       }
-
-       if (aniState->noiseImmunityLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                    aniState->noiseImmunityLevel);
-       if (aniState->spurImmunityLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                    aniState->spurImmunityLevel);
-       if (aniState->ofdmWeakSigDetectOff)
-               ath9k_hw_ani_control(ah,
-                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                    !aniState->ofdmWeakSigDetectOff);
-       if (aniState->cckWeakSigThreshold)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
-                                    aniState->cckWeakSigThreshold);
-       if (aniState->firstepLevel != 0)
-               ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                    aniState->firstepLevel);
-       if (ahp->ah_hasHwPhyCounters) {
-               ath9k_hw_setrxfilter(ah,
-                                    ath9k_hw_getrxfilter(ah) &
-                                    ~ATH9K_RX_FILTER_PHYERR);
-               ath9k_ani_restart(ah);
-               REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-               REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-       } else {
-               ath9k_ani_restart(ah);
-               ath9k_hw_setrxfilter(ah,
-                                    ath9k_hw_getrxfilter(ah) |
-                                    ATH9K_RX_FILTER_PHYERR);
-       }
-}
-
-/*
- * Process a MIB interrupt.  We may potentially be invoked because
- * any of the MIB counters overflow/trigger so don't assume we're
- * here because a PHY error counter triggered.
- */
-void ath9k_hw_procmibevent(struct ath_hal *ah,
-                          const struct ath9k_node_stats *stats)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 phyCnt1, phyCnt2;
-
-       DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
-       /* Reset these counters regardless */
-       REG_WRITE(ah, AR_FILT_OFDM, 0);
-       REG_WRITE(ah, AR_FILT_CCK, 0);
-       if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
-               REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
-
-       /* Clear the mib counters and save them in the stats */
-       ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-       ahp->ah_stats.ast_nodestats = *stats;
-
-       if (!DO_ANI(ah))
-               return;
-
-       /* NB: these are not reset-on-read */
-       phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-       phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-       if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
-           ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
-               struct ar5416AniState *aniState = ahp->ah_curani;
-               u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-               /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
-               ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-               ahp->ah_stats.ast_ani_ofdmerrs +=
-                       ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-               aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-               cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-               ahp->ah_stats.ast_ani_cckerrs +=
-                       cckPhyErrCnt - aniState->cckPhyErrCount;
-               aniState->cckPhyErrCount = cckPhyErrCnt;
-
-               /*
-                * NB: figure out which counter triggered.  If both
-                * trigger we'll only deal with one as the processing
-                * clobbers the error counter so the trigger threshold
-                * check will never be true.
-                */
-               if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
-                       ath9k_hw_ani_ofdm_err_trigger(ah);
-               if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
-                       ath9k_hw_ani_cck_err_trigger(ah);
-               /* NB: always restart to insure the h/w counters are reset */
-               ath9k_ani_restart(ah);
-       }
-}
-
-static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState;
-       int32_t rssi;
-
-       aniState = ahp->ah_curani;
-
-       if (ah->ah_opmode == ATH9K_M_HOSTAP) {
-               if (aniState->firstepLevel > 0) {
-                       if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                                aniState->firstepLevel - 1)) {
-                               return;
-                       }
-               }
-       } else {
-               rssi = BEACON_RSSI(ahp);
-               if (rssi > aniState->rssiThrHigh) {
-                       /* XXX: Handle me */
-               } else if (rssi > aniState->rssiThrLow) {
-                       if (aniState->ofdmWeakSigDetectOff) {
-                               if (ath9k_hw_ani_control(ah,
-                                        ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                                        true) ==
-                                   true) {
-                                       return;
-                               }
-                       }
-                       if (aniState->firstepLevel > 0) {
-                               if (ath9k_hw_ani_control
-                                   (ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                    aniState->firstepLevel - 1) ==
-                                   true) {
-                                       return;
-                               }
-                       }
-               } else {
-                       if (aniState->firstepLevel > 0) {
-                               if (ath9k_hw_ani_control
-                                   (ah, ATH9K_ANI_FIRSTEP_LEVEL,
-                                    aniState->firstepLevel - 1) ==
-                                   true) {
-                                       return;
-                               }
-                       }
-               }
-       }
-
-       if (aniState->spurImmunityLevel > 0) {
-               if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
-                                        aniState->spurImmunityLevel - 1)) {
-                       return;
-               }
-       }
-
-       if (aniState->noiseImmunityLevel > 0) {
-               ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
-                                    aniState->noiseImmunityLevel - 1);
-               return;
-       }
-}
-
-static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState;
-       u32 txFrameCount, rxFrameCount, cycleCount;
-       int32_t listenTime;
-
-       txFrameCount = REG_READ(ah, AR_TFCNT);
-       rxFrameCount = REG_READ(ah, AR_RFCNT);
-       cycleCount = REG_READ(ah, AR_CCCNT);
-
-       aniState = ahp->ah_curani;
-       if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
-
-               listenTime = 0;
-               ahp->ah_stats.ast_ani_lzero++;
-       } else {
-               int32_t ccdelta = cycleCount - aniState->cycleCount;
-               int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
-               int32_t tfdelta = txFrameCount - aniState->txFrameCount;
-               listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
-       }
-       aniState->cycleCount = cycleCount;
-       aniState->txFrameCount = txFrameCount;
-       aniState->rxFrameCount = rxFrameCount;
-
-       return listenTime;
-}
-
-void ath9k_hw_ani_monitor(struct ath_hal *ah,
-                         const struct ath9k_node_stats *stats,
-                         struct ath9k_channel *chan)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416AniState *aniState;
-       int32_t listenTime;
-
-       aniState = ahp->ah_curani;
-       ahp->ah_stats.ast_nodestats = *stats;
-
-       listenTime = ath9k_hw_ani_get_listen_time(ah);
-       if (listenTime < 0) {
-               ahp->ah_stats.ast_ani_lneg++;
-               ath9k_ani_restart(ah);
-               return;
-       }
-
-       aniState->listenTime += listenTime;
-
-       if (ahp->ah_hasHwPhyCounters) {
-               u32 phyCnt1, phyCnt2;
-               u32 ofdmPhyErrCnt, cckPhyErrCnt;
-
-               ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
-
-               phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
-               phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
-
-               if (phyCnt1 < aniState->ofdmPhyErrBase ||
-                   phyCnt2 < aniState->cckPhyErrBase) {
-                       if (phyCnt1 < aniState->ofdmPhyErrBase) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                        "%s: phyCnt1 0x%x, resetting "
-                                        "counter value to 0x%x\n",
-                                        __func__, phyCnt1,
-                                        aniState->ofdmPhyErrBase);
-                               REG_WRITE(ah, AR_PHY_ERR_1,
-                                         aniState->ofdmPhyErrBase);
-                               REG_WRITE(ah, AR_PHY_ERR_MASK_1,
-                                         AR_PHY_ERR_OFDM_TIMING);
-                       }
-                       if (phyCnt2 < aniState->cckPhyErrBase) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_ANI,
-                                        "%s: phyCnt2 0x%x, resetting "
-                                        "counter value to 0x%x\n",
-                                        __func__, phyCnt2,
-                                        aniState->cckPhyErrBase);
-                               REG_WRITE(ah, AR_PHY_ERR_2,
-                                         aniState->cckPhyErrBase);
-                               REG_WRITE(ah, AR_PHY_ERR_MASK_2,
-                                         AR_PHY_ERR_CCK_TIMING);
-                       }
-                       return;
-               }
-
-               ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
-               ahp->ah_stats.ast_ani_ofdmerrs +=
-                       ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
-               aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
-
-               cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
-               ahp->ah_stats.ast_ani_cckerrs +=
-                       cckPhyErrCnt - aniState->cckPhyErrCount;
-               aniState->cckPhyErrCount = cckPhyErrCnt;
-       }
-
-       if (!DO_ANI(ah))
-               return;
-
-       if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
-               if (aniState->ofdmPhyErrCount <= aniState->listenTime *
-                   aniState->ofdmTrigLow / 1000 &&
-                   aniState->cckPhyErrCount <= aniState->listenTime *
-                   aniState->cckTrigLow / 1000)
-                       ath9k_hw_ani_lower_immunity(ah);
-               ath9k_ani_restart(ah);
-       } else if (aniState->listenTime > ahp->ah_aniPeriod) {
-               if (aniState->ofdmPhyErrCount > aniState->listenTime *
-                   aniState->ofdmTrigHigh / 1000) {
-                       ath9k_hw_ani_ofdm_err_trigger(ah);
-                       ath9k_ani_restart(ah);
-               } else if (aniState->cckPhyErrCount >
-                          aniState->listenTime * aniState->cckTrigHigh /
-                          1000) {
-                       ath9k_hw_ani_cck_err_trigger(ah);
-                       ath9k_ani_restart(ah);
-               }
-       }
-}
-
-#ifndef ATH_NF_PER_CHAN
-static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
-{
-       int i, j;
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               ah->nfCalHist[i].currIndex = 0;
-               ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
-               ah->nfCalHist[i].invalidNFcount =
-                       AR_PHY_CCA_FILTERWINDOW_LENGTH;
-               for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
-                       ah->nfCalHist[i].nfCalBuffer[j] =
-                               AR_PHY_CCA_MAX_GOOD_VALUE;
-               }
-       }
-       return;
-}
-#endif
-
-static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
-                                        u32 gpio, u32 type)
-{
-       int addr;
-       u32 gpio_shift, tmp;
-
-       if (gpio > 11)
-               addr = AR_GPIO_OUTPUT_MUX3;
-       else if (gpio > 5)
-               addr = AR_GPIO_OUTPUT_MUX2;
-       else
-               addr = AR_GPIO_OUTPUT_MUX1;
-
-       gpio_shift = (gpio % 6) * 5;
-
-       if (AR_SREV_9280_20_OR_LATER(ah)
-           || (addr != AR_GPIO_OUTPUT_MUX1)) {
-               REG_RMW(ah, addr, (type << gpio_shift),
-                       (0x1f << gpio_shift));
-       } else {
-               tmp = REG_READ(ah, addr);
-               tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
-               tmp &= ~(0x1f << gpio_shift);
-               tmp |= (type << gpio_shift);
-               REG_WRITE(ah, addr, tmp);
-       }
-}
-
-void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
-                        u32 ah_signal_type)
-{
-       u32 gpio_shift;
-
-       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
-
-       gpio_shift = 2 * gpio;
-
-       REG_RMW(ah,
-               AR_GPIO_OE_OUT,
-               (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
-               (AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
-{
-       REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
-               AR_GPIO_BIT(gpio));
-}
-
-/*
- * Configure GPIO Input lines
- */
-void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
-{
-       u32 gpio_shift;
-
-       ASSERT(gpio < ah->ah_caps.num_gpio_pins);
-
-       gpio_shift = gpio << 1;
-
-       REG_RMW(ah,
-               AR_GPIO_OE_OUT,
-               (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
-               (AR_GPIO_OE_OUT_DRV << gpio_shift));
-}
-
-#ifdef CONFIG_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
-       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-                   AR_GPIO_INPUT_MUX2_RFSILENT);
-
-       ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
-       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-#endif
-
-u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
-{
-       if (gpio >= ah->ah_caps.num_gpio_pins)
-               return 0xffffffff;
-
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               return (MS
-                       (REG_READ(ah, AR_GPIO_IN_OUT),
-                        AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
-       } else {
-               return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
-                       AR_GPIO_BIT(gpio)) != 0;
-       }
-}
-
-static int ath9k_hw_post_attach(struct ath_hal *ah)
-{
-       int ecode;
-
-       if (!ath9k_hw_chip_test(ah)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                        "%s: hardware self-test failed\n", __func__);
-               return -ENODEV;
-       }
-
-       ecode = ath9k_hw_rf_claim(ah);
-       if (ecode != 0)
-               return ecode;
-
-       ecode = ath9k_hw_eeprom_attach(ah);
-       if (ecode != 0)
-               return ecode;
-       ecode = ath9k_hw_rfattach(ah);
-       if (ecode != 0)
-               return ecode;
-
-       if (!AR_SREV_9100(ah)) {
-               ath9k_hw_ani_setup(ah);
-               ath9k_hw_ani_attach(ah);
-       }
-       return 0;
-}
-
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
-                                   struct ar5416_eeprom *pEepData,
-                                   u32 reg, u32 value)
-{
-       struct base_eep_header *pBase = &(pEepData->baseEepHeader);
-
-       switch (ah->ah_devid) {
-       case AR9280_DEVID_PCI:
-               if (reg == 0x7894) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                "ini VAL: %x  EEPROM: %x\n", value,
-                                (pBase->version & 0xff));
-
-                       if ((pBase->version & 0xff) > 0x0a) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                        "PWDCLKIND: %d\n",
-                                        pBase->pwdclkind);
-                               value &= ~AR_AN_TOP2_PWDCLKIND;
-                               value |= AR_AN_TOP2_PWDCLKIND & (pBase->
-                                        pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
-                       } else {
-                               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                        "PWDCLKIND Earlier Rev\n");
-                       }
-
-                       DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                "final ini VAL: %x\n", value);
-               }
-               break;
-       }
-       return value;
-}
-
-static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       u16 capField = 0, eeval;
-
-       eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0);
-
-       ah->ah_currentRD = eeval;
-
-       eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1);
-       ah->ah_currentRDExt = eeval;
-
-       capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP);
-
-       if (ah->ah_opmode != ATH9K_M_HOSTAP &&
-           ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
-               if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
-                       ah->ah_currentRD += 5;
-               else if (ah->ah_currentRD == 0x41)
-                       ah->ah_currentRD = 0x43;
-               DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
-                        "%s: regdomain mapped to 0x%x\n", __func__,
-                        ah->ah_currentRD);
-       }
-
-       eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE);
-       bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
-
-       if (eeval & AR5416_OPFLAGS_11A) {
-               set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
-               if (ah->ah_config.ht_enable) {
-                       if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
-                               set_bit(ATH9K_MODE_11NA_HT20,
-                                       pCap->wireless_modes);
-                       if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
-                               set_bit(ATH9K_MODE_11NA_HT40PLUS,
-                                       pCap->wireless_modes);
-                               set_bit(ATH9K_MODE_11NA_HT40MINUS,
-                                       pCap->wireless_modes);
-                       }
-               }
-       }
-
-       if (eeval & AR5416_OPFLAGS_11G) {
-               set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
-               set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
-               if (ah->ah_config.ht_enable) {
-                       if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
-                               set_bit(ATH9K_MODE_11NG_HT20,
-                                       pCap->wireless_modes);
-                       if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
-                               set_bit(ATH9K_MODE_11NG_HT40PLUS,
-                                       pCap->wireless_modes);
-                               set_bit(ATH9K_MODE_11NG_HT40MINUS,
-                                       pCap->wireless_modes);
-                       }
-               }
-       }
-
-       pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK);
-       if ((ah->ah_isPciExpress)
-           || (eeval & AR5416_OPFLAGS_11A)) {
-               pCap->rx_chainmask =
-                       ath9k_hw_get_eeprom(ahp, EEP_RX_MASK);
-       } else {
-               pCap->rx_chainmask =
-                       (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
-       }
-
-       if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
-               ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
-
-       pCap->low_2ghz_chan = 2312;
-       pCap->high_2ghz_chan = 2732;
-
-       pCap->low_5ghz_chan = 4920;
-       pCap->high_5ghz_chan = 6100;
-
-       pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
-       pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
-       pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
-
-       pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
-       pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
-       pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
-
-       pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
-
-       if (ah->ah_config.ht_enable)
-               pCap->hw_caps |= ATH9K_HW_CAP_HT;
-       else
-               pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
-
-       pCap->hw_caps |= ATH9K_HW_CAP_GTT;
-       pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
-       pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
-       pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
-
-       if (capField & AR_EEPROM_EEPCAP_MAXQCU)
-               pCap->total_queues =
-                       MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
-       else
-               pCap->total_queues = ATH9K_NUM_TX_QUEUES;
-
-       if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
-               pCap->keycache_size =
-                       1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
-       else
-               pCap->keycache_size = AR_KEYTABLE_SIZE;
-
-       pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
-       pCap->num_mr_retries = 4;
-       pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               pCap->num_gpio_pins = AR928X_NUM_GPIO;
-       else
-               pCap->num_gpio_pins = AR_NUM_GPIO;
-
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               pCap->hw_caps |= ATH9K_HW_CAP_WOW;
-               pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
-       } else {
-               pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
-               pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
-       }
-
-       if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
-               pCap->hw_caps |= ATH9K_HW_CAP_CST;
-               pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
-       } else {
-               pCap->rts_aggr_limit = (8 * 1024);
-       }
-
-       pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-
-#ifdef CONFIG_RFKILL
-       ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
-       if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-               ah->ah_rfkill_gpio =
-                       MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-               ah->ah_rfkill_polarity =
-                       MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
-
-               pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
-       }
-#endif
-
-       if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
-           (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
-           (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
-           (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
-           (ah->ah_macVersion == AR_SREV_VERSION_9280))
-               pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
-       else
-               pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
-
-       if (AR_SREV_9280(ah))
-               pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
-       else
-               pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
-
-       if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
-               pCap->reg_cap =
-                       AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-                       AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
-                       AR_EEPROM_EEREGCAP_EN_KK_U2 |
-                       AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
-       } else {
-               pCap->reg_cap =
-                       AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
-                       AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
-       }
-
-       pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-
-       pCap->num_antcfg_5ghz =
-               ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ);
-       pCap->num_antcfg_2ghz =
-               ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ);
-
-       return true;
-}
-
-static void ar5416DisablePciePhy(struct ath_hal *ah)
-{
-       if (!AR_SREV_9100(ah))
-               return;
-
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-       REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
-
-       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-}
-
-static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
-{
-       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-       if (setChip) {
-               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-                           AR_RTC_FORCE_WAKE_EN);
-               if (!AR_SREV_9100(ah))
-                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-
-               REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
-                           AR_RTC_RESET_EN);
-       }
-}
-
-static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
-{
-       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-       if (setChip) {
-               struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-               if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-                       REG_WRITE(ah, AR_RTC_FORCE_WAKE,
-                                 AR_RTC_FORCE_WAKE_ON_INT);
-               } else {
-                       REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
-                                   AR_RTC_FORCE_WAKE_EN);
-               }
-       }
-}
-
-static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
-                                    int setChip)
-{
-       u32 val;
-       int i;
-
-       if (setChip) {
-               if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
-                   AR_RTC_STATUS_SHUTDOWN) {
-                       if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)
-                           != true) {
-                               return false;
-                       }
-               }
-               if (AR_SREV_9100(ah))
-                       REG_SET_BIT(ah, AR_RTC_RESET,
-                                      AR_RTC_RESET_EN);
-
-               REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-                           AR_RTC_FORCE_WAKE_EN);
-               udelay(50);
-
-               for (i = POWER_UP_TIME / 50; i > 0; i--) {
-                       val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
-                       if (val == AR_RTC_STATUS_ON)
-                               break;
-                       udelay(50);
-                       REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
-                                      AR_RTC_FORCE_WAKE_EN);
-               }
-               if (i == 0) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                                "%s: Failed to wakeup in %uus\n",
-                                __func__, POWER_UP_TIME / 20);
-                       return false;
-               }
-       }
-
-       REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
-       return true;
-}
-
-bool ath9k_hw_setpower(struct ath_hal *ah,
-                      enum ath9k_power_mode mode)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       static const char *modes[] = {
-               "AWAKE",
-               "FULL-SLEEP",
-               "NETWORK SLEEP",
-               "UNDEFINED"
-       };
-       int status = true, setChip = true;
-
-       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,
-                modes[ahp->ah_powerMode], modes[mode],
-                setChip ? "set chip " : "");
-
-       switch (mode) {
-       case ATH9K_PM_AWAKE:
-               status = ath9k_hw_set_power_awake(ah, setChip);
-               break;
-       case ATH9K_PM_FULL_SLEEP:
-               ath9k_set_power_sleep(ah, setChip);
-               ahp->ah_chipFullSleep = true;
-               break;
-       case ATH9K_PM_NETWORK_SLEEP:
-               ath9k_set_power_network_sleep(ah, setChip);
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                        "%s: unknown power mode %u\n", __func__, mode);
-               return false;
-       }
-       ahp->ah_powerMode = mode;
-       return status;
-}
-
-static struct ath_hal *ath9k_hw_do_attach(u16 devid,
-                                         struct ath_softc *sc,
-                                         void __iomem *mem,
-                                         int *status)
-{
-       struct ath_hal_5416 *ahp;
-       struct ath_hal *ah;
-       int ecode;
-#ifndef CONFIG_SLOW_ANT_DIV
-       u32 i;
-       u32 j;
-#endif
-
-       ahp = ath9k_hw_newstate(devid, sc, mem, status);
-       if (ahp == NULL)
-               return NULL;
-
-       ah = &ahp->ah;
-
-       ath9k_hw_set_defaults(ah);
-
-       if (ah->ah_config.intr_mitigation != 0)
-               ahp->ah_intrMitigation = true;
-
-       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n",
-                        __func__);
-               ecode = -EIO;
-               goto bad;
-       }
-
-       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n",
-                        __func__);
-               ecode = -EIO;
-               goto bad;
-       }
-
-       if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) {
-                       ah->ah_config.serialize_regmode =
-                               SER_REG_MODE_ON;
-               } else {
-                       ah->ah_config.serialize_regmode =
-                               SER_REG_MODE_OFF;
-               }
-       }
-       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-               "%s: serialize_regmode is %d\n",
-               __func__, ah->ah_config.serialize_regmode);
-
-       if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
-           (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
-           (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
-           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                        "%s: Mac Chip Rev 0x%02x.%x is not supported by "
-                        "this driver\n", __func__,
-                        ah->ah_macVersion, ah->ah_macRev);
-               ecode = -EOPNOTSUPP;
-               goto bad;
-       }
-
-       if (AR_SREV_9100(ah)) {
-               ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
-               ahp->ah_suppCals = IQ_MISMATCH_CAL;
-               ah->ah_isPciExpress = false;
-       }
-       ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
-
-       if (AR_SREV_9160_10_OR_LATER(ah)) {
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       ahp->ah_iqCalData.calData = &iq_cal_single_sample;
-                       ahp->ah_adcGainCalData.calData =
-                               &adc_gain_cal_single_sample;
-                       ahp->ah_adcDcCalData.calData =
-                               &adc_dc_cal_single_sample;
-                       ahp->ah_adcDcCalInitData.calData =
-                               &adc_init_dc_cal;
-               } else {
-                       ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
-                       ahp->ah_adcGainCalData.calData =
-                               &adc_gain_cal_multi_sample;
-                       ahp->ah_adcDcCalData.calData =
-                               &adc_dc_cal_multi_sample;
-                       ahp->ah_adcDcCalInitData.calData =
-                               &adc_init_dc_cal;
-               }
-               ahp->ah_suppCals =
-                       ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
-       }
-
-       if (AR_SREV_9160(ah)) {
-               ah->ah_config.enable_ani = 1;
-               ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
-                                       ATH9K_ANI_FIRSTEP_LEVEL);
-       } else {
-               ahp->ah_ani_function = ATH9K_ANI_ALL;
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       ahp->ah_ani_function &=
-                               ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
-               }
-       }
-
-       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__,
-                ah->ah_macVersion, ah->ah_macRev);
-
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
-                              ARRAY_SIZE(ar9280Modes_9280_2), 6);
-               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
-                              ARRAY_SIZE(ar9280Common_9280_2), 2);
-
-               if (ah->ah_config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
-                                      ar9280PciePhy_clkreq_off_L1_9280,
-                                      ARRAY_SIZE
-                                      (ar9280PciePhy_clkreq_off_L1_9280),
-                                      2);
-               } else {
-                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
-                                      ar9280PciePhy_clkreq_always_on_L1_9280,
-                                      ARRAY_SIZE
-                                      (ar9280PciePhy_clkreq_always_on_L1_9280),
-                                      2);
-               }
-               INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
-                              ar9280Modes_fast_clock_9280_2,
-                              ARRAY_SIZE(ar9280Modes_fast_clock_9280_2),
-                              3);
-       } else if (AR_SREV_9280_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
-                              ARRAY_SIZE(ar9280Modes_9280), 6);
-               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280,
-                              ARRAY_SIZE(ar9280Common_9280), 2);
-       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160,
-                              ARRAY_SIZE(ar5416Modes_9160), 6);
-               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160,
-                              ARRAY_SIZE(ar5416Common_9160), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160,
-                              ARRAY_SIZE(ar5416Bank0_9160), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160,
-                              ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160,
-                              ARRAY_SIZE(ar5416Bank1_9160), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160,
-                              ARRAY_SIZE(ar5416Bank2_9160), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160,
-                              ARRAY_SIZE(ar5416Bank3_9160), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160,
-                              ARRAY_SIZE(ar5416Bank6_9160), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160,
-                              ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160,
-                              ARRAY_SIZE(ar5416Bank7_9160), 2);
-               if (AR_SREV_9160_11(ah)) {
-                       INIT_INI_ARRAY(&ahp->ah_iniAddac,
-                                      ar5416Addac_91601_1,
-                                      ARRAY_SIZE(ar5416Addac_91601_1), 2);
-               } else {
-                       INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160,
-                                      ARRAY_SIZE(ar5416Addac_9160), 2);
-               }
-       } else if (AR_SREV_9100_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100,
-                              ARRAY_SIZE(ar5416Modes_9100), 6);
-               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100,
-                              ARRAY_SIZE(ar5416Common_9100), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100,
-                              ARRAY_SIZE(ar5416Bank0_9100), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100,
-                              ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100,
-                              ARRAY_SIZE(ar5416Bank1_9100), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100,
-                              ARRAY_SIZE(ar5416Bank2_9100), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100,
-                              ARRAY_SIZE(ar5416Bank3_9100), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100,
-                              ARRAY_SIZE(ar5416Bank6_9100), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100,
-                              ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100,
-                              ARRAY_SIZE(ar5416Bank7_9100), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100,
-                              ARRAY_SIZE(ar5416Addac_9100), 2);
-       } else {
-               INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes,
-                              ARRAY_SIZE(ar5416Modes), 6);
-               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common,
-                              ARRAY_SIZE(ar5416Common), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0,
-                              ARRAY_SIZE(ar5416Bank0), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain,
-                              ARRAY_SIZE(ar5416BB_RfGain), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1,
-                              ARRAY_SIZE(ar5416Bank1), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2,
-                              ARRAY_SIZE(ar5416Bank2), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3,
-                              ARRAY_SIZE(ar5416Bank3), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6,
-                              ARRAY_SIZE(ar5416Bank6), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC,
-                              ARRAY_SIZE(ar5416Bank6TPC), 3);
-               INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7,
-                              ARRAY_SIZE(ar5416Bank7), 2);
-               INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac,
-                              ARRAY_SIZE(ar5416Addac), 2);
-       }
-
-       if (ah->ah_isPciExpress)
-               ath9k_hw_configpcipowersave(ah, 0);
-       else
-               ar5416DisablePciePhy(ah);
-
-       ecode = ath9k_hw_post_attach(ah);
-       if (ecode != 0)
-               goto bad;
-
-#ifndef CONFIG_SLOW_ANT_DIV
-       if (ah->ah_devid == AR9280_DEVID_PCI) {
-               for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
-                       u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
-
-                       for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) {
-                               u32 val = INI_RA(&ahp->ah_iniModes, i, j);
-
-                               INI_RA(&ahp->ah_iniModes, i, j) =
-                                       ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
-                                                          reg, val);
-                       }
-               }
-       }
-#endif
-
-       if (!ath9k_hw_fill_cap_info(ah)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                        "%s:failed ath9k_hw_fill_cap_info\n", __func__);
-               ecode = -EINVAL;
-               goto bad;
-       }
-
-       ecode = ath9k_hw_init_macaddr(ah);
-       if (ecode != 0) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                        "%s: failed initializing mac address\n",
-                        __func__);
-               goto bad;
-       }
-
-       if (AR_SREV_9285(ah))
-               ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S);
-       else
-               ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
-
-#ifndef ATH_NF_PER_CHAN
-
-       ath9k_init_nfcal_hist_buffer(ah);
-#endif
-
-       return ah;
-
-bad:
-       if (ahp)
-               ath9k_hw_detach((struct ath_hal *) ahp);
-       if (status)
-               *status = ecode;
-       return NULL;
-}
-
-void ath9k_hw_detach(struct ath_hal *ah)
-{
-       if (!AR_SREV_9100(ah))
-               ath9k_hw_ani_detach(ah);
-       ath9k_hw_rfdetach(ah);
-
-       ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
-       kfree(ah);
-}
-
-bool ath9k_get_channel_edges(struct ath_hal *ah,
-                            u16 flags, u16 *low,
-                            u16 *high)
-{
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-       if (flags & CHANNEL_5GHZ) {
-               *low = pCap->low_5ghz_chan;
-               *high = pCap->high_5ghz_chan;
-               return true;
-       }
-       if ((flags & CHANNEL_2GHZ)) {
-               *low = pCap->low_2ghz_chan;
-               *high = pCap->high_2ghz_chan;
-
-               return true;
-       }
-       return false;
-}
-
-static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin,
-                                          u8 pwrMax,
-                                          u8 *pPwrList,
-                                          u8 *pVpdList,
-                                          u16
-                                          numIntercepts,
-                                          u8 *pRetVpdList)
-{
-       u16 i, k;
-       u8 currPwr = pwrMin;
-       u16 idxL = 0, idxR = 0;
-
-       for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
-               ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
-                                              numIntercepts, &(idxL),
-                                              &(idxR));
-               if (idxR < 1)
-                       idxR = 1;
-               if (idxL == numIntercepts - 1)
-                       idxL = (u16) (numIntercepts - 2);
-               if (pPwrList[idxL] == pPwrList[idxR])
-                       k = pVpdList[idxL];
-               else
-                       k = (u16) (((currPwr -
-                                          pPwrList[idxL]) *
-                                         pVpdList[idxR] +
-                                         (pPwrList[idxR] -
-                                          currPwr) * pVpdList[idxL]) /
-                                        (pPwrList[idxR] -
-                                         pPwrList[idxL]));
-               pRetVpdList[i] = (u8) k;
-               currPwr += 2;
-       }
-
-       return true;
-}
-
-static void
-ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
-                                   struct ath9k_channel *chan,
-                                   struct cal_data_per_freq *pRawDataSet,
-                                   u8 *bChans,
-                                   u16 availPiers,
-                                   u16 tPdGainOverlap,
-                                   int16_t *pMinCalPower,
-                                   u16 *pPdGainBoundaries,
-                                   u8 *pPDADCValues,
-                                   u16 numXpdGains)
-{
-       int i, j, k;
-       int16_t ss;
-       u16 idxL = 0, idxR = 0, numPiers;
-       static u8 vpdTableL[AR5416_NUM_PD_GAINS]
-               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-       static u8 vpdTableR[AR5416_NUM_PD_GAINS]
-               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-       static u8 vpdTableI[AR5416_NUM_PD_GAINS]
-               [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
-
-       u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
-       u8 minPwrT4[AR5416_NUM_PD_GAINS];
-       u8 maxPwrT4[AR5416_NUM_PD_GAINS];
-       int16_t vpdStep;
-       int16_t tmpVal;
-       u16 sizeCurrVpdTable, maxIndex, tgtIndex;
-       bool match;
-       int16_t minDelta = 0;
-       struct chan_centers centers;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-       for (numPiers = 0; numPiers < availPiers; numPiers++) {
-               if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
-                       break;
-       }
-
-       match = ath9k_hw_get_lower_upper_index((u8)
-                                              FREQ2FBIN(centers.
-                                                        synth_center,
-                                                        IS_CHAN_2GHZ
-                                                        (chan)), bChans,
-                                              numPiers, &idxL, &idxR);
-
-       if (match) {
-               for (i = 0; i < numXpdGains; i++) {
-                       minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
-                       maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
-                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-                                               pRawDataSet[idxL].
-                                               pwrPdg[i],
-                                               pRawDataSet[idxL].
-                                               vpdPdg[i],
-                                               AR5416_PD_GAIN_ICEPTS,
-                                               vpdTableI[i]);
-               }
-       } else {
-               for (i = 0; i < numXpdGains; i++) {
-                       pVpdL = pRawDataSet[idxL].vpdPdg[i];
-                       pPwrL = pRawDataSet[idxL].pwrPdg[i];
-                       pVpdR = pRawDataSet[idxR].vpdPdg[i];
-                       pPwrR = pRawDataSet[idxR].pwrPdg[i];
-
-                       minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
-
-                       maxPwrT4[i] =
-                               min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
-                                   pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
-
-
-                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-                                               pPwrL, pVpdL,
-                                               AR5416_PD_GAIN_ICEPTS,
-                                               vpdTableL[i]);
-                       ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
-                                               pPwrR, pVpdR,
-                                               AR5416_PD_GAIN_ICEPTS,
-                                               vpdTableR[i]);
-
-                       for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
-                               vpdTableI[i][j] =
-                                       (u8) (ath9k_hw_interpolate
-                                                   ((u16)
-                                                    FREQ2FBIN(centers.
-                                                              synth_center,
-                                                              IS_CHAN_2GHZ
-                                                              (chan)),
-                                                    bChans[idxL],
-                                                    bChans[idxR], vpdTableL[i]
-                                                    [j], vpdTableR[i]
-                                                    [j]));
-                       }
-               }
-       }
-
-       *pMinCalPower = (int16_t) (minPwrT4[0] / 2);
-
-       k = 0;
-       for (i = 0; i < numXpdGains; i++) {
-               if (i == (numXpdGains - 1))
-                       pPdGainBoundaries[i] =
-                               (u16) (maxPwrT4[i] / 2);
-               else
-                       pPdGainBoundaries[i] =
-                               (u16) ((maxPwrT4[i] +
-                                             minPwrT4[i + 1]) / 4);
-
-               pPdGainBoundaries[i] =
-                       min((u16) AR5416_MAX_RATE_POWER,
-                           pPdGainBoundaries[i]);
-
-               if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
-                       minDelta = pPdGainBoundaries[0] - 23;
-                       pPdGainBoundaries[0] = 23;
-               } else {
-                       minDelta = 0;
-               }
-
-               if (i == 0) {
-                       if (AR_SREV_9280_10_OR_LATER(ah))
-                               ss = (int16_t) (0 - (minPwrT4[i] / 2));
-                       else
-                               ss = 0;
-               } else {
-                       ss = (int16_t) ((pPdGainBoundaries[i - 1] -
-                                        (minPwrT4[i] / 2)) -
-                                       tPdGainOverlap + 1 + minDelta);
-               }
-               vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]);
-               vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
-               while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-                       tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep);
-                       pPDADCValues[k++] =
-                               (u8) ((tmpVal < 0) ? 0 : tmpVal);
-                       ss++;
-               }
-
-               sizeCurrVpdTable =
-                       (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
-               tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap -
-                                      (minPwrT4[i] / 2));
-               maxIndex = (tgtIndex <
-                           sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
-
-               while ((ss < maxIndex)
-                      && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-                       pPDADCValues[k++] = vpdTableI[i][ss++];
-               }
-
-               vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] -
-                                    vpdTableI[i][sizeCurrVpdTable - 2]);
-               vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
-
-               if (tgtIndex > maxIndex) {
-                       while ((ss <= tgtIndex)
-                              && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
-                               tmpVal = (int16_t) ((vpdTableI[i]
-                                                    [sizeCurrVpdTable -
-                                                     1] + (ss - maxIndex +
-                                                           1) * vpdStep));
-                               pPDADCValues[k++] = (u8) ((tmpVal >
-                                                255) ? 255 : tmpVal);
-                               ss++;
-                       }
-               }
-       }
-
-       while (i < AR5416_PD_GAINS_IN_MASK) {
-               pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
-               i++;
-       }
-
-       while (k < AR5416_NUM_PDADC_VALUES) {
-               pPDADCValues[k] = pPDADCValues[k - 1];
-               k++;
-       }
-       return;
-}
-
-static bool
-ath9k_hw_set_power_cal_table(struct ath_hal *ah,
-                            struct ar5416_eeprom *pEepData,
-                            struct ath9k_channel *chan,
-                            int16_t *pTxPowerIndexOffset)
-{
-       struct cal_data_per_freq *pRawDataset;
-       u8 *pCalBChans = NULL;
-       u16 pdGainOverlap_t2;
-       static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
-       u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
-       u16 numPiers, i, j;
-       int16_t tMinCalPower;
-       u16 numXpdGain, xpdMask;
-       u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
-       u32 reg32, regOffset, regChainOffset;
-       int16_t modalIdx;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
-       xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
-
-       if ((pEepData->baseEepHeader.
-            version & AR5416_EEP_VER_MINOR_MASK) >=
-           AR5416_EEP_MINOR_VER_2) {
-               pdGainOverlap_t2 =
-                       pEepData->modalHeader[modalIdx].pdGainOverlap;
-       } else {
-               pdGainOverlap_t2 =
-                       (u16) (MS
-                                    (REG_READ(ah, AR_PHY_TPCRG5),
-                                     AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
-       }
-
-       if (IS_CHAN_2GHZ(chan)) {
-               pCalBChans = pEepData->calFreqPier2G;
-               numPiers = AR5416_NUM_2G_CAL_PIERS;
-       } else {
-               pCalBChans = pEepData->calFreqPier5G;
-               numPiers = AR5416_NUM_5G_CAL_PIERS;
-       }
-
-       numXpdGain = 0;
-
-       for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
-               if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
-                       if (numXpdGain >= AR5416_NUM_PD_GAINS)
-                               break;
-                       xpdGainValues[numXpdGain] =
-                               (u16) (AR5416_PD_GAINS_IN_MASK - i);
-                       numXpdGain++;
-               }
-       }
-
-       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
-                     (numXpdGain - 1) & 0x3);
-       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
-                     xpdGainValues[0]);
-       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
-                     xpdGainValues[1]);
-       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
-                     xpdGainValues[2]);
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               if (AR_SREV_5416_V20_OR_LATER(ah) &&
-                   (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
-                   && (i != 0)) {
-                       regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-               } else
-                       regChainOffset = i * 0x1000;
-               if (pEepData->baseEepHeader.txMask & (1 << i)) {
-                       if (IS_CHAN_2GHZ(chan))
-                               pRawDataset = pEepData->calPierData2G[i];
-                       else
-                               pRawDataset = pEepData->calPierData5G[i];
-
-                       ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
-                                                           pRawDataset,
-                                                           pCalBChans,
-                                                           numPiers,
-                                                           pdGainOverlap_t2,
-                                                           &tMinCalPower,
-                                                           gainBoundaries,
-                                                           pdadcValues,
-                                                           numXpdGain);
-
-                       if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-
-                               REG_WRITE(ah,
-                                         AR_PHY_TPCRG5 + regChainOffset,
-                                         SM(pdGainOverlap_t2,
-                                            AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
-                                         | SM(gainBoundaries[0],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
-                                         | SM(gainBoundaries[1],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
-                                         | SM(gainBoundaries[2],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
-                                         | SM(gainBoundaries[3],
-                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
-                       }
-
-                       regOffset =
-                               AR_PHY_BASE + (672 << 2) + regChainOffset;
-                       for (j = 0; j < 32; j++) {
-                               reg32 =
-                                       ((pdadcValues[4 * j + 0] & 0xFF) << 0)
-                                       | ((pdadcValues[4 * j + 1] & 0xFF) <<
-                                          8) | ((pdadcValues[4 * j + 2] &
-                                                 0xFF) << 16) |
-                                       ((pdadcValues[4 * j + 3] & 0xFF) <<
-                                        24);
-                               REG_WRITE(ah, regOffset, reg32);
-
-                               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-                                        "PDADC (%d,%4x): %4.4x %8.8x\n",
-                                        i, regChainOffset, regOffset,
-                                        reg32);
-                               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-                               "PDADC: Chain %d | PDADC %3d Value %3d | "
-                               "PDADC %3d Value %3d | PDADC %3d Value %3d | "
-                               "PDADC %3d Value %3d |\n",
-                                        i, 4 * j, pdadcValues[4 * j],
-                                        4 * j + 1, pdadcValues[4 * j + 1],
-                                        4 * j + 2, pdadcValues[4 * j + 2],
-                                        4 * j + 3,
-                                        pdadcValues[4 * j + 3]);
-
-                               regOffset += 4;
-                       }
-               }
-       }
-       *pTxPowerIndexOffset = 0;
-
-       return true;
-}
-
-void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u8 i;
-
-       if (ah->ah_isPciExpress != true)
-               return;
-
-       if (ah->ah_config.pcie_powersave_enable == 2)
-               return;
-
-       if (restore)
-               return;
-
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
-                       REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
-                                 INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
-               }
-               udelay(1000);
-       } else if (AR_SREV_9280(ah)
-                  && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-
-               if (ah->ah_config.pcie_clock_req)
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
-               else
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
-
-               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
-               udelay(1000);
-       } else {
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-               REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
-               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-       }
-
-       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
-
-       if (ah->ah_config.pcie_waen) {
-               REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
-       } else {
-               if (AR_SREV_9280(ah))
-                       REG_WRITE(ah, AR_WA, 0x0040073f);
-               else
-                       REG_WRITE(ah, AR_WA, 0x0000073f);
-       }
-}
-
-static void
-ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
-                                 struct ath9k_channel *chan,
-                                 struct cal_target_power_leg *powInfo,
-                                 u16 numChannels,
-                                 struct cal_target_power_leg *pNewPower,
-                                 u16 numRates,
-                                 bool isExtTarget)
-{
-       u16 clo, chi;
-       int i;
-       int matchIndex = -1, lowIndex = -1;
-       u16 freq;
-       struct chan_centers centers;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
-
-       if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
-               IS_CHAN_2GHZ(chan))) {
-               matchIndex = 0;
-       } else {
-               for (i = 0; (i < numChannels)
-                    && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-                       if (freq ==
-                           ath9k_hw_fbin2freq(powInfo[i].bChannel,
-                                              IS_CHAN_2GHZ(chan))) {
-                               matchIndex = i;
-                               break;
-                       } else if ((freq <
-                                   ath9k_hw_fbin2freq(powInfo[i].bChannel,
-                                                      IS_CHAN_2GHZ(chan)))
-                                  && (freq >
-                                      ath9k_hw_fbin2freq(powInfo[i - 1].
-                                                         bChannel,
-                                                         IS_CHAN_2GHZ
-                                                         (chan)))) {
-                               lowIndex = i - 1;
-                               break;
-                       }
-               }
-               if ((matchIndex == -1) && (lowIndex == -1))
-                       matchIndex = i - 1;
-       }
-
-       if (matchIndex != -1) {
-               *pNewPower = powInfo[matchIndex];
-       } else {
-               clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-                                        IS_CHAN_2GHZ(chan));
-               chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-                                        IS_CHAN_2GHZ(chan));
-
-               for (i = 0; i < numRates; i++) {
-                       pNewPower->tPow2x[i] =
-                               (u8) ath9k_hw_interpolate(freq, clo, chi,
-                                                               powInfo
-                                                               [lowIndex].
-                                                               tPow2x[i],
-                                                               powInfo
-                                                               [lowIndex +
-                                                                1].tPow2x[i]);
-               }
-       }
-}
-
-static void
-ath9k_hw_get_target_powers(struct ath_hal *ah,
-                          struct ath9k_channel *chan,
-                          struct cal_target_power_ht *powInfo,
-                          u16 numChannels,
-                          struct cal_target_power_ht *pNewPower,
-                          u16 numRates,
-                          bool isHt40Target)
-{
-       u16 clo, chi;
-       int i;
-       int matchIndex = -1, lowIndex = -1;
-       u16 freq;
-       struct chan_centers centers;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = isHt40Target ? centers.synth_center : centers.ctl_center;
-
-       if (freq <=
-               ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
-               matchIndex = 0;
-       } else {
-               for (i = 0; (i < numChannels)
-                    && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-                       if (freq ==
-                           ath9k_hw_fbin2freq(powInfo[i].bChannel,
-                                              IS_CHAN_2GHZ(chan))) {
-                               matchIndex = i;
-                               break;
-                       } else
-                               if ((freq <
-                                    ath9k_hw_fbin2freq(powInfo[i].bChannel,
-                                                       IS_CHAN_2GHZ(chan)))
-                                   && (freq >
-                                       ath9k_hw_fbin2freq(powInfo[i - 1].
-                                                          bChannel,
-                                                          IS_CHAN_2GHZ
-                                                          (chan)))) {
-                                       lowIndex = i - 1;
-                                       break;
-                               }
-               }
-               if ((matchIndex == -1) && (lowIndex == -1))
-                       matchIndex = i - 1;
-       }
-
-       if (matchIndex != -1) {
-               *pNewPower = powInfo[matchIndex];
-       } else {
-               clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
-                                        IS_CHAN_2GHZ(chan));
-               chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
-                                        IS_CHAN_2GHZ(chan));
-
-               for (i = 0; i < numRates; i++) {
-                       pNewPower->tPow2x[i] =
-                               (u8) ath9k_hw_interpolate(freq, clo, chi,
-                                                               powInfo
-                                                               [lowIndex].
-                                                               tPow2x[i],
-                                                               powInfo
-                                                               [lowIndex +
-                                                                1].tPow2x[i]);
-               }
-       }
-}
-
-static u16
-ath9k_hw_get_max_edge_power(u16 freq,
-                           struct cal_ctl_edges *pRdEdgesPower,
-                           bool is2GHz)
-{
-       u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-       int i;
-
-       for (i = 0; (i < AR5416_NUM_BAND_EDGES)
-            && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
-               if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
-                                              is2GHz)) {
-                       twiceMaxEdgePower = pRdEdgesPower[i].tPower;
-                       break;
-               } else if ((i > 0)
-                          && (freq <
-                              ath9k_hw_fbin2freq(pRdEdgesPower[i].
-                                                 bChannel, is2GHz))) {
-                       if (ath9k_hw_fbin2freq
-                           (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq
-                           && pRdEdgesPower[i - 1].flag) {
-                               twiceMaxEdgePower =
-                                       pRdEdgesPower[i - 1].tPower;
-                       }
-                       break;
-               }
-       }
-       return twiceMaxEdgePower;
-}
-
-static bool
-ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
-                                 struct ar5416_eeprom *pEepData,
-                                 struct ath9k_channel *chan,
-                                 int16_t *ratesArray,
-                                 u16 cfgCtl,
-                                 u8 AntennaReduction,
-                                 u8 twiceMaxRegulatoryPower,
-                                 u8 powerLimit)
-{
-       u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-       static const u16 tpScaleReductionTable[5] =
-               { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
-
-       int i;
-       int8_t twiceLargestAntenna;
-       struct cal_ctl_data *rep;
-       struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
-               0, { 0, 0, 0, 0}
-       };
-       struct cal_target_power_leg targetPowerOfdmExt = {
-               0, { 0, 0, 0, 0} }, targetPowerCckExt = {
-               0, { 0, 0, 0, 0 }
-       };
-       struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
-               0, {0, 0, 0, 0}
-       };
-       u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
-       u16 ctlModesFor11a[] =
-               { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
-       u16 ctlModesFor11g[] =
-               { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
-                 CTL_2GHT40
-               };
-       u16 numCtlModes, *pCtlMode, ctlMode, freq;
-       struct chan_centers centers;
-       int tx_chainmask;
-       u8 twiceMinEdgePower;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       tx_chainmask = ahp->ah_txchainmask;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-       twiceLargestAntenna = max(
-               pEepData->modalHeader
-                       [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
-               pEepData->modalHeader
-                       [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
-
-       twiceLargestAntenna = max((u8) twiceLargestAntenna,
-               pEepData->modalHeader
-                       [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
-
-       twiceLargestAntenna =
-               (int8_t) min(AntennaReduction - twiceLargestAntenna, 0);
-
-       maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
-
-       if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
-               maxRegAllowedPower -=
-                       (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
-       }
-
-       scaledPower = min(powerLimit, maxRegAllowedPower);
-
-       switch (ar5416_get_ntxchains(tx_chainmask)) {
-       case 1:
-               break;
-       case 2:
-               scaledPower -=
-                       pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
-                       pwrDecreaseFor2Chain;
-               break;
-       case 3:
-               scaledPower -=
-                       pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
-                       pwrDecreaseFor3Chain;
-               break;
-       }
-
-       scaledPower = max(0, (int32_t) scaledPower);
-
-       if (IS_CHAN_2GHZ(chan)) {
-               numCtlModes =
-                       ARRAY_SIZE(ctlModesFor11g) -
-                       SUB_NUM_CTL_MODES_AT_2G_40;
-               pCtlMode = ctlModesFor11g;
-
-               ath9k_hw_get_legacy_target_powers(ah, chan,
-                       pEepData->
-                       calTargetPowerCck,
-                       AR5416_NUM_2G_CCK_TARGET_POWERS,
-                       &targetPowerCck, 4,
-                       false);
-               ath9k_hw_get_legacy_target_powers(ah, chan,
-                       pEepData->
-                       calTargetPower2G,
-                       AR5416_NUM_2G_20_TARGET_POWERS,
-                       &targetPowerOfdm, 4,
-                       false);
-               ath9k_hw_get_target_powers(ah, chan,
-                       pEepData->calTargetPower2GHT20,
-                       AR5416_NUM_2G_20_TARGET_POWERS,
-                       &targetPowerHt20, 8, false);
-
-               if (IS_CHAN_HT40(chan)) {
-                       numCtlModes = ARRAY_SIZE(ctlModesFor11g);
-                       ath9k_hw_get_target_powers(ah, chan,
-                               pEepData->
-                               calTargetPower2GHT40,
-                               AR5416_NUM_2G_40_TARGET_POWERS,
-                               &targetPowerHt40, 8,
-                               true);
-                       ath9k_hw_get_legacy_target_powers(ah, chan,
-                               pEepData->
-                               calTargetPowerCck,
-                               AR5416_NUM_2G_CCK_TARGET_POWERS,
-                               &targetPowerCckExt,
-                               4, true);
-                       ath9k_hw_get_legacy_target_powers(ah, chan,
-                               pEepData->
-                               calTargetPower2G,
-                               AR5416_NUM_2G_20_TARGET_POWERS,
-                               &targetPowerOfdmExt,
-                               4, true);
-               }
-       } else {
-
-               numCtlModes =
-                       ARRAY_SIZE(ctlModesFor11a) -
-                       SUB_NUM_CTL_MODES_AT_5G_40;
-               pCtlMode = ctlModesFor11a;
-
-               ath9k_hw_get_legacy_target_powers(ah, chan,
-                       pEepData->
-                       calTargetPower5G,
-                       AR5416_NUM_5G_20_TARGET_POWERS,
-                       &targetPowerOfdm, 4,
-                       false);
-               ath9k_hw_get_target_powers(ah, chan,
-                       pEepData->calTargetPower5GHT20,
-                       AR5416_NUM_5G_20_TARGET_POWERS,
-                       &targetPowerHt20, 8, false);
-
-               if (IS_CHAN_HT40(chan)) {
-                       numCtlModes = ARRAY_SIZE(ctlModesFor11a);
-                       ath9k_hw_get_target_powers(ah, chan,
-                               pEepData->
-                               calTargetPower5GHT40,
-                               AR5416_NUM_5G_40_TARGET_POWERS,
-                               &targetPowerHt40, 8,
-                               true);
-                       ath9k_hw_get_legacy_target_powers(ah, chan,
-                               pEepData->
-                               calTargetPower5G,
-                               AR5416_NUM_5G_20_TARGET_POWERS,
-                               &targetPowerOfdmExt,
-                               4, true);
-               }
-       }
-
-       for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
-               bool isHt40CtlMode =
-                       (pCtlMode[ctlMode] == CTL_5GHT40)
-                       || (pCtlMode[ctlMode] == CTL_2GHT40);
-               if (isHt40CtlMode)
-                       freq = centers.synth_center;
-               else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
-                       freq = centers.ext_center;
-               else
-                       freq = centers.ctl_center;
-
-               if (ar5416_get_eep_ver(ahp) == 14
-                   && ar5416_get_eep_rev(ahp) <= 2)
-                       twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
-               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                       "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
-                       "EXT_ADDITIVE %d\n",
-                        ctlMode, numCtlModes, isHt40CtlMode,
-                        (pCtlMode[ctlMode] & EXT_ADDITIVE));
-
-               for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i];
-                    i++) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                               "  LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
-                               "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
-                               "chan %d\n",
-                               i, cfgCtl, pCtlMode[ctlMode],
-                               pEepData->ctlIndex[i], chan->channel);
-
-                       if ((((cfgCtl & ~CTL_MODE_M) |
-                             (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-                            pEepData->ctlIndex[i])
-                           ||
-                           (((cfgCtl & ~CTL_MODE_M) |
-                             (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-                            ((pEepData->
-                              ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
-                               rep = &(pEepData->ctlData[i]);
-
-                               twiceMinEdgePower =
-                                       ath9k_hw_get_max_edge_power(freq,
-                                               rep->
-                                               ctlEdges
-                                               [ar5416_get_ntxchains
-                                               (tx_chainmask)
-                                               - 1],
-                                               IS_CHAN_2GHZ
-                                               (chan));
-
-                               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                                       "    MATCH-EE_IDX %d: ch %d is2 %d "
-                                       "2xMinEdge %d chainmask %d chains %d\n",
-                                        i, freq, IS_CHAN_2GHZ(chan),
-                                        twiceMinEdgePower, tx_chainmask,
-                                        ar5416_get_ntxchains
-                                        (tx_chainmask));
-                               if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
-                                       twiceMaxEdgePower =
-                                               min(twiceMaxEdgePower,
-                                                   twiceMinEdgePower);
-                               } else {
-                                       twiceMaxEdgePower =
-                                               twiceMinEdgePower;
-                                       break;
-                               }
-                       }
-               }
-
-               minCtlPower = min(twiceMaxEdgePower, scaledPower);
-
-               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                               "    SEL-Min ctlMode %d pCtlMode %d "
-                               "2xMaxEdge %d sP %d minCtlPwr %d\n",
-                        ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
-                        scaledPower, minCtlPower);
-
-               switch (pCtlMode[ctlMode]) {
-               case CTL_11B:
-                       for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
-                            i++) {
-                               targetPowerCck.tPow2x[i] =
-                                       min(targetPowerCck.tPow2x[i],
-                                           minCtlPower);
-                       }
-                       break;
-               case CTL_11A:
-               case CTL_11G:
-                       for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
-                            i++) {
-                               targetPowerOfdm.tPow2x[i] =
-                                       min(targetPowerOfdm.tPow2x[i],
-                                           minCtlPower);
-                       }
-                       break;
-               case CTL_5GHT20:
-               case CTL_2GHT20:
-                       for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
-                            i++) {
-                               targetPowerHt20.tPow2x[i] =
-                                       min(targetPowerHt20.tPow2x[i],
-                                           minCtlPower);
-                       }
-                       break;
-               case CTL_11B_EXT:
-                       targetPowerCckExt.tPow2x[0] =
-                               min(targetPowerCckExt.tPow2x[0], minCtlPower);
-                       break;
-               case CTL_11A_EXT:
-               case CTL_11G_EXT:
-                       targetPowerOfdmExt.tPow2x[0] =
-                               min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
-                       break;
-               case CTL_5GHT40:
-               case CTL_2GHT40:
-                       for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
-                            i++) {
-                               targetPowerHt40.tPow2x[i] =
-                                       min(targetPowerHt40.tPow2x[i],
-                                           minCtlPower);
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
-               ratesArray[rate18mb] = ratesArray[rate24mb] =
-               targetPowerOfdm.tPow2x[0];
-       ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
-       ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
-       ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
-       ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
-
-       for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
-               ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
-
-       if (IS_CHAN_2GHZ(chan)) {
-               ratesArray[rate1l] = targetPowerCck.tPow2x[0];
-               ratesArray[rate2s] = ratesArray[rate2l] =
-                       targetPowerCck.tPow2x[1];
-               ratesArray[rate5_5s] = ratesArray[rate5_5l] =
-                       targetPowerCck.tPow2x[2];
-               ;
-               ratesArray[rate11s] = ratesArray[rate11l] =
-                       targetPowerCck.tPow2x[3];
-               ;
-       }
-       if (IS_CHAN_HT40(chan)) {
-               for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
-                       ratesArray[rateHt40_0 + i] =
-                               targetPowerHt40.tPow2x[i];
-               }
-               ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
-               ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
-               ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
-               if (IS_CHAN_2GHZ(chan)) {
-                       ratesArray[rateExtCck] =
-                               targetPowerCckExt.tPow2x[0];
-               }
-       }
-       return true;
-}
-
-static int
-ath9k_hw_set_txpower(struct ath_hal *ah,
-                    struct ar5416_eeprom *pEepData,
-                    struct ath9k_channel *chan,
-                    u16 cfgCtl,
-                    u8 twiceAntennaReduction,
-                    u8 twiceMaxRegulatoryPower,
-                    u8 powerLimit)
-{
-       struct modal_eep_header *pModal =
-               &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
-       int16_t ratesArray[Ar5416RateSize];
-       int16_t txPowerIndexOffset = 0;
-       u8 ht40PowerIncForPdadc = 2;
-       int i;
-
-       memset(ratesArray, 0, sizeof(ratesArray));
-
-       if ((pEepData->baseEepHeader.
-            version & AR5416_EEP_VER_MINOR_MASK) >=
-           AR5416_EEP_MINOR_VER_2) {
-               ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
-       }
-
-       if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan,
-                                              &ratesArray[0], cfgCtl,
-                                              twiceAntennaReduction,
-                                              twiceMaxRegulatoryPower,
-                                              powerLimit)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                       "ath9k_hw_set_txpower: unable to set "
-                       "tx power per rate table\n");
-               return -EIO;
-       }
-
-       if (!ath9k_hw_set_power_cal_table
-           (ah, pEepData, chan, &txPowerIndexOffset)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "ath9k_hw_set_txpower: unable to set power table\n");
-               return -EIO;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
-               ratesArray[i] =
-                       (int16_t) (txPowerIndexOffset + ratesArray[i]);
-               if (ratesArray[i] > AR5416_MAX_RATE_POWER)
-                       ratesArray[i] = AR5416_MAX_RATE_POWER;
-       }
-
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               for (i = 0; i < Ar5416RateSize; i++)
-                       ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
-       }
-
-       REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
-                 ATH9K_POW_SM(ratesArray[rate18mb], 24)
-                 | ATH9K_POW_SM(ratesArray[rate12mb], 16)
-                 | ATH9K_POW_SM(ratesArray[rate9mb], 8)
-                 | ATH9K_POW_SM(ratesArray[rate6mb], 0)
-               );
-       REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
-                 ATH9K_POW_SM(ratesArray[rate54mb], 24)
-                 | ATH9K_POW_SM(ratesArray[rate48mb], 16)
-                 | ATH9K_POW_SM(ratesArray[rate36mb], 8)
-                 | ATH9K_POW_SM(ratesArray[rate24mb], 0)
-               );
-
-       if (IS_CHAN_2GHZ(chan)) {
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
-                         ATH9K_POW_SM(ratesArray[rate2s], 24)
-                         | ATH9K_POW_SM(ratesArray[rate2l], 16)
-                         | ATH9K_POW_SM(ratesArray[rateXr], 8)
-                         | ATH9K_POW_SM(ratesArray[rate1l], 0)
-                       );
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
-                         ATH9K_POW_SM(ratesArray[rate11s], 24)
-                         | ATH9K_POW_SM(ratesArray[rate11l], 16)
-                         | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
-                         | ATH9K_POW_SM(ratesArray[rate5_5l], 0)
-                       );
-       }
-
-       REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
-                 ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)
-               );
-       REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
-                 ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
-                 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)
-               );
-
-       if (IS_CHAN_HT40(chan)) {
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
-                         ATH9K_POW_SM(ratesArray[rateHt40_3] +
-                                      ht40PowerIncForPdadc, 24)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_2] +
-                                        ht40PowerIncForPdadc, 16)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_1] +
-                                        ht40PowerIncForPdadc, 8)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_0] +
-                                        ht40PowerIncForPdadc, 0)
-                       );
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
-                         ATH9K_POW_SM(ratesArray[rateHt40_7] +
-                                      ht40PowerIncForPdadc, 24)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_6] +
-                                        ht40PowerIncForPdadc, 16)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_5] +
-                                        ht40PowerIncForPdadc, 8)
-                         | ATH9K_POW_SM(ratesArray[rateHt40_4] +
-                                        ht40PowerIncForPdadc, 0)
-                       );
-
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
-                         ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
-                         | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
-                         | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
-                         | ATH9K_POW_SM(ratesArray[rateDupCck], 0)
-                       );
-       }
-
-       REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
-                 ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
-                 | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)
-               );
-
-       i = rate6mb;
-       if (IS_CHAN_HT40(chan))
-               i = rateHt40_0;
-       else if (IS_CHAN_HT20(chan))
-               i = rateHt20_0;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               ah->ah_maxPowerLevel =
-                       ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
-       else
-               ah->ah_maxPowerLevel = ratesArray[i];
-
-       return 0;
-}
-
-static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
-                                                u32 coef_scaled,
-                                                u32 *coef_mantissa,
-                                                u32 *coef_exponent)
-{
-       u32 coef_exp, coef_man;
-
-       for (coef_exp = 31; coef_exp > 0; coef_exp--)
-               if ((coef_scaled >> coef_exp) & 0x1)
-                       break;
-
-       coef_exp = 14 - (coef_exp - COEF_SCALE_S);
-
-       coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
-
-       *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
-       *coef_exponent = coef_exp - 16;
-}
-
-static void
-ath9k_hw_set_delta_slope(struct ath_hal *ah,
-                        struct ath9k_channel *chan)
-{
-       u32 coef_scaled, ds_coef_exp, ds_coef_man;
-       u32 clockMhzScaled = 0x64000000;
-       struct chan_centers centers;
-
-       if (IS_CHAN_HALF_RATE(chan))
-               clockMhzScaled = clockMhzScaled >> 1;
-       else if (IS_CHAN_QUARTER_RATE(chan))
-               clockMhzScaled = clockMhzScaled >> 2;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       coef_scaled = clockMhzScaled / centers.synth_center;
-
-       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
-                                     &ds_coef_exp);
-
-       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
-                     AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
-       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
-                     AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
-
-       coef_scaled = (9 * coef_scaled) / 10;
-
-       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
-                                     &ds_coef_exp);
-
-       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
-                     AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
-       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
-                     AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
-}
-
-static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah,
-                                       struct ath9k_channel *chan)
-{
-       int bb_spur = AR_NO_SPUR;
-       int freq;
-       int bin, cur_bin;
-       int bb_spur_off, spur_subchannel_sd;
-       int spur_freq_sd;
-       int spur_delta_phase;
-       int denominator;
-       int upper, lower, cur_vit_mask;
-       int tmp, newVal;
-       int i;
-       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
-                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
-       };
-       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
-                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
-       };
-       int inc[4] = { 0, 100, 0, 0 };
-       struct chan_centers centers;
-
-       int8_t mask_m[123];
-       int8_t mask_p[123];
-       int8_t mask_amt;
-       int tmp_mask;
-       int cur_bb_spur;
-       bool is2GHz = IS_CHAN_2GHZ(chan);
-
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = centers.synth_center;
-
-       ah->ah_config.spurmode = SPUR_ENABLE_EEPROM;
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
-
-               if (is2GHz)
-                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
-               else
-                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
-
-               if (AR_NO_SPUR == cur_bb_spur)
-                       break;
-               cur_bb_spur = cur_bb_spur - freq;
-
-               if (IS_CHAN_HT40(chan)) {
-                       if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
-                           (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
-                               bb_spur = cur_bb_spur;
-                               break;
-                       }
-               } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
-                          (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
-                       bb_spur = cur_bb_spur;
-                       break;
-               }
-       }
-
-       if (AR_NO_SPUR == bb_spur) {
-               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
-                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
-               return;
-       } else {
-               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
-                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
-       }
-
-       bin = bb_spur * 320;
-
-       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
-
-       newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
-                       AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
-                       AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
-                       AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
-
-       newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
-                 AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
-                 AR_PHY_SPUR_REG_MASK_RATE_SELECT |
-                 AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
-                 SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
-       REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
-
-       if (IS_CHAN_HT40(chan)) {
-               if (bb_spur < 0) {
-                       spur_subchannel_sd = 1;
-                       bb_spur_off = bb_spur + 10;
-               } else {
-                       spur_subchannel_sd = 0;
-                       bb_spur_off = bb_spur - 10;
-               }
-       } else {
-               spur_subchannel_sd = 0;
-               bb_spur_off = bb_spur;
-       }
-
-       if (IS_CHAN_HT40(chan))
-               spur_delta_phase =
-                       ((bb_spur * 262144) /
-                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-       else
-               spur_delta_phase =
-                       ((bb_spur * 524288) /
-                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
-       denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
-       spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
-
-       newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
-                 SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
-                 SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
-       REG_WRITE(ah, AR_PHY_TIMING11, newVal);
-
-       newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
-       REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
-
-       cur_bin = -6000;
-       upper = bin + 100;
-       lower = bin - 100;
-
-       for (i = 0; i < 4; i++) {
-               int pilot_mask = 0;
-               int chan_mask = 0;
-               int bp = 0;
-               for (bp = 0; bp < 30; bp++) {
-                       if ((cur_bin > lower) && (cur_bin < upper)) {
-                               pilot_mask = pilot_mask | 0x1 << bp;
-                               chan_mask = chan_mask | 0x1 << bp;
-                       }
-                       cur_bin += 100;
-               }
-               cur_bin += inc[i];
-               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
-               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
-       }
-
-       cur_vit_mask = 6100;
-       upper = bin + 120;
-       lower = bin - 120;
-
-       for (i = 0; i < 123; i++) {
-               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
-                       /* workaround for gcc bug #37014 */
-                       volatile int tmp = abs(cur_vit_mask - bin);
-
-                       if (tmp < 75)
-                               mask_amt = 1;
-                       else
-                               mask_amt = 0;
-                       if (cur_vit_mask < 0)
-                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
-                       else
-                               mask_p[cur_vit_mask / 100] = mask_amt;
-               }
-               cur_vit_mask -= 100;
-       }
-
-       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
-               | (mask_m[48] << 26) | (mask_m[49] << 24)
-               | (mask_m[50] << 22) | (mask_m[51] << 20)
-               | (mask_m[52] << 18) | (mask_m[53] << 16)
-               | (mask_m[54] << 14) | (mask_m[55] << 12)
-               | (mask_m[56] << 10) | (mask_m[57] << 8)
-               | (mask_m[58] << 6) | (mask_m[59] << 4)
-               | (mask_m[60] << 2) | (mask_m[61] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
-
-       tmp_mask = (mask_m[31] << 28)
-               | (mask_m[32] << 26) | (mask_m[33] << 24)
-               | (mask_m[34] << 22) | (mask_m[35] << 20)
-               | (mask_m[36] << 18) | (mask_m[37] << 16)
-               | (mask_m[48] << 14) | (mask_m[39] << 12)
-               | (mask_m[40] << 10) | (mask_m[41] << 8)
-               | (mask_m[42] << 6) | (mask_m[43] << 4)
-               | (mask_m[44] << 2) | (mask_m[45] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
-
-       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
-               | (mask_m[18] << 26) | (mask_m[18] << 24)
-               | (mask_m[20] << 22) | (mask_m[20] << 20)
-               | (mask_m[22] << 18) | (mask_m[22] << 16)
-               | (mask_m[24] << 14) | (mask_m[24] << 12)
-               | (mask_m[25] << 10) | (mask_m[26] << 8)
-               | (mask_m[27] << 6) | (mask_m[28] << 4)
-               | (mask_m[29] << 2) | (mask_m[30] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
-
-       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
-               | (mask_m[2] << 26) | (mask_m[3] << 24)
-               | (mask_m[4] << 22) | (mask_m[5] << 20)
-               | (mask_m[6] << 18) | (mask_m[7] << 16)
-               | (mask_m[8] << 14) | (mask_m[9] << 12)
-               | (mask_m[10] << 10) | (mask_m[11] << 8)
-               | (mask_m[12] << 6) | (mask_m[13] << 4)
-               | (mask_m[14] << 2) | (mask_m[15] << 0);
-       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
-
-       tmp_mask = (mask_p[15] << 28)
-               | (mask_p[14] << 26) | (mask_p[13] << 24)
-               | (mask_p[12] << 22) | (mask_p[11] << 20)
-               | (mask_p[10] << 18) | (mask_p[9] << 16)
-               | (mask_p[8] << 14) | (mask_p[7] << 12)
-               | (mask_p[6] << 10) | (mask_p[5] << 8)
-               | (mask_p[4] << 6) | (mask_p[3] << 4)
-               | (mask_p[2] << 2) | (mask_p[1] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
-
-       tmp_mask = (mask_p[30] << 28)
-               | (mask_p[29] << 26) | (mask_p[28] << 24)
-               | (mask_p[27] << 22) | (mask_p[26] << 20)
-               | (mask_p[25] << 18) | (mask_p[24] << 16)
-               | (mask_p[23] << 14) | (mask_p[22] << 12)
-               | (mask_p[21] << 10) | (mask_p[20] << 8)
-               | (mask_p[19] << 6) | (mask_p[18] << 4)
-               | (mask_p[17] << 2) | (mask_p[16] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
-
-       tmp_mask = (mask_p[45] << 28)
-               | (mask_p[44] << 26) | (mask_p[43] << 24)
-               | (mask_p[42] << 22) | (mask_p[41] << 20)
-               | (mask_p[40] << 18) | (mask_p[39] << 16)
-               | (mask_p[38] << 14) | (mask_p[37] << 12)
-               | (mask_p[36] << 10) | (mask_p[35] << 8)
-               | (mask_p[34] << 6) | (mask_p[33] << 4)
-               | (mask_p[32] << 2) | (mask_p[31] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
-
-       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
-               | (mask_p[59] << 26) | (mask_p[58] << 24)
-               | (mask_p[57] << 22) | (mask_p[56] << 20)
-               | (mask_p[55] << 18) | (mask_p[54] << 16)
-               | (mask_p[53] << 14) | (mask_p[52] << 12)
-               | (mask_p[51] << 10) | (mask_p[50] << 8)
-               | (mask_p[49] << 6) | (mask_p[48] << 4)
-               | (mask_p[47] << 2) | (mask_p[46] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
-}
-
-static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
-                                  struct ath9k_channel *chan)
-{
-       int bb_spur = AR_NO_SPUR;
-       int bin, cur_bin;
-       int spur_freq_sd;
-       int spur_delta_phase;
-       int denominator;
-       int upper, lower, cur_vit_mask;
-       int tmp, new;
-       int i;
-       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
-                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
-       };
-       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
-                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
-       };
-       int inc[4] = { 0, 100, 0, 0 };
-
-       int8_t mask_m[123];
-       int8_t mask_p[123];
-       int8_t mask_amt;
-       int tmp_mask;
-       int cur_bb_spur;
-       bool is2GHz = IS_CHAN_2GHZ(chan);
-
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
-               if (AR_NO_SPUR == cur_bb_spur)
-                       break;
-               cur_bb_spur = cur_bb_spur - (chan->channel * 10);
-               if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
-                       bb_spur = cur_bb_spur;
-                       break;
-               }
-       }
-
-       if (AR_NO_SPUR == bb_spur)
-               return;
-
-       bin = bb_spur * 32;
-
-       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
-       new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
-                    AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
-                    AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
-                    AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-
-       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
-
-       new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
-              AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
-              AR_PHY_SPUR_REG_MASK_RATE_SELECT |
-              AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
-              SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
-       REG_WRITE(ah, AR_PHY_SPUR_REG, new);
-
-       spur_delta_phase = ((bb_spur * 524288) / 100) &
-               AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
-       denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
-       spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
-
-       new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
-              SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
-              SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
-       REG_WRITE(ah, AR_PHY_TIMING11, new);
-
-       cur_bin = -6000;
-       upper = bin + 100;
-       lower = bin - 100;
-
-       for (i = 0; i < 4; i++) {
-               int pilot_mask = 0;
-               int chan_mask = 0;
-               int bp = 0;
-               for (bp = 0; bp < 30; bp++) {
-                       if ((cur_bin > lower) && (cur_bin < upper)) {
-                               pilot_mask = pilot_mask | 0x1 << bp;
-                               chan_mask = chan_mask | 0x1 << bp;
-                       }
-                       cur_bin += 100;
-               }
-               cur_bin += inc[i];
-               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
-               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
-       }
-
-       cur_vit_mask = 6100;
-       upper = bin + 120;
-       lower = bin - 120;
-
-       for (i = 0; i < 123; i++) {
-               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
-                       /* workaround for gcc bug #37014 */
-                       volatile int tmp = abs(cur_vit_mask - bin);
-
-                       if (tmp < 75)
-                               mask_amt = 1;
-                       else
-                               mask_amt = 0;
-                       if (cur_vit_mask < 0)
-                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
-                       else
-                               mask_p[cur_vit_mask / 100] = mask_amt;
-               }
-               cur_vit_mask -= 100;
-       }
 
-       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
-               | (mask_m[48] << 26) | (mask_m[49] << 24)
-               | (mask_m[50] << 22) | (mask_m[51] << 20)
-               | (mask_m[52] << 18) | (mask_m[53] << 16)
-               | (mask_m[54] << 14) | (mask_m[55] << 12)
-               | (mask_m[56] << 10) | (mask_m[57] << 8)
-               | (mask_m[58] << 6) | (mask_m[59] << 4)
-               | (mask_m[60] << 2) | (mask_m[61] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+                               if (AR_SREV_9280_20(ah)) {
+                                       if (((chan->channel % 20) == 0)
+                                           || ((chan->channel % 10) == 0))
+                                               pll = 0x2850;
+                                       else
+                                               pll = 0x142c;
+                               }
+                       } else {
+                               pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
+                       }
 
-       tmp_mask = (mask_m[31] << 28)
-               | (mask_m[32] << 26) | (mask_m[33] << 24)
-               | (mask_m[34] << 22) | (mask_m[35] << 20)
-               | (mask_m[36] << 18) | (mask_m[37] << 16)
-               | (mask_m[48] << 14) | (mask_m[39] << 12)
-               | (mask_m[40] << 10) | (mask_m[41] << 8)
-               | (mask_m[42] << 6) | (mask_m[43] << 4)
-               | (mask_m[44] << 2) | (mask_m[45] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+               } else if (AR_SREV_9160_10_OR_LATER(ah)) {
 
-       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
-               | (mask_m[18] << 26) | (mask_m[18] << 24)
-               | (mask_m[20] << 22) | (mask_m[20] << 20)
-               | (mask_m[22] << 18) | (mask_m[22] << 16)
-               | (mask_m[24] << 14) | (mask_m[24] << 12)
-               | (mask_m[25] << 10) | (mask_m[26] << 8)
-               | (mask_m[27] << 6) | (mask_m[28] << 4)
-               | (mask_m[29] << 2) | (mask_m[30] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
 
-       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
-               | (mask_m[2] << 26) | (mask_m[3] << 24)
-               | (mask_m[4] << 22) | (mask_m[5] << 20)
-               | (mask_m[6] << 18) | (mask_m[7] << 16)
-               | (mask_m[8] << 14) | (mask_m[9] << 12)
-               | (mask_m[10] << 10) | (mask_m[11] << 8)
-               | (mask_m[12] << 6) | (mask_m[13] << 4)
-               | (mask_m[14] << 2) | (mask_m[15] << 0);
-       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+                       if (chan && IS_CHAN_HALF_RATE(chan))
+                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
 
-       tmp_mask = (mask_p[15] << 28)
-               | (mask_p[14] << 26) | (mask_p[13] << 24)
-               | (mask_p[12] << 22) | (mask_p[11] << 20)
-               | (mask_p[10] << 18) | (mask_p[9] << 16)
-               | (mask_p[8] << 14) | (mask_p[7] << 12)
-               | (mask_p[6] << 10) | (mask_p[5] << 8)
-               | (mask_p[4] << 6) | (mask_p[3] << 4)
-               | (mask_p[2] << 2) | (mask_p[1] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+                       if (chan && IS_CHAN_5GHZ(chan))
+                               pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
+                       else
+                               pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+               } else {
+                       pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
 
-       tmp_mask = (mask_p[30] << 28)
-               | (mask_p[29] << 26) | (mask_p[28] << 24)
-               | (mask_p[27] << 22) | (mask_p[26] << 20)
-               | (mask_p[25] << 18) | (mask_p[24] << 16)
-               | (mask_p[23] << 14) | (mask_p[22] << 12)
-               | (mask_p[21] << 10) | (mask_p[20] << 8)
-               | (mask_p[19] << 6) | (mask_p[18] << 4)
-               | (mask_p[17] << 2) | (mask_p[16] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+                       if (chan && IS_CHAN_HALF_RATE(chan))
+                               pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+                               pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
 
-       tmp_mask = (mask_p[45] << 28)
-               | (mask_p[44] << 26) | (mask_p[43] << 24)
-               | (mask_p[42] << 22) | (mask_p[41] << 20)
-               | (mask_p[40] << 18) | (mask_p[39] << 16)
-               | (mask_p[38] << 14) | (mask_p[37] << 12)
-               | (mask_p[36] << 10) | (mask_p[35] << 8)
-               | (mask_p[34] << 6) | (mask_p[33] << 4)
-               | (mask_p[32] << 2) | (mask_p[31] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+                       if (chan && IS_CHAN_5GHZ(chan))
+                               pll |= SM(0xa, AR_RTC_PLL_DIV);
+                       else
+                               pll |= SM(0xb, AR_RTC_PLL_DIV);
+               }
+       }
+       REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
 
-       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
-               | (mask_p[59] << 26) | (mask_p[58] << 24)
-               | (mask_p[57] << 22) | (mask_p[56] << 20)
-               | (mask_p[55] << 18) | (mask_p[54] << 16)
-               | (mask_p[53] << 14) | (mask_p[52] << 12)
-               | (mask_p[51] << 10) | (mask_p[50] << 8)
-               | (mask_p[49] << 6) | (mask_p[48] << 4)
-               | (mask_p[47] << 2) | (mask_p[46] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+       udelay(RTC_PLL_SETTLE_DELAY);
+
+       REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
 }
 
 static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
@@ -5159,102 +987,34 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
                          REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
 }
 
-static void ath9k_hw_set_addac(struct ath_hal *ah,
-                              struct ath9k_channel *chan)
+static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, enum ath9k_opmode opmode)
 {
-       struct modal_eep_header *pModal;
        struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ar5416_eeprom *eep = &ahp->ah_eeprom;
-       u8 biaslevel;
-
-       if (ah->ah_macVersion != AR_SREV_VERSION_9160)
-               return;
-
-       if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
-               return;
-
-       pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
-
-       if (pModal->xpaBiasLvl != 0xff) {
-               biaslevel = pModal->xpaBiasLvl;
-       } else {
-
-               u16 resetFreqBin, freqBin, freqCount = 0;
-               struct chan_centers centers;
-
-               ath9k_hw_get_channel_centers(ah, chan, &centers);
-
-               resetFreqBin =
-                       FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
-               freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
-               biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
-
-               freqCount++;
-
-               while (freqCount < 3) {
-                       if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
-                               break;
-
-                       freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
-                       if (resetFreqBin >= freqBin) {
-                               biaslevel =
-                                       (u8) (pModal->
-                                                   xpaBiasLvlFreq[freqCount]
-                                                   >> 14);
-                       } else {
-                               break;
-                       }
-                       freqCount++;
-               }
-       }
 
-       if (IS_CHAN_2GHZ(chan)) {
-               INI_RA(&ahp->ah_iniAddac, 7, 1) =
-                       (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel
-                       << 3;
-       } else {
-               INI_RA(&ahp->ah_iniAddac, 6, 1) =
-                       (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel
-                       << 6;
-       }
-}
+       ahp->ah_maskReg = AR_IMR_TXERR |
+               AR_IMR_TXURN |
+               AR_IMR_RXERR |
+               AR_IMR_RXORN |
+               AR_IMR_BCNMISC;
 
-static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
-{
-       if (ah->ah_curchan != NULL)
-               return clks /
-               CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
+       if (ahp->ah_intrMitigation)
+               ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
        else
-               return clks / CLOCK_RATE[ATH9K_MODE_11B];
-}
-
-static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
-{
-       struct ath9k_channel *chan = ah->ah_curchan;
+               ahp->ah_maskReg |= AR_IMR_RXOK;
 
-       if (chan && IS_CHAN_HT40(chan))
-               return ath9k_hw_mac_usec(ah, clks) / 2;
-       else
-               return ath9k_hw_mac_usec(ah, clks);
-}
+       ahp->ah_maskReg |= AR_IMR_TXOK;
 
-static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
-{
-       if (ah->ah_curchan != NULL)
-               return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
-                       ah->ah_curchan)];
-       else
-               return usecs * CLOCK_RATE[ATH9K_MODE_11B];
-}
+       if (opmode == ATH9K_M_HOSTAP)
+               ahp->ah_maskReg |= AR_IMR_MIB;
 
-static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
-{
-       struct ath9k_channel *chan = ah->ah_curchan;
+       REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+       REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
 
-       if (chan && IS_CHAN_HT40(chan))
-               return ath9k_hw_mac_clks(ah, usecs) * 2;
-       else
-               return ath9k_hw_mac_clks(ah, usecs);
+       if (!AR_SREV_9100(ah)) {
+               REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
+               REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+               REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+       }
 }
 
 static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
@@ -5290,8 +1050,8 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
                return true;
        }
 }
-static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah,
-                                         u32 tu)
+
+static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
 
@@ -5307,45 +1067,117 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah,
        }
 }
 
-bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
+static void ath9k_hw_init_user_settings(struct ath_hal *ah)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
 
-       if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n",
-                        __func__, us);
-               ahp->ah_slottime = (u32) -1;
-               return false;
-       } else {
-               REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
-               ahp->ah_slottime = us;
-               return true;
+       DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n",
+                __func__, ahp->ah_miscMode);
+
+       if (ahp->ah_miscMode != 0)
+               REG_WRITE(ah, AR_PCU_MISC,
+                         REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
+       if (ahp->ah_slottime != (u32) -1)
+               ath9k_hw_setslottime(ah, ahp->ah_slottime);
+       if (ahp->ah_acktimeout != (u32) -1)
+               ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
+       if (ahp->ah_ctstimeout != (u32) -1)
+               ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
+       if (ahp->ah_globaltxtimeout != (u32) -1)
+               ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
+}
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid)
+{
+       return vendorid == ATHEROS_VENDOR_ID ?
+               ath9k_hw_devname(devid) : NULL;
+}
+
+void ath9k_hw_detach(struct ath_hal *ah)
+{
+       if (!AR_SREV_9100(ah))
+               ath9k_hw_ani_detach(ah);
+
+       ath9k_hw_rfdetach(ah);
+       ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+       kfree(ah);
+}
+
+struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
+                               void __iomem *mem, int *error)
+{
+       struct ath_hal *ah = NULL;
+
+       switch (devid) {
+       case AR5416_DEVID_PCI:
+       case AR5416_DEVID_PCIE:
+       case AR9160_DEVID_PCI:
+       case AR9280_DEVID_PCI:
+       case AR9280_DEVID_PCIE:
+               ah = ath9k_hw_do_attach(devid, sc, mem, error);
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+                        "devid=0x%x not supported.\n", devid);
+               ah = NULL;
+               *error = -ENXIO;
+               break;
        }
+
+       return ah;
+}
+
+/*******/
+/* INI */
+/*******/
+
+static void ath9k_hw_override_ini(struct ath_hal *ah,
+                                 struct ath9k_channel *chan)
+{
+       if (!AR_SREV_5416_V20_OR_LATER(ah) ||
+           AR_SREV_9280_10_OR_LATER(ah))
+               return;
+
+       REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
 }
 
-static void ath9k_hw_init_user_settings(struct ath_hal *ah)
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+                             struct ar5416_eeprom *pEepData,
+                             u32 reg, u32 value)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct base_eep_header *pBase = &(pEepData->baseEepHeader);
 
-       DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n",
-                __func__, ahp->ah_miscMode);
-       if (ahp->ah_miscMode != 0)
-               REG_WRITE(ah, AR_PCU_MISC,
-                         REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
-       if (ahp->ah_slottime != (u32) -1)
-               ath9k_hw_setslottime(ah, ahp->ah_slottime);
-       if (ahp->ah_acktimeout != (u32) -1)
-               ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
-       if (ahp->ah_ctstimeout != (u32) -1)
-               ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
-       if (ahp->ah_globaltxtimeout != (u32) -1)
-               ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
+       switch (ah->ah_devid) {
+       case AR9280_DEVID_PCI:
+               if (reg == 0x7894) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+                               "ini VAL: %x  EEPROM: %x\n", value,
+                               (pBase->version & 0xff));
+
+                       if ((pBase->version & 0xff) > 0x0a) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+                                       "PWDCLKIND: %d\n",
+                                       pBase->pwdclkind);
+                               value &= ~AR_AN_TOP2_PWDCLKIND;
+                               value |= AR_AN_TOP2_PWDCLKIND &
+                                       (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
+                       } else {
+                               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+                                       "PWDCLKIND Earlier Rev\n");
+                       }
+
+                       DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+                               "final ini VAL: %x\n", value);
+               }
+               break;
+       }
+
+       return value;
 }
 
-static int
-ath9k_hw_process_ini(struct ath_hal *ah,
-                    struct ath9k_channel *chan,
-                    enum ath9k_ht_macmode macmode)
+static int ath9k_hw_process_ini(struct ath_hal *ah,
+                               struct ath9k_channel *chan,
+                               enum ath9k_ht_macmode macmode)
 {
        int i, regWrites = 0;
        struct ath_hal_5416 *ahp = AH5416(ah);
@@ -5396,14 +1228,14 @@ ath9k_hw_process_ini(struct ath_hal *ah,
                memcpy(ahp->ah_addac5416_21,
                       ahp->ah_iniAddac.ia_array, addacSize);
 
-               (ahp->ah_addac5416_21)[31 *
-                                      ahp->ah_iniAddac.ia_columns + 1] = 0;
+               (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0;
 
                temp.ia_array = ahp->ah_addac5416_21;
                temp.ia_columns = ahp->ah_iniAddac.ia_columns;
                temp.ia_rows = ahp->ah_iniAddac.ia_rows;
                REG_WRITE_ARRAY(&temp, 1, regWrites);
        }
+
        REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
 
        for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
@@ -5412,8 +1244,7 @@ ath9k_hw_process_ini(struct ath_hal *ah,
 
 #ifdef CONFIG_SLOW_ANT_DIV
                if (ah->ah_devid == AR9280_DEVID_PCI)
-                       val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg,
-                                                val);
+                       val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, val);
 #endif
 
                REG_WRITE(ah, reg, val);
@@ -5451,7 +1282,7 @@ ath9k_hw_process_ini(struct ath_hal *ah,
        ath9k_hw_set_regs(ah, chan, macmode);
        ath9k_hw_init_chain_masks(ah);
 
-       status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
+       status = ath9k_hw_set_txpower(ah, chan,
                                      ath9k_regd_get_ctl(ah, chan),
                                      ath9k_regd_get_antenna_allowed(ah,
                                                                     chan),
@@ -5460,178 +1291,323 @@ ath9k_hw_process_ini(struct ath_hal *ah,
                                          (u32) ah->ah_powerLimit));
        if (status != 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
-                        "%s: error init'ing transmit power\n", __func__);
+                       "%s: error init'ing transmit power\n", __func__);
                return -EIO;
        }
 
        if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-                        "%s: ar5416SetRfRegs failed\n", __func__);
+                       "%s: ar5416SetRfRegs failed\n", __func__);
                return -EIO;
        }
 
        return 0;
 }
 
-static void ath9k_hw_setup_calibration(struct ath_hal *ah,
-                                             struct hal_cal_list *currCal)
+/****************************************/
+/* Reset and Channel Switching Routines */
+/****************************************/
+
+static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
 {
-       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
-                     AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
-                     currCal->calData->calCountMax);
-
-       switch (currCal->calData->calType) {
-       case IQ_MISMATCH_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: starting IQ Mismatch Calibration\n",
-                        __func__);
+       u32 rfMode = 0;
+
+       if (chan == NULL)
+               return;
+
+       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+       if (!AR_SREV_9280_10_OR_LATER(ah))
+               rfMode |= (IS_CHAN_5GHZ(chan)) ?
+                       AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
+
+       if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
+               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+       REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
+{
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static inline void ath9k_hw_set_dma(struct ath_hal *ah)
+{
+       u32 regval;
+
+       regval = REG_READ(ah, AR_AHB_MODE);
+       REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+
+       regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
+       REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+
+       REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
+
+       regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
+       REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+
+       REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+
+       if (AR_SREV_9285(ah)) {
+               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+                         AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
+       } else {
+               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+                         AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+       }
+}
+
+static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
+{
+       u32 val;
+
+       val = REG_READ(ah, AR_STA_ID1);
+       val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
+       switch (opmode) {
+       case ATH9K_M_HOSTAP:
+               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
+                         | AR_STA_ID1_KSRCH_MODE);
+               REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
                break;
-       case ADC_GAIN_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: starting ADC Gain Calibration\n", __func__);
+       case ATH9K_M_IBSS:
+               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
+                         | AR_STA_ID1_KSRCH_MODE);
+               REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
                break;
-       case ADC_DC_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: starting ADC DC Calibration\n", __func__);
+       case ATH9K_M_STA:
+       case ATH9K_M_MONITOR:
+               REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
                break;
-       case ADC_DC_INIT_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: starting Init ADC DC Calibration\n",
+       }
+}
+
+static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
+                                                u32 coef_scaled,
+                                                u32 *coef_mantissa,
+                                                u32 *coef_exponent)
+{
+       u32 coef_exp, coef_man;
+
+       for (coef_exp = 31; coef_exp > 0; coef_exp--)
+               if ((coef_scaled >> coef_exp) & 0x1)
+                       break;
+
+       coef_exp = 14 - (coef_exp - COEF_SCALE_S);
+
+       coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
+
+       *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
+       *coef_exponent = coef_exp - 16;
+}
+
+static void ath9k_hw_set_delta_slope(struct ath_hal *ah,
+                                    struct ath9k_channel *chan)
+{
+       u32 coef_scaled, ds_coef_exp, ds_coef_man;
+       u32 clockMhzScaled = 0x64000000;
+       struct chan_centers centers;
+
+       if (IS_CHAN_HALF_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 1;
+       else if (IS_CHAN_QUARTER_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 2;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       coef_scaled = clockMhzScaled / centers.synth_center;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+       coef_scaled = (9 * coef_scaled) / 10;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+                     AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+                     AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
+}
+
+static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
+{
+       u32 rst_flags;
+       u32 tmpReg;
+
+       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+                 AR_RTC_FORCE_WAKE_ON_INT);
+
+       if (AR_SREV_9100(ah)) {
+               rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
+                       AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
+       } else {
+               tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+               if (tmpReg &
+                   (AR_INTR_SYNC_LOCAL_TIMEOUT |
+                    AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+               } else {
+                       REG_WRITE(ah, AR_RC, AR_RC_AHB);
+               }
+
+               rst_flags = AR_RTC_RC_MAC_WARM;
+               if (type == ATH9K_RESET_COLD)
+                       rst_flags |= AR_RTC_RC_MAC_COLD;
+       }
+
+       REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+       udelay(50);
+
+       REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
+       if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "%s: RTC stuck in MAC reset\n",
+                       __func__);
+               return false;
+       }
+
+       if (!AR_SREV_9100(ah))
+               REG_WRITE(ah, AR_RC, 0);
+
+       ath9k_hw_init_pll(ah, NULL);
+
+       if (AR_SREV_9100(ah))
+               udelay(50);
+
+       return true;
+}
+
+static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+{
+       REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+                 AR_RTC_FORCE_WAKE_ON_INT);
+
+       REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
+       REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+
+       if (!ath9k_hw_wait(ah,
+                          AR_RTC_STATUS,
+                          AR_RTC_STATUS_M,
+                          AR_RTC_STATUS_ON)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n",
                         __func__);
-               break;
+               return false;
        }
 
-       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-                   AR_PHY_TIMING_CTRL4_DO_CAL);
+       ath9k_hw_read_revisions(ah);
+
+       return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+}
+
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type)
+{
+       REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+                 AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
+       switch (type) {
+       case ATH9K_RESET_POWER_ON:
+               return ath9k_hw_set_reset_power_on(ah);
+               break;
+       case ATH9K_RESET_WARM:
+       case ATH9K_RESET_COLD:
+               return ath9k_hw_set_reset(ah, type);
+               break;
+       default:
+               return false;
+       }
 }
 
-static void ath9k_hw_reset_calibration(struct ath_hal *ah,
-                                      struct hal_cal_list *currCal)
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+                             enum ath9k_ht_macmode macmode)
 {
+       u32 phymode;
        struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
 
-       ath9k_hw_setup_calibration(ah, currCal);
+       phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
+
+       if (IS_CHAN_HT40(chan)) {
+               phymode |= AR_PHY_FC_DYN2040_EN;
 
-       currCal->calState = CAL_RUNNING;
+               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+                   (chan->chanmode == CHANNEL_G_HT40PLUS))
+                       phymode |= AR_PHY_FC_DYN2040_PRI_CH;
 
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ahp->ah_Meas0.sign[i] = 0;
-               ahp->ah_Meas1.sign[i] = 0;
-               ahp->ah_Meas2.sign[i] = 0;
-               ahp->ah_Meas3.sign[i] = 0;
+               if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
+                       phymode |= AR_PHY_FC_DYN2040_EXT_CH;
        }
+       REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+       ath9k_hw_set11nmac2040(ah, macmode);
 
-       ahp->ah_CalSamples = 0;
+       REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+       REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
 }
 
-static void
-ath9k_hw_per_calibration(struct ath_hal *ah,
-                        struct ath9k_channel *ichan,
-                        u8 rxchainmask,
-                        struct hal_cal_list *currCal,
-                        bool *isCalDone)
+static bool ath9k_hw_chip_reset(struct ath_hal *ah,
+                               struct ath9k_channel *chan)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
 
-       *isCalDone = false;
-
-       if (currCal->calState == CAL_RUNNING) {
-               if (!(REG_READ(ah,
-                              AR_PHY_TIMING_CTRL4(0)) &
-                     AR_PHY_TIMING_CTRL4_DO_CAL)) {
+       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+               return false;
 
-                       currCal->calData->calCollect(ah);
+       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+               return false;
 
-                       ahp->ah_CalSamples++;
+       ahp->ah_chipFullSleep = false;
 
-                       if (ahp->ah_CalSamples >=
-                           currCal->calData->calNumSamples) {
-                               int i, numChains = 0;
-                               for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-                                       if (rxchainmask & (1 << i))
-                                               numChains++;
-                               }
+       ath9k_hw_init_pll(ah, chan);
 
-                               currCal->calData->calPostProc(ah,
-                                                             numChains);
+       ath9k_hw_set_rfmode(ah, chan);
 
-                               ichan->CalValid |=
-                                       currCal->calData->calType;
-                               currCal->calState = CAL_DONE;
-                               *isCalDone = true;
-                       } else {
-                               ath9k_hw_setup_calibration(ah, currCal);
-                       }
-               }
-       } else if (!(ichan->CalValid & currCal->calData->calType)) {
-               ath9k_hw_reset_calibration(ah, currCal);
-       }
+       return true;
 }
 
-static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah,
-                                         int init_cal_count)
+static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
+                                                struct ath9k_channel *chan)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel ichan;
-       bool isCalDone;
-       struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-       const struct hal_percal_data *calData = currCal->calData;
-       int i;
-
-       if (currCal == NULL)
-               return false;
-
-       ichan.CalValid = 0;
-
-       for (i = 0; i < init_cal_count; i++) {
-               ath9k_hw_reset_calibration(ah, currCal);
-
-               if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0),
-                                  AR_PHY_TIMING_CTRL4_DO_CAL, 0)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: Cal %d failed to complete in 100ms.\n",
-                                __func__, calData->calType);
-
-                       ahp->ah_cal_list = ahp->ah_cal_list_last =
-                               ahp->ah_cal_list_curr = NULL;
-                       return false;
-               }
+       if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: invalid channel %u/0x%x; not marked as "
+                       "2GHz or 5GHz\n", __func__, chan->channel,
+                       chan->channelFlags);
+               return NULL;
+       }
 
-               ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask,
-                                        currCal, &isCalDone);
-               if (!isCalDone) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: Not able to run Init Cal %d.\n",
-                                __func__, calData->calType);
-               }
-               if (currCal->calNext) {
-                       currCal = currCal->calNext;
-                       calData = currCal->calData;
-               }
+       if (!IS_CHAN_OFDM(chan) &&
+           !IS_CHAN_CCK(chan) &&
+           !IS_CHAN_HT20(chan) &&
+           !IS_CHAN_HT40(chan)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+                       "%s: invalid channel %u/0x%x; not marked as "
+                       "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
+                       __func__, chan->channel, chan->channelFlags);
+               return NULL;
        }
 
-       ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
-       return true;
+       return ath9k_regd_check_channel(ah, chan);
 }
 
-static bool
-ath9k_hw_channel_change(struct ath_hal *ah,
-                       struct ath9k_channel *chan,
-                       enum ath9k_ht_macmode macmode)
+static bool ath9k_hw_channel_change(struct ath_hal *ah,
+                                   struct ath9k_channel *chan,
+                                   enum ath9k_ht_macmode macmode)
 {
        u32 synthDelay, qnum;
-       struct ath_hal_5416 *ahp = AH5416(ah);
 
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
                if (ath9k_hw_numtxpending(ah, qnum)) {
                        DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                                "%s: Transmit frames pending on queue %d\n",
-                                __func__, qnum);
+                               "%s: Transmit frames pending on queue %d\n",
+                               __func__, qnum);
                        return false;
                }
        }
@@ -5640,7 +1616,7 @@ ath9k_hw_channel_change(struct ath_hal *ah,
        if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
                           AR_PHY_RFBUS_GRANT_EN)) {
                DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-                        "%s: Could not kill baseband RX\n", __func__);
+                       "%s: Could not kill baseband RX\n", __func__);
                return false;
        }
 
@@ -5649,25 +1625,25 @@ ath9k_hw_channel_change(struct ath_hal *ah,
        if (AR_SREV_9280_10_OR_LATER(ah)) {
                if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
                        DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                                "%s: failed to set channel\n", __func__);
+                               "%s: failed to set channel\n", __func__);
                        return false;
                }
        } else {
                if (!(ath9k_hw_set_channel(ah, chan))) {
                        DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                                "%s: failed to set channel\n", __func__);
+                               "%s: failed to set channel\n", __func__);
                        return false;
                }
        }
 
-       if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
+       if (ath9k_hw_set_txpower(ah, chan,
                                 ath9k_regd_get_ctl(ah, chan),
                                 ath9k_regd_get_antenna_allowed(ah, chan),
                                 chan->maxRegTxPower * 2,
                                 min((u32) MAX_RATE_POWER,
                                     (u32) ah->ah_powerLimit)) != 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "%s: error init'ing transmit power\n", __func__);
+                       "%s: error init'ing transmit power\n", __func__);
                return false;
        }
 
@@ -5681,190 +1657,476 @@ ath9k_hw_channel_change(struct ath_hal *ah,
 
        REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
 
-       if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
-               ath9k_hw_set_delta_slope(ah, chan);
+       if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+               ath9k_hw_set_delta_slope(ah, chan);
+
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               ath9k_hw_9280_spur_mitigate(ah, chan);
+       else
+               ath9k_hw_spur_mitigate(ah, chan);
+
+       if (!chan->oneTimeCalsDone)
+               chan->oneTimeCalsDone = true;
+
+       return true;
+}
+
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+       int bb_spur = AR_NO_SPUR;
+       int freq;
+       int bin, cur_bin;
+       int bb_spur_off, spur_subchannel_sd;
+       int spur_freq_sd;
+       int spur_delta_phase;
+       int denominator;
+       int upper, lower, cur_vit_mask;
+       int tmp, newVal;
+       int i;
+       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+       };
+       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+       };
+       int inc[4] = { 0, 100, 0, 0 };
+       struct chan_centers centers;
+
+       int8_t mask_m[123];
+       int8_t mask_p[123];
+       int8_t mask_amt;
+       int tmp_mask;
+       int cur_bb_spur;
+       bool is2GHz = IS_CHAN_2GHZ(chan);
+
+       memset(&mask_m, 0, sizeof(int8_t) * 123);
+       memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = centers.synth_center;
+
+       ah->ah_config.spurmode = SPUR_ENABLE_EEPROM;
+       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+               cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+
+               if (is2GHz)
+                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
+               else
+                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
+
+               if (AR_NO_SPUR == cur_bb_spur)
+                       break;
+               cur_bb_spur = cur_bb_spur - freq;
+
+               if (IS_CHAN_HT40(chan)) {
+                       if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
+                           (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
+                               bb_spur = cur_bb_spur;
+                               break;
+                       }
+               } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
+                          (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
+                       bb_spur = cur_bb_spur;
+                       break;
+               }
+       }
+
+       if (AR_NO_SPUR == bb_spur) {
+               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+               return;
+       } else {
+               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+       }
+
+       bin = bb_spur * 320;
+
+       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+
+       newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+                       AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+                       AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+                       AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
+
+       newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+                 AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+                 AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+                 AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+                 SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+       REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
+
+       if (IS_CHAN_HT40(chan)) {
+               if (bb_spur < 0) {
+                       spur_subchannel_sd = 1;
+                       bb_spur_off = bb_spur + 10;
+               } else {
+                       spur_subchannel_sd = 0;
+                       bb_spur_off = bb_spur - 10;
+               }
+       } else {
+               spur_subchannel_sd = 0;
+               bb_spur_off = bb_spur;
+       }
+
+       if (IS_CHAN_HT40(chan))
+               spur_delta_phase =
+                       ((bb_spur * 262144) /
+                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+       else
+               spur_delta_phase =
+                       ((bb_spur * 524288) /
+                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+       denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
+       spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
+
+       newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+                 SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+                 SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+       REG_WRITE(ah, AR_PHY_TIMING11, newVal);
+
+       newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
+       REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
+
+       cur_bin = -6000;
+       upper = bin + 100;
+       lower = bin - 100;
+
+       for (i = 0; i < 4; i++) {
+               int pilot_mask = 0;
+               int chan_mask = 0;
+               int bp = 0;
+               for (bp = 0; bp < 30; bp++) {
+                       if ((cur_bin > lower) && (cur_bin < upper)) {
+                               pilot_mask = pilot_mask | 0x1 << bp;
+                               chan_mask = chan_mask | 0x1 << bp;
+                       }
+                       cur_bin += 100;
+               }
+               cur_bin += inc[i];
+               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+       }
+
+       cur_vit_mask = 6100;
+       upper = bin + 120;
+       lower = bin - 120;
+
+       for (i = 0; i < 123; i++) {
+               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+                       /* workaround for gcc bug #37014 */
+                       volatile int tmp = abs(cur_vit_mask - bin);
+
+                       if (tmp < 75)
+                               mask_amt = 1;
+                       else
+                               mask_amt = 0;
+                       if (cur_vit_mask < 0)
+                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+                       else
+                               mask_p[cur_vit_mask / 100] = mask_amt;
+               }
+               cur_vit_mask -= 100;
+       }
+
+       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+               | (mask_m[48] << 26) | (mask_m[49] << 24)
+               | (mask_m[50] << 22) | (mask_m[51] << 20)
+               | (mask_m[52] << 18) | (mask_m[53] << 16)
+               | (mask_m[54] << 14) | (mask_m[55] << 12)
+               | (mask_m[56] << 10) | (mask_m[57] << 8)
+               | (mask_m[58] << 6) | (mask_m[59] << 4)
+               | (mask_m[60] << 2) | (mask_m[61] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+       tmp_mask = (mask_m[31] << 28)
+               | (mask_m[32] << 26) | (mask_m[33] << 24)
+               | (mask_m[34] << 22) | (mask_m[35] << 20)
+               | (mask_m[36] << 18) | (mask_m[37] << 16)
+               | (mask_m[48] << 14) | (mask_m[39] << 12)
+               | (mask_m[40] << 10) | (mask_m[41] << 8)
+               | (mask_m[42] << 6) | (mask_m[43] << 4)
+               | (mask_m[44] << 2) | (mask_m[45] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+               | (mask_m[18] << 26) | (mask_m[18] << 24)
+               | (mask_m[20] << 22) | (mask_m[20] << 20)
+               | (mask_m[22] << 18) | (mask_m[22] << 16)
+               | (mask_m[24] << 14) | (mask_m[24] << 12)
+               | (mask_m[25] << 10) | (mask_m[26] << 8)
+               | (mask_m[27] << 6) | (mask_m[28] << 4)
+               | (mask_m[29] << 2) | (mask_m[30] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+               | (mask_m[2] << 26) | (mask_m[3] << 24)
+               | (mask_m[4] << 22) | (mask_m[5] << 20)
+               | (mask_m[6] << 18) | (mask_m[7] << 16)
+               | (mask_m[8] << 14) | (mask_m[9] << 12)
+               | (mask_m[10] << 10) | (mask_m[11] << 8)
+               | (mask_m[12] << 6) | (mask_m[13] << 4)
+               | (mask_m[14] << 2) | (mask_m[15] << 0);
+       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+       tmp_mask = (mask_p[15] << 28)
+               | (mask_p[14] << 26) | (mask_p[13] << 24)
+               | (mask_p[12] << 22) | (mask_p[11] << 20)
+               | (mask_p[10] << 18) | (mask_p[9] << 16)
+               | (mask_p[8] << 14) | (mask_p[7] << 12)
+               | (mask_p[6] << 10) | (mask_p[5] << 8)
+               | (mask_p[4] << 6) | (mask_p[3] << 4)
+               | (mask_p[2] << 2) | (mask_p[1] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
 
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               ath9k_hw_9280_spur_mitigate(ah, chan);
-       else
-               ath9k_hw_spur_mitigate(ah, chan);
+       tmp_mask = (mask_p[30] << 28)
+               | (mask_p[29] << 26) | (mask_p[28] << 24)
+               | (mask_p[27] << 22) | (mask_p[26] << 20)
+               | (mask_p[25] << 18) | (mask_p[24] << 16)
+               | (mask_p[23] << 14) | (mask_p[22] << 12)
+               | (mask_p[21] << 10) | (mask_p[20] << 8)
+               | (mask_p[19] << 6) | (mask_p[18] << 4)
+               | (mask_p[17] << 2) | (mask_p[16] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
 
-       if (!chan->oneTimeCalsDone)
-               chan->oneTimeCalsDone = true;
+       tmp_mask = (mask_p[45] << 28)
+               | (mask_p[44] << 26) | (mask_p[43] << 24)
+               | (mask_p[42] << 22) | (mask_p[41] << 20)
+               | (mask_p[40] << 18) | (mask_p[39] << 16)
+               | (mask_p[38] << 14) | (mask_p[37] << 12)
+               | (mask_p[36] << 10) | (mask_p[35] << 8)
+               | (mask_p[34] << 6) | (mask_p[33] << 4)
+               | (mask_p[32] << 2) | (mask_p[31] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
 
-       return true;
+       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+               | (mask_p[59] << 26) | (mask_p[58] << 24)
+               | (mask_p[57] << 22) | (mask_p[56] << 20)
+               | (mask_p[55] << 18) | (mask_p[54] << 16)
+               | (mask_p[53] << 14) | (mask_p[52] << 12)
+               | (mask_p[51] << 10) | (mask_p[50] << 8)
+               | (mask_p[49] << 6) | (mask_p[48] << 4)
+               | (mask_p[47] << 2) | (mask_p[46] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-static bool ath9k_hw_chip_reset(struct ath_hal *ah,
-                               struct ath9k_channel *chan)
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
-               return false;
+       int bb_spur = AR_NO_SPUR;
+       int bin, cur_bin;
+       int spur_freq_sd;
+       int spur_delta_phase;
+       int denominator;
+       int upper, lower, cur_vit_mask;
+       int tmp, new;
+       int i;
+       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+       };
+       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+       };
+       int inc[4] = { 0, 100, 0, 0 };
 
-       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-               return false;
+       int8_t mask_m[123];
+       int8_t mask_p[123];
+       int8_t mask_amt;
+       int tmp_mask;
+       int cur_bb_spur;
+       bool is2GHz = IS_CHAN_2GHZ(chan);
 
-       ahp->ah_chipFullSleep = false;
+       memset(&mask_m, 0, sizeof(int8_t) * 123);
+       memset(&mask_p, 0, sizeof(int8_t) * 123);
 
-       ath9k_hw_init_pll(ah, chan);
+       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+               cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+               if (AR_NO_SPUR == cur_bb_spur)
+                       break;
+               cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+               if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+                       bb_spur = cur_bb_spur;
+                       break;
+               }
+       }
 
-       ath9k_hw_set_rfmode(ah, chan);
+       if (AR_NO_SPUR == bb_spur)
+               return;
 
-       return true;
-}
+       bin = bb_spur * 32;
 
-static inline void ath9k_hw_set_dma(struct ath_hal *ah)
-{
-       u32 regval;
+       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+       new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+                    AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+                    AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+                    AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
 
-       regval = REG_READ(ah, AR_AHB_MODE);
-       REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
 
-       regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
-       REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+       new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+              AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+              AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+              AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+              SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+       REG_WRITE(ah, AR_PHY_SPUR_REG, new);
 
-       REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
+       spur_delta_phase = ((bb_spur * 524288) / 100) &
+               AR_PHY_TIMING11_SPUR_DELTA_PHASE;
 
-       regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
-       REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+       denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+       spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
 
-       REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+       new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+              SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+              SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+       REG_WRITE(ah, AR_PHY_TIMING11, new);
 
-       if (AR_SREV_9285(ah)) {
-               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-                         AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
-       } else {
-               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-                         AR_PCU_TXBUF_CTRL_USABLE_SIZE);
-       }
-}
+       cur_bin = -6000;
+       upper = bin + 100;
+       lower = bin - 100;
 
-bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
-{
-       REG_WRITE(ah, AR_CR, AR_CR_RXD);
-       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                       "%s: dma failed to stop in 10ms\n"
-                       "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
-                       __func__,
-                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
-               return false;
-       } else {
-               return true;
+       for (i = 0; i < 4; i++) {
+               int pilot_mask = 0;
+               int chan_mask = 0;
+               int bp = 0;
+               for (bp = 0; bp < 30; bp++) {
+                       if ((cur_bin > lower) && (cur_bin < upper)) {
+                               pilot_mask = pilot_mask | 0x1 << bp;
+                               chan_mask = chan_mask | 0x1 << bp;
+                       }
+                       cur_bin += 100;
+               }
+               cur_bin += inc[i];
+               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
        }
-}
-
-void ath9k_hw_startpcureceive(struct ath_hal *ah)
-{
-       REG_CLR_BIT(ah, AR_DIAG_SW,
-                   (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
-       ath9k_enable_mib_counters(ah);
 
-       ath9k_ani_reset(ah);
-}
-
-void ath9k_hw_stoppcurecv(struct ath_hal *ah)
-{
-       REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+       cur_vit_mask = 6100;
+       upper = bin + 120;
+       lower = bin - 120;
 
-       ath9k_hw_disable_mib_counters(ah);
-}
+       for (i = 0; i < 123; i++) {
+               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
 
-static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
-                                    struct ath9k_channel *chan,
-                                    enum hal_cal_types calType)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       bool retval = false;
+                       /* workaround for gcc bug #37014 */
+                       volatile int tmp = abs(cur_vit_mask - bin);
 
-       switch (calType & ahp->ah_suppCals) {
-       case IQ_MISMATCH_CAL:
-               if (!IS_CHAN_B(chan))
-                       retval = true;
-               break;
-       case ADC_GAIN_CAL:
-       case ADC_DC_CAL:
-               if (!IS_CHAN_B(chan)
-                   && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
-                       retval = true;
-               break;
+                       if (tmp < 75)
+                               mask_amt = 1;
+                       else
+                               mask_amt = 0;
+                       if (cur_vit_mask < 0)
+                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+                       else
+                               mask_p[cur_vit_mask / 100] = mask_amt;
+               }
+               cur_vit_mask -= 100;
        }
 
-       return retval;
-}
-
-static bool ath9k_hw_init_cal(struct ath_hal *ah,
-                             struct ath9k_channel *chan)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *ichan =
-               ath9k_regd_check_channel(ah, chan);
-
-       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
-                 AR_PHY_AGC_CONTROL_CAL);
-
-       if (!ath9k_hw_wait
-           (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: offset calibration failed to complete in 1ms; "
-                        "noisy environment?\n", __func__);
-               return false;
-       }
+       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+               | (mask_m[48] << 26) | (mask_m[49] << 24)
+               | (mask_m[50] << 22) | (mask_m[51] << 20)
+               | (mask_m[52] << 18) | (mask_m[53] << 16)
+               | (mask_m[54] << 14) | (mask_m[55] << 12)
+               | (mask_m[56] << 10) | (mask_m[57] << 8)
+               | (mask_m[58] << 6) | (mask_m[59] << 4)
+               | (mask_m[60] << 2) | (mask_m[61] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
 
-       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
-                 AR_PHY_AGC_CONTROL_NF);
+       tmp_mask = (mask_m[31] << 28)
+               | (mask_m[32] << 26) | (mask_m[33] << 24)
+               | (mask_m[34] << 22) | (mask_m[35] << 20)
+               | (mask_m[36] << 18) | (mask_m[37] << 16)
+               | (mask_m[48] << 14) | (mask_m[39] << 12)
+               | (mask_m[40] << 10) | (mask_m[41] << 8)
+               | (mask_m[42] << 6) | (mask_m[43] << 4)
+               | (mask_m[44] << 2) | (mask_m[45] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
 
-       ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr =
-               NULL;
+       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+               | (mask_m[18] << 26) | (mask_m[18] << 24)
+               | (mask_m[20] << 22) | (mask_m[20] << 20)
+               | (mask_m[22] << 18) | (mask_m[22] << 16)
+               | (mask_m[24] << 14) | (mask_m[24] << 12)
+               | (mask_m[25] << 10) | (mask_m[26] << 8)
+               | (mask_m[27] << 6) | (mask_m[28] << 4)
+               | (mask_m[29] << 2) | (mask_m[30] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
 
-       if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
-               if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
-                       INIT_CAL(&ahp->ah_adcGainCalData);
-                       INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: enabling ADC Gain Calibration.\n",
-                                __func__);
-               }
-               if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
-                       INIT_CAL(&ahp->ah_adcDcCalData);
-                       INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: enabling ADC DC Calibration.\n",
-                                __func__);
-               }
-               if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
-                       INIT_CAL(&ahp->ah_iqCalData);
-                       INSERT_CAL(ahp, &ahp->ah_iqCalData);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "%s: enabling IQ Calibration.\n",
-                                __func__);
-               }
+       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+               | (mask_m[2] << 26) | (mask_m[3] << 24)
+               | (mask_m[4] << 22) | (mask_m[5] << 20)
+               | (mask_m[6] << 18) | (mask_m[7] << 16)
+               | (mask_m[8] << 14) | (mask_m[9] << 12)
+               | (mask_m[10] << 10) | (mask_m[11] << 8)
+               | (mask_m[12] << 6) | (mask_m[13] << 4)
+               | (mask_m[14] << 2) | (mask_m[15] << 0);
+       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
 
-               ahp->ah_cal_list_curr = ahp->ah_cal_list;
+       tmp_mask = (mask_p[15] << 28)
+               | (mask_p[14] << 26) | (mask_p[13] << 24)
+               | (mask_p[12] << 22) | (mask_p[11] << 20)
+               | (mask_p[10] << 18) | (mask_p[9] << 16)
+               | (mask_p[8] << 14) | (mask_p[7] << 12)
+               | (mask_p[6] << 10) | (mask_p[5] << 8)
+               | (mask_p[4] << 6) | (mask_p[3] << 4)
+               | (mask_p[2] << 2) | (mask_p[1] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
 
-               if (ahp->ah_cal_list_curr)
-                       ath9k_hw_reset_calibration(ah,
-                                                  ahp->ah_cal_list_curr);
-       }
+       tmp_mask = (mask_p[30] << 28)
+               | (mask_p[29] << 26) | (mask_p[28] << 24)
+               | (mask_p[27] << 22) | (mask_p[26] << 20)
+               | (mask_p[25] << 18) | (mask_p[24] << 16)
+               | (mask_p[23] << 14) | (mask_p[22] << 12)
+               | (mask_p[21] << 10) | (mask_p[20] << 8)
+               | (mask_p[19] << 6) | (mask_p[18] << 4)
+               | (mask_p[17] << 2) | (mask_p[16] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
 
-       ichan->CalValid = 0;
+       tmp_mask = (mask_p[45] << 28)
+               | (mask_p[44] << 26) | (mask_p[43] << 24)
+               | (mask_p[42] << 22) | (mask_p[41] << 20)
+               | (mask_p[40] << 18) | (mask_p[39] << 16)
+               | (mask_p[38] << 14) | (mask_p[37] << 12)
+               | (mask_p[36] << 10) | (mask_p[35] << 8)
+               | (mask_p[34] << 6) | (mask_p[33] << 4)
+               | (mask_p[32] << 2) | (mask_p[31] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
 
-       return true;
+       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+               | (mask_p[59] << 26) | (mask_p[58] << 24)
+               | (mask_p[57] << 22) | (mask_p[56] << 20)
+               | (mask_p[55] << 18) | (mask_p[54] << 16)
+               | (mask_p[53] << 14) | (mask_p[52] << 12)
+               | (mask_p[51] << 10) | (mask_p[50] << 8)
+               | (mask_p[49] << 6) | (mask_p[48] << 4)
+               | (mask_p[47] << 2) | (mask_p[46] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
-
-bool ath9k_hw_reset(struct ath_hal *ah,
-                   struct ath9k_channel *chan,
+bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan,
                    enum ath9k_ht_macmode macmode,
                    u8 txchainmask, u8 rxchainmask,
                    enum ath9k_ht_extprotspacing extprotspacing,
-                   bool bChannelChange,
-                   int *status)
+                   bool bChannelChange, int *status)
 {
        u32 saveLedState;
        struct ath_hal_5416 *ahp = AH5416(ah);
@@ -5885,8 +2147,8 @@ bool ath9k_hw_reset(struct ath_hal *ah,
 
        if (ath9k_hw_check_chan(ah, chan) == NULL) {
                DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: invalid channel %u/0x%x; no mapping\n",
-                        __func__, chan->channel, chan->channelFlags);
+                       "%s: invalid channel %u/0x%x; no mapping\n",
+                       __func__, chan->channel, chan->channelFlags);
                ecode = -EINVAL;
                goto bad;
        }
@@ -5964,7 +2226,7 @@ bool ath9k_hw_reset(struct ath_hal *ah,
 
        if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
-                        "%s: error setting board options\n", __func__);
+                       "%s: error setting board options\n", __func__);
                ecode = -EIO;
                goto bad;
        }
@@ -6054,15 +2316,15 @@ bool ath9k_hw_reset(struct ath_hal *ah,
                mask = REG_READ(ah, AR_CFG);
                if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
                        DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                                "%s CFG Byte Swap Set 0x%x\n", __func__,
-                                mask);
+                               "%s CFG Byte Swap Set 0x%x\n", __func__,
+                               mask);
                } else {
                        mask =
                                INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
                        REG_WRITE(ah, AR_CFG, mask);
                        DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                                "%s Setting CFG 0x%x\n", __func__,
-                                REG_READ(ah, AR_CFG));
+                               "%s Setting CFG 0x%x\n", __func__,
+                               REG_READ(ah, AR_CFG));
                }
        } else {
 #ifdef __BIG_ENDIAN
@@ -6077,693 +2339,404 @@ bad:
        return false;
 }
 
-bool ath9k_hw_phy_disable(struct ath_hal *ah)
-{
-       return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
-}
-
-bool ath9k_hw_disable(struct ath_hal *ah)
-{
-       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-               return false;
-
-       return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
-}
+/************************/
+/* Key Cache Management */
+/************************/
 
-bool
-ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
-                  u8 rxchainmask, bool longcal,
-                  bool *isCalDone)
+bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-       struct ath9k_channel *ichan =
-               ath9k_regd_check_channel(ah, chan);
-
-       *isCalDone = true;
+       u32 keyType;
 
-       if (ichan == NULL) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
-                        "%s: invalid channel %u/0x%x; no mapping\n",
-                        __func__, chan->channel, chan->channelFlags);
+       if (entry >= ah->ah_caps.keycache_size) {
+               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                       "%s: entry %u out of range\n", __func__, entry);
                return false;
        }
 
-       if (currCal &&
-           (currCal->calState == CAL_RUNNING ||
-            currCal->calState == CAL_WAITING)) {
-               ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
-                                        isCalDone);
-               if (*isCalDone) {
-                       ahp->ah_cal_list_curr = currCal = currCal->calNext;
-
-                       if (currCal->calState == CAL_WAITING) {
-                               *isCalDone = false;
-                               ath9k_hw_reset_calibration(ah, currCal);
-                       }
-               }
-       }
-
-       if (longcal) {
-               ath9k_hw_getnf(ah, ichan);
-               ath9k_hw_loadnf(ah, ah->ah_curchan);
-               ath9k_hw_start_nfcal(ah);
-
-               if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
-
-                       chan->channelFlags |= CHANNEL_CW_INT;
-                       ichan->channelFlags &= ~CHANNEL_CW_INT;
-               }
-       }
-
-       return true;
-}
-
-static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ahp->ah_totalPowerMeasI[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ahp->ah_totalPowerMeasQ[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ahp->ah_totalIqCorrMeas[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
-                        ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
-                        ahp->ah_totalPowerMeasQ[i],
-                        ahp->ah_totalIqCorrMeas[i]);
-       }
-}
-
-static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ahp->ah_totalAdcIOddPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ahp->ah_totalAdcIEvenPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ahp->ah_totalAdcQOddPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               ahp->ah_totalAdcQEvenPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                       "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-                       "oddq=0x%08x; evenq=0x%08x;\n",
-                        ahp->ah_CalSamples, i,
-                        ahp->ah_totalAdcIOddPhase[i],
-                        ahp->ah_totalAdcIEvenPhase[i],
-                        ahp->ah_totalAdcQOddPhase[i],
-                        ahp->ah_totalAdcQEvenPhase[i]);
-       }
-}
-
-static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                       "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-                       "oddq=0x%08x; evenq=0x%08x;\n",
-                        ahp->ah_CalSamples, i,
-                        ahp->ah_totalAdcDcOffsetIOddPhase[i],
-                        ahp->ah_totalAdcDcOffsetIEvenPhase[i],
-                        ahp->ah_totalAdcDcOffsetQOddPhase[i],
-                        ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
-       }
-}
-
-static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 powerMeasQ, powerMeasI, iqCorrMeas;
-       u32 qCoffDenom, iCoffDenom;
-       int32_t qCoff, iCoff;
-       int iqCorrNeg, i;
-
-       for (i = 0; i < numChains; i++) {
-               powerMeasI = ahp->ah_totalPowerMeasI[i];
-               powerMeasQ = ahp->ah_totalPowerMeasQ[i];
-               iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Starting IQ Cal and Correction for Chain %d\n",
-                        i);
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Orignal: Chn %diq_corr_meas = 0x%08x\n",
-                        i, ahp->ah_totalIqCorrMeas[i]);
-
-               iqCorrNeg = 0;
-
-
-               if (iqCorrMeas > 0x80000000) {
-                       iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
-                       iqCorrNeg = 1;
-               }
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
-                        iqCorrNeg);
-
-               iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
-               qCoffDenom = powerMeasQ / 64;
-
-               if (powerMeasQ != 0) {
-
-                       iCoff = iqCorrMeas / iCoffDenom;
-                       qCoff = powerMeasI / qCoffDenom - 64;
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "Chn %d iCoff = 0x%08x\n", i, iCoff);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "Chn %d qCoff = 0x%08x\n", i, qCoff);
-
-
-                       iCoff = iCoff & 0x3f;
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
-                       if (iqCorrNeg == 0x0)
-                               iCoff = 0x40 - iCoff;
-
-                       if (qCoff > 15)
-                               qCoff = 15;
-                       else if (qCoff <= -16)
-                               qCoff = 16;
-
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
-                               i, iCoff, qCoff);
-
-                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
-                                     iCoff);
-                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
-                                     qCoff);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                               "IQ Cal and Correction done for Chain %d\n",
-                               i);
-               }
-       }
+       keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
 
-       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-                   AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
-}
+       REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+       REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+       REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
 
-static void
-ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset,
-               qEvenMeasOffset;
-       u32 qGainMismatch, iGainMismatch, val, i;
-
-       for (i = 0; i < numChains; i++) {
-               iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
-               iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
-               qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
-               qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Starting ADC Gain Cal for Chain %d\n", i);
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
-                        iOddMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_even_i = 0x%08x\n", i,
-                        iEvenMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
-                        qOddMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_even_q = 0x%08x\n", i,
-                        qEvenMeasOffset);
-
-               if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
-                       iGainMismatch =
-                               ((iEvenMeasOffset * 32) /
-                                iOddMeasOffset) & 0x3f;
-                       qGainMismatch =
-                               ((qOddMeasOffset * 32) /
-                                qEvenMeasOffset) & 0x3f;
-
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "Chn %d gain_mismatch_i = 0x%08x\n", i,
-                                iGainMismatch);
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "Chn %d gain_mismatch_q = 0x%08x\n", i,
-                                qGainMismatch);
-
-                       val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-                       val &= 0xfffff000;
-                       val |= (qGainMismatch) | (iGainMismatch << 6);
-                       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                                "ADC Gain Cal done for Chain %d\n", i);
-               }
-       }
+       if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+               u16 micentry = entry + 64;
 
-       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-                 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
-}
+               REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
 
-static void
-ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 iOddMeasOffset, iEvenMeasOffset, val, i;
-       int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
-       const struct hal_percal_data *calData =
-               ahp->ah_cal_list_curr->calData;
-       u32 numSamples =
-               (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
-
-       for (i = 0; i < numChains; i++) {
-               iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
-               iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
-               qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
-               qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Starting ADC DC Offset Cal for Chain %d\n", i);
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_odd_i = %d\n", i,
-                        iOddMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_even_i = %d\n", i,
-                        iEvenMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_odd_q = %d\n", i,
-                        qOddMeasOffset);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d pwr_meas_even_q = %d\n", i,
-                        qEvenMeasOffset);
-
-               iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
-                              numSamples) & 0x1ff;
-               qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
-                              numSamples) & 0x1ff;
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
-                        iDcMismatch);
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
-                        qDcMismatch);
-
-               val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-               val &= 0xc0000fff;
-               val |= (qDcMismatch << 12) | (iDcMismatch << 21);
-               REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "ADC DC Offset Cal done for Chain %d\n", i);
        }
 
-       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-                 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
-}
-
-bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *chan = ah->ah_curchan;
-
-       ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
-
-       if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
-                                ath9k_regd_get_ctl(ah, chan),
-                                ath9k_regd_get_antenna_allowed(ah,
-                                                               chan),
-                                chan->maxRegTxPower * 2,
-                                min((u32) MAX_RATE_POWER,
-                                    (u32) ah->ah_powerLimit)) != 0)
-               return false;
+       if (ah->ah_curchan == NULL)
+               return true;
 
        return true;
 }
 
-void
-ath9k_hw_get_channel_centers(struct ath_hal *ah,
-                            struct ath9k_channel *chan,
-                            struct chan_centers *centers)
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac)
 {
-       int8_t extoff;
-       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 macHi, macLo;
 
-       if (!IS_CHAN_HT40(chan)) {
-               centers->ctl_center = centers->ext_center =
-                       centers->synth_center = chan->channel;
-               return;
+       if (entry >= ah->ah_caps.keycache_size) {
+               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                       "%s: entry %u out of range\n", __func__, entry);
+               return false;
        }
 
-       if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-           (chan->chanmode == CHANNEL_G_HT40PLUS)) {
-               centers->synth_center =
-                       chan->channel + HT40_CHANNEL_CENTER_SHIFT;
-               extoff = 1;
+       if (mac != NULL) {
+               macHi = (mac[5] << 8) | mac[4];
+               macLo = (mac[3] << 24) |
+                       (mac[2] << 16) |
+                       (mac[1] << 8) |
+                       mac[0];
+               macLo >>= 1;
+               macLo |= (macHi & 1) << 31;
+               macHi >>= 1;
        } else {
-               centers->synth_center =
-                       chan->channel - HT40_CHANNEL_CENTER_SHIFT;
-               extoff = -1;
+               macLo = macHi = 0;
        }
+       REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+       REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
 
-       centers->ctl_center = centers->synth_center - (extoff *
-               HT40_CHANNEL_CENTER_SHIFT);
-       centers->ext_center = centers->synth_center + (extoff *
-               ((ahp->
-               ah_extprotspacing
-               ==
-               ATH9K_HT_EXTPROTSPACING_20)
-               ?
-               HT40_CHANNEL_CENTER_SHIFT
-               : 15));
-
+       return true;
 }
 
-void
-ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
-                       bool *isCalDone)
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+                                const struct ath9k_keyval *k,
+                                const u8 *mac, int xorKey)
 {
+       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       u32 key0, key1, key2, key3, key4;
+       u32 keyType;
+       u32 xorMask = xorKey ?
+               (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
+                | ATH9K_KEY_XOR) : 0;
        struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *ichan =
-               ath9k_regd_check_channel(ah, chan);
-       struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
-
-       *isCalDone = true;
-
-       if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
-               return;
 
-       if (currCal == NULL)
-               return;
-
-       if (ichan == NULL) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: invalid channel %u/0x%x; no mapping\n",
-                        __func__, chan->channel, chan->channelFlags);
-               return;
+       if (entry >= pCap->keycache_size) {
+               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                       "%s: entry %u out of range\n", __func__, entry);
+               return false;
        }
 
-
-       if (currCal->calState != CAL_DONE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                        "%s: Calibration state incorrect, %d\n",
-                        __func__, currCal->calState);
-               return;
+       switch (k->kv_type) {
+       case ATH9K_CIPHER_AES_OCB:
+               keyType = AR_KEYTABLE_TYPE_AES;
+               break;
+       case ATH9K_CIPHER_AES_CCM:
+               if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                               "%s: AES-CCM not supported by "
+                               "mac rev 0x%x\n", __func__,
+                               ah->ah_macRev);
+                       return false;
+               }
+               keyType = AR_KEYTABLE_TYPE_CCM;
+               break;
+       case ATH9K_CIPHER_TKIP:
+               keyType = AR_KEYTABLE_TYPE_TKIP;
+               if (ATH9K_IS_MIC_ENABLED(ah)
+                   && entry + 64 >= pCap->keycache_size) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                               "%s: entry %u inappropriate for TKIP\n",
+                               __func__, entry);
+                       return false;
+               }
+               break;
+       case ATH9K_CIPHER_WEP:
+               if (k->kv_len < LEN_WEP40) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                               "%s: WEP key length %u too small\n",
+                               __func__, k->kv_len);
+                       return false;
+               }
+               if (k->kv_len <= LEN_WEP40)
+                       keyType = AR_KEYTABLE_TYPE_40;
+               else if (k->kv_len <= LEN_WEP104)
+                       keyType = AR_KEYTABLE_TYPE_104;
+               else
+                       keyType = AR_KEYTABLE_TYPE_128;
+               break;
+       case ATH9K_CIPHER_CLR:
+               keyType = AR_KEYTABLE_TYPE_CLR;
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+                       "%s: cipher %u not supported\n", __func__,
+                       k->kv_type);
+               return false;
        }
 
+       key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
+       key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
+       key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
+       key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
+       key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
+       if (k->kv_len <= LEN_WEP104)
+               key4 &= 0xff;
 
-       if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
-               return;
-
-       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                "%s: Resetting Cal %d state for channel %u/0x%x\n",
-                __func__, currCal->calData->calType, chan->channel,
-                chan->channelFlags);
-
-       ichan->CalValid &= ~currCal->calData->calType;
-       currCal->calState = CAL_WAITING;
-
-       *isCalDone = false;
-}
-
-void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
-}
+       if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+               u16 micentry = entry + 64;
 
-bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
+               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+               REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+               REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+               REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+               REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+               (void) ath9k_hw_keysetmac(ah, entry, mac);
 
-       memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
-       return true;
-}
+               if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
+                       u32 mic0, mic1, mic2, mic3, mic4;
 
-void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
+                       mic0 = get_unaligned_le32(k->kv_mic + 0);
+                       mic2 = get_unaligned_le32(k->kv_mic + 4);
+                       mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
+                       mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
+                       mic4 = get_unaligned_le32(k->kv_txmic + 4);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
+                       REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+                                 AR_KEYTABLE_TYPE_CLR);
 
-       memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
-}
+               } else {
+                       u32 mic0, mic2;
 
-bool
-ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
+                       mic0 = get_unaligned_le32(k->kv_mic + 0);
+                       mic2 = get_unaligned_le32(k->kv_mic + 4);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+                       REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+                       REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+                                 AR_KEYTABLE_TYPE_CLR);
+               }
+               REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
+               REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+       } else {
+               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+               REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+               REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+               REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+               REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
 
-       memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
+               (void) ath9k_hw_keysetmac(ah, entry, mac);
+       }
 
-       REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
-       REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+       if (ah->ah_curchan == NULL)
+               return true;
 
        return true;
 }
 
-void
-ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
-                      u16 assocId)
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
-       ahp->ah_assocId = assocId;
-
-       REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
-       REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
-                 ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
+       if (entry < ah->ah_caps.keycache_size) {
+               u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
+               if (val & AR_KEYTABLE_VALID)
+                       return true;
+       }
+       return false;
 }
 
-u64 ath9k_hw_gettsf64(struct ath_hal *ah)
+/******************************/
+/* Power Management (Chipset) */
+/******************************/
+
+static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
 {
-       u64 tsf;
+       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+       if (setChip) {
+               REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+                           AR_RTC_FORCE_WAKE_EN);
+               if (!AR_SREV_9100(ah))
+                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
-       tsf = REG_READ(ah, AR_TSF_U32);
-       tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
-       return tsf;
+               REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+                           AR_RTC_RESET_EN);
+       }
 }
 
-void ath9k_hw_reset_tsf(struct ath_hal *ah)
+static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
 {
-       int count;
+       REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+       if (setChip) {
+               struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 
-       count = 0;
-       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
-               count++;
-               if (count > 10) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                        "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n",
-                                __func__);
-                       break;
+               if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+                       REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+                                 AR_RTC_FORCE_WAKE_ON_INT);
+               } else {
+                       REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+                                   AR_RTC_FORCE_WAKE_EN);
                }
-               udelay(10);
        }
-       REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
-}
-
-u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
-{
-       return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
 }
 
-void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
+static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
+                                    int setChip)
 {
-       REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
-}
+       u32 val;
+       int i;
 
-bool
-ath9k_hw_setantennaswitch(struct ath_hal *ah,
-                         enum ath9k_ant_setting settings,
-                         struct ath9k_channel *chan,
-                         u8 *tx_chainmask,
-                         u8 *rx_chainmask,
-                         u8 *antenna_cfgd)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       static u8 tx_chainmask_cfg, rx_chainmask_cfg;
+       if (setChip) {
+               if ((REG_READ(ah, AR_RTC_STATUS) &
+                    AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+                       if (ath9k_hw_set_reset_reg(ah,
+                                          ATH9K_RESET_POWER_ON) != true) {
+                               return false;
+                       }
+               }
+               if (AR_SREV_9100(ah))
+                       REG_SET_BIT(ah, AR_RTC_RESET,
+                                   AR_RTC_RESET_EN);
 
-       if (AR_SREV_9280(ah)) {
-               if (!tx_chainmask_cfg) {
+               REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+                           AR_RTC_FORCE_WAKE_EN);
+               udelay(50);
 
-                       tx_chainmask_cfg = *tx_chainmask;
-                       rx_chainmask_cfg = *rx_chainmask;
+               for (i = POWER_UP_TIME / 50; i > 0; i--) {
+                       val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+                       if (val == AR_RTC_STATUS_ON)
+                               break;
+                       udelay(50);
+                       REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+                                   AR_RTC_FORCE_WAKE_EN);
                }
-
-               switch (settings) {
-               case ATH9K_ANT_FIXED_A:
-                       *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-                       *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
-                       *antenna_cfgd = true;
-                       break;
-               case ATH9K_ANT_FIXED_B:
-                       if (ah->ah_caps.tx_chainmask >
-                           ATH9K_ANTENNA1_CHAINMASK) {
-                               *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
-                       }
-                       *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
-                       *antenna_cfgd = true;
-                       break;
-               case ATH9K_ANT_VARIABLE:
-                       *tx_chainmask = tx_chainmask_cfg;
-                       *rx_chainmask = rx_chainmask_cfg;
-                       *antenna_cfgd = true;
-                       break;
-               default:
-                       break;
+               if (i == 0) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                               "%s: Failed to wakeup in %uus\n",
+                               __func__, POWER_UP_TIME / 20);
+                       return false;
                }
-       } else {
-               ahp->ah_diversityControl = settings;
        }
 
-       return true;
-}
+       REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
 
-void ath9k_hw_setopmode(struct ath_hal *ah)
-{
-       ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
+       return true;
 }
 
-bool
-ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
-                      u32 capability, u32 *result)
+bool ath9k_hw_setpower(struct ath_hal *ah,
+                      enum ath9k_power_mode mode)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
-       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-       switch (type) {
-       case ATH9K_CAP_CIPHER:
-               switch (capability) {
-               case ATH9K_CIPHER_AES_CCM:
-               case ATH9K_CIPHER_AES_OCB:
-               case ATH9K_CIPHER_TKIP:
-               case ATH9K_CIPHER_WEP:
-               case ATH9K_CIPHER_MIC:
-               case ATH9K_CIPHER_CLR:
-                       return true;
-               default:
-                       return false;
-               }
-       case ATH9K_CAP_TKIP_MIC:
-               switch (capability) {
-               case 0:
-                       return true;
-               case 1:
-                       return (ahp->ah_staId1Defaults &
-                               AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
-                       false;
-               }
-       case ATH9K_CAP_TKIP_SPLIT:
-               return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
-                       false : true;
-       case ATH9K_CAP_WME_TKIPMIC:
-               return 0;
-       case ATH9K_CAP_PHYCOUNTERS:
-               return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
-       case ATH9K_CAP_DIVERSITY:
-               return (REG_READ(ah, AR_PHY_CCK_DETECT) &
-                       AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
-                       true : false;
-       case ATH9K_CAP_PHYDIAG:
-               return true;
-       case ATH9K_CAP_MCAST_KEYSRCH:
-               switch (capability) {
-               case 0:
-                       return true;
-               case 1:
-                       if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
-                               return false;
-                       } else {
-                               return (ahp->ah_staId1Defaults &
-                                       AR_STA_ID1_MCAST_KSRCH) ? true :
-                                       false;
-                       }
-               }
-               return false;
-       case ATH9K_CAP_TSF_ADJUST:
-               return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
-                       true : false;
-       case ATH9K_CAP_RFSILENT:
-               if (capability == 3)
-                       return false;
-       case ATH9K_CAP_ANT_CFG_2GHZ:
-               *result = pCap->num_antcfg_2ghz;
-               return true;
-       case ATH9K_CAP_ANT_CFG_5GHZ:
-               *result = pCap->num_antcfg_5ghz;
-               return true;
-       case ATH9K_CAP_TXPOW:
-               switch (capability) {
-               case 0:
-                       return 0;
-               case 1:
-                       *result = ah->ah_powerLimit;
-                       return 0;
-               case 2:
-                       *result = ah->ah_maxPowerLevel;
-                       return 0;
-               case 3:
-                       *result = ah->ah_tpScale;
-                       return 0;
-               }
-               return false;
+       static const char *modes[] = {
+               "AWAKE",
+               "FULL-SLEEP",
+               "NETWORK SLEEP",
+               "UNDEFINED"
+       };
+       int status = true, setChip = true;
+
+       DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,
+               modes[ahp->ah_powerMode], modes[mode],
+               setChip ? "set chip " : "");
+
+       switch (mode) {
+       case ATH9K_PM_AWAKE:
+               status = ath9k_hw_set_power_awake(ah, setChip);
+               break;
+       case ATH9K_PM_FULL_SLEEP:
+               ath9k_set_power_sleep(ah, setChip);
+               ahp->ah_chipFullSleep = true;
+               break;
+       case ATH9K_PM_NETWORK_SLEEP:
+               ath9k_set_power_network_sleep(ah, setChip);
+               break;
        default:
+               DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+                       "%s: unknown power mode %u\n", __func__, mode);
                return false;
        }
+       ahp->ah_powerMode = mode;
+
+       return status;
 }
 
-int
-ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_channel *chan = ah->ah_curchan;
-       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       u16 ant_config;
-       u32 halNumAntConfig;
+       u8 i;
 
-       halNumAntConfig =
-               IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap->
-               num_antcfg_5ghz;
+       if (ah->ah_isPciExpress != true)
+               return;
 
-       if (cfg < halNumAntConfig) {
-               if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan,
-                                                    cfg, &ant_config)) {
-                       REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
-                       return 0;
+       if (ah->ah_config.pcie_powersave_enable == 2)
+               return;
+
+       if (restore)
+               return;
+
+       if (AR_SREV_9280_20_OR_LATER(ah)) {
+               for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
+                       REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
+                                 INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
                }
+               udelay(1000);
+       } else if (AR_SREV_9280(ah) &&
+                  (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+               REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+
+               if (ah->ah_config.pcie_clock_req)
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+               else
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
+
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+
+               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+               udelay(1000);
+       } else {
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+               REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+               REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
        }
 
-       return -EINVAL;
+       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+       if (ah->ah_config.pcie_waen) {
+               REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+       } else {
+               if (AR_SREV_9280(ah))
+                       REG_WRITE(ah, AR_WA, 0x0040073f);
+               else
+                       REG_WRITE(ah, AR_WA, 0x0000073f);
+       }
 }
 
+/**********************/
+/* Interrupt Handling */
+/**********************/
+
 bool ath9k_hw_intrpend(struct ath_hal *ah)
 {
        u32 host_isr;
@@ -6790,6 +2763,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
        struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
        u32 sync_cause = 0;
        bool fatal_int = false;
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
        if (!AR_SREV_9100(ah)) {
                if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
@@ -6799,9 +2773,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
                        }
                }
 
-               sync_cause =
-                       REG_READ(ah,
-                                AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
+               sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
+                       AR_INTR_SYNC_DEFAULT;
 
                *masked = 0;
 
@@ -6813,8 +2786,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
        }
 
        if (isr) {
-               struct ath_hal_5416 *ahp = AH5416(ah);
-
                if (isr & AR_ISR_BCNMISC) {
                        u32 isr2;
                        isr2 = REG_READ(ah, AR_ISR_S2);
@@ -6841,7 +2812,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
                *masked = isr & ATH9K_INT_COMMON;
 
                if (ahp->ah_intrMitigation) {
-
                        if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
                                *masked |= ATH9K_INT_RX;
                }
@@ -6866,8 +2836,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
 
                if (isr & AR_ISR_RXORN) {
                        DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-                                "%s: receive FIFO overrun interrupt\n",
-                                __func__);
+                               "%s: receive FIFO overrun interrupt\n",
+                               __func__);
                }
 
                if (!AR_SREV_9100(ah)) {
@@ -6880,8 +2850,10 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
 
                *masked |= mask2;
        }
+
        if (AR_SREV_9100(ah))
                return true;
+
        if (sync_cause) {
                fatal_int =
                        (sync_cause &
@@ -6891,32 +2863,33 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
                if (fatal_int) {
                        if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
                                DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                        "%s: received PCI FATAL interrupt\n",
-                                        __func__);
+                                       "%s: received PCI FATAL interrupt\n",
+                                       __func__);
                        }
                        if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
                                DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                                        "%s: received PCI PERR interrupt\n",
-                                        __func__);
+                                       "%s: received PCI PERR interrupt\n",
+                                       __func__);
                        }
                }
                if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
                        DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-                                "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n",
-                                __func__);
+                               "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n",
+                               __func__);
                        REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
                        REG_WRITE(ah, AR_RC, 0);
                        *masked |= ATH9K_INT_FATAL;
                }
                if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
                        DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-                                "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n",
-                                __func__);
+                               "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n",
+                               __func__);
                }
 
                REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
                (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
        }
+
        return true;
 }
 
@@ -7034,9 +3007,11 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
        return omask;
 }
 
-void
-ath9k_hw_beaconinit(struct ath_hal *ah,
-                   u32 next_beacon, u32 beacon_period)
+/*******************/
+/* Beacon Handling */
+/*******************/
+
+void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
        int flags = 0;
@@ -7088,9 +3063,8 @@ ath9k_hw_beaconinit(struct ath_hal *ah,
        REG_SET_BIT(ah, AR_TIMER_MODE, flags);
 }
 
-void
-ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
-                              const struct ath9k_beacon_state *bs)
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+                                   const struct ath9k_beacon_state *bs)
 {
        u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
        struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
@@ -7124,1450 +3098,898 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
        DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__,
                 nextTbtt);
        DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__,
-                beaconintval);
-       DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__,
-                dtimperiod);
-
-       REG_WRITE(ah, AR_NEXT_DTIM,
-                 TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
-       REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
-
-       REG_WRITE(ah, AR_SLEEP1,
-                 SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
-                 | AR_SLEEP1_ASSUME_DTIM);
-
-       if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)
-               beacontimeout = (BEACON_TIMEOUT_VAL << 3);
-       else
-               beacontimeout = MIN_BEACON_TIMEOUT_VAL;
-
-       REG_WRITE(ah, AR_SLEEP2,
-                 SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
-
-       REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
-       REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
-
-       REG_SET_BIT(ah, AR_TIMER_MODE,
-                   AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
-                   AR_DTIM_TIMER_EN);
-
-}
-
-bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
-{
-       if (entry < ah->ah_caps.keycache_size) {
-               u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
-               if (val & AR_KEYTABLE_VALID)
-                       return true;
-       }
-       return false;
-}
-
-bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
-{
-       u32 keyType;
-
-       if (entry >= ah->ah_caps.keycache_size) {
-               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                        "%s: entry %u out of range\n", __func__, entry);
-               return false;
-       }
-       keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
-
-       REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
-       REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
-       REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
-
-       if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
-               u16 micentry = entry + 64;
-
-               REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-
-       }
-
-       return true;
-}
-
-bool
-ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
-                  const u8 *mac)
-{
-       u32 macHi, macLo;
-
-       if (entry >= ah->ah_caps.keycache_size) {
-               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                        "%s: entry %u out of range\n", __func__, entry);
-               return false;
-       }
-
-       if (mac != NULL) {
-               macHi = (mac[5] << 8) | mac[4];
-               macLo = (mac[3] << 24) | (mac[2] << 16)
-                       | (mac[1] << 8) | mac[0];
-               macLo >>= 1;
-               macLo |= (macHi & 1) << 31;
-               macHi >>= 1;
-       } else {
-               macLo = macHi = 0;
-       }
-       REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
-       REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
-
-       return true;
-}
-
-bool
-ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
-                           const struct ath9k_keyval *k,
-                           const u8 *mac, int xorKey)
-{
-       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       u32 key0, key1, key2, key3, key4;
-       u32 keyType;
-       u32 xorMask = xorKey ?
-               (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
-                | ATH9K_KEY_XOR) : 0;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       if (entry >= pCap->keycache_size) {
-               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                        "%s: entry %u out of range\n", __func__, entry);
-               return false;
-       }
-       switch (k->kv_type) {
-       case ATH9K_CIPHER_AES_OCB:
-               keyType = AR_KEYTABLE_TYPE_AES;
-               break;
-       case ATH9K_CIPHER_AES_CCM:
-               if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                                "%s: AES-CCM not supported by "
-                                "mac rev 0x%x\n", __func__,
-                                ah->ah_macRev);
-                       return false;
-               }
-               keyType = AR_KEYTABLE_TYPE_CCM;
-               break;
-       case ATH9K_CIPHER_TKIP:
-               keyType = AR_KEYTABLE_TYPE_TKIP;
-               if (ATH9K_IS_MIC_ENABLED(ah)
-                   && entry + 64 >= pCap->keycache_size) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                                "%s: entry %u inappropriate for TKIP\n",
-                                __func__, entry);
-                       return false;
-               }
-               break;
-       case ATH9K_CIPHER_WEP:
-               if (k->kv_len < LEN_WEP40) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                                "%s: WEP key length %u too small\n",
-                                __func__, k->kv_len);
-                       return false;
-               }
-               if (k->kv_len <= LEN_WEP40)
-                       keyType = AR_KEYTABLE_TYPE_40;
-               else if (k->kv_len <= LEN_WEP104)
-                       keyType = AR_KEYTABLE_TYPE_104;
-               else
-                       keyType = AR_KEYTABLE_TYPE_128;
-               break;
-       case ATH9K_CIPHER_CLR:
-               keyType = AR_KEYTABLE_TYPE_CLR;
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
-                        "%s: cipher %u not supported\n", __func__,
-                        k->kv_type);
-               return false;
-       }
-
-       key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
-       key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
-       key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
-       key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
-       key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
-       if (k->kv_len <= LEN_WEP104)
-               key4 &= 0xff;
-
-       if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
-               u16 micentry = entry + 64;
-
-               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
-               REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
-               REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-               REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
-               REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
-               (void) ath9k_hw_keysetmac(ah, entry, mac);
+                beaconintval);
+       DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__,
+                dtimperiod);
 
-               if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
-                       u32 mic0, mic1, mic2, mic3, mic4;
+       REG_WRITE(ah, AR_NEXT_DTIM,
+                 TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
+       REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
 
-                       mic0 = get_unaligned_le32(k->kv_mic + 0);
-                       mic2 = get_unaligned_le32(k->kv_mic + 4);
-                       mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
-                       mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
-                       mic4 = get_unaligned_le32(k->kv_txmic + 4);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
-                       REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
-                                 AR_KEYTABLE_TYPE_CLR);
+       REG_WRITE(ah, AR_SLEEP1,
+                 SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
+                 | AR_SLEEP1_ASSUME_DTIM);
 
-               } else {
-                       u32 mic0, mic2;
+       if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)
+               beacontimeout = (BEACON_TIMEOUT_VAL << 3);
+       else
+               beacontimeout = MIN_BEACON_TIMEOUT_VAL;
 
-                       mic0 = get_unaligned_le32(k->kv_mic + 0);
-                       mic2 = get_unaligned_le32(k->kv_mic + 4);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
-                       REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
-                       REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
-                                 AR_KEYTABLE_TYPE_CLR);
-               }
-               REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
-               REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
-       } else {
-               REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
-               REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
-               REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
-               REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
-               REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
-               REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+       REG_WRITE(ah, AR_SLEEP2,
+                 SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
 
-               (void) ath9k_hw_keysetmac(ah, entry, mac);
-       }
+       REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
+       REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
 
-       if (ah->ah_curchan == NULL)
-               return true;
+       REG_SET_BIT(ah, AR_TIMER_MODE,
+                   AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
+                   AR_DTIM_TIMER_EN);
 
-       return true;
 }
 
-bool
-ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       u32 txcfg, curLevel, newLevel;
-       enum ath9k_int omask;
+/***************/
+/* Rate tables */
+/***************/
 
-       if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
-               return false;
+static struct ath9k_rate_table ar5416_11a_table = {
+       8,
+       {0},
+       {
+               {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
+               {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
+               {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
+               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
+               {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
+               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
+               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
+               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
+       },
+};
 
-       omask = ath9k_hw_set_interrupts(ah,
-                                       ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+static struct ath9k_rate_table ar5416_11b_table = {
+       4,
+       {0},
+       {
+               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
+               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
+       },
+};
 
-       txcfg = REG_READ(ah, AR_TXCFG);
-       curLevel = MS(txcfg, AR_FTRIG);
-       newLevel = curLevel;
-       if (bIncTrigLevel) {
-               if (curLevel < MAX_TX_FIFO_THRESHOLD)
-                       newLevel++;
-       } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
-               newLevel--;
-       if (newLevel != curLevel)
-               REG_WRITE(ah, AR_TXCFG,
-                         (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+static struct ath9k_rate_table ar5416_11g_table = {
+       12,
+       {0},
+       {
+               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
+               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
 
-       ath9k_hw_set_interrupts(ah, omask);
+               {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
+               {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
+               {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
+               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
+               {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
+               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
+               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
+               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
+       },
+};
 
-       ah->ah_txTrigLevel = newLevel;
+static struct ath9k_rate_table ar5416_11ng_table = {
+       28,
+       {0},
+       {
+               {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+               {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+               {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
+               {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
 
-       return newLevel != curLevel;
-}
+               {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
+               {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
+               {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
+               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
+               {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
+               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
+               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
+               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
+               {true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
+               {true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
+               {true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
+               {true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
+               {true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
+               {true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
+               {true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
+               {true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
+               {true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
+               {true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
+               {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
+               {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
+               {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
+               {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
+               {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
+               {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
+       },
+};
+
+static struct ath9k_rate_table ar5416_11na_table = {
+       24,
+       {0},
+       {
+               {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
+               {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
+               {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
+               {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
+               {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
+               {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
+               {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
+               {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
+               {true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
+               {true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
+               {true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
+               {true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
+               {true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
+               {true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
+               {true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
+               {true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
+               {true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
+               {true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
+               {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
+               {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
+               {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
+               {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
+               {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
+               {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
+       },
+};
 
-bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
-                           const struct ath9k_tx_queue_info *qinfo)
+static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
+                                     struct ath9k_rate_table *rt)
 {
-       u32 cw;
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       struct ath9k_tx_queue_info *qi;
+       int i;
 
-       if (q >= pCap->total_queues) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-                        __func__, q);
-               return false;
-       }
+       if (rt->rateCodeToIndex[0] != 0)
+               return;
 
-       qi = &ahp->ah_txq[q];
-       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
-                        __func__);
-               return false;
+       for (i = 0; i < 256; i++)
+               rt->rateCodeToIndex[i] = (u8) -1;
+
+       for (i = 0; i < rt->rateCount; i++) {
+               u8 code = rt->info[i].rateCode;
+               u8 cix = rt->info[i].controlRate;
+
+               rt->rateCodeToIndex[code] = i;
+               rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
+
+               rt->info[i].lpAckDuration =
+                       ath9k_hw_computetxtime(ah, rt,
+                                              WLAN_CTRL_FRAME_SIZE,
+                                              cix,
+                                              false);
+               rt->info[i].spAckDuration =
+                       ath9k_hw_computetxtime(ah, rt,
+                                              WLAN_CTRL_FRAME_SIZE,
+                                              cix,
+                                              true);
        }
+}
 
-       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
+const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
+                                                    u32 mode)
+{
+       struct ath9k_rate_table *rt;
 
-       qi->tqi_ver = qinfo->tqi_ver;
-       qi->tqi_subtype = qinfo->tqi_subtype;
-       qi->tqi_qflags = qinfo->tqi_qflags;
-       qi->tqi_priority = qinfo->tqi_priority;
-       if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
-               qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
-       else
-               qi->tqi_aifs = INIT_AIFS;
-       if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
-               cw = min(qinfo->tqi_cwmin, 1024U);
-               qi->tqi_cwmin = 1;
-               while (qi->tqi_cwmin < cw)
-                       qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
-       } else
-               qi->tqi_cwmin = qinfo->tqi_cwmin;
-       if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
-               cw = min(qinfo->tqi_cwmax, 1024U);
-               qi->tqi_cwmax = 1;
-               while (qi->tqi_cwmax < cw)
-                       qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
-       } else
-               qi->tqi_cwmax = INIT_CWMAX;
-
-       if (qinfo->tqi_shretry != 0)
-               qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
-       else
-               qi->tqi_shretry = INIT_SH_RETRY;
-       if (qinfo->tqi_lgretry != 0)
-               qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
-       else
-               qi->tqi_lgretry = INIT_LG_RETRY;
-       qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
-       qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
-       qi->tqi_burstTime = qinfo->tqi_burstTime;
-       qi->tqi_readyTime = qinfo->tqi_readyTime;
-
-       switch (qinfo->tqi_subtype) {
-       case ATH9K_WME_UPSD:
-               if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
-                       qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+       switch (mode) {
+       case ATH9K_MODE_11A:
+               rt = &ar5416_11a_table;
                break;
-       default:
+       case ATH9K_MODE_11B:
+               rt = &ar5416_11b_table;
+               break;
+       case ATH9K_MODE_11G:
+               rt = &ar5416_11g_table;
+               break;
+       case ATH9K_MODE_11NG_HT20:
+       case ATH9K_MODE_11NG_HT40PLUS:
+       case ATH9K_MODE_11NG_HT40MINUS:
+               rt = &ar5416_11ng_table;
+               break;
+       case ATH9K_MODE_11NA_HT20:
+       case ATH9K_MODE_11NA_HT40PLUS:
+       case ATH9K_MODE_11NA_HT40MINUS:
+               rt = &ar5416_11na_table;
                break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
+                       __func__, mode);
+               return NULL;
        }
-       return true;
+
+       ath9k_hw_setup_rate_table(ah, rt);
+
+       return rt;
 }
 
-bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
-                           struct ath9k_tx_queue_info *qinfo)
+/*******************/
+/* HW Capabilities */
+/*******************/
+
+bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
        struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       struct ath9k_tx_queue_info *qi;
+       u16 capField = 0, eeval;
 
-       if (q >= pCap->total_queues) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-                        __func__, q);
-               return false;
-       }
+       eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0);
 
-       qi = &ahp->ah_txq[q];
-       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
-                        __func__);
-               return false;
-       }
+       ah->ah_currentRD = eeval;
 
-       qinfo->tqi_qflags = qi->tqi_qflags;
-       qinfo->tqi_ver = qi->tqi_ver;
-       qinfo->tqi_subtype = qi->tqi_subtype;
-       qinfo->tqi_qflags = qi->tqi_qflags;
-       qinfo->tqi_priority = qi->tqi_priority;
-       qinfo->tqi_aifs = qi->tqi_aifs;
-       qinfo->tqi_cwmin = qi->tqi_cwmin;
-       qinfo->tqi_cwmax = qi->tqi_cwmax;
-       qinfo->tqi_shretry = qi->tqi_shretry;
-       qinfo->tqi_lgretry = qi->tqi_lgretry;
-       qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
-       qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
-       qinfo->tqi_burstTime = qi->tqi_burstTime;
-       qinfo->tqi_readyTime = qi->tqi_readyTime;
+       eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1);
+       ah->ah_currentRDExt = eeval;
 
-       return true;
-}
+       capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP);
+
+       if (ah->ah_opmode != ATH9K_M_HOSTAP &&
+           ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+               if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
+                       ah->ah_currentRD += 5;
+               else if (ah->ah_currentRD == 0x41)
+                       ah->ah_currentRD = 0x43;
+               DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+                       "%s: regdomain mapped to 0x%x\n", __func__,
+                       ah->ah_currentRD);
+       }
 
-int
-ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
-                     const struct ath9k_tx_queue_info *qinfo)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_tx_queue_info *qi;
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       int q;
+       eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE);
+       bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
 
-       switch (type) {
-       case ATH9K_TX_QUEUE_BEACON:
-               q = pCap->total_queues - 1;
-               break;
-       case ATH9K_TX_QUEUE_CAB:
-               q = pCap->total_queues - 2;
-               break;
-       case ATH9K_TX_QUEUE_PSPOLL:
-               q = 1;
-               break;
-       case ATH9K_TX_QUEUE_UAPSD:
-               q = pCap->total_queues - 3;
-               break;
-       case ATH9K_TX_QUEUE_DATA:
-               for (q = 0; q < pCap->total_queues; q++)
-                       if (ahp->ah_txq[q].tqi_type ==
-                           ATH9K_TX_QUEUE_INACTIVE)
-                               break;
-               if (q == pCap->total_queues) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                                "%s: no available tx queue\n", __func__);
-                       return -1;
+       if (eeval & AR5416_OPFLAGS_11A) {
+               set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
+               if (ah->ah_config.ht_enable) {
+                       if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
+                               set_bit(ATH9K_MODE_11NA_HT20,
+                                       pCap->wireless_modes);
+                       if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
+                               set_bit(ATH9K_MODE_11NA_HT40PLUS,
+                                       pCap->wireless_modes);
+                               set_bit(ATH9K_MODE_11NA_HT40MINUS,
+                                       pCap->wireless_modes);
+                       }
                }
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
-                        __func__, type);
-               return -1;
        }
 
-       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
-
-       qi = &ahp->ah_txq[q];
-       if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                        "%s: tx queue %u already active\n", __func__, q);
-               return -1;
+       if (eeval & AR5416_OPFLAGS_11G) {
+               set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
+               set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
+               if (ah->ah_config.ht_enable) {
+                       if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
+                               set_bit(ATH9K_MODE_11NG_HT20,
+                                       pCap->wireless_modes);
+                       if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
+                               set_bit(ATH9K_MODE_11NG_HT40PLUS,
+                                       pCap->wireless_modes);
+                               set_bit(ATH9K_MODE_11NG_HT40MINUS,
+                                       pCap->wireless_modes);
+                       }
+               }
        }
-       memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
-       qi->tqi_type = type;
-       if (qinfo == NULL) {
-               qi->tqi_qflags =
-                       TXQ_FLAG_TXOKINT_ENABLE
-                       | TXQ_FLAG_TXERRINT_ENABLE
-                       | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
-               qi->tqi_aifs = INIT_AIFS;
-               qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
-               qi->tqi_cwmax = INIT_CWMAX;
-               qi->tqi_shretry = INIT_SH_RETRY;
-               qi->tqi_lgretry = INIT_LG_RETRY;
-               qi->tqi_physCompBuf = 0;
+
+       pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK);
+       if ((ah->ah_isPciExpress)
+           || (eeval & AR5416_OPFLAGS_11A)) {
+               pCap->rx_chainmask =
+                       ath9k_hw_get_eeprom(ah, EEP_RX_MASK);
        } else {
-               qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
-               (void) ath9k_hw_set_txq_props(ah, q, qinfo);
+               pCap->rx_chainmask =
+                       (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
        }
 
-       return q;
-}
-
-static void
-ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
-                           struct ath9k_tx_queue_info *qi)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
-                "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
-                __func__, ahp->ah_txOkInterruptMask,
-                ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
-                ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
-
-       REG_WRITE(ah, AR_IMR_S0,
-                 SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
-                 | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
-       REG_WRITE(ah, AR_IMR_S1,
-                 SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
-                 | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
-       REG_RMW_FIELD(ah, AR_IMR_S2,
-                     AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
-}
+       if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
+               ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
 
-bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       struct ath9k_tx_queue_info *qi;
+       pCap->low_2ghz_chan = 2312;
+       pCap->high_2ghz_chan = 2732;
 
-       if (q >= pCap->total_queues) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-                        __func__, q);
-               return false;
-       }
-       qi = &ahp->ah_txq[q];
-       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
-                        __func__, q);
-               return false;
-       }
+       pCap->low_5ghz_chan = 4920;
+       pCap->high_5ghz_chan = 6100;
 
-       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
-               __func__, q);
+       pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
+       pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
+       pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
 
-       qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
-       ahp->ah_txOkInterruptMask &= ~(1 << q);
-       ahp->ah_txErrInterruptMask &= ~(1 << q);
-       ahp->ah_txDescInterruptMask &= ~(1 << q);
-       ahp->ah_txEolInterruptMask &= ~(1 << q);
-       ahp->ah_txUrnInterruptMask &= ~(1 << q);
-       ath9k_hw_set_txq_interrupts(ah, qi);
+       pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
+       pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
+       pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
 
-       return true;
-}
+       pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
 
-bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-       struct ath9k_channel *chan = ah->ah_curchan;
-       struct ath9k_tx_queue_info *qi;
-       u32 cwMin, chanCwMin, value;
+       if (ah->ah_config.ht_enable)
+               pCap->hw_caps |= ATH9K_HW_CAP_HT;
+       else
+               pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
 
-       if (q >= pCap->total_queues) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
-                        __func__, q);
-               return false;
-       }
-       qi = &ahp->ah_txq[q];
-       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
-                        __func__, q);
-               return true;
-       }
+       pCap->hw_caps |= ATH9K_HW_CAP_GTT;
+       pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
+       pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
+       pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
 
-       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
+       if (capField & AR_EEPROM_EEPCAP_MAXQCU)
+               pCap->total_queues =
+                       MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
+       else
+               pCap->total_queues = ATH9K_NUM_TX_QUEUES;
 
-       if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
-               if (chan && IS_CHAN_B(chan))
-                       chanCwMin = INIT_CWMIN_11B;
-               else
-                       chanCwMin = INIT_CWMIN;
-
-               for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
-       } else
-               cwMin = qi->tqi_cwmin;
-
-       REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN)
-                 | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
-                 | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
-
-       REG_WRITE(ah, AR_DRETRY_LIMIT(q),
-                 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
-                 | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
-                 | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
-
-       REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
-       REG_WRITE(ah, AR_DMISC(q),
-                 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
-
-       if (qi->tqi_cbrPeriod) {
-               REG_WRITE(ah, AR_QCBRCFG(q),
-                         SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL)
-                         | SM(qi->tqi_cbrOverflowLimit,
-                              AR_Q_CBRCFG_OVF_THRESH));
-               REG_WRITE(ah, AR_QMISC(q),
-                         REG_READ(ah,
-                                  AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi->
-                                       tqi_cbrOverflowLimit
-                                       ?
-                                       AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN
-                                       :
-                                       0));
-       }
-       if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
-               REG_WRITE(ah, AR_QRDYTIMECFG(q),
-                         SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
-                         AR_Q_RDYTIMECFG_EN);
-       }
+       if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
+               pCap->keycache_size =
+                       1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
+       else
+               pCap->keycache_size = AR_KEYTABLE_SIZE;
 
-       REG_WRITE(ah, AR_DCHNTIME(q),
-                 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
-                 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+       pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
+       pCap->num_mr_retries = 4;
+       pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
 
-       if (qi->tqi_burstTime
-           && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
-               REG_WRITE(ah, AR_QMISC(q),
-                         REG_READ(ah,
-                                  AR_QMISC(q)) |
-                         AR_Q_MISC_RDYTIME_EXP_POLICY);
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               pCap->num_gpio_pins = AR928X_NUM_GPIO;
+       else
+               pCap->num_gpio_pins = AR_NUM_GPIO;
 
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               pCap->hw_caps |= ATH9K_HW_CAP_WOW;
+               pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+       } else {
+               pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
+               pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
        }
 
-       if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
-               REG_WRITE(ah, AR_DMISC(q),
-                         REG_READ(ah, AR_DMISC(q)) |
-                         AR_D_MISC_POST_FR_BKOFF_DIS);
-       }
-       if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
-               REG_WRITE(ah, AR_DMISC(q),
-                         REG_READ(ah, AR_DMISC(q)) |
-                         AR_D_MISC_FRAG_BKOFF_EN);
-       }
-       switch (qi->tqi_type) {
-       case ATH9K_TX_QUEUE_BEACON:
-               REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-                         | AR_Q_MISC_FSP_DBA_GATED
-                         | AR_Q_MISC_BEACON_USE
-                         | AR_Q_MISC_CBR_INCR_DIS1);
-
-               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-                         | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
-                            AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
-                         | AR_D_MISC_BEACON_USE
-                         | AR_D_MISC_POST_FR_BKOFF_DIS);
-               break;
-       case ATH9K_TX_QUEUE_CAB:
-               REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
-                         | AR_Q_MISC_FSP_DBA_GATED
-                         | AR_Q_MISC_CBR_INCR_DIS1
-                         | AR_Q_MISC_CBR_INCR_DIS0);
-               value = (qi->tqi_readyTime
-                        - (ah->ah_config.sw_beacon_response_time -
-                           ah->ah_config.dma_beacon_response_time)
-                        -
-                        ah->ah_config.additional_swba_backoff) *
-                       1024;
-               REG_WRITE(ah, AR_QRDYTIMECFG(q),
-                         value | AR_Q_RDYTIMECFG_EN);
-               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-                         | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
-                            AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
-               break;
-       case ATH9K_TX_QUEUE_PSPOLL:
-               REG_WRITE(ah, AR_QMISC(q),
-                         REG_READ(ah,
-                                  AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
-               break;
-       case ATH9K_TX_QUEUE_UAPSD:
-               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
-                         | AR_D_MISC_POST_FR_BKOFF_DIS);
-               break;
-       default:
-               break;
+       if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
+               pCap->hw_caps |= ATH9K_HW_CAP_CST;
+               pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
+       } else {
+               pCap->rts_aggr_limit = (8 * 1024);
        }
 
-       if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
-               REG_WRITE(ah, AR_DMISC(q),
-                         REG_READ(ah, AR_DMISC(q)) |
-                         SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
-                            AR_D_MISC_ARB_LOCKOUT_CNTRL) |
-                         AR_D_MISC_POST_FR_BKOFF_DIS);
+       pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
+
+#ifdef CONFIG_RFKILL
+       ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT);
+       if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
+               ah->ah_rfkill_gpio =
+                       MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
+               ah->ah_rfkill_polarity =
+                       MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
+
+               pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
        }
+#endif
 
-       if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
-               ahp->ah_txOkInterruptMask |= 1 << q;
-       else
-               ahp->ah_txOkInterruptMask &= ~(1 << q);
-       if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
-               ahp->ah_txErrInterruptMask |= 1 << q;
-       else
-               ahp->ah_txErrInterruptMask &= ~(1 << q);
-       if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
-               ahp->ah_txDescInterruptMask |= 1 << q;
-       else
-               ahp->ah_txDescInterruptMask &= ~(1 << q);
-       if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
-               ahp->ah_txEolInterruptMask |= 1 << q;
-       else
-               ahp->ah_txEolInterruptMask &= ~(1 << q);
-       if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
-               ahp->ah_txUrnInterruptMask |= 1 << q;
+       if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
+           (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
+           (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
+           (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
+           (ah->ah_macVersion == AR_SREV_VERSION_9280))
+               pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
        else
-               ahp->ah_txUrnInterruptMask &= ~(1 << q);
-       ath9k_hw_set_txq_interrupts(ah, qi);
-
-       return true;
-}
+               pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
 
-void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
-{
-       struct ath_hal_5416 *ahp = AH5416(ah);
-       *txqs &= ahp->ah_intrTxqs;
-       ahp->ah_intrTxqs &= ~(*txqs);
-}
+       if (AR_SREV_9280(ah))
+               pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
+       else
+               pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
 
-bool
-ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
-                   u32 segLen, bool firstSeg,
-                   bool lastSeg, const struct ath_desc *ds0)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if (firstSeg) {
-               ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
-       } else if (lastSeg) {
-               ads->ds_ctl0 = 0;
-               ads->ds_ctl1 = segLen;
-               ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
-               ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+       if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
+               pCap->reg_cap =
+                       AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+                       AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
+                       AR_EEPROM_EEREGCAP_EN_KK_U2 |
+                       AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
        } else {
-               ads->ds_ctl0 = 0;
-               ads->ds_ctl1 = segLen | AR_TxMore;
-               ads->ds_ctl2 = 0;
-               ads->ds_ctl3 = 0;
+               pCap->reg_cap =
+                       AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+                       AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
        }
-       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-       return true;
-}
 
-void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
+       pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
+
+       pCap->num_antcfg_5ghz =
+               ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_5GHZ);
+       pCap->num_antcfg_2ghz =
+               ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_2GHZ);
 
-       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+       return true;
 }
 
-int
-ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+                           u32 capability, u32 *result)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if ((ads->ds_txstatus9 & AR_TxDone) == 0)
-               return -EINPROGRESS;
-
-       ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
-       ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
-       ds->ds_txstat.ts_status = 0;
-       ds->ds_txstat.ts_flags = 0;
-
-       if (ads->ds_txstatus1 & AR_ExcessiveRetries)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
-       if (ads->ds_txstatus1 & AR_Filtered)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
-       if (ads->ds_txstatus1 & AR_FIFOUnderrun)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
-       if (ads->ds_txstatus9 & AR_TxOpExceeded)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
-       if (ads->ds_txstatus1 & AR_TxTimerExpired)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
-       if (ads->ds_txstatus1 & AR_DescCfgErr)
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
-       if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
-               ath9k_hw_updatetxtriglevel(ah, true);
-       }
-       if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
-               ath9k_hw_updatetxtriglevel(ah, true);
-       }
-       if (ads->ds_txstatus0 & AR_TxBaStatus) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
-               ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
-               ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
-       }
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
 
-       ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
-       switch (ds->ds_txstat.ts_rateindex) {
-       case 0:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
-               break;
-       case 1:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
-               break;
-       case 2:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
-               break;
-       case 3:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
-               break;
+       switch (type) {
+       case ATH9K_CAP_CIPHER:
+               switch (capability) {
+               case ATH9K_CIPHER_AES_CCM:
+               case ATH9K_CIPHER_AES_OCB:
+               case ATH9K_CIPHER_TKIP:
+               case ATH9K_CIPHER_WEP:
+               case ATH9K_CIPHER_MIC:
+               case ATH9K_CIPHER_CLR:
+                       return true;
+               default:
+                       return false;
+               }
+       case ATH9K_CAP_TKIP_MIC:
+               switch (capability) {
+               case 0:
+                       return true;
+               case 1:
+                       return (ahp->ah_staId1Defaults &
+                               AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
+                       false;
+               }
+       case ATH9K_CAP_TKIP_SPLIT:
+               return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
+                       false : true;
+       case ATH9K_CAP_WME_TKIPMIC:
+               return 0;
+       case ATH9K_CAP_PHYCOUNTERS:
+               return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
+       case ATH9K_CAP_DIVERSITY:
+               return (REG_READ(ah, AR_PHY_CCK_DETECT) &
+                       AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
+                       true : false;
+       case ATH9K_CAP_PHYDIAG:
+               return true;
+       case ATH9K_CAP_MCAST_KEYSRCH:
+               switch (capability) {
+               case 0:
+                       return true;
+               case 1:
+                       if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
+                               return false;
+                       } else {
+                               return (ahp->ah_staId1Defaults &
+                                       AR_STA_ID1_MCAST_KSRCH) ? true :
+                                       false;
+                       }
+               }
+               return false;
+       case ATH9K_CAP_TSF_ADJUST:
+               return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
+                       true : false;
+       case ATH9K_CAP_RFSILENT:
+               if (capability == 3)
+                       return false;
+       case ATH9K_CAP_ANT_CFG_2GHZ:
+               *result = pCap->num_antcfg_2ghz;
+               return true;
+       case ATH9K_CAP_ANT_CFG_5GHZ:
+               *result = pCap->num_antcfg_5ghz;
+               return true;
+       case ATH9K_CAP_TXPOW:
+               switch (capability) {
+               case 0:
+                       return 0;
+               case 1:
+                       *result = ah->ah_powerLimit;
+                       return 0;
+               case 2:
+                       *result = ah->ah_maxPowerLevel;
+                       return 0;
+               case 3:
+                       *result = ah->ah_tpScale;
+                       return 0;
+               }
+               return false;
+       default:
+               return false;
        }
-
-       ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
-       ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
-       ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
-       ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
-       ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
-       ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
-       ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
-       ds->ds_txstat.evm0 = ads->AR_TxEVM0;
-       ds->ds_txstat.evm1 = ads->AR_TxEVM1;
-       ds->ds_txstat.evm2 = ads->AR_TxEVM2;
-       ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
-       ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
-       ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
-       ds->ds_txstat.ts_antenna = 1;
-
-       return 0;
 }
 
-void
-ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
-                      u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
-                      u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+                           u32 capability, u32 setting, int *status)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
        struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 v;
 
-       txPower += ahp->ah_txPowerIndexOffset;
-       if (txPower > 63)
-               txPower = 63;
-
-       ads->ds_ctl0 = (pktLen & AR_FrameLen)
-               | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
-               | SM(txPower, AR_XmitPower)
-               | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-               | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
-               | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
-               | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
-       ads->ds_ctl1 =
-               (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
-               | SM(type, AR_FrameType)
-               | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
-               | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
-               | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
-
-       ads->ds_ctl6 = SM(keyType, AR_EncrType);
-
-       if (AR_SREV_9285(ah)) {
-
-               ads->ds_ctl8 = 0;
-               ads->ds_ctl9 = 0;
-               ads->ds_ctl10 = 0;
-               ads->ds_ctl11 = 0;
+       switch (type) {
+       case ATH9K_CAP_TKIP_MIC:
+               if (setting)
+                       ahp->ah_staId1Defaults |=
+                               AR_STA_ID1_CRPT_MIC_ENABLE;
+               else
+                       ahp->ah_staId1Defaults &=
+                               ~AR_STA_ID1_CRPT_MIC_ENABLE;
+               return true;
+       case ATH9K_CAP_DIVERSITY:
+               v = REG_READ(ah, AR_PHY_CCK_DETECT);
+               if (setting)
+                       v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+               else
+                       v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+               REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+               return true;
+       case ATH9K_CAP_MCAST_KEYSRCH:
+               if (setting)
+                       ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
+               else
+                       ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
+               return true;
+       case ATH9K_CAP_TSF_ADJUST:
+               if (setting)
+                       ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+               else
+                       ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+               return true;
+       default:
+               return false;
        }
 }
 
-void
-ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
-                            struct ath_desc *lastds,
-                            u32 durUpdateEn, u32 rtsctsRate,
-                            u32 rtsctsDuration,
-                            struct ath9k_11n_rate_series series[],
-                            u32 nseries, u32 flags)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       struct ar5416_desc *last_ads = AR5416DESC(lastds);
-       u32 ds_ctl0;
+/****************************/
+/* GPIO / RFKILL / Antennae */
+/****************************/
 
-       (void) nseries;
-       (void) rtsctsDuration;
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
+                                        u32 gpio, u32 type)
+{
+       int addr;
+       u32 gpio_shift, tmp;
 
-       if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
-               ds_ctl0 = ads->ds_ctl0;
+       if (gpio > 11)
+               addr = AR_GPIO_OUTPUT_MUX3;
+       else if (gpio > 5)
+               addr = AR_GPIO_OUTPUT_MUX2;
+       else
+               addr = AR_GPIO_OUTPUT_MUX1;
 
-               if (flags & ATH9K_TXDESC_RTSENA) {
-                       ds_ctl0 &= ~AR_CTSEnable;
-                       ds_ctl0 |= AR_RTSEnable;
-               } else {
-                       ds_ctl0 &= ~AR_RTSEnable;
-                       ds_ctl0 |= AR_CTSEnable;
-               }
+       gpio_shift = (gpio % 6) * 5;
 
-               ads->ds_ctl0 = ds_ctl0;
+       if (AR_SREV_9280_20_OR_LATER(ah)
+           || (addr != AR_GPIO_OUTPUT_MUX1)) {
+               REG_RMW(ah, addr, (type << gpio_shift),
+                       (0x1f << gpio_shift));
        } else {
-               ads->ds_ctl0 =
-                       (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+               tmp = REG_READ(ah, addr);
+               tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+               tmp &= ~(0x1f << gpio_shift);
+               tmp |= (type << gpio_shift);
+               REG_WRITE(ah, addr, tmp);
        }
-
-       ads->ds_ctl2 = set11nTries(series, 0)
-               | set11nTries(series, 1)
-               | set11nTries(series, 2)
-               | set11nTries(series, 3)
-               | (durUpdateEn ? AR_DurUpdateEna : 0)
-               | SM(0, AR_BurstDur);
-
-       ads->ds_ctl3 = set11nRate(series, 0)
-               | set11nRate(series, 1)
-               | set11nRate(series, 2)
-               | set11nRate(series, 3);
-
-       ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
-               | set11nPktDurRTSCTS(series, 1);
-
-       ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
-               | set11nPktDurRTSCTS(series, 3);
-
-       ads->ds_ctl7 = set11nRateFlags(series, 0)
-               | set11nRateFlags(series, 1)
-               | set11nRateFlags(series, 2)
-               | set11nRateFlags(series, 3)
-               | SM(rtsctsRate, AR_RTSCTSRate);
-       last_ads->ds_ctl2 = ads->ds_ctl2;
-       last_ads->ds_ctl3 = ads->ds_ctl3;
 }
 
-void
-ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
-                          u32 aggrLen)
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
-       ads->ds_ctl6 &= ~AR_AggrLen;
-       ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
-}
+       u32 gpio_shift;
 
-void
-ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
-                           u32 numDelims)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       unsigned int ctl6;
+       ASSERT(gpio < ah->ah_caps.num_gpio_pins);
 
-       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+       gpio_shift = gpio << 1;
 
-       ctl6 = ads->ds_ctl6;
-       ctl6 &= ~AR_PadDelim;
-       ctl6 |= SM(numDelims, AR_PadDelim);
-       ads->ds_ctl6 = ctl6;
+       REG_RMW(ah,
+               AR_GPIO_OE_OUT,
+               (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+               (AR_GPIO_OE_OUT_DRV << gpio_shift));
 }
 
-void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
+       if (gpio >= ah->ah_caps.num_gpio_pins)
+               return 0xffffffff;
 
-       ads->ds_ctl1 |= AR_IsAggr;
-       ads->ds_ctl1 &= ~AR_MoreAggr;
-       ads->ds_ctl6 &= ~AR_PadDelim;
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               return (MS
+                       (REG_READ(ah, AR_GPIO_IN_OUT),
+                        AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
+       } else {
+               return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
+                       AR_GPIO_BIT(gpio)) != 0;
+       }
 }
 
-void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+                        u32 ah_signal_type)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
+       u32 gpio_shift;
 
-       ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
-}
+       ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
 
-void
-ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
-                             u32 burstDuration)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
+       gpio_shift = 2 * gpio;
 
-       ads->ds_ctl2 &= ~AR_BurstDur;
-       ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+       REG_RMW(ah,
+               AR_GPIO_OE_OUT,
+               (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
+               (AR_GPIO_OE_OUT_DRV << gpio_shift));
 }
 
-void
-ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
-                               u32 vmf)
+void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if (vmf)
-               ads->ds_ctl0 |= AR_VirtMoreFrag;
-       else
-               ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+       REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
+               AR_GPIO_BIT(gpio));
 }
 
-void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+#ifdef CONFIG_RFKILL
+void ath9k_enable_rfkill(struct ath_hal *ah)
 {
-       REG_WRITE(ah, AR_RXDP, rxdp);
-}
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
 
-void ath9k_hw_rxena(struct ath_hal *ah)
-{
-       REG_WRITE(ah, AR_CR, AR_CR_RXE);
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+                   AR_GPIO_INPUT_MUX2_RFSILENT);
+
+       ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
 }
+#endif
 
-bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
 {
-       if (set) {
-
-               REG_SET_BIT(ah, AR_DIAG_SW,
-                           (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
-               if (!ath9k_hw_wait
-                   (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
-                       u32 reg;
-
-                       REG_CLR_BIT(ah, AR_DIAG_SW,
-                                   (AR_DIAG_RX_DIS |
-                                    AR_DIAG_RX_ABORT));
+       struct ath9k_channel *chan = ah->ah_curchan;
+       const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       u16 ant_config;
+       u32 halNumAntConfig;
 
-                       reg = REG_READ(ah, AR_OBS_BUS_1);
-                       DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
-                               "%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
-                               __func__, reg);
+       halNumAntConfig = IS_CHAN_2GHZ(chan) ?
+               pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz;
 
-                       return false;
+       if (cfg < halNumAntConfig) {
+               if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan,
+                                                    cfg, &ant_config)) {
+                       REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+                       return 0;
                }
-       } else {
-               REG_CLR_BIT(ah, AR_DIAG_SW,
-                           (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
        }
 
-       return true;
-}
-
-void
-ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
-                       u32 filter1)
-{
-       REG_WRITE(ah, AR_MCAST_FIL0, filter0);
-       REG_WRITE(ah, AR_MCAST_FIL1, filter1);
+       return -EINVAL;
 }
 
-bool
-ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
-                    u32 size, u32 flags)
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
 {
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
-
-       ads->ds_ctl1 = size & AR_BufLen;
-       if (flags & ATH9K_RXDESC_INTREQ)
-               ads->ds_ctl1 |= AR_RxIntrReq;
-
-       ads->ds_rxstatus8 &= ~AR_RxDone;
-       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
-               memset(&(ads->u), 0, sizeof(ads->u));
-       return true;
+       return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
 }
 
-int
-ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
-                   u32 pa, struct ath_desc *nds, u64 tsf)
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
 {
-       struct ar5416_desc ads;
-       struct ar5416_desc *adsp = AR5416DESC(ds);
-
-       if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
-               return -EINPROGRESS;
-
-       ads.u.rx = adsp->u.rx;
-
-       ds->ds_rxstat.rs_status = 0;
-       ds->ds_rxstat.rs_flags = 0;
-
-       ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
-       ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
-
-       ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-       ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
-       ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
-       ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
-       ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
-       ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
-       ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
-       if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
-               ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
-       else
-               ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
-
-       ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
-       ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
-
-       ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
-       ds->ds_rxstat.rs_moreaggr =
-               (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
-       ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
-       ds->ds_rxstat.rs_flags =
-               (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
-       ds->ds_rxstat.rs_flags |=
-               (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
-
-       if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
-       if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
-       if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
-
-       if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
-
-               if (ads.ds_rxstatus8 & AR_CRCErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
-               else if (ads.ds_rxstatus8 & AR_PHYErr) {
-                       u32 phyerr;
-
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
-                       phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
-                       ds->ds_rxstat.rs_phyerr = phyerr;
-               } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
-               else if (ads.ds_rxstatus8 & AR_MichaelErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
-       }
-
-       return 0;
+       REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
 }
 
-static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
-                                     struct ath9k_rate_table *rt)
+bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
+                              enum ath9k_ant_setting settings,
+                              struct ath9k_channel *chan,
+                              u8 *tx_chainmask,
+                              u8 *rx_chainmask,
+                              u8 *antenna_cfgd)
 {
-       int i;
-
-       if (rt->rateCodeToIndex[0] != 0)
-               return;
-       for (i = 0; i < 256; i++)
-               rt->rateCodeToIndex[i] = (u8) -1;
-       for (i = 0; i < rt->rateCount; i++) {
-               u8 code = rt->info[i].rateCode;
-               u8 cix = rt->info[i].controlRate;
-
-               rt->rateCodeToIndex[code] = i;
-               rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       static u8 tx_chainmask_cfg, rx_chainmask_cfg;
 
-               rt->info[i].lpAckDuration =
-                       ath9k_hw_computetxtime(ah, rt,
-                                              WLAN_CTRL_FRAME_SIZE,
-                                              cix,
-                                              false);
-               rt->info[i].spAckDuration =
-                       ath9k_hw_computetxtime(ah, rt,
-                                              WLAN_CTRL_FRAME_SIZE,
-                                              cix,
-                                              true);
-       }
-}
+       if (AR_SREV_9280(ah)) {
+               if (!tx_chainmask_cfg) {
 
-const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
-                                                  u32 mode)
-{
-       struct ath9k_rate_table *rt;
-       switch (mode) {
-       case ATH9K_MODE_11A:
-               rt = &ar5416_11a_table;
-               break;
-       case ATH9K_MODE_11B:
-               rt = &ar5416_11b_table;
-               break;
-       case ATH9K_MODE_11G:
-               rt = &ar5416_11g_table;
-               break;
-       case ATH9K_MODE_11NG_HT20:
-       case ATH9K_MODE_11NG_HT40PLUS:
-       case ATH9K_MODE_11NG_HT40MINUS:
-               rt = &ar5416_11ng_table;
-               break;
-       case ATH9K_MODE_11NA_HT20:
-       case ATH9K_MODE_11NA_HT40PLUS:
-       case ATH9K_MODE_11NA_HT40MINUS:
-               rt = &ar5416_11na_table;
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
-                        __func__, mode);
-               return NULL;
-       }
-       ath9k_hw_setup_rate_table(ah, rt);
-       return rt;
-}
+                       tx_chainmask_cfg = *tx_chainmask;
+                       rx_chainmask_cfg = *rx_chainmask;
+               }
 
-static const char *ath9k_hw_devname(u16 devid)
-{
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-       case AR5416_DEVID_PCIE:
-               return "Atheros 5416";
-       case AR9160_DEVID_PCI:
-               return "Atheros 9160";
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-               return "Atheros 9280";
+               switch (settings) {
+               case ATH9K_ANT_FIXED_A:
+                       *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+                       *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+                       *antenna_cfgd = true;
+                       break;
+               case ATH9K_ANT_FIXED_B:
+                       if (ah->ah_caps.tx_chainmask >
+                           ATH9K_ANTENNA1_CHAINMASK) {
+                               *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+                       }
+                       *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+                       *antenna_cfgd = true;
+                       break;
+               case ATH9K_ANT_VARIABLE:
+                       *tx_chainmask = tx_chainmask_cfg;
+                       *rx_chainmask = rx_chainmask_cfg;
+                       *antenna_cfgd = true;
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               ahp->ah_diversityControl = settings;
        }
-       return NULL;
-}
 
-const char *ath9k_hw_probe(u16 vendorid, u16 devid)
-{
-       return vendorid == ATHEROS_VENDOR_ID ?
-               ath9k_hw_devname(devid) : NULL;
+       return true;
 }
 
-struct ath_hal *ath9k_hw_attach(u16 devid,
-                               struct ath_softc *sc,
-                               void __iomem *mem,
-                               int *error)
+/*********************/
+/* General Operation */
+/*********************/
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
 {
-       struct ath_hal *ah = NULL;
+       u32 bits = REG_READ(ah, AR_RX_FILTER);
+       u32 phybits = REG_READ(ah, AR_PHY_ERR);
 
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-       case AR5416_DEVID_PCIE:
-       case AR9160_DEVID_PCI:
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-               ah = ath9k_hw_do_attach(devid, sc, mem, error);
-               break;
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                        "devid=0x%x not supported.\n", devid);
-               ah = NULL;
-               *error = -ENXIO;
-               break;
-       }
+       if (phybits & AR_PHY_ERR_RADAR)
+               bits |= ATH9K_RX_FILTER_PHYRADAR;
+       if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
+               bits |= ATH9K_RX_FILTER_PHYERR;
 
-       return ah;
+       return bits;
 }
 
-u16
-ath9k_hw_computetxtime(struct ath_hal *ah,
-                      const struct ath9k_rate_table *rates,
-                      u32 frameLen, u16 rateix,
-                      bool shortPreamble)
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
 {
-       u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
-       u32 kbps;
-
-       kbps = rates->info[rateix].rateKbps;
-
-       if (kbps == 0)
-               return 0;
-       switch (rates->info[rateix].phy) {
+       u32 phybits;
 
-       case PHY_CCK:
-               phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
-               if (shortPreamble && rates->info[rateix].shortPreamble)
-                       phyTime >>= 1;
-               numBits = frameLen << 3;
-               txTime = CCK_SIFS_TIME + phyTime
-                       + ((numBits * 1000) / kbps);
-               break;
-       case PHY_OFDM:
-               if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
-                       bitsPerSymbol =
-                               (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+       REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
+       phybits = 0;
+       if (bits & ATH9K_RX_FILTER_PHYRADAR)
+               phybits |= AR_PHY_ERR_RADAR;
+       if (bits & ATH9K_RX_FILTER_PHYERR)
+               phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+       REG_WRITE(ah, AR_PHY_ERR, phybits);
 
-                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
-                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-                       txTime = OFDM_SIFS_TIME_QUARTER
-                               + OFDM_PREAMBLE_TIME_QUARTER
-                               + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
-               } else if (ah->ah_curchan &&
-                          IS_CHAN_HALF_RATE(ah->ah_curchan)) {
-                       bitsPerSymbol =
-                               (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+       if (phybits)
+               REG_WRITE(ah, AR_RXCFG,
+                         REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
+       else
+               REG_WRITE(ah, AR_RXCFG,
+                         REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+}
 
-                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
-                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-                       txTime = OFDM_SIFS_TIME_HALF +
-                               OFDM_PREAMBLE_TIME_HALF
-                               + (numSymbols * OFDM_SYMBOL_TIME_HALF);
-               } else {
-                       bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+bool ath9k_hw_phy_disable(struct ath_hal *ah)
+{
+       return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
+}
 
-                       numBits = OFDM_PLCP_BITS + (frameLen << 3);
-                       numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
-                       txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
-                               + (numSymbols * OFDM_SYMBOL_TIME);
-               }
-               break;
+bool ath9k_hw_disable(struct ath_hal *ah)
+{
+       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+               return false;
 
-       default:
-               DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
-                        "%s: unknown phy %u (rate ix %u)\n", __func__,
-                        rates->info[rateix].phy, rateix);
-               txTime = 0;
-               break;
-       }
-       return txTime;
+       return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
 }
 
-u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
 {
-       if (flags & CHANNEL_2GHZ) {
-               if (freq == 2484)
-                       return 14;
-               if (freq < 2484)
-                       return (freq - 2407) / 5;
-               else
-                       return 15 + ((freq - 2512) / 20);
-       } else if (flags & CHANNEL_5GHZ) {
-               if (ath9k_regd_is_public_safety_sku(ah) &&
-                   IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
-                       return ((freq * 10) +
-                               (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
-               } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
-                       return (freq - 4000) / 5;
-               } else {
-                       return (freq - 5000) / 5;
-               }
-       } else {
-               if (freq == 2484)
-                       return 14;
-               if (freq < 2484)
-                       return (freq - 2407) / 5;
-               if (freq < 5000) {
-                       if (ath9k_regd_is_public_safety_sku(ah)
-                           && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
-                               return ((freq * 10) +
-                                       (((freq % 5) ==
-                                         2) ? 5 : 0) - 49400) / 5;
-                       } else if (freq > 4900) {
-                               return (freq - 4000) / 5;
-                       } else {
-                               return 15 + ((freq - 2512) / 20);
-                       }
-               }
-               return (freq - 5000) / 5;
-       }
-}
+       struct ath9k_channel *chan = ah->ah_curchan;
 
-/* We can tune this as we go by monitoring really low values */
-#define ATH9K_NF_TOO_LOW       -60
+       ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
 
-/* AR5416 may return very high value (like -31 dBm), in those cases the nf
- * is incorrect and we should use the static NF value. Later we can try to
- * find out why they are reporting these values */
-static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
-{
-       if (nf > ATH9K_NF_TOO_LOW) {
-               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                        "%s: noise floor value detected (%d) is "
-                       "lower than what we think is a "
-                       "reasonable value (%d)\n",
-                        __func__, nf, ATH9K_NF_TOO_LOW);
+       if (ath9k_hw_set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(ah, chan),
+                                ath9k_regd_get_antenna_allowed(ah, chan),
+                                chan->maxRegTxPower * 2,
+                                min((u32) MAX_RATE_POWER,
+                                    (u32) ah->ah_powerLimit)) != 0)
                return false;
-       }
+
        return true;
 }
 
-s16
-ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
 {
-       struct ath9k_channel *ichan;
-       s16 nf;
-
-       ichan = ath9k_regd_check_channel(ah, chan);
-       if (ichan == NULL) {
-               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
-                        "%s: invalid channel %u/0x%x; no mapping\n",
-                        __func__, chan->channel, chan->channelFlags);
-               return ATH_DEFAULT_NOISE_FLOOR;
-       }
-       if (ichan->rawNoiseFloor == 0) {
-               enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
-               nf = NOISE_FLOOR[mode];
-       } else
-               nf = ichan->rawNoiseFloor;
-
-       if (!ath9k_hw_nf_in_range(ah, nf))
-               nf = ATH_DEFAULT_NOISE_FLOOR;
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
-       return nf;
+       memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
 }
 
-bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
 {
        struct ath_hal_5416 *ahp = AH5416(ah);
 
-       if (setting)
-               ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
-       else
-               ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+       memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
+
        return true;
 }
 
-bool ath9k_hw_phycounters(struct ath_hal *ah)
+void ath9k_hw_setopmode(struct ath_hal *ah)
 {
-       struct ath_hal_5416 *ahp = AH5416(ah);
-
-       return ahp->ah_hasHwPhyCounters ? true : false;
+       ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
 }
 
-u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1)
 {
-       return REG_READ(ah, AR_QTXDP(q));
+       REG_WRITE(ah, AR_MCAST_FIL0, filter0);
+       REG_WRITE(ah, AR_MCAST_FIL1, filter1);
 }
 
-bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
-                      u32 txdp)
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
 {
-       REG_WRITE(ah, AR_QTXDP(q), txdp);
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
-       return true;
+       memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
 }
 
-bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
 {
-       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
 
-       REG_WRITE(ah, AR_Q_TXE, 1 << q);
+       REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
+       REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
 
        return true;
 }
 
-u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId)
 {
-       u32 npend;
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
-       npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
-       if (npend == 0) {
+       memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
+       ahp->ah_assocId = assocId;
 
-               if (REG_READ(ah, AR_Q_TXE) & (1 << q))
-                       npend = 1;
-       }
-       return npend;
+       REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
+       REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
+                 ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
 }
 
-bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+u64 ath9k_hw_gettsf64(struct ath_hal *ah)
 {
-       u32 wait;
-
-       REG_WRITE(ah, AR_Q_TXD, 1 << q);
-
-       for (wait = 1000; wait != 0; wait--) {
-               if (ath9k_hw_numtxpending(ah, q) == 0)
-                       break;
-               udelay(100);
-       }
+       u64 tsf;
 
-       if (ath9k_hw_numtxpending(ah, q)) {
-               u32 tsfLow, j;
+       tsf = REG_READ(ah, AR_TSF_U32);
+       tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
 
-               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                        "%s: Num of pending TX Frames %d on Q %d\n",
-                        __func__, ath9k_hw_numtxpending(ah, q), q);
+       return tsf;
+}
 
-               for (j = 0; j < 2; j++) {
-                       tsfLow = REG_READ(ah, AR_TSF_L32);
-                       REG_WRITE(ah, AR_QUIET2,
-                                 SM(10, AR_QUIET2_QUIET_DUR));
-                       REG_WRITE(ah, AR_QUIET_PERIOD, 100);
-                       REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
-                       REG_SET_BIT(ah, AR_TIMER_MODE,
-                                      AR_QUIET_TIMER_EN);
+void ath9k_hw_reset_tsf(struct ath_hal *ah)
+{
+       int count;
 
-                       if ((REG_READ(ah, AR_TSF_L32) >> 10) ==
-                           (tsfLow >> 10)) {
-                               break;
-                       }
-                       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                               "%s: TSF have moved while trying to set "
-                               "quiet time TSF: 0x%08x\n",
-                               __func__, tsfLow);
+       count = 0;
+       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+               count++;
+               if (count > 10) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                               "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n",
+                               __func__);
+                       break;
                }
+               udelay(10);
+       }
+       REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+}
 
-               REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
-               udelay(200);
-               REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+       if (setting)
+               ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+       else
+               ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
 
-               wait = 1000;
+       return true;
+}
 
-               while (ath9k_hw_numtxpending(ah, q)) {
-                       if ((--wait) == 0) {
-                               DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
-                                       "%s: Failed to stop Tx DMA in 100 "
-                                       "msec after killing last frame\n",
-                                       __func__);
-                               break;
-                       }
-                       udelay(100);
-               }
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
 
-               REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n",
+                        __func__, us);
+               ahp->ah_slottime = (u32) -1;
+               return false;
+       } else {
+               REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
+               ahp->ah_slottime = us;
+               return true;
        }
+}
+
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
+{
+       u32 macmode;
+
+       if (mode == ATH9K_HT_MACMODE_2040 &&
+           !ah->ah_config.cwm_ignore_extcca)
+               macmode = AR_2040_JOINED_RX_CLEAR;
+       else
+               macmode = 0;
 
-       REG_WRITE(ah, AR_Q_TXD, 0);
-       return wait != 0;
+       REG_WRITE(ah, AR_2040_MODE, macmode);
 }
index 2113818ee9348dffdd4cc2334c85abac662d4683..6a29f2d43c21ed4540cb99b2e615dcd7bebbd4b7 100644 (file)
@@ -923,7 +923,7 @@ struct ath_hal_5416 {
 #define OFDM_PLCP_BITS_QUARTER      22
 #define OFDM_SYMBOL_TIME_QUARTER    16
 
-u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+u32 ath9k_hw_get_eeprom(struct ath_hal *ah,
                        enum eeprom_param param);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c
new file mode 100644 (file)
index 0000000..c344a81
--- /dev/null
@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+                                       struct ath9k_tx_queue_info *qi)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+               "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+               __func__, ahp->ah_txOkInterruptMask,
+               ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
+               ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
+
+       REG_WRITE(ah, AR_IMR_S0,
+                 SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+                 | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+       REG_WRITE(ah, AR_IMR_S1,
+                 SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+                 | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+       REG_RMW_FIELD(ah, AR_IMR_S2,
+                     AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+void ath9k_hw_dmaRegDump(struct ath_hal *ah)
+{
+       u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
+       int qcuOffset = 0, dcuOffset = 0;
+       u32 *qcuBase = &val[0], *dcuBase = &val[4];
+       int i;
+
+       REG_WRITE(ah, AR_MACMISC,
+                 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+                  (AR_MACMISC_MISC_OBS_BUS_1 <<
+                   AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
+
+       for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
+               if (i % 4 == 0)
+                       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+
+               val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+
+       for (i = 0; i < ATH9K_NUM_QUEUES;
+            i++, qcuOffset += 4, dcuOffset += 5) {
+               if (i == 8) {
+                       qcuOffset = 0;
+                       qcuBase++;
+               }
+
+               if (i == 6) {
+                       dcuOffset = 0;
+                       dcuBase++;
+               }
+
+               DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+                       "%2d          %2x      %1x     %2x           %2x\n",
+                       i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+                       (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
+                       val[2] & (0x7 << (i * 3)) >> (i * 3),
+                       (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
+               (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "qcu_complete state: %2x    dcu_complete state:     %2x\n",
+               (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
+               (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
+               (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
+               (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
+               (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
+
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
+               REG_READ(ah, AR_OBS_BUS_1));
+       DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+               "AR_CR 0x%x \n", REG_READ(ah, AR_CR));
+}
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+{
+       return REG_READ(ah, AR_QTXDP(q));
+}
+
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
+{
+       REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+       return true;
+}
+
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+{
+       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+       REG_WRITE(ah, AR_Q_TXE, 1 << q);
+
+       return true;
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+{
+       u32 npend;
+
+       npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+       if (npend == 0) {
+
+               if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+                       npend = 1;
+       }
+
+       return npend;
+}
+
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       u32 txcfg, curLevel, newLevel;
+       enum ath9k_int omask;
+
+       if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+               return false;
+
+       omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+
+       txcfg = REG_READ(ah, AR_TXCFG);
+       curLevel = MS(txcfg, AR_FTRIG);
+       newLevel = curLevel;
+       if (bIncTrigLevel) {
+               if (curLevel < MAX_TX_FIFO_THRESHOLD)
+                       newLevel++;
+       } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+               newLevel--;
+       if (newLevel != curLevel)
+               REG_WRITE(ah, AR_TXCFG,
+                         (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+       ath9k_hw_set_interrupts(ah, omask);
+
+       ah->ah_txTrigLevel = newLevel;
+
+       return newLevel != curLevel;
+}
+
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+{
+       u32 tsfLow, j, wait;
+
+       REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+       for (wait = 1000; wait != 0; wait--) {
+               if (ath9k_hw_numtxpending(ah, q) == 0)
+                       break;
+               udelay(100);
+       }
+
+       if (ath9k_hw_numtxpending(ah, q)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+                       "%s: Num of pending TX Frames %d on Q %d\n",
+                       __func__, ath9k_hw_numtxpending(ah, q), q);
+
+               for (j = 0; j < 2; j++) {
+                       tsfLow = REG_READ(ah, AR_TSF_L32);
+                       REG_WRITE(ah, AR_QUIET2,
+                                 SM(10, AR_QUIET2_QUIET_DUR));
+                       REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+                       REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+                       REG_SET_BIT(ah, AR_TIMER_MODE,
+                                      AR_QUIET_TIMER_EN);
+
+                       if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
+                               break;
+
+                       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+                               "%s: TSF have moved while trying to set "
+                               "quiet time TSF: 0x%08x\n",
+                               __func__, tsfLow);
+               }
+
+               REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+
+               udelay(200);
+               REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+
+               wait = 1000;
+
+               while (ath9k_hw_numtxpending(ah, q)) {
+                       if ((--wait) == 0) {
+                               DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+                                       "%s: Failed to stop Tx DMA in 100 "
+                                       "msec after killing last frame\n",
+                                       __func__);
+                               break;
+                       }
+                       udelay(100);
+               }
+
+               REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+       }
+
+       REG_WRITE(ah, AR_Q_TXD, 0);
+
+       return wait != 0;
+}
+
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+                        u32 segLen, bool firstSeg,
+                        bool lastSeg, const struct ath_desc *ds0)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       if (firstSeg) {
+               ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
+       } else if (lastSeg) {
+               ads->ds_ctl0 = 0;
+               ads->ds_ctl1 = segLen;
+               ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+               ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+       } else {
+               ads->ds_ctl0 = 0;
+               ads->ds_ctl1 = segLen | AR_TxMore;
+               ads->ds_ctl2 = 0;
+               ads->ds_ctl3 = 0;
+       }
+       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+
+       return true;
+}
+
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+               return -EINPROGRESS;
+
+       ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+       ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
+       ds->ds_txstat.ts_status = 0;
+       ds->ds_txstat.ts_flags = 0;
+
+       if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+               ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+       if (ads->ds_txstatus1 & AR_Filtered)
+               ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+       if (ads->ds_txstatus1 & AR_FIFOUnderrun)
+               ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+       if (ads->ds_txstatus9 & AR_TxOpExceeded)
+               ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+       if (ads->ds_txstatus1 & AR_TxTimerExpired)
+               ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+       if (ads->ds_txstatus1 & AR_DescCfgErr)
+               ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+       if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+               ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+               ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->ds_txstatus0 & AR_TxBaStatus) {
+               ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
+               ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
+               ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
+       }
+
+       ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+       switch (ds->ds_txstat.ts_rateindex) {
+       case 0:
+               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+               break;
+       case 1:
+               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+               break;
+       case 2:
+               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+               break;
+       case 3:
+               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+               break;
+       }
+
+       ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+       ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+       ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+       ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+       ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+       ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+       ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+       ds->ds_txstat.evm0 = ads->AR_TxEVM0;
+       ds->ds_txstat.evm1 = ads->AR_TxEVM1;
+       ds->ds_txstat.evm2 = ads->AR_TxEVM2;
+       ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+       ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+       ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+       ds->ds_txstat.ts_antenna = 1;
+
+       return 0;
+}
+
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+                           u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+                           u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       txPower += ahp->ah_txPowerIndexOffset;
+       if (txPower > 63)
+               txPower = 63;
+
+       ads->ds_ctl0 = (pktLen & AR_FrameLen)
+               | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+               | SM(txPower, AR_XmitPower)
+               | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+               | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+               | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+               | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+       ads->ds_ctl1 =
+               (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+               | SM(type, AR_FrameType)
+               | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+               | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+               | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+       ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+       if (AR_SREV_9285(ah)) {
+               ads->ds_ctl8 = 0;
+               ads->ds_ctl9 = 0;
+               ads->ds_ctl10 = 0;
+               ads->ds_ctl11 = 0;
+       }
+}
+
+void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+                                 struct ath_desc *lastds,
+                                 u32 durUpdateEn, u32 rtsctsRate,
+                                 u32 rtsctsDuration,
+                                 struct ath9k_11n_rate_series series[],
+                                 u32 nseries, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       struct ar5416_desc *last_ads = AR5416DESC(lastds);
+       u32 ds_ctl0;
+
+       (void) nseries;
+       (void) rtsctsDuration;
+
+       if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+               ds_ctl0 = ads->ds_ctl0;
+
+               if (flags & ATH9K_TXDESC_RTSENA) {
+                       ds_ctl0 &= ~AR_CTSEnable;
+                       ds_ctl0 |= AR_RTSEnable;
+               } else {
+                       ds_ctl0 &= ~AR_RTSEnable;
+                       ds_ctl0 |= AR_CTSEnable;
+               }
+
+               ads->ds_ctl0 = ds_ctl0;
+       } else {
+               ads->ds_ctl0 =
+                       (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+       }
+
+       ads->ds_ctl2 = set11nTries(series, 0)
+               | set11nTries(series, 1)
+               | set11nTries(series, 2)
+               | set11nTries(series, 3)
+               | (durUpdateEn ? AR_DurUpdateEna : 0)
+               | SM(0, AR_BurstDur);
+
+       ads->ds_ctl3 = set11nRate(series, 0)
+               | set11nRate(series, 1)
+               | set11nRate(series, 2)
+               | set11nRate(series, 3);
+
+       ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+               | set11nPktDurRTSCTS(series, 1);
+
+       ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+               | set11nPktDurRTSCTS(series, 3);
+
+       ads->ds_ctl7 = set11nRateFlags(series, 0)
+               | set11nRateFlags(series, 1)
+               | set11nRateFlags(series, 2)
+               | set11nRateFlags(series, 3)
+               | SM(rtsctsRate, AR_RTSCTSRate);
+       last_ads->ds_ctl2 = ads->ds_ctl2;
+       last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+                               u32 aggrLen)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+       ads->ds_ctl6 &= ~AR_AggrLen;
+       ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+                                u32 numDelims)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       unsigned int ctl6;
+
+       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+       ctl6 = ads->ds_ctl6;
+       ctl6 &= ~AR_PadDelim;
+       ctl6 |= SM(numDelims, AR_PadDelim);
+       ads->ds_ctl6 = ctl6;
+}
+
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 |= AR_IsAggr;
+       ads->ds_ctl1 &= ~AR_MoreAggr;
+       ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+                                  u32 burstDuration)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl2 &= ~AR_BurstDur;
+       ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+                                    u32 vmf)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       if (vmf)
+               ads->ds_ctl0 |= AR_VirtMoreFrag;
+       else
+               ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       *txqs &= ahp->ah_intrTxqs;
+       ahp->ah_intrTxqs &= ~(*txqs);
+}
+
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+                           const struct ath9k_tx_queue_info *qinfo)
+{
+       u32 cw;
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       struct ath9k_tx_queue_info *qi;
+
+       if (q >= pCap->total_queues) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+                        __func__, q);
+               return false;
+       }
+
+       qi = &ahp->ah_txq[q];
+       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+                        __func__);
+               return false;
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
+
+       qi->tqi_ver = qinfo->tqi_ver;
+       qi->tqi_subtype = qinfo->tqi_subtype;
+       qi->tqi_qflags = qinfo->tqi_qflags;
+       qi->tqi_priority = qinfo->tqi_priority;
+       if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+               qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+       else
+               qi->tqi_aifs = INIT_AIFS;
+       if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+               cw = min(qinfo->tqi_cwmin, 1024U);
+               qi->tqi_cwmin = 1;
+               while (qi->tqi_cwmin < cw)
+                       qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+       } else
+               qi->tqi_cwmin = qinfo->tqi_cwmin;
+       if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+               cw = min(qinfo->tqi_cwmax, 1024U);
+               qi->tqi_cwmax = 1;
+               while (qi->tqi_cwmax < cw)
+                       qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+       } else
+               qi->tqi_cwmax = INIT_CWMAX;
+
+       if (qinfo->tqi_shretry != 0)
+               qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+       else
+               qi->tqi_shretry = INIT_SH_RETRY;
+       if (qinfo->tqi_lgretry != 0)
+               qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+       else
+               qi->tqi_lgretry = INIT_LG_RETRY;
+       qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+       qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+       qi->tqi_burstTime = qinfo->tqi_burstTime;
+       qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+       switch (qinfo->tqi_subtype) {
+       case ATH9K_WME_UPSD:
+               if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
+                       qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+                           struct ath9k_tx_queue_info *qinfo)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       struct ath9k_tx_queue_info *qi;
+
+       if (q >= pCap->total_queues) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+                        __func__, q);
+               return false;
+       }
+
+       qi = &ahp->ah_txq[q];
+       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+                        __func__);
+               return false;
+       }
+
+       qinfo->tqi_qflags = qi->tqi_qflags;
+       qinfo->tqi_ver = qi->tqi_ver;
+       qinfo->tqi_subtype = qi->tqi_subtype;
+       qinfo->tqi_qflags = qi->tqi_qflags;
+       qinfo->tqi_priority = qi->tqi_priority;
+       qinfo->tqi_aifs = qi->tqi_aifs;
+       qinfo->tqi_cwmin = qi->tqi_cwmin;
+       qinfo->tqi_cwmax = qi->tqi_cwmax;
+       qinfo->tqi_shretry = qi->tqi_shretry;
+       qinfo->tqi_lgretry = qi->tqi_lgretry;
+       qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
+       qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
+       qinfo->tqi_burstTime = qi->tqi_burstTime;
+       qinfo->tqi_readyTime = qi->tqi_readyTime;
+
+       return true;
+}
+
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+                         const struct ath9k_tx_queue_info *qinfo)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_tx_queue_info *qi;
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       int q;
+
+       switch (type) {
+       case ATH9K_TX_QUEUE_BEACON:
+               q = pCap->total_queues - 1;
+               break;
+       case ATH9K_TX_QUEUE_CAB:
+               q = pCap->total_queues - 2;
+               break;
+       case ATH9K_TX_QUEUE_PSPOLL:
+               q = 1;
+               break;
+       case ATH9K_TX_QUEUE_UAPSD:
+               q = pCap->total_queues - 3;
+               break;
+       case ATH9K_TX_QUEUE_DATA:
+               for (q = 0; q < pCap->total_queues; q++)
+                       if (ahp->ah_txq[q].tqi_type ==
+                           ATH9K_TX_QUEUE_INACTIVE)
+                               break;
+               if (q == pCap->total_queues) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+                               "%s: no available tx queue\n", __func__);
+                       return -1;
+               }
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
+                       __func__, type);
+               return -1;
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+       qi = &ahp->ah_txq[q];
+       if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+                       "%s: tx queue %u already active\n", __func__, q);
+               return -1;
+       }
+       memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+       qi->tqi_type = type;
+       if (qinfo == NULL) {
+               qi->tqi_qflags =
+                       TXQ_FLAG_TXOKINT_ENABLE
+                       | TXQ_FLAG_TXERRINT_ENABLE
+                       | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+               qi->tqi_aifs = INIT_AIFS;
+               qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+               qi->tqi_cwmax = INIT_CWMAX;
+               qi->tqi_shretry = INIT_SH_RETRY;
+               qi->tqi_lgretry = INIT_LG_RETRY;
+               qi->tqi_physCompBuf = 0;
+       } else {
+               qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+               (void) ath9k_hw_set_txq_props(ah, q, qinfo);
+       }
+
+       return q;
+}
+
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       struct ath9k_tx_queue_info *qi;
+
+       if (q >= pCap->total_queues) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+                        __func__, q);
+               return false;
+       }
+       qi = &ahp->ah_txq[q];
+       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+                        __func__, q);
+               return false;
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
+               __func__, q);
+
+       qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+       ahp->ah_txOkInterruptMask &= ~(1 << q);
+       ahp->ah_txErrInterruptMask &= ~(1 << q);
+       ahp->ah_txDescInterruptMask &= ~(1 << q);
+       ahp->ah_txEolInterruptMask &= ~(1 << q);
+       ahp->ah_txUrnInterruptMask &= ~(1 << q);
+       ath9k_hw_set_txq_interrupts(ah, qi);
+
+       return true;
+}
+
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+       struct ath9k_channel *chan = ah->ah_curchan;
+       struct ath9k_tx_queue_info *qi;
+       u32 cwMin, chanCwMin, value;
+
+       if (q >= pCap->total_queues) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+                        __func__, q);
+               return false;
+       }
+
+       qi = &ahp->ah_txq[q];
+       if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+                        __func__, q);
+               return true;
+       }
+
+       DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
+
+       if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+               if (chan && IS_CHAN_B(chan))
+                       chanCwMin = INIT_CWMIN_11B;
+               else
+                       chanCwMin = INIT_CWMIN;
+
+               for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+       } else
+               cwMin = qi->tqi_cwmin;
+
+       REG_WRITE(ah, AR_DLCL_IFS(q),
+                 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
+                 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
+                 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+       REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+                 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
+                 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
+                 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
+
+       REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+       REG_WRITE(ah, AR_DMISC(q),
+                 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+       if (qi->tqi_cbrPeriod) {
+               REG_WRITE(ah, AR_QCBRCFG(q),
+                         SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
+                         SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
+               REG_WRITE(ah, AR_QMISC(q),
+                         REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
+                         (qi->tqi_cbrOverflowLimit ?
+                          AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+       }
+       if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
+               REG_WRITE(ah, AR_QRDYTIMECFG(q),
+                         SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+                         AR_Q_RDYTIMECFG_EN);
+       }
+
+       REG_WRITE(ah, AR_DCHNTIME(q),
+                 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+                 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+       if (qi->tqi_burstTime
+           && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
+               REG_WRITE(ah, AR_QMISC(q),
+                         REG_READ(ah, AR_QMISC(q)) |
+                         AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+       }
+
+       if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
+               REG_WRITE(ah, AR_DMISC(q),
+                         REG_READ(ah, AR_DMISC(q)) |
+                         AR_D_MISC_POST_FR_BKOFF_DIS);
+       }
+       if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
+               REG_WRITE(ah, AR_DMISC(q),
+                         REG_READ(ah, AR_DMISC(q)) |
+                         AR_D_MISC_FRAG_BKOFF_EN);
+       }
+       switch (qi->tqi_type) {
+       case ATH9K_TX_QUEUE_BEACON:
+               REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+                         | AR_Q_MISC_FSP_DBA_GATED
+                         | AR_Q_MISC_BEACON_USE
+                         | AR_Q_MISC_CBR_INCR_DIS1);
+
+               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+                         | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+                            AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
+                         | AR_D_MISC_BEACON_USE
+                         | AR_D_MISC_POST_FR_BKOFF_DIS);
+               break;
+       case ATH9K_TX_QUEUE_CAB:
+               REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+                         | AR_Q_MISC_FSP_DBA_GATED
+                         | AR_Q_MISC_CBR_INCR_DIS1
+                         | AR_Q_MISC_CBR_INCR_DIS0);
+               value = (qi->tqi_readyTime -
+                        (ah->ah_config.sw_beacon_response_time -
+                         ah->ah_config.dma_beacon_response_time) -
+                        ah->ah_config.additional_swba_backoff) * 1024;
+               REG_WRITE(ah, AR_QRDYTIMECFG(q),
+                         value | AR_Q_RDYTIMECFG_EN);
+               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+                         | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+                            AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+               break;
+       case ATH9K_TX_QUEUE_PSPOLL:
+               REG_WRITE(ah, AR_QMISC(q),
+                         REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+               break;
+       case ATH9K_TX_QUEUE_UAPSD:
+               REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
+                         AR_D_MISC_POST_FR_BKOFF_DIS);
+               break;
+       default:
+               break;
+       }
+
+       if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+               REG_WRITE(ah, AR_DMISC(q),
+                         REG_READ(ah, AR_DMISC(q)) |
+                         SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+                            AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+                         AR_D_MISC_POST_FR_BKOFF_DIS);
+       }
+
+       if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+               ahp->ah_txOkInterruptMask |= 1 << q;
+       else
+               ahp->ah_txOkInterruptMask &= ~(1 << q);
+       if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+               ahp->ah_txErrInterruptMask |= 1 << q;
+       else
+               ahp->ah_txErrInterruptMask &= ~(1 << q);
+       if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+               ahp->ah_txDescInterruptMask |= 1 << q;
+       else
+               ahp->ah_txDescInterruptMask &= ~(1 << q);
+       if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+               ahp->ah_txEolInterruptMask |= 1 << q;
+       else
+               ahp->ah_txEolInterruptMask &= ~(1 << q);
+       if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+               ahp->ah_txUrnInterruptMask |= 1 << q;
+       else
+               ahp->ah_txUrnInterruptMask &= ~(1 << q);
+       ath9k_hw_set_txq_interrupts(ah, qi);
+
+       return true;
+}
+
+int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+                       u32 pa, struct ath_desc *nds, u64 tsf)
+{
+       struct ar5416_desc ads;
+       struct ar5416_desc *adsp = AR5416DESC(ds);
+       u32 phyerr;
+
+       if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+               return -EINPROGRESS;
+
+       ads.u.rx = adsp->u.rx;
+
+       ds->ds_rxstat.rs_status = 0;
+       ds->ds_rxstat.rs_flags = 0;
+
+       ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+       ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+
+       ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+       ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
+       ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
+       ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
+       ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
+       ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
+       ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+       if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+               ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+       else
+               ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+       ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
+       ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+       ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+       ds->ds_rxstat.rs_moreaggr =
+               (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+       ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+       ds->ds_rxstat.rs_flags =
+               (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+       ds->ds_rxstat.rs_flags |=
+               (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+       if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+       if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+       if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+               ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+       if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+               if (ads.ds_rxstatus8 & AR_CRCErr)
+                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+               else if (ads.ds_rxstatus8 & AR_PHYErr) {
+                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+                       phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+                       ds->ds_rxstat.rs_phyerr = phyerr;
+               } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+               else if (ads.ds_rxstatus8 & AR_MichaelErr)
+                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+       }
+
+       return 0;
+}
+
+bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+                         u32 size, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+       ads->ds_ctl1 = size & AR_BufLen;
+       if (flags & ATH9K_RXDESC_INTREQ)
+               ads->ds_ctl1 |= AR_RxIntrReq;
+
+       ads->ds_rxstatus8 &= ~AR_RxDone;
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+               memset(&(ads->u), 0, sizeof(ads->u));
+
+       return true;
+}
+
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+{
+       u32 reg;
+
+       if (set) {
+               REG_SET_BIT(ah, AR_DIAG_SW,
+                           (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+               if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+                       REG_CLR_BIT(ah, AR_DIAG_SW,
+                                   (AR_DIAG_RX_DIS |
+                                    AR_DIAG_RX_ABORT));
+
+                       reg = REG_READ(ah, AR_OBS_BUS_1);
+                       DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+                               "%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
+                               __func__, reg);
+
+                       return false;
+               }
+       } else {
+               REG_CLR_BIT(ah, AR_DIAG_SW,
+                           (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+       }
+
+       return true;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+{
+       REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_rxena(struct ath_hal *ah)
+{
+       REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+void ath9k_hw_startpcureceive(struct ath_hal *ah)
+{
+       REG_CLR_BIT(ah, AR_DIAG_SW,
+                   (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+       ath9k_enable_mib_counters(ah);
+
+       ath9k_ani_reset(ah);
+}
+
+void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+{
+       REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+
+       ath9k_hw_disable_mib_counters(ah);
+}
+
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+{
+       REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+                       "%s: dma failed to stop in 10ms\n"
+                       "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+                       __func__,
+                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+               return false;
+       } else {
+               return true;
+       }
+}
index f6dc4c8260447a7855263c1281a06dca65b2b18c..fb50aa0fc996a2539d4f65f608e3a3ecf97b13ef 100644 (file)
@@ -21,8 +21,6 @@
 
 #define ATH_PCI_VERSION "0.1"
 
-#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR      13
-
 static char *dev_info = "ath9k";
 
 MODULE_AUTHOR("Atheros Communications");
@@ -164,7 +162,7 @@ static int ath_key_config(struct ath_softc *sc,
        if (!sc->sc_vaps[0])
                return -EIO;
 
-       vif = sc->sc_vaps[0]->av_if_data;
+       vif = sc->sc_vaps[0];
        opmode = vif->type;
 
        /*
@@ -297,41 +295,6 @@ static void ath9k_rx_prepare(struct ath_softc *sc,
        rx_status->flag |= RX_FLAG_TSFT;
 }
 
-static u8 parse_mpdudensity(u8 mpdudensity)
-{
-       /*
-        * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
-        *   0 for no restriction
-        *   1 for 1/4 us
-        *   2 for 1/2 us
-        *   3 for 1 us
-        *   4 for 2 us
-        *   5 for 4 us
-        *   6 for 8 us
-        *   7 for 16 us
-        */
-       switch (mpdudensity) {
-       case 0:
-               return 0;
-       case 1:
-       case 2:
-       case 3:
-               /* Our lower layer calculations limit our precision to
-                  1 microsecond */
-               return 1;
-       case 4:
-               return 2;
-       case 5:
-               return 4;
-       case 6:
-               return 8;
-       case 7:
-               return 16;
-       default:
-               return 0;
-       }
-}
-
 static void ath9k_ht_conf(struct ath_softc *sc,
                          struct ieee80211_bss_conf *bss_conf)
 {
@@ -350,11 +313,12 @@ static void ath9k_ht_conf(struct ath_softc *sc,
 }
 
 static void ath9k_bss_assoc_info(struct ath_softc *sc,
+                                struct ieee80211_vif *vif,
                                 struct ieee80211_bss_conf *bss_conf)
 {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_channel *curchan = hw->conf.channel;
-       struct ath_vap *avp;
+       struct ath_vap *avp = (void *)vif->drv_priv;
        int pos;
 
        if (bss_conf->assoc) {
@@ -362,13 +326,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                        __func__,
                        bss_conf->aid);
 
-               avp = sc->sc_vaps[0];
-               if (avp == NULL) {
-                       DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-                               __func__);
-                       return;
-               }
-
                /* New association, store aid */
                if (avp->av_opmode == ATH9K_M_STA) {
                        sc->sc_curaid = bss_conf->aid;
@@ -449,7 +406,7 @@ void ath_get_beaconconfig(struct ath_softc *sc,
 }
 
 void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-                    struct ath_xmit_status *tx_status, struct ath_node *an)
+                    struct ath_xmit_status *tx_status)
 {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -479,8 +436,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        tx_info->status.rates[0].count = tx_status->retries + 1;
 
        ieee80211_tx_status(hw, skb);
-       if (an)
-               ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
 }
 
 int _ath_rx_indicate(struct ath_softc *sc,
@@ -489,12 +444,10 @@ int _ath_rx_indicate(struct ath_softc *sc,
                     u16 keyix)
 {
        struct ieee80211_hw *hw = sc->hw;
-       struct ath_node *an = NULL;
        struct ieee80211_rx_status rx_status;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
        int padsize;
-       enum ATH_RX_TYPE st;
 
        /* see if any padding is done by the hw and remove it */
        if (hdrlen & 3) {
@@ -518,33 +471,6 @@ int _ath_rx_indicate(struct ath_softc *sc,
                        rx_status.flag |= RX_FLAG_DECRYPTED;
        }
 
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, hdr->addr2);
-       spin_unlock_bh(&sc->node_lock);
-
-       if (an) {
-               ath_rx_input(sc, an,
-                            skb, status, &st);
-       }
-       if (!an || (st != ATH_RX_CONSUMED))
-               __ieee80211_rx(hw, skb, &rx_status);
-
-       return 0;
-}
-
-int ath_rx_subframe(struct ath_node *an,
-                   struct sk_buff *skb,
-                   struct ath_recv_status *status)
-{
-       struct ath_softc *sc = an->an_sc;
-       struct ieee80211_hw *hw = sc->hw;
-       struct ieee80211_rx_status rx_status;
-
-       /* Prepare rx status */
-       ath9k_rx_prepare(sc, skb, status, &rx_status);
-       if (!(status->flags & ATH_RX_DECRYPT_ERROR))
-               rx_status.flag |= RX_FLAG_DECRYPTED;
-
        __ieee80211_rx(hw, skb, &rx_status);
 
        return 0;
@@ -666,6 +592,7 @@ fail:
 }
 
 #ifdef CONFIG_RFKILL
+
 /*******************/
 /*     Rfkill     */
 /*******************/
@@ -866,43 +793,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc)
                sc->rf_kill.rfkill = NULL;
        }
 }
+
+static int ath_start_rfkill_poll(struct ath_softc *sc)
+{
+       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+               queue_delayed_work(sc->hw->workqueue,
+                                  &sc->rf_kill.rfkill_poll, 0);
+
+       if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+               if (rfkill_register(sc->rf_kill.rfkill)) {
+                       DPRINTF(sc, ATH_DBG_FATAL,
+                               "Unable to register rfkill\n");
+                       rfkill_free(sc->rf_kill.rfkill);
+
+                       /* Deinitialize the device */
+                       if (sc->pdev->irq)
+                               free_irq(sc->pdev->irq, sc);
+                       ath_detach(sc);
+                       pci_iounmap(sc->pdev, sc->mem);
+                       pci_release_region(sc->pdev, 0);
+                       pci_disable_device(sc->pdev);
+                       ieee80211_free_hw(hw);
+                       return -EIO;
+               } else {
+                       sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+               }
+       }
+
+       return 0;
+}
 #endif /* CONFIG_RFKILL */
 
-static int ath_detach(struct ath_softc *sc)
+static void ath_detach(struct ath_softc *sc)
 {
        struct ieee80211_hw *hw = sc->hw;
+       int i = 0;
 
        DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
 
-       /* Deinit LED control */
+       ieee80211_unregister_hw(hw);
+
        ath_deinit_leds(sc);
 
 #ifdef CONFIG_RFKILL
-       /* deinit rfkill */
        ath_deinit_rfkill(sc);
 #endif
-
-       /* Unregister hw */
-
-       ieee80211_unregister_hw(hw);
-
-       /* unregister Rate control */
        ath_rate_control_unregister();
-
-       /* tx/rx cleanup */
+       ath_rate_detach(sc->sc_rc);
 
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
 
-       /* Deinit */
+       tasklet_kill(&sc->intr_tq);
+       tasklet_kill(&sc->bcon_tasklet);
 
-       ath_deinit(sc);
+       if (!(sc->sc_flags & SC_OP_INVALID))
+               ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
 
-       return 0;
+       /* cleanup tx queues */
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i))
+                       ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+
+       ath9k_hw_detach(sc->sc_ah);
 }
 
-static int ath_attach(u16 devid,
-                     struct ath_softc *sc)
+static int ath_attach(u16 devid, struct ath_softc *sc)
 {
        struct ieee80211_hw *hw = sc->hw;
        int error = 0;
@@ -913,47 +869,23 @@ static int ath_attach(u16 devid,
        if (error != 0)
                return error;
 
-       /* Init nodes */
-
-       INIT_LIST_HEAD(&sc->node_list);
-       spin_lock_init(&sc->node_lock);
-
        /* get mac address from hardware and set in mac80211 */
 
        SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
 
-       /* setup channels and rates */
-
-       sc->sbands[IEEE80211_BAND_2GHZ].channels =
-               sc->channels[IEEE80211_BAND_2GHZ];
-       sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
-               sc->rates[IEEE80211_BAND_2GHZ];
-       sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-
-       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-               /* Setup HT capabilities for 2.4Ghz*/
-               setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
-
-       hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-               &sc->sbands[IEEE80211_BAND_2GHZ];
-
-       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
-               sc->sbands[IEEE80211_BAND_5GHZ].channels =
-                       sc->channels[IEEE80211_BAND_5GHZ];
-               sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-                       sc->rates[IEEE80211_BAND_5GHZ];
-               sc->sbands[IEEE80211_BAND_5GHZ].band =
-                       IEEE80211_BAND_5GHZ;
-
-               if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-                       /* Setup HT capabilities for 5Ghz*/
-                       setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+               IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+               IEEE80211_HW_SIGNAL_DBM |
+               IEEE80211_HW_AMPDU_AGGREGATION;
 
-               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &sc->sbands[IEEE80211_BAND_5GHZ];
-       }
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
 
        hw->queues = 4;
+       hw->sta_data_size = sizeof(struct ath_node);
+       hw->vif_data_size = sizeof(struct ath_vap);
 
        /* Register rate control */
        hw->rate_control_algorithm = "ath9k_rate_control";
@@ -966,6 +898,17 @@ static int ath_attach(u16 devid,
                goto bad;
        }
 
+       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+               setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+               if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+                       setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
+       }
+
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ];
+       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes))
+               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &sc->sbands[IEEE80211_BAND_5GHZ];
+
        error = ieee80211_register_hw(hw);
        if (error != 0) {
                ath_rate_control_unregister();
@@ -1011,62 +954,44 @@ static int ath9k_start(struct ieee80211_hw *hw)
        DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
                "initial channel: %d MHz\n", __func__, curchan->center_freq);
 
+       memset(&sc->sc_ht_info, 0, sizeof(struct ath_ht_info));
+
        /* setup initial channel */
 
        pos = ath_get_channel(sc, curchan);
        if (pos == -1) {
                DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
-               return -EINVAL;
+               error = -EINVAL;
+               goto exit;
        }
 
        sc->sc_ah->ah_channels[pos].chanmode =
                (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
 
-       /* open ath_dev */
        error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
        if (error) {
                DPRINTF(sc, ATH_DBG_FATAL,
                        "%s: Unable to complete ath_open\n", __func__);
-               return error;
+               goto exit;
        }
 
 #ifdef CONFIG_RFKILL
-       /* Start rfkill polling */
-       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               queue_delayed_work(sc->hw->workqueue,
-                                  &sc->rf_kill.rfkill_poll, 0);
-
-       if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
-               if (rfkill_register(sc->rf_kill.rfkill)) {
-                       DPRINTF(sc, ATH_DBG_FATAL,
-                                       "Unable to register rfkill\n");
-                       rfkill_free(sc->rf_kill.rfkill);
-
-                       /* Deinitialize the device */
-                       if (sc->pdev->irq)
-                               free_irq(sc->pdev->irq, sc);
-                       ath_detach(sc);
-                       pci_iounmap(sc->pdev, sc->mem);
-                       pci_release_region(sc->pdev, 0);
-                       pci_disable_device(sc->pdev);
-                       ieee80211_free_hw(hw);
-                       return -EIO;
-               } else {
-                       sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
-               }
-       }
+       error = ath_start_rfkill_poll(sc);
 #endif
 
-       ieee80211_wake_queues(hw);
-       return 0;
+exit:
+       return error;
 }
 
 static int ath9k_tx(struct ieee80211_hw *hw,
                    struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath_softc *sc = hw->priv;
+       struct ath_tx_control txctl;
        int hdrlen, padsize;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       memset(&txctl, 0, sizeof(struct ath_tx_control));
 
        /*
         * As a temporary workaround, assign seq# here; this will likely need
@@ -1091,45 +1016,47 @@ static int ath9k_tx(struct ieee80211_hw *hw,
                memmove(skb->data, skb->data + padsize, hdrlen);
        }
 
+       /* Check if a tx queue is available */
+
+       txctl.txq = ath_test_get_txq(sc, skb);
+       if (!txctl.txq)
+               goto exit;
+
        DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
                __func__,
                skb);
 
-       if (ath_tx_start(sc, skb) != 0) {
+       if (ath_tx_start(sc, skb, &txctl) != 0) {
                DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
-               dev_kfree_skb_any(skb);
-               /* FIXME: Check for proper return value from ATH_DEV */
-               return 0;
+               goto exit;
        }
 
+       return 0;
+exit:
+       dev_kfree_skb_any(skb);
        return 0;
 }
 
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
-       int error;
 
-       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
-
-       error = ath_suspend(sc);
-       if (error)
-               DPRINTF(sc, ATH_DBG_CONFIG,
-                       "%s: Device is no longer present\n", __func__);
+       if (sc->sc_flags & SC_OP_INVALID) {
+               DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__);
+               return;
+       }
 
-       ieee80211_stop_queues(hw);
+       ath_stop(sc);
 
-#ifdef CONFIG_RFKILL
-       if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-#endif
+       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_if_init_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
-       int error, ic_opmode = 0;
+       struct ath_vap *avp = (void *)conf->vif->drv_priv;
+       int ic_opmode = 0;
 
        /* Support only vap for now */
 
@@ -1157,13 +1084,22 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                __func__,
                ic_opmode);
 
-       error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
-       if (error) {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "%s: Unable to attach vap, error: %d\n",
-                       __func__, error);
-               return error;
-       }
+       /* Set the VAP opmode */
+       avp->av_opmode = ic_opmode;
+       avp->av_bslot = -1;
+
+       if (ic_opmode == ATH9K_M_HOSTAP)
+               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+
+       sc->sc_vaps[0] = conf->vif;
+       sc->sc_nvaps++;
+
+       /* Set the device opmode */
+       sc->sc_ah->ah_opmode = ic_opmode;
+
+       /* default VAP configuration */
+       avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
+       avp->av_config.av_fixed_retryset = 0x03030303;
 
        if (conf->type == NL80211_IFTYPE_AP) {
                /* TODO: is this a suitable place to start ANI for AP mode? */
@@ -1179,27 +1115,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_if_init_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
-       struct ath_vap *avp;
-       int error;
+       struct ath_vap *avp = (void *)conf->vif->drv_priv;
 
        DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
 
-       avp = sc->sc_vaps[0];
-       if (avp == NULL) {
-               DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-                       __func__);
-               return;
-       }
-
 #ifdef CONFIG_SLOW_ANT_DIV
        ath_slow_ant_div_stop(&sc->sc_antdiv);
 #endif
        /* Stop ANI */
        del_timer_sync(&sc->sc_ani.timer);
 
-       /* Update ratectrl */
-       ath_rate_newstate(sc, avp);
-
        /* Reclaim beacon resources */
        if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP ||
            sc->sc_ah->ah_opmode == ATH9K_M_IBSS) {
@@ -1207,16 +1132,10 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
                ath_beacon_return(sc, avp);
        }
 
-       /* Set interrupt mask */
-       sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
        sc->sc_flags &= ~SC_OP_BEACONS;
 
-       error = ath_vap_detach(sc, 0);
-       if (error)
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "%s: Unable to detach vap, error: %d\n",
-                       __func__, error);
+       sc->sc_vaps[0] = NULL;
+       sc->sc_nvaps--;
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1264,17 +1183,10 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hal *ah = sc->sc_ah;
-       struct ath_vap *avp;
+       struct ath_vap *avp = (void *)vif->drv_priv;
        u32 rfilt = 0;
        int error, i;
 
-       avp = sc->sc_vaps[0];
-       if (avp == NULL) {
-               DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-                       __func__);
-               return -EINVAL;
-       }
-
        /* TODO: Need to decide which hw opmode to use for multi-interface
         * cases */
        if (vif->type == NL80211_IFTYPE_AP &&
@@ -1303,23 +1215,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
                        /* Set aggregation protection mode parameters */
                        sc->sc_config.ath_aggr_prot = 0;
 
-                       /*
-                        * Reset our TSF so that its value is lower than the
-                        * beacon that we are trying to catch.
-                        * Only then hw will update its TSF register with the
-                        * new beacon. Reset the TSF before setting the BSSID
-                        * to avoid allowing in any frames that would update
-                        * our TSF only to have us clear it
-                        * immediately thereafter.
-                        */
-                       ath9k_hw_reset_tsf(sc->sc_ah);
-
-                       /* Disable BMISS interrupt when we're not associated */
-                       ath9k_hw_set_interrupts(sc->sc_ah,
-                                       sc->sc_imask &
-                                       ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
-                       sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-
                        DPRINTF(sc, ATH_DBG_CONFIG,
                                "%s: RX filter 0x%x bssid %pM aid 0x%x\n",
                                __func__, rfilt,
@@ -1355,7 +1250,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
        }
 
        /* Check for WLAN_CAPABILITY_PRIVACY ? */
-       if ((avp->av_opmode != NL80211_IFTYPE_STATION)) {
+       if ((avp->av_opmode != ATH9K_M_STA)) {
                for (i = 0; i < IEEE80211_WEP_NKID; i++)
                        if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
                                ath9k_hw_keysetmac(sc->sc_ah,
@@ -1410,44 +1305,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
                             struct ieee80211_sta *sta)
 {
        struct ath_softc *sc = hw->priv;
-       struct ath_node *an;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sc->node_lock, flags);
-       an = ath_node_find(sc, sta->addr);
-       spin_unlock_irqrestore(&sc->node_lock, flags);
 
        switch (cmd) {
        case STA_NOTIFY_ADD:
-               spin_lock_irqsave(&sc->node_lock, flags);
-               if (!an) {
-                       ath_node_attach(sc, sta->addr, 0);
-                       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %pM\n",
-                               __func__, sta->addr);
-               } else {
-                       ath_node_get(sc, sta->addr);
-               }
-
-               /* XXX: Is this right? Can the capabilities change? */
-               an = ath_node_find(sc, sta->addr);
-               an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
-                                       sta->ht_cap.ampdu_factor);
-               an->mpdudensity =
-                       parse_mpdudensity(sta->ht_cap.ampdu_density);
-
-               spin_unlock_irqrestore(&sc->node_lock, flags);
+               ath_node_attach(sc, sta);
                break;
        case STA_NOTIFY_REMOVE:
-               if (!an)
-                       DPRINTF(sc, ATH_DBG_FATAL,
-                               "%s: Removal of a non-existent node\n",
-                               __func__);
-               else {
-                       ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
-                       DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %pM\n",
-                               __func__,
-                               sta->addr);
-               }
+               ath_node_detach(sc, sta);
                break;
        default:
                break;
@@ -1562,7 +1426,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
                        __func__,
                        bss_conf->assoc);
-               ath9k_bss_assoc_info(sc, bss_conf);
+               ath9k_bss_assoc_info(sc, vif, bss_conf);
        }
 }
 
@@ -1595,21 +1459,13 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
-               ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn);
-               if (ret < 0)
-                       DPRINTF(sc, ATH_DBG_FATAL,
-                               "%s: Unable to start RX aggregation\n",
-                               __func__);
+               if (!(sc->sc_flags & SC_OP_RXAGGR))
+                       ret = -ENOTSUPP;
                break;
        case IEEE80211_AMPDU_RX_STOP:
-               ret = ath_rx_aggr_stop(sc, sta->addr, tid);
-               if (ret < 0)
-                       DPRINTF(sc, ATH_DBG_FATAL,
-                               "%s: Unable to stop RX aggregation\n",
-                               __func__);
                break;
        case IEEE80211_AMPDU_TX_START:
-               ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn);
+               ret = ath_tx_aggr_start(sc, sta, tid, ssn);
                if (ret < 0)
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "%s: Unable to start TX aggregation\n",
@@ -1618,7 +1474,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                        ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_STOP:
-               ret = ath_tx_aggr_stop(sc, sta->addr, tid);
+               ret = ath_tx_aggr_stop(sc, sta, tid);
                if (ret < 0)
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "%s: Unable to stop TX aggregation\n",
@@ -1626,6 +1482,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
 
                ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
                break;
+       case IEEE80211_AMPDU_TX_RESUME:
+               ath_tx_aggr_resume(sc, sta, tid);
+               break;
        default:
                DPRINTF(sc, ATH_DBG_FATAL,
                        "%s: Unknown AMPDU action\n", __func__);
@@ -1648,20 +1507,12 @@ static struct ieee80211_ops ath9k_ops = {
        .config             = ath9k_config,
        .config_interface   = ath9k_config_interface,
        .configure_filter   = ath9k_configure_filter,
-       .get_stats          = NULL,
        .sta_notify         = ath9k_sta_notify,
        .conf_tx            = ath9k_conf_tx,
-       .get_tx_stats       = NULL,
        .bss_info_changed   = ath9k_bss_info_changed,
-       .set_tim            = NULL,
        .set_key            = ath9k_set_key,
-       .hw_scan            = NULL,
-       .get_tkip_seq       = NULL,
-       .set_rts_threshold  = NULL,
-       .set_frag_threshold = NULL,
        .get_tsf            = ath9k_get_tsf,
        .reset_tsf          = ath9k_reset_tsf,
-       .tx_last_beacon     = NULL,
        .ampdu_action       = ath9k_ampdu_action,
        .set_frag_threshold = ath9k_no_fragmentation,
 };
@@ -1739,17 +1590,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto bad2;
        }
 
-       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-               IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-               IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM |
-               IEEE80211_HW_AMPDU_AGGREGATION;
-
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_AP) |
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
-
        SET_IEEE80211_DEV(hw, &pdev->dev);
        pci_set_drvdata(pdev, hw);
 
@@ -1797,17 +1637,10 @@ static void ath_pci_remove(struct pci_dev *pdev)
 {
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct ath_softc *sc = hw->priv;
-       enum ath9k_int status;
 
-       if (pdev->irq) {
-               ath9k_hw_set_interrupts(sc->sc_ah, 0);
-               /* clear the ISR */
-               ath9k_hw_getisr(sc->sc_ah, &status);
-               sc->sc_flags |= SC_OP_INVALID;
-               free_irq(pdev->irq, sc);
-       }
        ath_detach(sc);
-
+       if (pdev->irq)
+               free_irq(pdev->irq, sc);
        pci_iounmap(pdev, sc->mem);
        pci_release_region(pdev, 0);
        pci_disable_device(pdev);
index eb9121fdfd385389087807526edcc28924e12942..4f1c8bf8342b7aea430dcfc7ef3da59048f4908c 100644 (file)
@@ -215,7 +215,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
        if (AR_SREV_9280_10_OR_LATER(ah))
                return true;
 
-       eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
+       eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
 
        RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
 
@@ -235,15 +235,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
 
        if (eepMinorRev >= 2) {
                if (IS_CHAN_2GHZ(chan)) {
-                       ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
-                       db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
+                       ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
+                       db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
                        ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
                                                   ob2GHz, 3, 197, 0);
                        ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
                                                   db2GHz, 3, 194, 0);
                } else {
-                       ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
-                       db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
+                       ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
+                       db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
                        ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
                                                   ob5GHz, 3, 203, 0);
                        ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
index ecffd6f45fd013cac976e6becd8e22639464dfc8..aa6bfd717c2055693ebd2635ef95aca5dcae7639 100644 (file)
@@ -816,7 +816,7 @@ void ath_rate_detach(struct ath_rate_softc *asc)
 }
 
 u8 ath_rate_findrateix(struct ath_softc *sc,
-                            u8 dot11rate)
+                      u8 dot11rate)
 {
        const struct ath_rate_table *ratetable;
        struct ath_rate_softc *rsc = sc->sc_rc;
@@ -1867,9 +1867,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        /* XXX: UGLY HACK!! */
        tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
 
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, hdr->addr1);
-       spin_unlock_bh(&sc->node_lock);
+       an = (struct ath_node *)sta->drv_priv;
 
        if (tx_info_priv == NULL)
                return;
@@ -1881,49 +1879,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        tx_info->control.vif = NULL;
 }
 
-static void ath_tx_aggr_resp(struct ath_softc *sc,
-                            struct ieee80211_supported_band *sband,
-                            struct ieee80211_sta *sta,
-                            struct ath_node *an,
-                            u8 tidno)
-{
-       struct ath_atx_tid *txtid;
-       u16 buffersize = 0;
-       int state;
-       struct sta_info *si;
-
-       if (!(sc->sc_flags & SC_OP_TXAGGR))
-               return;
-
-       txtid = ATH_AN_2_TID(an, tidno);
-       if (!txtid->paused)
-               return;
-
-       /*
-        * XXX: This is entirely busted, we aren't supposed to
-        *      access the sta from here because it's internal
-        *      to mac80211, and looking at the state without
-        *      locking is wrong too.
-        */
-       si = container_of(sta, struct sta_info, sta);
-       buffersize = IEEE80211_MIN_AMPDU_BUF <<
-               sband->ht_cap.ampdu_factor; /* FIXME */
-       state = si->ampdu_mlme.tid_state_tx[tidno];
-
-       if (state & HT_ADDBA_RECEIVED_MSK) {
-               txtid->addba_exchangecomplete = 1;
-               txtid->addba_exchangeinprogress = 0;
-               txtid->baw_size = buffersize;
-
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: Resuming tid, buffersize: %d\n",
-                       __func__,
-                       buffersize);
-
-               ath_tx_resume_tid(sc, txtid);
-       }
-}
-
 static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
                         struct ieee80211_tx_rate_control *txrc)
 {
@@ -1936,7 +1891,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        struct ath_rate_node *ath_rc_priv = priv_sta;
        struct ath_node *an;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       int is_probe = FALSE, chk, ret;
+       int is_probe = FALSE;
        s8 lowest_idx;
        __le16 fc = hdr->frame_control;
        u8 *qc, tid;
@@ -1983,35 +1938,10 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
                if (ieee80211_is_data_qos(fc)) {
                        qc = ieee80211_get_qos_ctl(hdr);
                        tid = qc[0] & 0xf;
+                       an = (struct ath_node *)sta->drv_priv;
 
-                       spin_lock_bh(&sc->node_lock);
-                       an = ath_node_find(sc, hdr->addr1);
-                       spin_unlock_bh(&sc->node_lock);
-
-                       if (!an) {
-                               DPRINTF(sc, ATH_DBG_AGGR,
-                                       "%s: Node not found to "
-                                       "init/chk TX aggr\n", __func__);
-                               return;
-                       }
-
-                       chk = ath_tx_aggr_check(sc, an, tid);
-                       if (chk == AGGR_REQUIRED) {
-                               ret = ieee80211_start_tx_ba_session(hw,
-                                       hdr->addr1, tid);
-                               if (ret)
-                                       DPRINTF(sc, ATH_DBG_AGGR,
-                                               "%s: Unable to start tx "
-                                               "aggr for: %pM\n",
-                                               __func__,
-                                               hdr->addr1);
-                               else
-                                       DPRINTF(sc, ATH_DBG_AGGR,
-                                               "%s: Started tx aggr for: %pM\n",
-                                               __func__,
-                                               hdr->addr1);
-                       } else if (chk == AGGR_EXCHANGE_PROGRESS)
-                               ath_tx_aggr_resp(sc, sband, sta, an, tid);
+                       if(ath_tx_aggr_check(sc, an, tid))
+                               ieee80211_start_tx_ba_session(hw, hdr->addr1, tid);
                }
        }
 }
@@ -2053,12 +1983,18 @@ static void ath_rate_free(void *priv)
 
 static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
 {
+       struct ieee80211_vif *vif;
        struct ath_softc *sc = priv;
-       struct ath_vap *avp = sc->sc_vaps[0];
+       struct ath_vap *avp;
        struct ath_rate_node *rate_priv;
 
        DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
 
+       vif = sc->sc_vaps[0];
+       ASSERT(vif);
+
+       avp = (void *)vif->drv_priv;
+
        rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
        if (!rate_priv) {
                DPRINTF(sc, ATH_DBG_FATAL,
index 828322840a861fb31d681cf8bfedecfdfa5e7b3b..2ecb0a010ce2bcd738395ce0ac1c836e7d53f6a3 100644 (file)
@@ -64,328 +64,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
        ath9k_hw_rxena(ah);
 }
 
-/* Process received BAR frame */
-
-static int ath_bar_rx(struct ath_softc *sc,
-                     struct ath_node *an,
-                     struct sk_buff *skb)
-{
-       struct ieee80211_bar *bar;
-       struct ath_arx_tid *rxtid;
-       struct sk_buff *tskb;
-       struct ath_recv_status *rx_status;
-       int tidno, index, cindex;
-       u16 seqno;
-
-       /* look at BAR contents  */
-
-       bar = (struct ieee80211_bar *)skb->data;
-       tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M)
-               >> IEEE80211_BAR_CTL_TID_S;
-       seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-       /* process BAR - indicate all pending RX frames till the BAR seqno */
-
-       rxtid = &an->an_aggr.rx.tid[tidno];
-
-       spin_lock_bh(&rxtid->tidlock);
-
-       /* get relative index */
-
-       index = ATH_BA_INDEX(rxtid->seq_next, seqno);
-
-       /* drop BAR if old sequence (index is too large) */
-
-       if ((index > rxtid->baw_size) &&
-           (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))))
-               /* discard frame, ieee layer may not treat frame as a dup */
-               goto unlock_and_free;
-
-       /* complete receive processing for all pending frames upto BAR seqno */
-
-       cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-       while ((rxtid->baw_head != rxtid->baw_tail) &&
-              (rxtid->baw_head != cindex)) {
-               tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-               rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-               rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-               if (tskb != NULL)
-                       ath_rx_subframe(an, tskb, rx_status);
-
-               INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-               INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-       }
-
-       /* ... and indicate rest of the frames in-order */
-
-       while (rxtid->baw_head != rxtid->baw_tail &&
-              rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) {
-               tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
-               rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
-               rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
-
-               ath_rx_subframe(an, tskb, rx_status);
-
-               INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-               INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-       }
-
-unlock_and_free:
-       spin_unlock_bh(&rxtid->tidlock);
-       /* free bar itself */
-       dev_kfree_skb(skb);
-       return IEEE80211_FTYPE_CTL;
-}
-
-/* Function to handle a subframe of aggregation when HT is enabled */
-
-static int ath_ampdu_input(struct ath_softc *sc,
-                          struct ath_node *an,
-                          struct sk_buff *skb,
-                          struct ath_recv_status *rx_status)
-{
-       struct ieee80211_hdr *hdr;
-       struct ath_arx_tid *rxtid;
-       struct ath_rxbuf *rxbuf;
-       u8 type, subtype;
-       u16 rxseq;
-       int tid = 0, index, cindex, rxdiff;
-       __le16 fc;
-       u8 *qc;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-       fc = hdr->frame_control;
-
-       /* collect stats of frames with non-zero version */
-
-       if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) {
-               dev_kfree_skb(skb);
-               return -1;
-       }
-
-       type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
-       subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
-
-       if (ieee80211_is_back_req(fc))
-               return ath_bar_rx(sc, an, skb);
-
-       /* special aggregate processing only for qos unicast data frames */
-
-       if (!ieee80211_is_data(fc) ||
-           !ieee80211_is_data_qos(fc) ||
-           is_multicast_ether_addr(hdr->addr1))
-               return ath_rx_subframe(an, skb, rx_status);
-
-       /* lookup rx tid state */
-
-       if (ieee80211_is_data_qos(fc)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & 0xf;
-       }
-
-       if (sc->sc_ah->ah_opmode == ATH9K_M_STA) {
-               /* Drop the frame not belonging to me. */
-               if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
-                       dev_kfree_skb(skb);
-                       return -1;
-               }
-       }
-
-       rxtid = &an->an_aggr.rx.tid[tid];
-
-       spin_lock(&rxtid->tidlock);
-
-       rxdiff = (rxtid->baw_tail - rxtid->baw_head) &
-               (ATH_TID_MAX_BUFS - 1);
-
-       /*
-        * If the ADDBA exchange has not been completed by the source,
-        * process via legacy path (i.e. no reordering buffer is needed)
-        */
-       if (!rxtid->addba_exchangecomplete) {
-               spin_unlock(&rxtid->tidlock);
-               return ath_rx_subframe(an, skb, rx_status);
-       }
-
-       /* extract sequence number from recvd frame */
-
-       rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
-
-       if (rxtid->seq_reset) {
-               rxtid->seq_reset = 0;
-               rxtid->seq_next = rxseq;
-       }
-
-       index = ATH_BA_INDEX(rxtid->seq_next, rxseq);
-
-       /* drop frame if old sequence (index is too large) */
-
-       if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) {
-               /* discard frame, ieee layer may not treat frame as a dup */
-               spin_unlock(&rxtid->tidlock);
-               dev_kfree_skb(skb);
-               return IEEE80211_FTYPE_DATA;
-       }
-
-       /* sequence number is beyond block-ack window */
-
-       if (index >= rxtid->baw_size) {
-
-               /* complete receive processing for all pending frames */
-
-               while (index >= rxtid->baw_size) {
-
-                       rxbuf = rxtid->rxbuf + rxtid->baw_head;
-
-                       if (rxbuf->rx_wbuf != NULL) {
-                               ath_rx_subframe(an, rxbuf->rx_wbuf,
-                                               &rxbuf->rx_status);
-                               rxbuf->rx_wbuf = NULL;
-                       }
-
-                       INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-                       INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-
-                       index--;
-               }
-       }
-
-       /* add buffer to the recv ba window */
-
-       cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
-       rxbuf = rxtid->rxbuf + cindex;
-
-       if (rxbuf->rx_wbuf != NULL) {
-               spin_unlock(&rxtid->tidlock);
-               /* duplicate frame */
-               dev_kfree_skb(skb);
-               return IEEE80211_FTYPE_DATA;
-       }
-
-       rxbuf->rx_wbuf = skb;
-       rxbuf->rx_time = get_timestamp();
-       rxbuf->rx_status = *rx_status;
-
-       /* advance tail if sequence received is newer
-        * than any received so far */
-
-       if (index >= rxdiff) {
-               rxtid->baw_tail = cindex;
-               INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS);
-       }
-
-       /* indicate all in-order received frames */
-
-       while (rxtid->baw_head != rxtid->baw_tail) {
-               rxbuf = rxtid->rxbuf + rxtid->baw_head;
-               if (!rxbuf->rx_wbuf)
-                       break;
-
-               ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status);
-               rxbuf->rx_wbuf = NULL;
-
-               INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-               INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-       }
-
-       /*
-        * start a timer to flush all received frames if there are pending
-        * receive frames
-        */
-       if (rxtid->baw_head != rxtid->baw_tail)
-               mod_timer(&rxtid->timer, ATH_RX_TIMEOUT);
-       else
-               del_timer_sync(&rxtid->timer);
-
-       spin_unlock(&rxtid->tidlock);
-       return IEEE80211_FTYPE_DATA;
-}
-
-/* Timer to flush all received sub-frames */
-
-static void ath_rx_timer(unsigned long data)
-{
-       struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data;
-       struct ath_node *an = rxtid->an;
-       struct ath_rxbuf *rxbuf;
-       int nosched;
-
-       spin_lock_bh(&rxtid->tidlock);
-       while (rxtid->baw_head != rxtid->baw_tail) {
-               rxbuf = rxtid->rxbuf + rxtid->baw_head;
-               if (!rxbuf->rx_wbuf) {
-                       INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-                       INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-                       continue;
-               }
-
-               /*
-                * Stop if the next one is a very recent frame.
-                *
-                * Call get_timestamp in every iteration to protect against the
-                * case in which a new frame is received while we are executing
-                * this function. Using a timestamp obtained before entering
-                * the loop could lead to a very large time interval
-                * (a negative value typecast to unsigned), breaking the
-                * function's logic.
-                */
-               if ((get_timestamp() - rxbuf->rx_time) <
-                       (ATH_RX_TIMEOUT * HZ / 1000))
-                       break;
-
-               ath_rx_subframe(an, rxbuf->rx_wbuf,
-                               &rxbuf->rx_status);
-               rxbuf->rx_wbuf = NULL;
-
-               INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-               INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-       }
-
-       /*
-        * start a timer to flush all received frames if there are pending
-        * receive frames
-        */
-       if (rxtid->baw_head != rxtid->baw_tail)
-               nosched = 0;
-       else
-               nosched = 1; /* no need to re-arm the timer again */
-
-       spin_unlock_bh(&rxtid->tidlock);
-}
-
-/* Free all pending sub-frames in the re-ordering buffer */
-
-static void ath_rx_flush_tid(struct ath_softc *sc,
-       struct ath_arx_tid *rxtid, int drop)
-{
-       struct ath_rxbuf *rxbuf;
-       unsigned long flag;
-
-       spin_lock_irqsave(&rxtid->tidlock, flag);
-       while (rxtid->baw_head != rxtid->baw_tail) {
-               rxbuf = rxtid->rxbuf + rxtid->baw_head;
-               if (!rxbuf->rx_wbuf) {
-                       INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-                       INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-                       continue;
-               }
-
-               if (drop)
-                       dev_kfree_skb(rxbuf->rx_wbuf);
-               else
-                       ath_rx_subframe(rxtid->an,
-                                       rxbuf->rx_wbuf,
-                                       &rxbuf->rx_status);
-
-               rxbuf->rx_wbuf = NULL;
-
-               INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
-               INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
-       }
-       spin_unlock_irqrestore(&rxtid->tidlock, flag);
-}
-
 static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
        u32 len)
 {
@@ -716,23 +394,6 @@ void ath_flushrecv(struct ath_softc *sc)
        spin_unlock_bh(&sc->sc_rxflushlock);
 }
 
-/* Process an individual frame */
-
-int ath_rx_input(struct ath_softc *sc,
-                struct ath_node *an,
-                struct sk_buff *skb,
-                struct ath_recv_status *rx_status,
-                enum ATH_RX_TYPE *status)
-{
-       if (sc->sc_flags & SC_OP_RXAGGR) {
-               *status = ATH_RX_CONSUMED;
-               return ath_ampdu_input(sc, an, skb, rx_status);
-       } else {
-               *status = ATH_RX_NON_CONSUMED;
-               return -1;
-       }
-}
-
 /* Process receive queue, as well as LED, etc. */
 
 int ath_rx_tasklet(struct ath_softc *sc, int flush)
@@ -1091,200 +752,3 @@ rx_next:
        return 0;
 #undef PA2DESC
 }
-
-/* Process ADDBA request in per-TID data structure */
-
-int ath_rx_aggr_start(struct ath_softc *sc,
-                     const u8 *addr,
-                     u16 tid,
-                     u16 *ssn)
-{
-       struct ath_arx_tid *rxtid;
-       struct ath_node *an;
-       struct ieee80211_hw *hw = sc->hw;
-       struct ieee80211_supported_band *sband;
-       u16 buffersize = 0;
-
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, (u8 *) addr);
-       spin_unlock_bh(&sc->node_lock);
-
-       if (!an) {
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: Node not found to initialize RX aggregation\n",
-                       __func__);
-               return -1;
-       }
-
-       sband = hw->wiphy->bands[hw->conf.channel->band];
-       buffersize = IEEE80211_MIN_AMPDU_BUF <<
-               sband->ht_cap.ampdu_factor; /* FIXME */
-
-       rxtid = &an->an_aggr.rx.tid[tid];
-
-       spin_lock_bh(&rxtid->tidlock);
-       if (sc->sc_flags & SC_OP_RXAGGR) {
-               /* Allow aggregation reception
-                * Adjust rx BA window size. Peer might indicate a
-                * zero buffer size for a _dont_care_ condition.
-                */
-               if (buffersize)
-                       rxtid->baw_size = min(buffersize, rxtid->baw_size);
-
-               /* set rx sequence number */
-               rxtid->seq_next = *ssn;
-
-               /* Allocate the receive buffers for this TID */
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: Allcating rxbuffer for TID %d\n", __func__, tid);
-
-               if (rxtid->rxbuf == NULL) {
-                       /*
-                       * If the rxbuff is not NULL at this point, we *probably*
-                       * already allocated the buffer on a previous ADDBA,
-                       * and this is a subsequent ADDBA that got through.
-                       * Don't allocate, but use the value in the pointer,
-                       * we zero it out when we de-allocate.
-                       */
-                       rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS *
-                               sizeof(struct ath_rxbuf), GFP_ATOMIC);
-               }
-               if (rxtid->rxbuf == NULL) {
-                       DPRINTF(sc, ATH_DBG_AGGR,
-                               "%s: Unable to allocate RX buffer, "
-                               "refusing ADDBA\n", __func__);
-               } else {
-                       /* Ensure the memory is zeroed out (all internal
-                        * pointers are null) */
-                       memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS *
-                               sizeof(struct ath_rxbuf));
-                       DPRINTF(sc, ATH_DBG_AGGR,
-                               "%s: Allocated @%p\n", __func__, rxtid->rxbuf);
-
-                       /* Allow aggregation reception */
-                       rxtid->addba_exchangecomplete = 1;
-               }
-       }
-       spin_unlock_bh(&rxtid->tidlock);
-
-       return 0;
-}
-
-/* Process DELBA */
-
-int ath_rx_aggr_stop(struct ath_softc *sc,
-                    const u8 *addr,
-                    u16 tid)
-{
-       struct ath_node *an;
-
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, (u8 *) addr);
-       spin_unlock_bh(&sc->node_lock);
-
-       if (!an) {
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: RX aggr stop for non-existent node\n", __func__);
-               return -1;
-       }
-
-       ath_rx_aggr_teardown(sc, an, tid);
-       return 0;
-}
-
-/* Rx aggregation tear down */
-
-void ath_rx_aggr_teardown(struct ath_softc *sc,
-       struct ath_node *an, u8 tid)
-{
-       struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid];
-
-       if (!rxtid->addba_exchangecomplete)
-               return;
-
-       del_timer_sync(&rxtid->timer);
-       ath_rx_flush_tid(sc, rxtid, 0);
-       rxtid->addba_exchangecomplete = 0;
-
-       /* De-allocate the receive buffer array allocated when addba started */
-
-       if (rxtid->rxbuf) {
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: Deallocating TID %d rxbuff @%p\n",
-                       __func__, tid, rxtid->rxbuf);
-               kfree(rxtid->rxbuf);
-
-               /* Set pointer to null to avoid reuse*/
-               rxtid->rxbuf = NULL;
-       }
-}
-
-/* Initialize per-node receive state */
-
-void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
-{
-       if (sc->sc_flags & SC_OP_RXAGGR) {
-               struct ath_arx_tid *rxtid;
-               int tidno;
-
-               /* Init per tid rx state */
-               for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-                               tidno < WME_NUM_TID;
-                               tidno++, rxtid++) {
-                       rxtid->an        = an;
-                       rxtid->seq_reset = 1;
-                       rxtid->seq_next  = 0;
-                       rxtid->baw_size  = WME_MAX_BA;
-                       rxtid->baw_head  = rxtid->baw_tail = 0;
-
-                       /*
-                        * Ensure the buffer pointer is null at this point
-                        * (needs to be allocated when addba is received)
-                       */
-
-                       rxtid->rxbuf     = NULL;
-                       setup_timer(&rxtid->timer, ath_rx_timer,
-                               (unsigned long)rxtid);
-                       spin_lock_init(&rxtid->tidlock);
-
-                       /* ADDBA state */
-                       rxtid->addba_exchangecomplete = 0;
-               }
-       }
-}
-
-void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
-{
-       if (sc->sc_flags & SC_OP_RXAGGR) {
-               struct ath_arx_tid *rxtid;
-               int tidno, i;
-
-               /* Init per tid rx state */
-               for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
-                               tidno < WME_NUM_TID;
-                               tidno++, rxtid++) {
-
-                       if (!rxtid->addba_exchangecomplete)
-                               continue;
-
-                       /* must cancel timer first */
-                       del_timer_sync(&rxtid->timer);
-
-                       /* drop any pending sub-frames */
-                       ath_rx_flush_tid(sc, rxtid, 1);
-
-                       for (i = 0; i < ATH_TID_MAX_BUFS; i++)
-                               ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL);
-
-                       rxtid->addba_exchangecomplete = 0;
-               }
-       }
-
-}
-
-/* Cleanup per-node receive state */
-
-void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
-       ath_rx_node_cleanup(sc, an);
-}
index 7cfab5a542f0ed3b96f8c7b9e5a42b94c52fca05..8937728b03018a30a204913f49ba85c92e06c88b 100644 (file)
@@ -65,11 +65,12 @@ static u32 bits_per_symbol[][2] = {
  * NB: must be called with txq lock held
  */
 
-static void ath_tx_txqaddbuf(struct ath_softc *sc,
-               struct ath_txq *txq, struct list_head *head)
+static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+                            struct list_head *head)
 {
        struct ath_hal *ah = sc->sc_ah;
        struct ath_buf *bf;
+
        /*
         * Insert the frame on the outbound list and
         * pass it on to the hardware.
@@ -124,27 +125,29 @@ static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
 
 /* Check if it's okay to send out aggregates */
 
-static int ath_aggr_query(struct ath_softc *sc,
-       struct ath_node *an, u8 tidno)
+static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 {
        struct ath_atx_tid *tid;
        tid = ATH_AN_2_TID(an, tidno);
 
-       if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress)
+       if (tid->state & AGGR_ADDBA_COMPLETE ||
+           tid->state & AGGR_ADDBA_PROGRESS)
                return 1;
        else
                return 0;
 }
 
-static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
+/* Calculate Atheros packet type from IEEE80211 packet header */
+
+static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 {
+       struct ieee80211_hdr *hdr;
        enum ath9k_pkt_type htype;
        __le16 fc;
 
+       hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
 
-       /* Calculate Atheros packet type from IEEE80211 packet header */
-
        if (ieee80211_is_beacon(fc))
                htype = ATH9K_PKT_TYPE_BEACON;
        else if (ieee80211_is_probe_resp(fc))
@@ -159,223 +162,176 @@ static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
        return htype;
 }
 
-static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl)
+static bool check_min_rate(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_tx_info_priv *tx_info_priv;
+       bool use_minrate = false;
        __le16 fc;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
 
-       /* XXX: HACK! */
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
-
        if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
-               txctl->use_minrate = 1;
-               txctl->min_rate = tx_info_priv->min_rate;
+               use_minrate = true;
        } else if (ieee80211_is_data(fc)) {
                if (ieee80211_is_nullfunc(fc) ||
-                               /* Port Access Entity (IEEE 802.1X) */
-                               (skb->protocol == cpu_to_be16(ETH_P_PAE))) {
-                       txctl->use_minrate = 1;
-                       txctl->min_rate = tx_info_priv->min_rate;
+                   /* Port Access Entity (IEEE 802.1X) */
+                   (skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+                       use_minrate = true;
                }
-               if (is_multicast_ether_addr(hdr->addr1))
-                       txctl->mcast_rate = tx_info_priv->min_rate;
        }
 
+       return use_minrate;
 }
 
-/* This function will setup additional txctl information, mostly rate stuff */
-/* FIXME: seqno, ps */
-static int ath_tx_prepare(struct ath_softc *sc,
-                         struct sk_buff *skb,
-                         struct ath_tx_control *txctl)
+static int get_hw_crypto_keytype(struct sk_buff *skb)
 {
-       struct ieee80211_hw *hw = sc->hw;
-       struct ieee80211_hdr *hdr;
-       struct ath_rc_series *rcs;
-       struct ath_txq *txq = NULL;
-       const struct ath9k_rate_table *rt;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ath_tx_info_priv *tx_info_priv;
-       int hdrlen;
-       u8 rix, antenna;
-       __le16 fc;
-       u8 *qc;
-
-       txctl->dev = sc;
-       hdr = (struct ieee80211_hdr *)skb->data;
-       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-       fc = hdr->frame_control;
-
-       rt = sc->sc_currates;
-       BUG_ON(!rt);
-
-       /* Fill misc fields */
-
-       spin_lock_bh(&sc->node_lock);
-       txctl->an = ath_node_get(sc, hdr->addr1);
-       /* create a temp node, if the node is not there already */
-       if (!txctl->an)
-               txctl->an = ath_node_attach(sc, hdr->addr1, 0);
-       spin_unlock_bh(&sc->node_lock);
-
-       if (ieee80211_is_data_qos(fc)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               txctl->tidno = qc[0] & 0xf;
-       }
-
-       txctl->if_id = 0;
-       txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
-
-       /* Always try at highest power possible unless the the device
-        * was configured by the user to use another power. */
-       if (likely(sc->sc_config.txpowlimit == ATH_TXPOWER_MAX))
-               txctl->txpower = ATH_TXPOWER_MAX;
-       else
-               txctl->txpower = sc->sc_config.txpowlimit;
-
-       /* Fill Key related fields */
-
-       txctl->keytype = ATH9K_KEY_TYPE_CLEAR;
-       txctl->keyix = ATH9K_TXKEYIX_INVALID;
 
        if (tx_info->control.hw_key) {
-               txctl->keyix = tx_info->control.hw_key->hw_key_idx;
-               txctl->frmlen += tx_info->control.hw_key->icv_len;
-
                if (tx_info->control.hw_key->alg == ALG_WEP)
-                       txctl->keytype = ATH9K_KEY_TYPE_WEP;
+                       return ATH9K_KEY_TYPE_WEP;
                else if (tx_info->control.hw_key->alg == ALG_TKIP)
-                       txctl->keytype = ATH9K_KEY_TYPE_TKIP;
+                       return ATH9K_KEY_TYPE_TKIP;
                else if (tx_info->control.hw_key->alg == ALG_CCMP)
-                       txctl->keytype = ATH9K_KEY_TYPE_AES;
+                       return ATH9K_KEY_TYPE_AES;
        }
 
-       /* Fill packet type */
-
-       txctl->atype = get_hal_packet_type(hdr);
-
-       /* Fill qnum */
+       return ATH9K_KEY_TYPE_CLEAR;
+}
 
-       if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) {
-               txctl->qnum = 0;
-               txq = sc->sc_cabq;
-       } else {
-               txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
-               txq = &sc->sc_txq[txctl->qnum];
-       }
-       spin_lock_bh(&txq->axq_lock);
+static void setup_rate_retries(struct ath_softc *sc, struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_tx_info_priv *tx_info_priv;
+       struct ath_rc_series *rcs;
+       struct ieee80211_hdr *hdr;
+       const struct ath9k_rate_table *rt;
+       bool use_minrate;
+       __le16 fc;
+       u8 rix;
 
-       /* Try to avoid running out of descriptors */
-       if (txq->axq_depth >= (ATH_TXBUF - 20) &&
-           !(txctl->flags & ATH9K_TXDESC_CAB)) {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "%s: TX queue: %d is full, depth: %d\n",
-                       __func__,
-                       txctl->qnum,
-                       txq->axq_depth);
-               ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
-               txq->stopped = 1;
-               spin_unlock_bh(&txq->axq_lock);
-               return -1;
-       }
+       rt = sc->sc_currates;
+       BUG_ON(!rt);
 
-       spin_unlock_bh(&txq->axq_lock);
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = hdr->frame_control;
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif; /* HACK */
+       rcs = tx_info_priv->rcs;
 
-       /* Fill rate */
+       /* Check if min rates have to be used */
+       use_minrate = check_min_rate(skb);
 
-       fill_min_rates(skb, txctl);
+       if (ieee80211_is_data(fc) && !use_minrate) {
+               if (is_multicast_ether_addr(hdr->addr1)) {
+                       rcs[0].rix =
+                               ath_tx_findindex(rt, tx_info_priv->min_rate);
+                       /* mcast packets are not re-tried */
+                       rcs[0].tries = 1;
+               }
+       } else {
+               /* for management and control frames,
+                  or for NULL and EAPOL frames */
+               if (use_minrate)
+                       rcs[0].rix = ath_rate_findrateix(sc, tx_info_priv->min_rate);
+               else
+                       rcs[0].rix = 0;
+               rcs[0].tries = ATH_MGT_TXMAXTRY;
+       }
 
-       /* Fill flags */
+       rix = rcs[0].rix;
 
-       txctl->flags |= ATH9K_TXDESC_CLRDMASK /* needed for crypto errors */
-               | ATH9K_TXDESC_INTREQ; /* Generate an interrupt */
+       if (ieee80211_has_morefrags(fc) ||
+           (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
+               rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
+               rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
+               /* reset tries but keep rate index */
+               rcs[0].tries = ATH_TXMAXTRY;
+       }
+}
 
-       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
-               txctl->flags |= ATH9K_TXDESC_NOACK;
+/* Called only when tx aggregation is enabled and HT is supported */
 
-       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               txctl->flags |= ATH9K_TXDESC_RTSENA;
+static void assign_aggr_tid_seqno(struct sk_buff *skb,
+                                 struct ath_buf *bf)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr;
+       struct ath_node *an;
+       struct ath_atx_tid *tid;
+       __le16 fc;
+       u8 *qc;
 
-       /*
-        * Setup for rate calculations.
-        */
+       if (!tx_info->control.sta)
+               return;
 
-       /* XXX: HACK! */
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
-       rcs = tx_info_priv->rcs;
+       an = (struct ath_node *)tx_info->control.sta->drv_priv;
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = hdr->frame_control;
 
-       if (ieee80211_is_data(fc) && !txctl->use_minrate) {
+       /* Get tidno */
 
-               /* Enable HT only for DATA frames and not for EAPOL */
-               /* XXX why AMPDU only?? */
-               txctl->ht = (hw->conf.ht.enabled &&
-                           (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
+       if (ieee80211_is_data_qos(fc)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               bf->bf_tidno = qc[0] & 0xf;
+       }
 
-               if (is_multicast_ether_addr(hdr->addr1)) {
-                       rcs[0].rix = (u8)
-                               ath_tx_findindex(rt, txctl->mcast_rate);
+       /* Get seqno */
 
-                       /*
-                        * mcast packets are not re-tried.
-                        */
-                       rcs[0].tries = 1;
-               }
+       if (ieee80211_is_data(fc) && !check_min_rate(skb)) {
                /* For HT capable stations, we save tidno for later use.
                 * We also override seqno set by upper layer with the one
                 * in tx aggregation state.
                 *
-                * First, the fragmentation stat is determined.
                 * If fragmentation is on, the sequence number is
                 * not overridden, since it has been
                 * incremented by the fragmentation routine.
+                *
+                * FIXME: check if the fragmentation threshold exceeds
+                * IEEE80211 max.
                 */
-               if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
-                   txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-                       struct ath_atx_tid *tid;
+               tid = ATH_AN_2_TID(an, bf->bf_tidno);
+               hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
+                                           IEEE80211_SEQ_SEQ_SHIFT);
+               bf->bf_seqno = tid->seq_next;
+               INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+       }
+}
 
-                       tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
+static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
+                         struct ath_txq *txq)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       int flags = 0;
 
-                       hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
-                               IEEE80211_SEQ_SEQ_SHIFT);
-                       txctl->seqno = tid->seq_next;
-                       INCR(tid->seq_next, IEEE80211_SEQ_MAX);
-               }
-       } else {
-               /* for management and control frames,
-                * or for NULL and EAPOL frames */
-               if (txctl->min_rate)
-                       rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate);
-               else
-                       rcs[0].rix = 0;
-               rcs[0].tries = ATH_MGT_TXMAXTRY;
-       }
-       rix = rcs[0].rix;
+       flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+       flags |= ATH9K_TXDESC_INTREQ;
 
-       if (ieee80211_has_morefrags(fc) ||
-           (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-               /*
-               **  Force hardware to use computed duration for next
-               **  fragment by disabling multi-rate retry, which
-               **  updates duration based on the multi-rate
-               **  duration table.
-               */
-               rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
-               rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
-               /* reset tries but keep rate index */
-               rcs[0].tries = ATH_TXMAXTRY;
-       }
+       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+               flags |= ATH9K_TXDESC_NOACK;
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               flags |= ATH9K_TXDESC_RTSENA;
+
+       return flags;
+}
 
-       if (is_multicast_ether_addr(hdr->addr1)) {
-               antenna = sc->sc_mcastantenna + 1;
-               sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
+{
+       struct ath_buf *bf = NULL;
+
+       spin_lock_bh(&sc->sc_txbuflock);
+
+       if (unlikely(list_empty(&sc->sc_txbuf))) {
+               spin_unlock_bh(&sc->sc_txbuflock);
+               return NULL;
        }
 
-       return 0;
+       bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list);
+       list_del(&bf->list);
+
+       spin_unlock_bh(&sc->sc_txbuflock);
+
+       return bf;
 }
 
 /* To complete a chain of buffers associated a frame */
@@ -405,13 +361,14 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
                if (bf_isxretried(bf))
                        tx_status.flags |= ATH_TX_XRETRY;
        }
+
        /* Unmap this frame */
        pci_unmap_single(sc->pdev,
                         bf->bf_dmacontext,
                         skb->len,
                         PCI_DMA_TODEVICE);
        /* complete this frame */
-       ath_tx_complete(sc, skb, &tx_status, bf->bf_node);
+       ath_tx_complete(sc, skb, &tx_status);
 
        /*
         * Return the list of ath_buf of this mpdu to free queue
@@ -496,11 +453,9 @@ unlock:
 
 /* Compute the number of bad frames */
 
-static int ath_tx_num_badfrms(struct ath_softc *sc,
-       struct ath_buf *bf, int txok)
+static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
+                             int txok)
 {
-       struct ath_node *an = bf->bf_node;
-       int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
        struct ath_buf *bf_last = bf->bf_lastbf;
        struct ath_desc *ds = bf_last->bf_desc;
        u16 seq_st = 0;
@@ -509,7 +464,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc,
        int nbad = 0;
        int isaggr = 0;
 
-       if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+       if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
                return 0;
 
        isaggr = bf_isaggr(bf);
@@ -544,8 +499,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
 
 /* Update block ack window */
 
-static void ath_tx_update_baw(struct ath_softc *sc,
-       struct ath_atx_tid *tid, int seqno)
+static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
+                             int seqno)
 {
        int index, cindex;
 
@@ -569,12 +524,8 @@ static void ath_tx_update_baw(struct ath_softc *sc,
  * half_gi - to use 4us v/s 3.6 us for symbol time
  */
 
-static u32 ath_pkt_duration(struct ath_softc *sc,
-                                 u8 rix,
-                                 struct ath_buf *bf,
-                                 int width,
-                                 int half_gi,
-                                 bool shortPreamble)
+static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
+                           int width, int half_gi, bool shortPreamble)
 {
        const struct ath9k_rate_table *rt = sc->sc_currates;
        u32 nbits, nsymbits, duration, nsymbols;
@@ -588,11 +539,8 @@ static u32 ath_pkt_duration(struct ath_softc *sc,
         * for legacy rates, use old function to compute packet duration
         */
        if (!IS_HT_RATE(rc))
-               return ath9k_hw_computetxtime(sc->sc_ah,
-                                            rt,
-                                            pktlen,
-                                            rix,
-                                            shortPreamble);
+               return ath9k_hw_computetxtime(sc->sc_ah, rt, pktlen, rix,
+                                             shortPreamble);
        /*
         * find number of symbols: PLCP + data
         */
@@ -610,6 +558,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc,
         */
        streams = HT_RC_2_STREAMS(rc);
        duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+
        return duration;
 }
 
@@ -622,11 +571,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
        struct ath_desc *ds = bf->bf_desc;
        struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
        struct ath9k_11n_rate_series series[4];
-       int i, flags, rtsctsena = 0, dynamic_mimops = 0;
+       int i, flags, rtsctsena = 0;
        u32 ctsduration = 0;
        u8 rix = 0, cix, ctsrate = 0;
-       u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit;
-       struct ath_node *an = (struct ath_node *) bf->bf_node;
+       struct ath_node *an = NULL;
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *tx_info;
+
+       skb = (struct sk_buff *)bf->bf_mpdu;
+       tx_info = IEEE80211_SKB_CB(skb);
+
+       if (tx_info->control.sta)
+               an = (struct ath_node *)tx_info->control.sta->drv_priv;
 
        /*
         * get the cix for the lowest valid rix.
@@ -665,24 +621,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
         * use RTS.
         */
        if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
-               BUG_ON(!an);
                /*
                 * 802.11g protection not needed, use our default behavior
                 */
                if (!rtsctsena)
                        flags = ATH9K_TXDESC_RTSENA;
-               /*
-                * For dynamic MIMO PS, RTS needs to precede the first aggregate
-                * and the second aggregate should have any protection at all.
-                */
-               if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
-                       if (!bf_isaggrburst(bf)) {
-                               flags = ATH9K_TXDESC_RTSENA;
-                               dynamic_mimops = 1;
-                       } else {
-                               flags = 0;
-                       }
-               }
        }
 
        /*
@@ -698,7 +641,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
        /*
         *  For AR5416 - RTS cannot be followed by a frame larger than 8K.
         */
-       if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) {
+       if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) {
                /*
                 * Ensure that in the case of SM Dynamic power save
                 * while we are bursting the second aggregate the
@@ -711,8 +654,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
         * CTS transmit rate is derived from the transmit rate
         * by looking in the h/w rate table.  We must also factor
         * in whether or not a short preamble is to be used.
+        * NB: cix is set above where RTS/CTS is enabled
         */
-       /* NB: cix is set above where RTS/CTS is enabled */
        BUG_ON(cix == 0xff);
        ctsrate = rt->info[cix].rateCode |
                (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0);
@@ -741,39 +684,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                        ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
                                ATH9K_RATESERIES_HALFGI : 0);
 
-               series[i].PktDuration = ath_pkt_duration(
-                       sc, rix, bf,
-                       (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
-                       (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
-                       bf_isshpreamble(bf));
+               series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+                        (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
+                        (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
+                        bf_isshpreamble(bf));
 
-               if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
-                   (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
-                       /*
-                        * When sending to an HT node that has enabled static
-                        * SM/MIMO power save, send at single stream rates but
-                        * use maximum allowed transmit chains per user,
-                        * hardware, regulatory, or country limits for
-                        * better range.
-                        */
+               if (bf_isht(bf) && an)
+                       series[i].ChSel = ath_chainmask_sel_logic(sc, an);
+               else
                        series[i].ChSel = sc->sc_tx_chainmask;
-               } else {
-                       if (bf_isht(bf))
-                               series[i].ChSel =
-                                       ath_chainmask_sel_logic(sc, an);
-                       else
-                               series[i].ChSel = sc->sc_tx_chainmask;
-               }
 
                if (rtsctsena)
                        series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
-
-               /*
-                * Set RTS for all rates if node is in dynamic powersave
-                * mode and we are using dual stream rates.
-                */
-               if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG))
-                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
        }
 
        /*
@@ -819,6 +741,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                                     ctsrate,
                                     ctsduration,
                                     series, 4, flags);
+
        if (sc->sc_config.ath_aggr_prot && flags)
                ath9k_hw_set11n_burstduration(ah, ds, 8192);
 }
@@ -899,8 +822,10 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
                                      struct list_head *bf_q,
                                      int txok)
 {
-       struct ath_node *an = bf->bf_node;
-       struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno);
+       struct ath_node *an = NULL;
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *tx_info;
+       struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf_last = bf->bf_lastbf;
        struct ath_desc *ds = bf_last->bf_desc;
        struct ath_buf *bf_next, *bf_lastq = NULL;
@@ -908,7 +833,14 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
        u16 seq_st = 0;
        u32 ba[WME_BA_BMP_SIZE >> 5];
        int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
-       int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
+
+       skb = (struct sk_buff *)bf->bf_mpdu;
+       tx_info = IEEE80211_SKB_CB(skb);
+
+       if (tx_info->control.sta) {
+               an = (struct ath_node *)tx_info->control.sta->drv_priv;
+               tid = ATH_AN_2_TID(an, bf->bf_tidno);
+       }
 
        isaggr = bf_isaggr(bf);
        if (isaggr) {
@@ -954,7 +886,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
                        /* transmit completion */
                } else {
 
-                       if (!tid->cleanup_inprogress && !isnodegone &&
+                       if (!(tid->state & AGGR_CLEANUP) &&
                            ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
                                if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
                                        ath_tx_set_retry(sc, bf);
@@ -1042,7 +974,6 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
 
                                /* copy descriptor content */
                                tbf->bf_mpdu = bf_last->bf_mpdu;
-                               tbf->bf_node = bf_last->bf_node;
                                tbf->bf_buf_addr = bf_last->bf_buf_addr;
                                *(tbf->bf_desc) = *(bf_last->bf_desc);
 
@@ -1083,25 +1014,16 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
                bf = bf_next;
        }
 
-       /*
-        * node is already gone. no more assocication
-        * with the node. the node might have been freed
-        * any  node acces can result in panic.note tid
-        * is part of the node.
-        */
-       if (isnodegone)
-               return;
-
-       if (tid->cleanup_inprogress) {
+       if (tid->state & AGGR_CLEANUP) {
                /* check to see if we're done with cleaning the h/w queue */
                spin_lock_bh(&txq->axq_lock);
 
                if (tid->baw_head == tid->baw_tail) {
-                       tid->addba_exchangecomplete = 0;
+                       tid->state &= ~AGGR_ADDBA_COMPLETE;
                        tid->addba_exchangeattempts = 0;
                        spin_unlock_bh(&txq->axq_lock);
 
-                       tid->cleanup_inprogress = false;
+                       tid->state &= ~AGGR_CLEANUP;
 
                        /* send buffered frames as singles */
                        ath_tx_flush_tid(sc, tid);
@@ -1310,26 +1232,21 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
 static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
 {
        struct ath_hal *ah = sc->sc_ah;
-       int i;
-       int npend = 0;
+       int i, status, npend = 0;
 
-       /* XXX return value */
        if (!(sc->sc_flags & SC_OP_INVALID)) {
                for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
                        if (ATH_TXQ_SETUP(sc, i)) {
                                ath_tx_stopdma(sc, &sc->sc_txq[i]);
-
                                /* The TxDMA may not really be stopped.
                                 * Double check the hal tx pending count */
                                npend += ath9k_hw_numtxpending(ah,
-                                       sc->sc_txq[i].axq_qnum);
+                                                      sc->sc_txq[i].axq_qnum);
                        }
                }
        }
 
        if (npend) {
-               int status;
-
                /* TxDMA not stopped, reset the hal */
                DPRINTF(sc, ATH_DBG_XMIT,
                        "%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
@@ -1385,7 +1302,6 @@ static void ath_tx_addto_baw(struct ath_softc *sc,
  */
 
 static int ath_tx_send_ampdu(struct ath_softc *sc,
-                            struct ath_txq *txq,
                             struct ath_atx_tid *tid,
                             struct list_head *bf_head,
                             struct ath_tx_control *txctl)
@@ -1399,8 +1315,6 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
 
        bf = list_first_entry(bf_head, struct ath_buf, list);
        bf->bf_state.bf_type |= BUF_AMPDU;
-       bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
-       bf->bf_tidno = txctl->tidno;
 
        /*
         * Do not queue to h/w when any of the following conditions is true:
@@ -1411,13 +1325,13 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
         */
        if (!list_empty(&tid->buf_q) || tid->paused ||
            !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
-           txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
+           txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
                /*
                 * Add this frame to software queue for scheduling later
                 * for aggregation.
                 */
                list_splice_tail_init(bf_head, &tid->buf_q);
-               ath_tx_queue_tid(txq, tid);
+               ath_tx_queue_tid(txctl->txq, tid);
                return 0;
        }
 
@@ -1434,7 +1348,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
        bf->bf_nframes = 1;
        bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */
        ath_buf_set_rate(sc, bf);
-       ath_tx_txqaddbuf(sc, txq, bf_head);
+       ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
+
        return 0;
 }
 
@@ -1455,7 +1370,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
        u16 aggr_limit, legacy = 0, maxampdu;
        int i;
 
-
        skb = (struct sk_buff *)bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
        tx_info_priv = (struct ath_tx_info_priv *)
@@ -1795,8 +1709,8 @@ static void ath_tx_sched_aggr(struct ath_softc *sc,
 
 static void ath_tid_drain(struct ath_softc *sc,
                          struct ath_txq *txq,
-                         struct ath_atx_tid *tid,
-                         bool bh_flag)
+                         struct ath_atx_tid *tid)
+
 {
        struct ath_buf *bf;
        struct list_head bf_head;
@@ -1817,18 +1731,12 @@ static void ath_tid_drain(struct ath_softc *sc,
                 * do not indicate packets while holding txq spinlock.
                 * unlock is intentional here
                 */
-               if (likely(bh_flag))
-                       spin_unlock_bh(&txq->axq_lock);
-               else
-                       spin_unlock(&txq->axq_lock);
+               spin_unlock(&txq->axq_lock);
 
                /* complete this sub-frame */
                ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
 
-               if (likely(bh_flag))
-                       spin_lock_bh(&txq->axq_lock);
-               else
-                       spin_lock(&txq->axq_lock);
+               spin_lock(&txq->axq_lock);
        }
 
        /*
@@ -1847,8 +1755,7 @@ static void ath_tid_drain(struct ath_softc *sc,
  */
 
 static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
-                                         struct ath_txq *txq,
-                                         bool bh_flag)
+                                         struct ath_txq *txq)
 {
        struct ath_atx_ac *ac, *ac_tmp;
        struct ath_atx_tid *tid, *tid_tmp;
@@ -1859,51 +1766,32 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
                list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
                        list_del(&tid->list);
                        tid->sched = false;
-                       ath_tid_drain(sc, txq, tid, bh_flag);
+                       ath_tid_drain(sc, txq, tid);
                }
        }
 }
 
-static int ath_tx_start_dma(struct ath_softc *sc,
-                           struct sk_buff *skb,
-                           struct scatterlist *sg,
-                           u32 n_sg,
-                           struct ath_tx_control *txctl)
+static void ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+                               struct sk_buff *skb, struct scatterlist *sg,
+                               struct ath_tx_control *txctl)
 {
-       struct ath_node *an = txctl->an;
-       struct ath_buf *bf = NULL;
-       struct list_head bf_head;
-       struct ath_desc *ds;
-       struct ath_hal *ah = sc->sc_ah;
-       struct ath_txq *txq;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ath_tx_info_priv *tx_info_priv;
        struct ath_rc_series *rcs;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
-       __le16 fc = hdr->frame_control;
-
-       if (unlikely(txctl->flags & ATH9K_TXDESC_CAB))
-               txq = sc->sc_cabq;
-       else
-               txq = &sc->sc_txq[txctl->qnum];
+       int hdrlen;
+       __le16 fc;
 
-       /* For each sglist entry, allocate an ath_buf for DMA */
-       INIT_LIST_HEAD(&bf_head);
-       spin_lock_bh(&sc->sc_txbuflock);
-       if (unlikely(list_empty(&sc->sc_txbuf))) {
-               spin_unlock_bh(&sc->sc_txbuflock);
-               return -ENOMEM;
-       }
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+       fc = hdr->frame_control;
+       rcs = tx_info_priv->rcs;
 
-       bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list);
-       list_del(&bf->list);
-       spin_unlock_bh(&sc->sc_txbuflock);
+       ATH_TXBUF_RESET(bf);
 
-       list_add_tail(&bf->list, &bf_head);
+       /* Frame type */
 
-       /* set up this buffer */
-       ATH_TXBUF_RESET(bf);
-       bf->bf_frmlen = txctl->frmlen;
+       bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
        ieee80211_is_data(fc) ?
                (bf->bf_state.bf_type |= BUF_DATA) :
@@ -1917,121 +1805,142 @@ static int ath_tx_start_dma(struct ath_softc *sc,
        (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ?
                (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) :
                (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE);
+       (sc->hw->conf.ht.enabled &&
+        (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ?
+               (bf->bf_state.bf_type |= BUF_HT) :
+               (bf->bf_state.bf_type &= ~BUF_HT);
+
+       bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
+
+       /* Crypto */
+
+       bf->bf_keytype = get_hw_crypto_keytype(skb);
+
+       if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
+               bf->bf_frmlen += tx_info->control.hw_key->icv_len;
+               bf->bf_keyix = tx_info->control.hw_key->hw_key_idx;
+       } else {
+               bf->bf_keyix = ATH9K_TXKEYIX_INVALID;
+       }
+
+       /* Rate series */
+
+       setup_rate_retries(sc, skb);
 
-       bf->bf_flags = txctl->flags;
-       bf->bf_keytype = txctl->keytype;
-       /* XXX: HACK! */
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
-       rcs = tx_info_priv->rcs;
        bf->bf_rcs[0] = rcs[0];
        bf->bf_rcs[1] = rcs[1];
        bf->bf_rcs[2] = rcs[2];
        bf->bf_rcs[3] = rcs[3];
-       bf->bf_node = an;
+
+       /* Assign seqno, tidno */
+
+       if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
+               assign_aggr_tid_seqno(skb, bf);
+
+       /* DMA setup */
+
        bf->bf_mpdu = skb;
-       bf->bf_buf_addr = sg_dma_address(sg);
+       bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
+                                          skb->len, PCI_DMA_TODEVICE);
+       bf->bf_buf_addr = bf->bf_dmacontext;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+                            struct scatterlist *sg, u32 n_sg,
+                            struct ath_tx_control *txctl)
+{
+       struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+       struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
+       struct ath_node *an = NULL;
+       struct list_head bf_head;
+       struct ath_desc *ds;
+       struct ath_atx_tid *tid;
+       struct ath_hal *ah = sc->sc_ah;
+       int frm_type;
+
+       frm_type = get_hw_packet_type(skb);
+
+       INIT_LIST_HEAD(&bf_head);
+       list_add_tail(&bf->list, &bf_head);
 
        /* setup descriptor */
+
        ds = bf->bf_desc;
        ds->ds_link = 0;
        ds->ds_data = bf->bf_buf_addr;
 
-       /*
-        * Save the DMA context in the first ath_buf
-        */
-       bf->bf_dmacontext = txctl->dmacontext;
+       /* Formulate first tx descriptor with tx controls */
 
-       /*
-        * Formulate first tx descriptor with tx controls.
-        */
-       ath9k_hw_set11n_txdesc(ah,
-                              ds,
-                              bf->bf_frmlen, /* frame length */
-                              txctl->atype, /* Atheros packet type */
-                              min(txctl->txpower, (u16)60), /* txpower */
-                              txctl->keyix,            /* key cache index */
-                              txctl->keytype,          /* key type */
-                              txctl->flags);           /* flags */
-       ath9k_hw_filltxdesc(ah,
-                           ds,
-                           sg_dma_len(sg),     /* segment length */
-                           true,            /* first segment */
-                           (n_sg == 1) ? true : false, /* last segment */
-                           ds);                /* first descriptor */
+       ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
+                              bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
+
+       ath9k_hw_filltxdesc(ah, ds,
+                           sg_dma_len(sg),             /* segment length */
+                           true,                       /* first segment */
+                           (n_sg == 1) ? true : false, /* last segment */
+                           ds);                        /* first descriptor */
 
        bf->bf_lastfrm = bf;
-       (txctl->ht) ?
-               (bf->bf_state.bf_type |= BUF_HT) :
-               (bf->bf_state.bf_type &= ~BUF_HT);
 
-       spin_lock_bh(&txq->axq_lock);
+       spin_lock_bh(&txctl->txq->axq_lock);
+
+       if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) &&
+           tx_info->control.sta) {
+               an = (struct ath_node *)tx_info->control.sta->drv_priv;
+               tid = ATH_AN_2_TID(an, bf->bf_tidno);
 
-       if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-               struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
-               if (ath_aggr_query(sc, an, txctl->tidno)) {
+               if (ath_aggr_query(sc, an, bf->bf_tidno)) {
                        /*
                         * Try aggregation if it's a unicast data frame
                         * and the destination is HT capable.
                         */
-                       ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl);
+                       ath_tx_send_ampdu(sc, tid, &bf_head, txctl);
                } else {
                        /*
-                        * Send this frame as regular when ADDBA exchange
-                        * is neither complete nor pending.
+                        * Send this frame as regular when ADDBA
+                        * exchange is neither complete nor pending.
                         */
-                       ath_tx_send_normal(sc, txq, tid, &bf_head);
+                       ath_tx_send_normal(sc, txctl->txq,
+                                          tid, &bf_head);
                }
        } else {
                bf->bf_lastbf = bf;
                bf->bf_nframes = 1;
-               ath_buf_set_rate(sc, bf);
-
-               if (ieee80211_is_back_req(fc)) {
-                       /* This is required for resuming tid
-                        * during BAR completion */
-                       bf->bf_tidno = txctl->tidno;
-               }
 
-               ath_tx_txqaddbuf(sc, txq, &bf_head);
+               ath_buf_set_rate(sc, bf);
+               ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
        }
-       spin_unlock_bh(&txq->axq_lock);
-       return 0;
+
+       spin_unlock_bh(&txctl->txq->axq_lock);
 }
 
-static void xmit_map_sg(struct ath_softc *sc,
-                       struct sk_buff *skb,
-                       struct ath_tx_control *txctl)
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+                struct ath_tx_control *txctl)
 {
-       struct ath_xmit_status tx_status;
-       struct ath_atx_tid *tid;
+       struct ath_buf *bf;
        struct scatterlist sg;
 
-       txctl->dmacontext = pci_map_single(sc->pdev, skb->data,
-                                          skb->len, PCI_DMA_TODEVICE);
+       /* Check if a tx buffer is available */
+
+       bf = ath_tx_get_buffer(sc);
+       if (!bf) {
+               DPRINTF(sc, ATH_DBG_XMIT, "%s: TX buffers are full\n",
+                       __func__);
+               return -1;
+       }
+
+       ath_tx_setup_buffer(sc, bf, skb, &sg, txctl);
+
+       /* Setup S/G */
 
-       /* setup S/G list */
        memset(&sg, 0, sizeof(struct scatterlist));
-       sg_dma_address(&sg) = txctl->dmacontext;
+       sg_dma_address(&sg) = bf->bf_dmacontext;
        sg_dma_len(&sg) = skb->len;
 
-       if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
-               /*
-                *  We have to do drop frame here.
-                */
-               pci_unmap_single(sc->pdev, txctl->dmacontext,
-                                skb->len, PCI_DMA_TODEVICE);
-
-               tx_status.retries = 0;
-               tx_status.flags = ATH_TX_ERROR;
+       ath_tx_start_dma(sc, bf, &sg, 1, txctl);
 
-               if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) {
-                       /* Reclaim the seqno. */
-                       tid = ATH_AN_2_TID((struct ath_node *)
-                               txctl->an, txctl->tidno);
-                       DECR(tid->seq_next, IEEE80211_SEQ_MAX);
-               }
-               ath_tx_complete(sc, skb, &tx_status, txctl->an);
-       }
+       return 0;
 }
 
 /* Initialize TX queue and h/w */
@@ -2217,6 +2126,34 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
        return qnum;
 }
 
+/* Get a transmit queue, if available */
+
+struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
+{
+       struct ath_txq *txq = NULL;
+       int qnum;
+
+       qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+       txq = &sc->sc_txq[qnum];
+
+       spin_lock_bh(&txq->axq_lock);
+
+       /* Try to avoid running out of descriptors */
+       if (txq->axq_depth >= (ATH_TXBUF - 20)) {
+               DPRINTF(sc, ATH_DBG_FATAL,
+                       "%s: TX queue: %d is full, depth: %d\n",
+                       __func__, qnum, txq->axq_depth);
+               ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+               txq->stopped = 1;
+               spin_unlock_bh(&txq->axq_lock);
+               return NULL;
+       }
+
+       spin_unlock_bh(&txq->axq_lock);
+
+       return txq;
+}
+
 /* Update parameters for a transmit queue */
 
 int ath_txq_update(struct ath_softc *sc, int qnum,
@@ -2280,27 +2217,6 @@ int ath_cabq_update(struct ath_softc *sc)
        return 0;
 }
 
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
-{
-       struct ath_tx_control txctl;
-       int error = 0;
-
-       memset(&txctl, 0, sizeof(struct ath_tx_control));
-       error = ath_tx_prepare(sc, skb, &txctl);
-       if (error == 0)
-               /*
-                * Start DMA mapping.
-                * ath_tx_start_dma() will be called either synchronously
-                * or asynchrounsly once DMA is complete.
-                */
-               xmit_map_sg(sc, skb, &txctl);
-       else
-               ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
-
-       /* failed packets will be dropped by the caller */
-       return error;
-}
-
 /* Deferred processing of transmit interrupt */
 
 void ath_tx_tasklet(struct ath_softc *sc)
@@ -2374,8 +2290,7 @@ void ath_tx_draintxq(struct ath_softc *sc,
        if (sc->sc_flags & SC_OP_TXAGGR) {
                if (!retry_tx) {
                        spin_lock_bh(&txq->axq_lock);
-                       ath_txq_drain_pending_buffers(sc, txq,
-                               ATH9K_BH_STATUS_CHANGE);
+                       ath_txq_drain_pending_buffers(sc, txq);
                        spin_unlock_bh(&txq->axq_lock);
                }
        }
@@ -2406,63 +2321,39 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum)
        return sc->sc_txq[qnum].axq_aggr_depth;
 }
 
-/* Check if an ADDBA is required. A valid node must be passed. */
-enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
-                                     struct ath_node *an,
-                                     u8 tidno)
+bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 {
        struct ath_atx_tid *txtid;
 
        if (!(sc->sc_flags & SC_OP_TXAGGR))
-               return AGGR_NOT_REQUIRED;
+               return false;
 
-       /* ADDBA exchange must be completed before sending aggregates */
        txtid = ATH_AN_2_TID(an, tidno);
 
-       if (txtid->addba_exchangecomplete)
-               return AGGR_EXCHANGE_DONE;
-
-       if (txtid->cleanup_inprogress)
-               return AGGR_CLEANUP_PROGRESS;
-
-       if (txtid->addba_exchangeinprogress)
-               return AGGR_EXCHANGE_PROGRESS;
-
-       if (!txtid->addba_exchangecomplete) {
-               if (!txtid->addba_exchangeinprogress &&
+       if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
+               if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
                    (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
                        txtid->addba_exchangeattempts++;
-                       return AGGR_REQUIRED;
+                       return true;
                }
        }
 
-       return AGGR_NOT_REQUIRED;
+       return false;
 }
 
 /* Start TX aggregation */
 
-int ath_tx_aggr_start(struct ath_softc *sc,
-                     const u8 *addr,
-                     u16 tid,
-                     u16 *ssn)
+int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
+                     u16 tid, u16 *ssn)
 {
        struct ath_atx_tid *txtid;
        struct ath_node *an;
 
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, (u8 *) addr);
-       spin_unlock_bh(&sc->node_lock);
-
-       if (!an) {
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: Node not found to initialize "
-                       "TX aggregation\n", __func__);
-               return -1;
-       }
+       an = (struct ath_node *)sta->drv_priv;
 
        if (sc->sc_flags & SC_OP_TXAGGR) {
                txtid = ATH_AN_2_TID(an, tid);
-               txtid->addba_exchangeinprogress = 1;
+               txtid->state |= AGGR_ADDBA_PROGRESS;
                ath_tx_pause_tid(sc, txtid);
        }
 
@@ -2471,24 +2362,31 @@ int ath_tx_aggr_start(struct ath_softc *sc,
 
 /* Stop tx aggregation */
 
-int ath_tx_aggr_stop(struct ath_softc *sc,
-                    const u8 *addr,
-                    u16 tid)
+int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 {
+       struct ath_node *an = (struct ath_node *)sta->drv_priv;
+
+       ath_tx_aggr_teardown(sc, an, tid);
+       return 0;
+}
+
+/* Resume tx aggregation */
+
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+{
+       struct ath_atx_tid *txtid;
        struct ath_node *an;
 
-       spin_lock_bh(&sc->node_lock);
-       an = ath_node_find(sc, (u8 *) addr);
-       spin_unlock_bh(&sc->node_lock);
+       an = (struct ath_node *)sta->drv_priv;
 
-       if (!an) {
-               DPRINTF(sc, ATH_DBG_AGGR,
-                       "%s: TX aggr stop for non-existent node\n", __func__);
-               return -1;
+       if (sc->sc_flags & SC_OP_TXAGGR) {
+               txtid = ATH_AN_2_TID(an, tid);
+               txtid->baw_size =
+                       IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
+               txtid->state |= AGGR_ADDBA_COMPLETE;
+               txtid->state &= ~AGGR_ADDBA_PROGRESS;
+               ath_tx_resume_tid(sc, txtid);
        }
-
-       ath_tx_aggr_teardown(sc, an, tid);
-       return 0;
 }
 
 /*
@@ -2498,8 +2396,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc,
  * - Discard all retry frames from the s/w queue.
  */
 
-void ath_tx_aggr_teardown(struct ath_softc *sc,
-       struct ath_node *an, u8 tid)
+void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid)
 {
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
        struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum];
@@ -2509,10 +2406,10 @@ void ath_tx_aggr_teardown(struct ath_softc *sc,
 
        DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__);
 
-       if (txtid->cleanup_inprogress) /* cleanup is in progress */
+       if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */
                return;
 
-       if (!txtid->addba_exchangecomplete) {
+       if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
                txtid->addba_exchangeattempts = 0;
                return;
        }
@@ -2542,9 +2439,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc,
 
        if (txtid->baw_head != txtid->baw_tail) {
                spin_unlock_bh(&txq->axq_lock);
-               txtid->cleanup_inprogress = true;
+               txtid->state |= AGGR_CLEANUP;
        } else {
-               txtid->addba_exchangecomplete = 0;
+               txtid->state &= ~AGGR_ADDBA_COMPLETE;
                txtid->addba_exchangeattempts = 0;
                spin_unlock_bh(&txq->axq_lock);
                ath_tx_flush_tid(sc, txtid);
@@ -2586,10 +2483,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
                if (tid->paused)    /* check next tid to keep h/w busy */
                        continue;
 
-               if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) ||
-                   ((txq->axq_depth % 2) == 0)) {
+               if ((txq->axq_depth % 2) == 0)
                        ath_tx_sched_aggr(sc, txq, tid);
-               }
 
                /*
                 * add tid to round-robin queue if more frames
@@ -2620,72 +2515,67 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
 
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
-       if (sc->sc_flags & SC_OP_TXAGGR) {
-               struct ath_atx_tid *tid;
-               struct ath_atx_ac *ac;
-               int tidno, acno;
-
-               an->maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
+       struct ath_atx_tid *tid;
+       struct ath_atx_ac *ac;
+       int tidno, acno;
 
-               /*
-                * Init per tid tx state
-                */
-               for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
-                               tidno < WME_NUM_TID;
-                               tidno++, tid++) {
-                       tid->an        = an;
-                       tid->tidno     = tidno;
-                       tid->seq_start = tid->seq_next = 0;
-                       tid->baw_size  = WME_MAX_BA;
-                       tid->baw_head  = tid->baw_tail = 0;
-                       tid->sched     = false;
-                       tid->paused = false;
-                       tid->cleanup_inprogress = false;
-                       INIT_LIST_HEAD(&tid->buf_q);
-
-                       acno = TID_TO_WME_AC(tidno);
-                       tid->ac = &an->an_aggr.tx.ac[acno];
-
-                       /* ADDBA state */
-                       tid->addba_exchangecomplete     = 0;
-                       tid->addba_exchangeinprogress   = 0;
-                       tid->addba_exchangeattempts     = 0;
-               }
+       /*
+        * Init per tid tx state
+        */
+       for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
+            tidno < WME_NUM_TID;
+            tidno++, tid++) {
+               tid->an        = an;
+               tid->tidno     = tidno;
+               tid->seq_start = tid->seq_next = 0;
+               tid->baw_size  = WME_MAX_BA;
+               tid->baw_head  = tid->baw_tail = 0;
+               tid->sched     = false;
+               tid->paused = false;
+               tid->state &= ~AGGR_CLEANUP;
+               INIT_LIST_HEAD(&tid->buf_q);
+
+               acno = TID_TO_WME_AC(tidno);
+               tid->ac = &an->an_aggr.tx.ac[acno];
+
+               /* ADDBA state */
+               tid->state &= ~AGGR_ADDBA_COMPLETE;
+               tid->state &= ~AGGR_ADDBA_PROGRESS;
+               tid->addba_exchangeattempts = 0;
+       }
 
-               /*
-                * Init per ac tx state
-                */
-               for (acno = 0, ac = &an->an_aggr.tx.ac[acno];
-                               acno < WME_NUM_AC; acno++, ac++) {
-                       ac->sched    = false;
-                       INIT_LIST_HEAD(&ac->tid_q);
-
-                       switch (acno) {
-                       case WME_AC_BE:
-                               ac->qnum = ath_tx_get_qnum(sc,
-                                       ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-                               break;
-                       case WME_AC_BK:
-                               ac->qnum = ath_tx_get_qnum(sc,
-                                       ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
-                               break;
-                       case WME_AC_VI:
-                               ac->qnum = ath_tx_get_qnum(sc,
-                                       ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
-                               break;
-                       case WME_AC_VO:
-                               ac->qnum = ath_tx_get_qnum(sc,
-                                       ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
-                               break;
-                       }
+       /*
+        * Init per ac tx state
+        */
+       for (acno = 0, ac = &an->an_aggr.tx.ac[acno];
+            acno < WME_NUM_AC; acno++, ac++) {
+               ac->sched    = false;
+               INIT_LIST_HEAD(&ac->tid_q);
+
+               switch (acno) {
+               case WME_AC_BE:
+                       ac->qnum = ath_tx_get_qnum(sc,
+                                  ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+                       break;
+               case WME_AC_BK:
+                       ac->qnum = ath_tx_get_qnum(sc,
+                                  ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
+                       break;
+               case WME_AC_VI:
+                       ac->qnum = ath_tx_get_qnum(sc,
+                                  ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
+                       break;
+               case WME_AC_VO:
+                       ac->qnum = ath_tx_get_qnum(sc,
+                                  ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
+                       break;
                }
        }
 }
 
 /* Cleanupthe pending buffers for the node. */
 
-void ath_tx_node_cleanup(struct ath_softc *sc,
-       struct ath_node *an, bool bh_flag)
+void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
        int i;
        struct ath_atx_ac *ac, *ac_tmp;
@@ -2695,10 +2585,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc,
                if (ATH_TXQ_SETUP(sc, i)) {
                        txq = &sc->sc_txq[i];
 
-                       if (likely(bh_flag))
-                               spin_lock_bh(&txq->axq_lock);
-                       else
-                               spin_lock(&txq->axq_lock);
+                       spin_lock(&txq->axq_lock);
 
                        list_for_each_entry_safe(ac,
                                        ac_tmp, &txq->axq_acq, list) {
@@ -2713,36 +2600,14 @@ void ath_tx_node_cleanup(struct ath_softc *sc,
                                                tid_tmp, &ac->tid_q, list) {
                                        list_del(&tid->list);
                                        tid->sched = false;
-                                       ath_tid_drain(sc, txq, tid, bh_flag);
-                                       tid->addba_exchangecomplete = 0;
+                                       ath_tid_drain(sc, txq, tid);
+                                       tid->state &= ~AGGR_ADDBA_COMPLETE;
                                        tid->addba_exchangeattempts = 0;
-                                       tid->cleanup_inprogress = false;
+                                       tid->state &= ~AGGR_CLEANUP;
                                }
                        }
 
-                       if (likely(bh_flag))
-                               spin_unlock_bh(&txq->axq_lock);
-                       else
-                               spin_unlock(&txq->axq_lock);
-               }
-       }
-}
-
-/* Cleanup per node transmit state */
-
-void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
-{
-       if (sc->sc_flags & SC_OP_TXAGGR) {
-               struct ath_atx_tid *tid;
-               int tidno, i;
-
-               /* Init per tid rx state */
-               for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
-                       tidno < WME_NUM_TID;
-                    tidno++, tid++) {
-
-                       for (i = 0; i < ATH_TID_MAX_BUFS; i++)
-                               ASSERT(tid->tx_buf[i] == NULL);
+                       spin_unlock(&txq->axq_lock);
                }
        }
 }
@@ -2753,6 +2618,8 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath_tx_control txctl;
 
+       memset(&txctl, 0, sizeof(struct ath_tx_control));
+
        /*
         * As a temporary workaround, assign seq# here; this will likely need
         * to be cleaned up to work better with Beacon transmission and virtual
@@ -2780,23 +2647,18 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
                memmove(skb->data, skb->data + padsize, hdrlen);
        }
 
+       txctl.txq = sc->sc_cabq;
+
        DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n",
                __func__,
                skb);
 
-       memset(&txctl, 0, sizeof(struct ath_tx_control));
-       txctl.flags = ATH9K_TXDESC_CAB;
-       if (ath_tx_prepare(sc, skb, &txctl) == 0) {
-               /*
-                * Start DMA mapping.
-                * ath_tx_start_dma() will be called either synchronously
-                * or asynchrounsly once DMA is complete.
-                */
-               xmit_map_sg(sc, skb, &txctl);
-       } else {
-               ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
-               DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__);
-               dev_kfree_skb_any(skb);
+       if (ath_tx_start(sc, skb, &txctl) != 0) {
+               DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
+               goto exit;
        }
-}
 
+       return;
+exit:
+       dev_kfree_skb_any(skb);
+}
index d16931589f81ef53b4d01169187fcdee1e562528..3962b553fbf1ed73de0946203f83310a8560b2c1 100644 (file)
@@ -67,7 +67,7 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 #include "atmel.h"
 
 #define DRIVER_MAJOR 0
@@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
 static void atmel_command_irq(struct atmel_private *priv);
 static int atmel_validate_channel(struct atmel_private *priv, int channel);
 static void atmel_management_frame(struct atmel_private *priv,
-                                  struct ieee80211_hdr_4addr *header,
+                                  struct ieee80211_hdr *header,
                                   u16 frame_len, u8 rssi);
 static void atmel_management_timer(u_long a);
 static void atmel_send_command(struct atmel_private *priv, int command,
@@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command,
 static int atmel_send_command_wait(struct atmel_private *priv, int command,
                                   void *cmd, int cmd_size);
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-                                           struct ieee80211_hdr_4addr *header,
+                                           struct ieee80211_hdr *header,
                                            u8 *body, int body_len);
 
 static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
@@ -785,7 +785,7 @@ 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;
+       struct ieee80211_hdr header;
        unsigned long flags;
        u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
@@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        frame_ctl = IEEE80211_FTYPE_DATA;
        header.duration_id = 0;
-       header.seq_ctl = 0;
+       header.seq_ctrl = 0;
        if (priv->wep_is_on)
                frame_ctl |= IEEE80211_FCTL_PROTECTED;
        if (priv->operating_mode == IW_MODE_ADHOC) {
@@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        if (priv->use_wpa)
                memcpy(&header.addr4, SNAP_RFC1024, 6);
 
-       header.frame_ctl = cpu_to_le16(frame_ctl);
+       header.frame_control = cpu_to_le16(frame_ctl);
        /* Copy the wireless header into the card */
        atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
        /* Copy the packet sans its 802.3 header addresses which have been replaced */
@@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 }
 
 static void atmel_transmit_management_frame(struct atmel_private *priv,
-                                           struct ieee80211_hdr_4addr *header,
+                                           struct ieee80211_hdr *header,
                                            u8 *body, int body_len)
 {
        u16 buff;
@@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv,
 }
 
 static void fast_rx_path(struct atmel_private *priv,
-                        struct ieee80211_hdr_4addr *header,
+                        struct ieee80211_hdr *header,
                         u16 msdu_size, u16 rx_packet_loc, u32 crc)
 {
        /* fast path: unfragmented packet copy directly into skbuf */
@@ -914,7 +914,7 @@ static void fast_rx_path(struct atmel_private *priv,
        }
 
        memcpy(skbp, header->addr1, 6); /* destination address */
-       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+       if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
                memcpy(&skbp[6], header->addr3, 6);
        else
                memcpy(&skbp[6], header->addr2, 6); /* source address */
@@ -949,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
 }
 
 static void frag_rx_path(struct atmel_private *priv,
-                        struct ieee80211_hdr_4addr *header,
+                        struct ieee80211_hdr *header,
                         u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
                         u8 frag_no, int more_frags)
 {
@@ -957,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv,
        u8 source[6];
        struct sk_buff *skb;
 
-       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+       if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
                memcpy(source, header->addr3, 6);
        else
                memcpy(source, header->addr2, 6);
@@ -1039,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv,
 static void rx_done_irq(struct atmel_private *priv)
 {
        int i;
-       struct ieee80211_hdr_4addr header;
+       struct ieee80211_hdr header;
 
        for (i = 0;
             atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
@@ -1066,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv)
                        goto next;
                }
 
-               /* Get header as far as end of seq_ctl */
+               /* Get header as far as end of seq_ctrl */
                atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
-               frame_ctl = le16_to_cpu(header.frame_ctl);
-               seq_control = le16_to_cpu(header.seq_ctl);
+               frame_ctl = le16_to_cpu(header.frame_control);
+               seq_control = le16_to_cpu(header.seq_ctrl);
 
                /* probe for CRC use here if needed  once five packets have
                   arrived with the same crc status, we assume we know what's
@@ -1819,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev,
        /* Determine and validate the key index */
        idx = encoding->flags & IW_ENCODE_INDEX;
        if (idx) {
-               if (idx < 1 || idx > WEP_KEYS)
+               if (idx < 1 || idx > 4)
                        return -EINVAL;
                idx--;
        } else
@@ -1882,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev,
 
        idx = encoding->flags & IW_ENCODE_INDEX;
        if (idx) {
-               if (idx < 1 || idx > WEP_KEYS)
+               if (idx < 1 || idx > 4)
                        return -EINVAL;
                idx--;
        } else
@@ -2797,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
                                u8 channel)
 {
        int rejoin = 0;
-       int new = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+       int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
                SHORT_PREAMBLE : LONG_PREAMBLE;
 
        if (priv->preamble != new) {
@@ -2826,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
 static void send_authentication_request(struct atmel_private *priv, u16 system,
                                        u8 *challenge, int challenge_len)
 {
-       struct ieee80211_hdr_4addr header;
+       struct ieee80211_hdr header;
        struct auth_body auth;
 
-       header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
+       header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
        header.duration_id = cpu_to_le16(0x8000);
-       header.seq_ctl = 0;
+       header.seq_ctrl = 0;
        memcpy(header.addr1, priv->CurrentBSSID, 6);
        memcpy(header.addr2, priv->dev->dev_addr, 6);
        memcpy(header.addr3, priv->CurrentBSSID, 6);
 
        if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
                /* no WEP for authentication frames with TrSeqNo 1 */
-                header.frame_ctl |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+                header.frame_control |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
        auth.alg = cpu_to_le16(system);
 
@@ -2861,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 {
        u8 *ssid_el_p;
        int bodysize;
-       struct ieee80211_hdr_4addr header;
+       struct ieee80211_hdr header;
        struct ass_req_format {
                __le16 capability;
                __le16 listen_interval;
@@ -2874,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
                u8 rates[4];
        } body;
 
-       header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+       header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
        header.duration_id = cpu_to_le16(0x8000);
-       header.seq_ctl = 0;
+       header.seq_ctrl = 0;
 
        memcpy(header.addr1, priv->CurrentBSSID, 6);
        memcpy(header.addr2, priv->dev->dev_addr, 6);
@@ -2887,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
        if (priv->wep_is_on)
                body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
        if (priv->preamble == SHORT_PREAMBLE)
-               body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT);
+               body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
 
        body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
 
@@ -2901,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
                bodysize = 12 + priv->SSID_size;
        }
 
-       ssid_el_p[0] = MFIE_TYPE_SSID;
+       ssid_el_p[0] = WLAN_EID_SSID;
        ssid_el_p[1] = priv->SSID_size;
        memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
-       ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES;
+       ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES;
        ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */
        memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
 
@@ -2912,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 }
 
 static int is_frame_from_current_bss(struct atmel_private *priv,
-                                    struct ieee80211_hdr_4addr *header)
+                                    struct ieee80211_hdr *header)
 {
-       if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS)
+       if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
                return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
        else
                return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
@@ -2962,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv)
 }
 
 static void store_bss_info(struct atmel_private *priv,
-                          struct ieee80211_hdr_4addr *header, u16 capability,
+                          struct ieee80211_hdr *header, u16 capability,
                           u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
                           u8 *ssid, int is_beacon)
 {
@@ -3001,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv,
        else if (capability & WLAN_CAPABILITY_ESS)
                priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
 
-       priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ?
+       priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
                SHORT_PREAMBLE : LONG_PREAMBLE;
 }
 
@@ -3037,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
                        }
                } else if (system == WLAN_AUTH_SHARED_KEY) {
                        if (trans_seq_no == 0x0002 &&
-                           auth->el_id == MFIE_TYPE_CHALLENGE) {
+                           auth->el_id == WLAN_EID_CHALLENGE) {
                                send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
                                return;
                        } else if (trans_seq_no == 0x0004) {
@@ -3288,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv)
 
 /* deals with incoming managment frames. */
 static void atmel_management_frame(struct atmel_private *priv,
-                                  struct ieee80211_hdr_4addr *header,
+                                  struct ieee80211_hdr *header,
                                   u16 frame_len, u8 rssi)
 {
        u16 subtype;
 
-       subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE;
+       subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE;
        switch (subtype) {
        case IEEE80211_STYPE_BEACON:
        case IEEE80211_STYPE_PROBE_RESP:
index 427b8203e3f96af2d8367d5ef1e8b2fa0386ab4a..a53c378e74844ebdca86dd83fb3b5c9104511b27 100644 (file)
@@ -718,7 +718,6 @@ struct b43_wldev {
 
        bool bad_frames_preempt;        /* Use "Bad Frames Preemption" (default off) */
        bool dfq_valid;         /* Directed frame queue valid (IBSS PS mode, ATIM) */
-       bool short_slot;        /* TRUE, if short slot timing is enabled. */
        bool radio_hw_enable;   /* saved state of radio hardware enabled state */
        bool suspend_in_progress;       /* TRUE, if we are in a suspend/resume cycle */
 
index 2a599fb772d97b087444f61724315933311bff0e..ba7a5ab7fe1d8f9c44bd5d961bff1b06a4eb8bda 100644 (file)
@@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
 static void b43_short_slot_timing_enable(struct b43_wldev *dev)
 {
        b43_set_slot_time(dev, 9);
-       dev->short_slot = 1;
 }
 
 static void b43_short_slot_timing_disable(struct b43_wldev *dev)
 {
        b43_set_slot_time(dev, 20);
-       dev->short_slot = 0;
 }
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
@@ -1674,25 +1672,6 @@ static void b43_update_templates(struct b43_wl *wl)
        queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
 }
 
-static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
-{
-       u32 tmp;
-       u16 i, len;
-
-       len = min((u16) ssid_len, (u16) 0x100);
-       for (i = 0; i < len; i += sizeof(u32)) {
-               tmp = (u32) (ssid[i + 0]);
-               if (i + 1 < len)
-                       tmp |= (u32) (ssid[i + 1]) << 8;
-               if (i + 2 < len)
-                       tmp |= (u32) (ssid[i + 2]) << 16;
-               if (i + 3 < len)
-                       tmp |= (u32) (ssid[i + 3]) << 24;
-               b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
-       }
-       b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
-}
-
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
        b43_time_lock(dev);
@@ -3380,16 +3359,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        if (conf->channel->hw_value != phy->channel)
                b43_switch_channel(dev, conf->channel->hw_value);
 
-       /* Enable/Disable ShortSlot timing. */
-       if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
-           dev->short_slot) {
-               B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-               if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-                       b43_short_slot_timing_enable(dev);
-               else
-                       b43_short_slot_timing_disable(dev);
-       }
-
        dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
 
        /* Adjust the desired TX power level. */
@@ -3440,6 +3409,104 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        return err;
 }
 
+static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates)
+{
+       struct ieee80211_supported_band *sband =
+               dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)];
+       struct ieee80211_rate *rate;
+       int i;
+       u16 basic, direct, offset, basic_offset, rateptr;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               rate = &sband->bitrates[i];
+
+               if (b43_is_cck_rate(rate->hw_value)) {
+                       direct = B43_SHM_SH_CCKDIRECT;
+                       basic = B43_SHM_SH_CCKBASIC;
+                       offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+                       offset &= 0xF;
+               } else {
+                       direct = B43_SHM_SH_OFDMDIRECT;
+                       basic = B43_SHM_SH_OFDMBASIC;
+                       offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+                       offset &= 0xF;
+               }
+
+               rate = ieee80211_get_response_rate(sband, brates, rate->bitrate);
+
+               if (b43_is_cck_rate(rate->hw_value)) {
+                       basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value);
+                       basic_offset &= 0xF;
+               } else {
+                       basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value);
+                       basic_offset &= 0xF;
+               }
+
+               /*
+                * Get the pointer that we need to point to
+                * from the direct map
+                */
+               rateptr = b43_shm_read16(dev, B43_SHM_SHARED,
+                                        direct + 2 * basic_offset);
+               /* and write it to the basic map */
+               b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset,
+                               rateptr);
+       }
+}
+
+static void b43_op_bss_info_changed(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_bss_conf *conf,
+                                   u32 changed)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+       struct b43_phy *phy;
+       unsigned long flags;
+       u32 savedirqs;
+
+       mutex_lock(&wl->mutex);
+
+       dev = wl->current_dev;
+       phy = &dev->phy;
+
+       /* Disable IRQs while reconfiguring the device.
+        * This makes it possible to drop the spinlock throughout
+        * the reconfiguration process. */
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       if (b43_status(dev) < B43_STAT_STARTED) {
+               spin_unlock_irqrestore(&wl->irq_lock, flags);
+               goto out_unlock_mutex;
+       }
+       savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       b43_synchronize_irq(dev);
+
+       b43_mac_suspend(dev);
+
+       if (changed & BSS_CHANGED_BASIC_RATES)
+               b43_update_basic_rates(dev, conf->basic_rates);
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               if (conf->use_short_slot)
+                       b43_short_slot_timing_enable(dev);
+               else
+                       b43_short_slot_timing_disable(dev);
+       }
+
+       b43_mac_enable(dev);
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43_interrupt_enable(dev, savedirqs);
+       /* XXX: why? */
+       mmiowb();
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+       mutex_unlock(&wl->mutex);
+
+       return;
+}
+
 static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           const u8 *local_addr, const u8 *addr,
                           struct ieee80211_key_conf *key)
@@ -3602,8 +3669,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
                if (b43_is_mode(wl, NL80211_IFTYPE_AP) ||
                    b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) {
                        B43_WARN_ON(vif->type != wl->if_type);
-                       if (conf->changed & IEEE80211_IFCC_SSID)
-                               b43_set_ssid(dev, conf->ssid, conf->ssid_len);
                        if (conf->changed & IEEE80211_IFCC_BEACON)
                                b43_update_templates(wl);
                } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
@@ -4231,6 +4296,7 @@ static const struct ieee80211_ops b43_hw_ops = {
        .add_interface          = b43_op_add_interface,
        .remove_interface       = b43_op_remove_interface,
        .config                 = b43_op_config,
+       .bss_info_changed       = b43_op_bss_info_changed,
        .config_interface       = b43_op_config_interface,
        .configure_filter       = b43_op_configure_filter,
        .set_key                = b43_op_set_key,
index 308c2647f0027852036df5006d42255ad39afa9e..3649fc3670988219cd99185fc3acfbec6e162b3e 100644 (file)
@@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                               dma_test = ssb_dma_map_single(dev->dev,
+                       dma_test = ssb_dma_map_single(dev->dev,
                                        ring->txhdr_cache,
                                        sizeof(struct b43legacy_txhdr_fw3),
                                        DMA_TO_DEVICE);
index 9edbdf9cb50fd7811dd8289511bd40e7c41d29b9..6c8eb4d2519ad5da678bc41e0bd88ccc6074f236 100644 (file)
@@ -1160,29 +1160,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
        wl->beacon1_uploaded = 0;
 }
 
-static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
-                              const u8 *ssid, u8 ssid_len)
-{
-       u32 tmp;
-       u16 i;
-       u16 len;
-
-       len = min((u16)ssid_len, (u16)0x100);
-       for (i = 0; i < len; i += sizeof(u32)) {
-               tmp = (u32)(ssid[i + 0]);
-               if (i + 1 < len)
-                       tmp |= (u32)(ssid[i + 1]) << 8;
-               if (i + 2 < len)
-                       tmp |= (u32)(ssid[i + 2]) << 16;
-               if (i + 3 < len)
-                       tmp |= (u32)(ssid[i + 3]) << 24;
-               b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
-                                     0x380 + i, tmp);
-       }
-       b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
-                             0x48, len);
-}
-
 static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
                                     u16 beacon_int)
 {
@@ -2744,7 +2721,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
        if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
                if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) {
                        B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP);
-                       b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
                        if (conf->changed & IEEE80211_IFCC_BEACON)
                                b43legacy_update_templates(wl);
                } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) {
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
deleted file mode 100644 (file)
index bfa3753..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-/* hermes.c
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
- * particular order).
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- * 
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include "hermes.h"
-
-MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
-       " & David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* These are maximum timeouts. Most often, card wil react much faster */
-#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
-#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
-#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
-#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
-
-/*
- * Debugging helpers
- */
-
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
-                       printk(stuff);} while (0)
-
-#undef HERMES_DEBUG
-#ifdef HERMES_DEBUG
-#include <stdarg.h>
-
-#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
-
-#else /* ! HERMES_DEBUG */
-
-#define DEBUG(lvl, stuff...) do { } while (0)
-
-#endif /* ! HERMES_DEBUG */
-
-
-/*
- * Internal functions
- */
-
-/* Issue a command to the chip. Waiting for it to complete is the caller's
-   problem.
-
-   Returns -EBUSY if the command register is busy, 0 on success.
-
-   Callable from any context.
-*/
-static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
-                           u16 param1, u16 param2)
-{
-       int k = CMD_BUSY_TIMEOUT;
-       u16 reg;
-
-       /* First wait for the command register to unbusy */
-       reg = hermes_read_regn(hw, CMD);
-       while ( (reg & HERMES_CMD_BUSY) && k ) {
-               k--;
-               udelay(1);
-               reg = hermes_read_regn(hw, CMD);
-       }
-       if (reg & HERMES_CMD_BUSY) {
-               return -EBUSY;
-       }
-
-       hermes_write_regn(hw, PARAM2, param2);
-       hermes_write_regn(hw, PARAM1, param1);
-       hermes_write_regn(hw, PARAM0, param0);
-       hermes_write_regn(hw, CMD, cmd);
-       
-       return 0;
-}
-
-/*
- * Function definitions
- */
-
-/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp)
-{
-       int err = 0;
-       int k;
-       u16 status, reg;
-
-       err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
-       if (err)
-               return err;
-
-       reg = hermes_read_regn(hw, EVSTAT);
-       k = CMD_INIT_TIMEOUT;
-       while ((!(reg & HERMES_EV_CMD)) && k) {
-               k--;
-               udelay(10);
-               reg = hermes_read_regn(hw, EVSTAT);
-       }
-
-       hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
-
-       if (!hermes_present(hw)) {
-               DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
-                      hw->iobase);
-               err = -ENODEV;
-               goto out;
-       }
-
-       if (!(reg & HERMES_EV_CMD)) {
-               printk(KERN_ERR "hermes @ %p: "
-                      "Timeout waiting for card to reset (reg=0x%04x)!\n",
-                      hw->iobase, reg);
-               err = -ETIMEDOUT;
-               goto out;
-       }
-
-       status = hermes_read_regn(hw, STATUS);
-       if (resp) {
-               resp->status = status;
-               resp->resp0 = hermes_read_regn(hw, RESP0);
-               resp->resp1 = hermes_read_regn(hw, RESP1);
-               resp->resp2 = hermes_read_regn(hw, RESP2);
-       }
-
-       hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
-       if (status & HERMES_STATUS_RESULT)
-               err = -EIO;
-out:
-       return err;
-}
-EXPORT_SYMBOL(hermes_doicmd_wait);
-
-void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
-{
-       hw->iobase = address;
-       hw->reg_spacing = reg_spacing;
-       hw->inten = 0x0;
-}
-EXPORT_SYMBOL(hermes_struct_init);
-
-int hermes_init(hermes_t *hw)
-{
-       u16 reg;
-       int err = 0;
-       int k;
-
-       /* We don't want to be interrupted while resetting the chipset */
-       hw->inten = 0x0;
-       hermes_write_regn(hw, INTEN, 0);
-       hermes_write_regn(hw, EVACK, 0xffff);
-
-       /* Normally it's a "can't happen" for the command register to
-           be busy when we go to issue a command because we are
-           serializing all commands.  However we want to have some
-           chance of resetting the card even if it gets into a stupid
-           state, so we actually wait to see if the command register
-           will unbusy itself here. */
-       k = CMD_BUSY_TIMEOUT;
-       reg = hermes_read_regn(hw, CMD);
-       while (k && (reg & HERMES_CMD_BUSY)) {
-               if (reg == 0xffff) /* Special case - the card has probably been removed,
-                                     so don't wait for the timeout */
-                       return -ENODEV;
-
-               k--;
-               udelay(1);
-               reg = hermes_read_regn(hw, CMD);
-       }
-       
-       /* No need to explicitly handle the timeout - if we've timed
-          out hermes_issue_cmd() will probably return -EBUSY below */
-
-       /* According to the documentation, EVSTAT may contain
-          obsolete event occurrence information.  We have to acknowledge
-          it by writing EVACK. */
-       reg = hermes_read_regn(hw, EVSTAT);
-       hermes_write_regn(hw, EVACK, reg);
-
-       /* We don't use hermes_docmd_wait here, because the reset wipes
-          the magic constant in SWSUPPORT0 away, and it gets confused */
-       err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
-
-       return err;
-}
-EXPORT_SYMBOL(hermes_init);
-
-/* Issue a command to the chip, and (busy!) wait for it to
- * complete.
- *
- * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
- *
- * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp)
-{
-       int err;
-       int k;
-       u16 reg;
-       u16 status;
-
-       err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
-       if (err) {
-               if (! hermes_present(hw)) {
-                       if (net_ratelimit())
-                               printk(KERN_WARNING "hermes @ %p: "
-                                      "Card removed while issuing command "
-                                      "0x%04x.\n", hw->iobase, cmd);
-                       err = -ENODEV;
-               } else 
-                       if (net_ratelimit())
-                               printk(KERN_ERR "hermes @ %p: "
-                                      "Error %d issuing command 0x%04x.\n",
-                                      hw->iobase, err, cmd);
-               goto out;
-       }
-
-       reg = hermes_read_regn(hw, EVSTAT);
-       k = CMD_COMPL_TIMEOUT;
-       while ( (! (reg & HERMES_EV_CMD)) && k) {
-               k--;
-               udelay(10);
-               reg = hermes_read_regn(hw, EVSTAT);
-       }
-
-       if (! hermes_present(hw)) {
-               printk(KERN_WARNING "hermes @ %p: Card removed "
-                      "while waiting for command 0x%04x completion.\n",
-                      hw->iobase, cmd);
-               err = -ENODEV;
-               goto out;
-       }
-               
-       if (! (reg & HERMES_EV_CMD)) {
-               printk(KERN_ERR "hermes @ %p: Timeout waiting for "
-                      "command 0x%04x completion.\n", hw->iobase, cmd);
-               err = -ETIMEDOUT;
-               goto out;
-       }
-
-       status = hermes_read_regn(hw, STATUS);
-       if (resp) {
-               resp->status = status;
-               resp->resp0 = hermes_read_regn(hw, RESP0);
-               resp->resp1 = hermes_read_regn(hw, RESP1);
-               resp->resp2 = hermes_read_regn(hw, RESP2);
-       }
-
-       hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
-       if (status & HERMES_STATUS_RESULT)
-               err = -EIO;
-
- out:
-       return err;
-}
-EXPORT_SYMBOL(hermes_docmd_wait);
-
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
-{
-       int err = 0;
-       int k;
-       u16 reg;
-       
-       if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
-               return -EINVAL;
-
-       err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
-       if (err) {
-               return err;
-       }
-
-       reg = hermes_read_regn(hw, EVSTAT);
-       k = ALLOC_COMPL_TIMEOUT;
-       while ( (! (reg & HERMES_EV_ALLOC)) && k) {
-               k--;
-               udelay(10);
-               reg = hermes_read_regn(hw, EVSTAT);
-       }
-       
-       if (! hermes_present(hw)) {
-               printk(KERN_WARNING "hermes @ %p: "
-                      "Card removed waiting for frame allocation.\n",
-                      hw->iobase);
-               return -ENODEV;
-       }
-               
-       if (! (reg & HERMES_EV_ALLOC)) {
-               printk(KERN_ERR "hermes @ %p: "
-                      "Timeout waiting for frame allocation\n",
-                      hw->iobase);
-               return -ETIMEDOUT;
-       }
-
-       *fid = hermes_read_regn(hw, ALLOCFID);
-       hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
-       
-       return 0;
-}
-EXPORT_SYMBOL(hermes_allocate);
-
-/* Set up a BAP to read a particular chunk of data from card's internal buffer.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
- * from firmware
- *
- * Callable from any context */
-static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
-{
-       int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
-       int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
-       int k;
-       u16 reg;
-
-       /* Paranoia.. */
-       if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
-               return -EINVAL;
-
-       k = HERMES_BAP_BUSY_TIMEOUT;
-       reg = hermes_read_reg(hw, oreg);
-       while ((reg & HERMES_OFFSET_BUSY) && k) {
-               k--;
-               udelay(1);
-               reg = hermes_read_reg(hw, oreg);
-       }
-
-       if (reg & HERMES_OFFSET_BUSY)
-               return -ETIMEDOUT;
-
-       /* Now we actually set up the transfer */
-       hermes_write_reg(hw, sreg, id);
-       hermes_write_reg(hw, oreg, offset);
-
-       /* Wait for the BAP to be ready */
-       k = HERMES_BAP_BUSY_TIMEOUT;
-       reg = hermes_read_reg(hw, oreg);
-       while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
-               k--;
-               udelay(1);
-               reg = hermes_read_reg(hw, oreg);
-       }
-
-       if (reg != offset) {
-               printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
-                      "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
-                      (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
-                      reg, id, offset);
-
-               if (reg & HERMES_OFFSET_BUSY) {
-                       return -ETIMEDOUT;
-               }
-
-               return -EIO;            /* error or wrong offset */
-       }
-
-       return 0;
-}
-
-/* Read a block of data from the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem.  len
- * must be even.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
- */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                    u16 id, u16 offset)
-{
-       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-       int err = 0;
-
-       if ( (len < 0) || (len % 2) )
-               return -EINVAL;
-
-       err = hermes_bap_seek(hw, bap, id, offset);
-       if (err)
-               goto out;
-
-       /* Actually do the transfer */
-       hermes_read_words(hw, dreg, buf, len/2);
-
- out:
-       return err;
-}
-EXPORT_SYMBOL(hermes_bap_pread);
-
-/* Write a block of data to the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
- */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                     u16 id, u16 offset)
-{
-       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-       int err = 0;
-
-       if (len < 0)
-               return -EINVAL;
-
-       err = hermes_bap_seek(hw, bap, id, offset);
-       if (err)
-               goto out;
-       
-       /* Actually do the transfer */
-       hermes_write_bytes(hw, dreg, buf, len);
-
- out:  
-       return err;
-}
-EXPORT_SYMBOL(hermes_bap_pwrite);
-
-/* Read a Length-Type-Value record from the card.
- *
- * If length is NULL, we ignore the length read from the card, and
- * read the entire buffer regardless. This is useful because some of
- * the configuration records appear to have incorrect lengths in
- * practice.
- *
- * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
-                   u16 *length, void *buf)
-{
-       int err = 0;
-       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-       u16 rlength, rtype;
-       unsigned nwords;
-
-       if ( (bufsize < 0) || (bufsize % 2) )
-               return -EINVAL;
-
-       err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
-       if (err)
-               return err;
-
-       err = hermes_bap_seek(hw, bap, rid, 0);
-       if (err)
-               return err;
-
-       rlength = hermes_read_reg(hw, dreg);
-
-       if (! rlength)
-               return -ENODATA;
-
-       rtype = hermes_read_reg(hw, dreg);
-
-       if (length)
-               *length = rlength;
-
-       if (rtype != rid)
-               printk(KERN_WARNING "hermes @ %p: %s(): "
-                      "rid (0x%04x) does not match type (0x%04x)\n",
-                      hw->iobase, __func__, rid, rtype);
-       if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
-               printk(KERN_WARNING "hermes @ %p: "
-                      "Truncating LTV record from %d to %d bytes. "
-                      "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
-                      HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
-
-       nwords = min((unsigned)rlength - 1, bufsize / 2);
-       hermes_read_words(hw, dreg, buf, nwords);
-
-       return 0;
-}
-EXPORT_SYMBOL(hermes_read_ltv);
-
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
-                    u16 length, const void *value)
-{
-       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-       int err = 0;
-       unsigned count;
-
-       if (length == 0)
-               return -EINVAL;
-
-       err = hermes_bap_seek(hw, bap, rid, 0);
-       if (err)
-               return err;
-
-       hermes_write_reg(hw, dreg, length);
-       hermes_write_reg(hw, dreg, rid);
-
-       count = length - 1;
-
-       hermes_write_bytes(hw, dreg, value, count << 1);
-
-       err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
-                               rid, NULL);
-
-       return err;
-}
-EXPORT_SYMBOL(hermes_write_ltv);
-
-static int __init init_hermes(void)
-{
-       return 0;
-}
-
-static void __exit exit_hermes(void)
-{
-}
-
-module_init(init_hermes);
-module_exit(exit_hermes);
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
deleted file mode 100644 (file)
index 8b13c8f..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-/* hermes.h
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism I & II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver.
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- *
- * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * This file distributed under the GPL, version 2.
- */
-
-#ifndef _HERMES_H
-#define _HERMES_H
-
-/* Notes on locking:
- *
- * As a module of low level hardware access routines, there is no
- * locking. Users of this module should ensure that they serialize
- * access to the hermes_t structure, and to the hardware
-*/
-
-#include <linux/if_ether.h>
-#include <asm/io.h>
-
-/*
- * Limits and constants
- */
-#define                HERMES_ALLOC_LEN_MIN            (4)
-#define                HERMES_ALLOC_LEN_MAX            (2400)
-#define                HERMES_LTV_LEN_MAX              (34)
-#define                HERMES_BAP_DATALEN_MAX          (4096)
-#define                HERMES_BAP_OFFSET_MAX           (4096)
-#define                HERMES_PORTID_MAX               (7)
-#define                HERMES_NUMPORTS_MAX             (HERMES_PORTID_MAX+1)
-#define                HERMES_PDR_LEN_MAX              (260)   /* in bytes, from EK */
-#define                HERMES_PDA_RECS_MAX             (200)   /* a guess */
-#define                HERMES_PDA_LEN_MAX              (1024)  /* in bytes, from EK */
-#define                HERMES_SCANRESULT_MAX           (35)
-#define                HERMES_CHINFORESULT_MAX         (8)
-#define                HERMES_MAX_MULTICAST            (16)
-#define                HERMES_MAGIC                    (0x7d1f)
-
-/*
- * Hermes register offsets
- */
-#define                HERMES_CMD                      (0x00)
-#define                HERMES_PARAM0                   (0x02)
-#define                HERMES_PARAM1                   (0x04)
-#define                HERMES_PARAM2                   (0x06)
-#define                HERMES_STATUS                   (0x08)
-#define                HERMES_RESP0                    (0x0A)
-#define                HERMES_RESP1                    (0x0C)
-#define                HERMES_RESP2                    (0x0E)
-#define                HERMES_INFOFID                  (0x10)
-#define                HERMES_RXFID                    (0x20)
-#define                HERMES_ALLOCFID                 (0x22)
-#define                HERMES_TXCOMPLFID               (0x24)
-#define                HERMES_SELECT0                  (0x18)
-#define                HERMES_OFFSET0                  (0x1C)
-#define                HERMES_DATA0                    (0x36)
-#define                HERMES_SELECT1                  (0x1A)
-#define                HERMES_OFFSET1                  (0x1E)
-#define                HERMES_DATA1                    (0x38)
-#define                HERMES_EVSTAT                   (0x30)
-#define                HERMES_INTEN                    (0x32)
-#define                HERMES_EVACK                    (0x34)
-#define                HERMES_CONTROL                  (0x14)
-#define                HERMES_SWSUPPORT0               (0x28)
-#define                HERMES_SWSUPPORT1               (0x2A)
-#define                HERMES_SWSUPPORT2               (0x2C)
-#define                HERMES_AUXPAGE                  (0x3A)
-#define                HERMES_AUXOFFSET                (0x3C)
-#define                HERMES_AUXDATA                  (0x3E)
-
-/*
- * CMD register bitmasks
- */
-#define                HERMES_CMD_BUSY                 (0x8000)
-#define                HERMES_CMD_AINFO                (0x7f00)
-#define                HERMES_CMD_MACPORT              (0x0700)
-#define                HERMES_CMD_RECL                 (0x0100)
-#define                HERMES_CMD_WRITE                (0x0100)
-#define                HERMES_CMD_PROGMODE             (0x0300)
-#define                HERMES_CMD_CMDCODE              (0x003f)
-
-/*
- * STATUS register bitmasks
- */
-#define                HERMES_STATUS_RESULT            (0x7f00)
-#define                HERMES_STATUS_CMDCODE           (0x003f)
-
-/*
- * OFFSET register bitmasks
- */
-#define                HERMES_OFFSET_BUSY              (0x8000)
-#define                HERMES_OFFSET_ERR               (0x4000)
-#define                HERMES_OFFSET_DATAOFF           (0x0ffe)
-
-/*
- * Event register bitmasks (INTEN, EVSTAT, EVACK)
- */
-#define                HERMES_EV_TICK                  (0x8000)
-#define                HERMES_EV_WTERR                 (0x4000)
-#define                HERMES_EV_INFDROP               (0x2000)
-#define                HERMES_EV_INFO                  (0x0080)
-#define                HERMES_EV_DTIM                  (0x0020)
-#define                HERMES_EV_CMD                   (0x0010)
-#define                HERMES_EV_ALLOC                 (0x0008)
-#define                HERMES_EV_TXEXC                 (0x0004)
-#define                HERMES_EV_TX                    (0x0002)
-#define                HERMES_EV_RX                    (0x0001)
-
-/*
- * Command codes
- */
-/*--- Controller Commands ----------------------------*/
-#define                HERMES_CMD_INIT                 (0x0000)
-#define                HERMES_CMD_ENABLE               (0x0001)
-#define                HERMES_CMD_DISABLE              (0x0002)
-#define                HERMES_CMD_DIAG                 (0x0003)
-
-/*--- Buffer Mgmt Commands ---------------------------*/
-#define                HERMES_CMD_ALLOC                (0x000A)
-#define                HERMES_CMD_TX                   (0x000B)
-
-/*--- Regulate Commands ------------------------------*/
-#define                HERMES_CMD_NOTIFY               (0x0010)
-#define                HERMES_CMD_INQUIRE              (0x0011)
-
-/*--- Configure Commands -----------------------------*/
-#define                HERMES_CMD_ACCESS               (0x0021)
-#define                HERMES_CMD_DOWNLD               (0x0022)
-
-/*--- Serial I/O Commands ----------------------------*/
-#define                HERMES_CMD_READMIF              (0x0030)
-#define                HERMES_CMD_WRITEMIF             (0x0031)
-
-/*--- Debugging Commands -----------------------------*/
-#define        HERMES_CMD_TEST                 (0x0038)
-
-
-/* Test command arguments */
-#define                HERMES_TEST_SET_CHANNEL         0x0800
-#define                HERMES_TEST_MONITOR             0x0b00
-#define                HERMES_TEST_STOP                0x0f00
-
-/* Authentication algorithms */
-#define                HERMES_AUTH_OPEN                1
-#define                HERMES_AUTH_SHARED_KEY          2
-
-/* WEP settings */
-#define                HERMES_WEP_PRIVACY_INVOKED      0x0001
-#define                HERMES_WEP_EXCL_UNENCRYPTED     0x0002
-#define                HERMES_WEP_HOST_ENCRYPT         0x0010
-#define                HERMES_WEP_HOST_DECRYPT         0x0080
-
-/* Symbol hostscan options */
-#define                HERMES_HOSTSCAN_SYMBOL_5SEC     0x0001
-#define                HERMES_HOSTSCAN_SYMBOL_ONCE     0x0002
-#define                HERMES_HOSTSCAN_SYMBOL_PASSIVE  0x0040
-#define                HERMES_HOSTSCAN_SYMBOL_BCAST    0x0080
-
-/*
- * Frame structures and constants
- */
-
-#define HERMES_DESCRIPTOR_OFFSET       0
-#define HERMES_802_11_OFFSET           (14)
-#define HERMES_802_3_OFFSET            (14+32)
-#define HERMES_802_2_OFFSET            (14+32+14)
-#define HERMES_TXCNTL2_OFFSET          (HERMES_802_3_OFFSET - 2)
-
-#define HERMES_RXSTAT_ERR              (0x0003)
-#define        HERMES_RXSTAT_BADCRC            (0x0001)
-#define        HERMES_RXSTAT_UNDECRYPTABLE     (0x0002)
-#define        HERMES_RXSTAT_MIC               (0x0010)        /* Frame contains MIC */
-#define        HERMES_RXSTAT_MACPORT           (0x0700)
-#define HERMES_RXSTAT_PCF              (0x1000)        /* Frame was received in CF period */
-#define        HERMES_RXSTAT_MIC_KEY_ID        (0x1800)        /* MIC key used */
-#define        HERMES_RXSTAT_MSGTYPE           (0xE000)
-#define        HERMES_RXSTAT_1042              (0x2000)        /* RFC-1042 frame */
-#define        HERMES_RXSTAT_TUNNEL            (0x4000)        /* bridge-tunnel encoded frame */
-#define        HERMES_RXSTAT_WMP               (0x6000)        /* Wavelan-II Management Protocol frame */
-
-/* Shift amount for key ID in RXSTAT and TXCTRL */
-#define        HERMES_MIC_KEY_ID_SHIFT         11
-
-struct hermes_tx_descriptor {
-       __le16 status;
-       __le16 reserved1;
-       __le16 reserved2;
-       __le32 sw_support;
-       u8 retry_count;
-       u8 tx_rate;
-       __le16 tx_control;      
-} __attribute__ ((packed));
-
-#define HERMES_TXSTAT_RETRYERR         (0x0001)
-#define HERMES_TXSTAT_AGEDERR          (0x0002)
-#define HERMES_TXSTAT_DISCON           (0x0004)
-#define HERMES_TXSTAT_FORMERR          (0x0008)
-
-#define HERMES_TXCTRL_TX_OK            (0x0002)        /* ?? interrupt on Tx complete */
-#define HERMES_TXCTRL_TX_EX            (0x0004)        /* ?? interrupt on Tx exception */
-#define HERMES_TXCTRL_802_11           (0x0008)        /* We supply 802.11 header */
-#define HERMES_TXCTRL_MIC              (0x0010)        /* 802.3 + TKIP */
-#define HERMES_TXCTRL_MIC_KEY_ID       (0x1800)        /* MIC Key ID mask */
-#define HERMES_TXCTRL_ALT_RTRY         (0x0020)
-
-/* Inquiry constants and data types */
-
-#define HERMES_INQ_TALLIES             (0xF100)
-#define HERMES_INQ_SCAN                        (0xF101)
-#define HERMES_INQ_CHANNELINFO         (0xF102)
-#define HERMES_INQ_HOSTSCAN            (0xF103)
-#define HERMES_INQ_HOSTSCAN_SYMBOL     (0xF104)
-#define HERMES_INQ_LINKSTATUS          (0xF200)
-#define HERMES_INQ_SEC_STAT_AGERE      (0xF202)
-
-struct hermes_tallies_frame {
-       __le16 TxUnicastFrames;
-       __le16 TxMulticastFrames;
-       __le16 TxFragments;
-       __le16 TxUnicastOctets;
-       __le16 TxMulticastOctets;
-       __le16 TxDeferredTransmissions;
-       __le16 TxSingleRetryFrames;
-       __le16 TxMultipleRetryFrames;
-       __le16 TxRetryLimitExceeded;
-       __le16 TxDiscards;
-       __le16 RxUnicastFrames;
-       __le16 RxMulticastFrames;
-       __le16 RxFragments;
-       __le16 RxUnicastOctets;
-       __le16 RxMulticastOctets;
-       __le16 RxFCSErrors;
-       __le16 RxDiscards_NoBuffer;
-       __le16 TxDiscardsWrongSA;
-       __le16 RxWEPUndecryptable;
-       __le16 RxMsgInMsgFragments;
-       __le16 RxMsgInBadMsgFragments;
-       /* Those last are probably not available in very old firmwares */
-       __le16 RxDiscards_WEPICVError;
-       __le16 RxDiscards_WEPExcluded;
-} __attribute__ ((packed));
-
-/* Grabbed from wlan-ng - Thanks Mark... - Jean II
- * This is the result of a scan inquiry command */
-/* Structure describing info about an Access Point */
-struct prism2_scan_apinfo {
-       __le16 channel;         /* Channel where the AP sits */
-       __le16 noise;           /* Noise level */
-       __le16 level;           /* Signal level */
-       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
-       __le16 beacon_interv;   /* Beacon interval */
-       __le16 capabilities;    /* Capabilities */
-       __le16 essid_len;       /* ESSID length */
-       u8 essid[32];           /* ESSID of the network */
-       u8 rates[10];           /* Bit rate supported */
-       __le16 proberesp_rate;  /* Data rate of the response frame */
-       __le16 atim;            /* ATIM window time, Kus (hostscan only) */
-} __attribute__ ((packed));
-
-/* Same stuff for the Lucent/Agere card.
- * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
-struct agere_scan_apinfo {
-       __le16 channel;         /* Channel where the AP sits */
-       __le16 noise;           /* Noise level */
-       __le16 level;           /* Signal level */
-       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
-       __le16 beacon_interv;   /* Beacon interval */
-       __le16 capabilities;    /* Capabilities */
-       /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
-       __le16 essid_len;       /* ESSID length */
-       u8 essid[32];           /* ESSID of the network */
-} __attribute__ ((packed));
-
-/* Moustafa: Scan structure for Symbol cards */
-struct symbol_scan_apinfo {
-       u8 channel;             /* Channel where the AP sits */
-       u8 unknown1;            /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
-       __le16 noise;           /* Noise level */
-       __le16 level;           /* Signal level */
-       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
-       __le16 beacon_interv;   /* Beacon interval */
-       __le16 capabilities;    /* Capabilities */
-       /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
-       __le16 essid_len;       /* ESSID length */
-       u8 essid[32];           /* ESSID of the network */
-       __le16 rates[5];        /* Bit rate supported */
-       __le16 basic_rates;     /* Basic rates bitmask */
-       u8 unknown2[6];         /* Always FF:FF:FF:FF:00:00 */
-       u8 unknown3[8];         /* Always 0, appeared in f/w 3.91-68 */
-} __attribute__ ((packed));
-
-union hermes_scan_info {
-       struct agere_scan_apinfo        a;
-       struct prism2_scan_apinfo       p;
-       struct symbol_scan_apinfo       s;
-};
-
-/* Extended scan struct for HERMES_INQ_CHANNELINFO.
- * wl_lkm calls this an ACS scan (Automatic Channel Select).
- * Keep out of union hermes_scan_info because it is much bigger than
- * the older scan structures. */
-struct agere_ext_scan_info {
-       __le16  reserved0;
-
-       u8      noise;
-       u8      level;
-       u8      rx_flow;
-       u8      rate;
-       __le16  reserved1[2];
-
-       __le16  frame_control;
-       __le16  dur_id;
-       u8      addr1[ETH_ALEN];
-       u8      addr2[ETH_ALEN];
-       u8      bssid[ETH_ALEN];
-       __le16  sequence;
-       u8      addr4[ETH_ALEN];
-
-       __le16  data_length;
-
-       /* Next 3 fields do not get filled in. */
-       u8      daddr[ETH_ALEN];
-       u8      saddr[ETH_ALEN];
-       __le16  len_type;
-
-       __le64  timestamp;
-       __le16  beacon_interval;
-       __le16  capabilities;
-       u8      data[316];
-} __attribute__ ((packed));
-
-#define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
-#define HERMES_LINKSTATUS_CONNECTED       (0x0001)
-#define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
-#define HERMES_LINKSTATUS_AP_CHANGE       (0x0003)
-#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
-#define HERMES_LINKSTATUS_AP_IN_RANGE     (0x0005)
-#define HERMES_LINKSTATUS_ASSOC_FAILED    (0x0006)
-  
-struct hermes_linkstatus {
-       __le16 linkstatus;         /* Link status */
-} __attribute__ ((packed));
-
-struct hermes_response {
-       u16 status, resp0, resp1, resp2;
-};
-
-/* "ID" structure - used for ESSID and station nickname */
-struct hermes_idstring {
-       __le16 len;
-       __le16 val[16];
-} __attribute__ ((packed));
-
-struct hermes_multicast {
-       u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed));
-
-/* Timeouts */
-#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
-
-/* Basic control structure */
-typedef struct hermes {
-       void __iomem *iobase;
-       int reg_spacing;
-#define HERMES_16BIT_REGSPACING        0
-#define HERMES_32BIT_REGSPACING        1
-       u16 inten; /* Which interrupts should be enabled? */
-} hermes_t;
-
-/* Register access convenience macros */
-#define hermes_read_reg(hw, off) \
-       (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing )))
-#define hermes_write_reg(hw, off, val) \
-       (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
-#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
-#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val))
-
-/* Function prototypes */
-void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
-int hermes_init(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp);
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp);
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                      u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                       u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
-                   u16 *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-                     u16 length, const void *value);
-
-/* Inline functions */
-
-static inline int hermes_present(hermes_t *hw)
-{
-       return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
-}
-
-static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
-{
-       hw->inten = events;
-       hermes_write_regn(hw, INTEN, events);
-}
-
-static inline int hermes_enable_port(hermes_t *hw, int port)
-{
-       return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
-                                0, NULL);
-}
-
-static inline int hermes_disable_port(hermes_t *hw, int port)
-{
-       return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 
-                                0, NULL);
-}
-
-/* Initiate an INQUIRE command (tallies or scan).  The result will come as an
- * information frame in __orinoco_ev_info() */
-static inline int hermes_inquire(hermes_t *hw, u16 rid)
-{
-       return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
-}
-
-#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 )
-#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
-{
-       off = off << hw->reg_spacing;
-       ioread16_rep(hw->iobase + off, buf, count);
-}
-
-static inline void hermes_write_bytes(struct hermes *hw, int off,
-                                     const char *buf, unsigned count)
-{
-       off = off << hw->reg_spacing;
-       iowrite16_rep(hw->iobase + off, buf, count >> 1);
-       if (unlikely(count & 1))
-               iowrite8(buf[count - 1], hw->iobase + off);
-}
-
-static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
-{
-       unsigned i;
-
-       off = off << hw->reg_spacing;
-
-       for (i = 0; i < count; i++)
-               iowrite16(0, hw->iobase + off);
-}
-
-#define HERMES_READ_RECORD(hw, bap, rid, buf) \
-       (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
-       (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
-
-static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
-{
-       __le16 rec;
-       int err;
-
-       err = HERMES_READ_RECORD(hw, bap, rid, &rec);
-       *word = le16_to_cpu(rec);
-       return err;
-}
-
-static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word)
-{
-       __le16 rec = cpu_to_le16(word);
-       return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
-}
-
-#endif  /* _HERMES_H */
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c
deleted file mode 100644 (file)
index d8c626e..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * Hermes download helper driver.
- *
- * This could be entirely merged into hermes.c.
- *
- * I'm keeping it separate to minimise the amount of merging between
- * kernel upgrades. It also means the memory overhead for drivers that
- * don't need firmware download low.
- *
- * This driver:
- *  - is capable of writing to the volatile area of the hermes device
- *  - is currently not capable of writing to non-volatile areas
- *  - provide helpers to identify and update plugin data
- *  - is not capable of interpreting a fw image directly. That is up to
- *    the main card driver.
- *  - deals with Hermes I devices. It can probably be modified to deal
- *    with Hermes II devices
- *
- * Copyright (C) 2007, David Kilroy
- *
- * Plug data code slightly modified from spectrum_cs driver
- *    Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
- * Portions based on information in wl_lkm_718 Agere driver
- *    COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "hermes.h"
-#include "hermes_dld.h"
-
-MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
-MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
-MODULE_LICENSE("Dual MPL/GPL");
-
-#define PFX "hermes_dld: "
-
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
-
-/* End markers used in dblocks */
-#define PDI_END                0x00000000      /* End of PDA */
-#define BLOCK_END      0xFFFFFFFF      /* Last image block */
-#define TEXT_END       0x1A            /* End of text header */
-
-/*
- * PDA == Production Data Area
- *
- * In principle, the max. size of the PDA is is 4096 words. Currently,
- * however, only about 500 bytes of this area are used.
- *
- * Some USB implementations can't handle sizes in excess of 1016. Note
- * that PDA is not actually used in those USB environments, but may be
- * retrieved by common code.
- */
-#define MAX_PDA_SIZE   1000
-
-/* Limit the amout we try to download in a single shot.
- * Size is in bytes.
- */
-#define MAX_DL_SIZE 1024
-#define LIMIT_PROGRAM_SIZE 0
-
-/*
- * The following structures have little-endian fields denoted by
- * the leading underscore.  Don't access them directly - use inline
- * functions defined below.
- */
-
-/*
- * The binary image to be downloaded consists of series of data blocks.
- * Each block has the following structure.
- */
-struct dblock {
-       __le32 addr;            /* adapter address where to write the block */
-       __le16 len;             /* length of the data only, in bytes */
-       char data[0];           /* data to be written */
-} __attribute__ ((packed));
-
-/*
- * Plug Data References are located in in the image after the last data
- * block.  They refer to areas in the adapter memory where the plug data
- * items with matching ID should be written.
- */
-struct pdr {
-       __le32 id;              /* record ID */
-       __le32 addr;            /* adapter address where to write the data */
-       __le32 len;             /* expected length of the data, in bytes */
-       char next[0];           /* next PDR starts here */
-} __attribute__ ((packed));
-
-/*
- * Plug Data Items are located in the EEPROM read from the adapter by
- * primary firmware.  They refer to the device-specific data that should
- * be plugged into the secondary firmware.
- */
-struct pdi {
-       __le16 len;             /* length of ID and data, in words */
-       __le16 id;              /* record ID */
-       char data[0];           /* plug data */
-} __attribute__ ((packed));
-
-/*** FW data block access functions ***/
-
-static inline u32
-dblock_addr(const struct dblock *blk)
-{
-       return le32_to_cpu(blk->addr);
-}
-
-static inline u32
-dblock_len(const struct dblock *blk)
-{
-       return le16_to_cpu(blk->len);
-}
-
-/*** PDR Access functions ***/
-
-static inline u32
-pdr_id(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->id);
-}
-
-static inline u32
-pdr_addr(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->addr);
-}
-
-static inline u32
-pdr_len(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->len);
-}
-
-/*** PDI Access functions ***/
-
-static inline u32
-pdi_id(const struct pdi *pdi)
-{
-       return le16_to_cpu(pdi->id);
-}
-
-/* Return length of the data only, in bytes */
-static inline u32
-pdi_len(const struct pdi *pdi)
-{
-       return 2 * (le16_to_cpu(pdi->len) - 1);
-}
-
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(hermes_t *hw, u32 addr)
-{
-       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(hermes_t *hw, int enabled)
-{
-       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
-       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
-       int i;
-
-       /* Already open? */
-       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
-               return 0;
-
-       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-       hermes_write_reg(hw, HERMES_CONTROL, action);
-
-       for (i = 0; i < 20; i++) {
-               udelay(10);
-               if (hermes_read_reg(hw, HERMES_CONTROL) ==
-                   desired_state)
-                       return 0;
-       }
-
-       return -EBUSY;
-}
-
-/*** Plug Data Functions ***/
-
-/*
- * Scan PDR for the record with the specified RECORD_ID.
- * If it's not found, return NULL.
- */
-static struct pdr *
-hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
-{
-       struct pdr *pdr = first_pdr;
-       void *end = (void *)first_pdr + MAX_PDA_SIZE;
-
-       while (((void *)pdr < end) &&
-              (pdr_id(pdr) != PDI_END)) {
-               /*
-                * PDR area is currently not terminated by PDI_END.
-                * It's followed by CRC records, which have the type
-                * field where PDR has length.  The type can be 0 or 1.
-                */
-               if (pdr_len(pdr) < 2)
-                       return NULL;
-
-               /* If the record ID matches, we are done */
-               if (pdr_id(pdr) == record_id)
-                       return pdr;
-
-               pdr = (struct pdr *) pdr->next;
-       }
-       return NULL;
-}
-
-/* Scan production data items for a particular entry */
-static struct pdi *
-hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
-{
-       struct pdi *pdi = first_pdi;
-
-       while (pdi_id(pdi) != PDI_END) {
-
-               /* If the record ID matches, we are done */
-               if (pdi_id(pdi) == record_id)
-                       return pdi;
-
-               pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
-       }
-       return NULL;
-}
-
-/* Process one Plug Data Item - find corresponding PDR and plug it */
-static int
-hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
-{
-       struct pdr *pdr;
-
-       /* Find the PDR corresponding to this PDI */
-       pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
-
-       /* No match is found, safe to ignore */
-       if (!pdr)
-               return 0;
-
-       /* Lengths of the data in PDI and PDR must match */
-       if (pdi_len(pdi) != pdr_len(pdr))
-               return -EINVAL;
-
-       /* do the actual plugging */
-       hermes_aux_setaddr(hw, pdr_addr(pdr));
-       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-       return 0;
-}
-
-/* Read PDA from the adapter */
-int hermes_read_pda(hermes_t *hw,
-                   __le16 *pda,
-                   u32 pda_addr,
-                   u16 pda_len,
-                   int use_eeprom) /* can we get this into hw? */
-{
-       int ret;
-       u16 pda_size;
-       u16 data_len = pda_len;
-       __le16 *data = pda;
-
-       if (use_eeprom) {
-               /* PDA of spectrum symbol is in eeprom */
-
-               /* Issue command to read EEPROM */
-               ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-               if (ret)
-                       return ret;
-       } else {
-               /* wl_lkm does not include PDA size in the PDA area.
-                * We will pad the information into pda, so other routines
-                * don't have to be modified */
-               pda[0] = cpu_to_le16(pda_len - 2);
-                       /* Includes CFG_PROD_DATA but not itself */
-               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-               data_len = pda_len - 4;
-               data = pda + 2;
-       }
-
-       /* Open auxiliary port */
-       ret = hermes_aux_control(hw, 1);
-       printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
-       if (ret)
-               return ret;
-
-       /* read PDA from EEPROM */
-       hermes_aux_setaddr(hw, pda_addr);
-       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
-       /* Close aux port */
-       ret = hermes_aux_control(hw, 0);
-       printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
-
-       /* Check PDA length */
-       pda_size = le16_to_cpu(pda[0]);
-       printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
-              pda_size, pda_len);
-       if (pda_size > pda_len)
-               return -EINVAL;
-
-       return 0;
-}
-EXPORT_SYMBOL(hermes_read_pda);
-
-/* Parse PDA and write the records into the adapter
- *
- * Attempt to write every records that is in the specified pda
- * which also has a valid production data record for the firmware.
- */
-int hermes_apply_pda(hermes_t *hw,
-                    const char *first_pdr,
-                    const __le16 *pda)
-{
-       int ret;
-       const struct pdi *pdi;
-       struct pdr *pdr;
-
-       pdr = (struct pdr *) first_pdr;
-
-       /* Go through every PDI and plug them into the adapter */
-       pdi = (const struct pdi *) (pda + 2);
-       while (pdi_id(pdi) != PDI_END) {
-               ret = hermes_plug_pdi(hw, pdr, pdi);
-               if (ret)
-                       return ret;
-
-               /* Increment to the next PDI */
-               pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
-       }
-       return 0;
-}
-EXPORT_SYMBOL(hermes_apply_pda);
-
-/* Identify the total number of bytes in all blocks
- * including the header data.
- */
-size_t
-hermes_blocks_length(const char *first_block)
-{
-       const struct dblock *blk = (const struct dblock *) first_block;
-       int total_len = 0;
-       int len;
-
-       /* Skip all blocks to locate Plug Data References
-        * (Spectrum CS) */
-       while (dblock_addr(blk) != BLOCK_END) {
-               len = dblock_len(blk);
-               total_len += sizeof(*blk) + len;
-               blk = (struct dblock *) &blk->data[len];
-       }
-
-       return total_len;
-}
-EXPORT_SYMBOL(hermes_blocks_length);
-
-/*** Hermes programming ***/
-
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_init(hermes_t *hw, u32 offset)
-{
-       int err;
-
-       /* Disable interrupts?*/
-       /*hw->inten = 0x0;*/
-       /*hermes_write_regn(hw, INTEN, 0);*/
-       /*hermes_set_irqmask(hw, 0);*/
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Using doicmd_wait rather than docmd_wait */
-       err = hermes_doicmd_wait(hw,
-                                0x0100 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_doicmd_wait(hw,
-                                0x0000 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_aux_control(hw, 1);
-       printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
-
-       if (err)
-               return err;
-
-       printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
-       err = hermes_doicmd_wait(hw,
-                                HERMES_PROGRAM_ENABLE_VOLATILE,
-                                offset & 0xFFFFu,
-                                offset >> 16,
-                                0,
-                                NULL);
-       printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
-              err);
-
-       return err;
-}
-EXPORT_SYMBOL(hermesi_program_init);
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_end(hermes_t *hw)
-{
-       struct hermes_response resp;
-       int rc = 0;
-       int err;
-
-       rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
-       printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
-              "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
-              rc, resp.resp0, resp.resp1, resp.resp2);
-
-       if ((rc == 0) &&
-           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
-               rc = -EIO;
-
-       err = hermes_aux_control(hw, 0);
-       printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Reinitialise, ignoring return */
-       (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
-                                 0, 0, 0, NULL);
-
-       return rc ? rc : err;
-}
-EXPORT_SYMBOL(hermesi_program_end);
-
-/* Program the data blocks */
-int hermes_program(hermes_t *hw, const char *first_block, const char *end)
-{
-       const struct dblock *blk;
-       u32 blkaddr;
-       u32 blklen;
-#if LIMIT_PROGRAM_SIZE
-       u32 addr;
-       u32 len;
-#endif
-
-       blk = (const struct dblock *) first_block;
-
-       if ((const char *) blk > (end - sizeof(*blk)))
-               return -EIO;
-
-       blkaddr = dblock_addr(blk);
-       blklen = dblock_len(blk);
-
-       while ((blkaddr != BLOCK_END) &&
-              (((const char *) blk + blklen) <= end)) {
-               printk(KERN_DEBUG PFX
-                      "Programming block of length %d to address 0x%08x\n",
-                      blklen, blkaddr);
-
-#if !LIMIT_PROGRAM_SIZE
-               /* wl_lkm driver splits this into writes of 2000 bytes */
-               hermes_aux_setaddr(hw, blkaddr);
-               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-                                  blklen);
-#else
-               len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
-               addr = blkaddr;
-
-               while (addr < (blkaddr + blklen)) {
-                       printk(KERN_DEBUG PFX
-                              "Programming subblock of length %d "
-                              "to address 0x%08x. Data @ %p\n",
-                              len, addr, &blk->data[addr - blkaddr]);
-
-                       hermes_aux_setaddr(hw, addr);
-                       hermes_write_bytes(hw, HERMES_AUXDATA,
-                                          &blk->data[addr - blkaddr],
-                                          len);
-
-                       addr += len;
-                       len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
-                               (blkaddr + blklen - addr) : MAX_DL_SIZE;
-               }
-#endif
-               blk = (const struct dblock *) &blk->data[blklen];
-
-               if ((const char *) blk > (end - sizeof(*blk)))
-                       return -EIO;
-
-               blkaddr = dblock_addr(blk);
-               blklen = dblock_len(blk);
-       }
-       return 0;
-}
-EXPORT_SYMBOL(hermes_program);
-
-static int __init init_hermes_dld(void)
-{
-       return 0;
-}
-
-static void __exit exit_hermes_dld(void)
-{
-}
-
-module_init(init_hermes_dld);
-module_exit(exit_hermes_dld);
-
-/*** Default plugging data for Hermes I ***/
-/* Values from wl_lkm_718/hcf/dhf.c */
-
-#define DEFINE_DEFAULT_PDR(pid, length, data)                          \
-static const struct {                                                  \
-       __le16 len;                                                     \
-       __le16 id;                                                      \
-       u8 val[length];                                                 \
-} __attribute__ ((packed)) default_pdr_data_##pid = {                  \
-       __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/         \
-                               sizeof(__le16)) - 1),                   \
-       __constant_cpu_to_le16(pid),                                    \
-       data                                                            \
-}
-
-#define DEFAULT_PDR(pid) default_pdr_data_##pid
-
-/*  HWIF Compatiblity */
-DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
-
-/* PPPPSign */
-DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
-
-/* PPPPProf */
-DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
-
-/* Antenna diversity */
-DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
-
-/* Modem VCO band Set-up */
-DEFINE_DEFAULT_PDR(0x0160, 28,
-                  "\x00\x00\x00\x00\x00\x00\x00\x00"
-                  "\x00\x00\x00\x00\x00\x00\x00\x00"
-                  "\x00\x00\x00\x00\x00\x00\x00\x00"
-                  "\x00\x00\x00\x00");
-
-/* Modem Rx Gain Table Values */
-DEFINE_DEFAULT_PDR(0x0161, 256,
-                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
-                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
-                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
-                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
-                  "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
-                  "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
-                  "\x3B\x01\x3A\01\x3A\x01\x39\x01"
-                  "\x39\x01\x38\01\x38\x01\x37\x01"
-                  "\x37\x01\x36\01\x36\x01\x35\x01"
-                  "\x35\x01\x34\01\x34\x01\x33\x01"
-                  "\x33\x01\x32\x01\x32\x01\x31\x01"
-                  "\x31\x01\x30\x01\x30\x01\x7B\x01"
-                  "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
-                  "\x79\x01\x78\x01\x78\x01\x77\x01"
-                  "\x77\x01\x76\x01\x76\x01\x75\x01"
-                  "\x75\x01\x74\x01\x74\x01\x73\x01"
-                  "\x73\x01\x72\x01\x72\x01\x71\x01"
-                  "\x71\x01\x70\x01\x70\x01\x68\x01"
-                  "\x68\x01\x67\x01\x67\x01\x66\x01"
-                  "\x66\x01\x65\x01\x65\x01\x57\x01"
-                  "\x57\x01\x56\x01\x56\x01\x55\x01"
-                  "\x55\x01\x54\x01\x54\x01\x53\x01"
-                  "\x53\x01\x52\x01\x52\x01\x51\x01"
-                  "\x51\x01\x50\x01\x50\x01\x48\x01"
-                  "\x48\x01\x47\x01\x47\x01\x46\x01"
-                  "\x46\x01\x45\x01\x45\x01\x44\x01"
-                  "\x44\x01\x43\x01\x43\x01\x42\x01"
-                  "\x42\x01\x41\x01\x41\x01\x40\x01"
-                  "\x40\x01\x40\x01\x40\x01\x40\x01"
-                  "\x40\x01\x40\x01\x40\x01\x40\x01"
-                  "\x40\x01\x40\x01\x40\x01\x40\x01"
-                  "\x40\x01\x40\x01\x40\x01\x40\x01");
-
-/* Write PDA according to certain rules.
- *
- * For every production data record, look for a previous setting in
- * the pda, and use that.
- *
- * For certain records, use defaults if they are not found in pda.
- */
-int hermes_apply_pda_with_defaults(hermes_t *hw,
-                                  const char *first_pdr,
-                                  const __le16 *pda)
-{
-       const struct pdr *pdr = (const struct pdr *) first_pdr;
-       struct pdi *first_pdi = (struct pdi *) &pda[2];
-       struct pdi *pdi;
-       struct pdi *default_pdi = NULL;
-       struct pdi *outdoor_pdi;
-       void *end = (void *)first_pdr + MAX_PDA_SIZE;
-       int record_id;
-
-       while (((void *)pdr < end) &&
-              (pdr_id(pdr) != PDI_END)) {
-               /*
-                * For spectrum_cs firmwares,
-                * PDR area is currently not terminated by PDI_END.
-                * It's followed by CRC records, which have the type
-                * field where PDR has length.  The type can be 0 or 1.
-                */
-               if (pdr_len(pdr) < 2)
-                       break;
-               record_id = pdr_id(pdr);
-
-               pdi = hermes_find_pdi(first_pdi, record_id);
-               if (pdi)
-                       printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
-                              record_id, pdi);
-
-               switch (record_id) {
-               case 0x110: /* Modem REFDAC values */
-               case 0x120: /* Modem VGDAC values */
-                       outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
-                       default_pdi = NULL;
-                       if (outdoor_pdi) {
-                               pdi = outdoor_pdi;
-                               printk(KERN_DEBUG PFX
-                                      "Using outdoor record 0x%04x at %p\n",
-                                      record_id + 1, pdi);
-                       }
-                       break;
-               case 0x5: /*  HWIF Compatiblity */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
-                       break;
-               case 0x108: /* PPPPSign */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
-                       break;
-               case 0x109: /* PPPPProf */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
-                       break;
-               case 0x150: /* Antenna diversity */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
-                       break;
-               case 0x160: /* Modem VCO band Set-up */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
-                       break;
-               case 0x161: /* Modem Rx Gain Table Values */
-                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
-                       break;
-               default:
-                       default_pdi = NULL;
-                       break;
-               }
-               if (!pdi && default_pdi) {
-                       /* Use default */
-                       pdi = default_pdi;
-                       printk(KERN_DEBUG PFX
-                              "Using default record 0x%04x at %p\n",
-                              record_id, pdi);
-               }
-
-               if (pdi) {
-                       /* Lengths of the data in PDI and PDR must match */
-                       if (pdi_len(pdi) == pdr_len(pdr)) {
-                               /* do the actual plugging */
-                               hermes_aux_setaddr(hw, pdr_addr(pdr));
-                               hermes_write_bytes(hw, HERMES_AUXDATA,
-                                                  pdi->data, pdi_len(pdi));
-                       }
-               }
-
-               pdr++;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h
deleted file mode 100644 (file)
index 6fcb262..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007, David Kilroy
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-#ifndef _HERMES_DLD_H
-#define _HERMES_DLD_H
-
-#include "hermes.h"
-
-int hermesi_program_init(hermes_t *hw, u32 offset);
-int hermesi_program_end(hermes_t *hw);
-int hermes_program(hermes_t *hw, const char *first_block, const char *end);
-
-int hermes_read_pda(hermes_t *hw,
-                   __le16 *pda,
-                   u32 pda_addr,
-                   u16 pda_len,
-                   int use_eeprom);
-int hermes_apply_pda(hermes_t *hw,
-                    const char *first_pdr,
-                    const __le16 *pda);
-int hermes_apply_pda_with_defaults(hermes_t *hw,
-                                  const char *first_pdr,
-                                  const __le16 *pda);
-
-size_t hermes_blocks_length(const char *first_block);
-
-#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/hermes_rid.h
deleted file mode 100644 (file)
index 42eb67d..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef _HERMES_RID_H
-#define _HERMES_RID_H
-
-/*
- * Configuration RIDs
- */
-#define HERMES_RID_CNFPORTTYPE                 0xFC00
-#define HERMES_RID_CNFOWNMACADDR               0xFC01
-#define HERMES_RID_CNFDESIREDSSID              0xFC02
-#define HERMES_RID_CNFOWNCHANNEL               0xFC03
-#define HERMES_RID_CNFOWNSSID                  0xFC04
-#define HERMES_RID_CNFOWNATIMWINDOW            0xFC05
-#define HERMES_RID_CNFSYSTEMSCALE              0xFC06
-#define HERMES_RID_CNFMAXDATALEN               0xFC07
-#define HERMES_RID_CNFWDSADDRESS               0xFC08
-#define HERMES_RID_CNFPMENABLED                        0xFC09
-#define HERMES_RID_CNFPMEPS                    0xFC0A
-#define HERMES_RID_CNFMULTICASTRECEIVE         0xFC0B
-#define HERMES_RID_CNFMAXSLEEPDURATION         0xFC0C
-#define HERMES_RID_CNFPMHOLDOVERDURATION       0xFC0D
-#define HERMES_RID_CNFOWNNAME                  0xFC0E
-#define HERMES_RID_CNFOWNDTIMPERIOD            0xFC10
-#define HERMES_RID_CNFWDSADDRESS1              0xFC11
-#define HERMES_RID_CNFWDSADDRESS2              0xFC12
-#define HERMES_RID_CNFWDSADDRESS3              0xFC13
-#define HERMES_RID_CNFWDSADDRESS4              0xFC14
-#define HERMES_RID_CNFWDSADDRESS5              0xFC15
-#define HERMES_RID_CNFWDSADDRESS6              0xFC16
-#define HERMES_RID_CNFMULTICASTPMBUFFERING     0xFC17
-#define HERMES_RID_CNFWEPENABLED_AGERE         0xFC20
-#define HERMES_RID_CNFAUTHENTICATION_AGERE     0xFC21
-#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL    0xFC21
-#define HERMES_RID_CNFDROPUNENCRYPTED          0xFC22
-#define HERMES_RID_CNFWEPDEFAULTKEYID          0xFC23
-#define HERMES_RID_CNFDEFAULTKEY0              0xFC24
-#define HERMES_RID_CNFDEFAULTKEY1              0xFC25
-#define HERMES_RID_CNFMWOROBUST_AGERE          0xFC25
-#define HERMES_RID_CNFDEFAULTKEY2              0xFC26
-#define HERMES_RID_CNFDEFAULTKEY3              0xFC27
-#define HERMES_RID_CNFWEPFLAGS_INTERSIL                0xFC28
-#define HERMES_RID_CNFWEPKEYMAPPINGTABLE       0xFC29
-#define HERMES_RID_CNFAUTHENTICATION           0xFC2A
-#define HERMES_RID_CNFMAXASSOCSTA              0xFC2B
-#define        HERMES_RID_CNFKEYLENGTH_SYMBOL          0xFC2B
-#define HERMES_RID_CNFTXCONTROL                        0xFC2C
-#define HERMES_RID_CNFROAMINGMODE              0xFC2D
-#define HERMES_RID_CNFHOSTAUTHENTICATION       0xFC2E
-#define HERMES_RID_CNFRCVCRCERROR              0xFC30
-#define HERMES_RID_CNFMMLIFE                   0xFC31
-#define HERMES_RID_CNFALTRETRYCOUNT            0xFC32
-#define HERMES_RID_CNFBEACONINT                        0xFC33
-#define HERMES_RID_CNFAPPCFINFO                        0xFC34
-#define HERMES_RID_CNFSTAPCFINFO               0xFC35
-#define HERMES_RID_CNFPRIORITYQUSAGE           0xFC37
-#define HERMES_RID_CNFTIMCTRL                  0xFC40
-#define HERMES_RID_CNFTHIRTY2TALLY             0xFC42
-#define HERMES_RID_CNFENHSECURITY              0xFC43
-#define HERMES_RID_CNFGROUPADDRESSES           0xFC80
-#define HERMES_RID_CNFCREATEIBSS               0xFC81
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD   0xFC82
-#define HERMES_RID_CNFRTSTHRESHOLD             0xFC83
-#define HERMES_RID_CNFTXRATECONTROL            0xFC84
-#define HERMES_RID_CNFPROMISCUOUSMODE          0xFC85
-#define HERMES_RID_CNFBASICRATES_SYMBOL                0xFC8A
-#define HERMES_RID_CNFPREAMBLE_SYMBOL          0xFC8C
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0  0xFC90
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1  0xFC91
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2  0xFC92
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3  0xFC93
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4  0xFC94
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5  0xFC95
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6  0xFC96
-#define HERMES_RID_CNFRTSTHRESHOLD0            0xFC97
-#define HERMES_RID_CNFRTSTHRESHOLD1            0xFC98
-#define HERMES_RID_CNFRTSTHRESHOLD2            0xFC99
-#define HERMES_RID_CNFRTSTHRESHOLD3            0xFC9A
-#define HERMES_RID_CNFRTSTHRESHOLD4            0xFC9B
-#define HERMES_RID_CNFRTSTHRESHOLD5            0xFC9C
-#define HERMES_RID_CNFRTSTHRESHOLD6            0xFC9D
-#define HERMES_RID_CNFHOSTSCAN_SYMBOL          0xFCAB
-#define HERMES_RID_CNFSHORTPREAMBLE            0xFCB0
-#define HERMES_RID_CNFWEPKEYS_AGERE            0xFCB0
-#define HERMES_RID_CNFEXCLUDELONGPREAMBLE      0xFCB1
-#define HERMES_RID_CNFTXKEY_AGERE              0xFCB1
-#define HERMES_RID_CNFAUTHENTICATIONRSPTO      0xFCB2
-#define HERMES_RID_CNFSCANSSID_AGERE           0xFCB2
-#define HERMES_RID_CNFBASICRATES               0xFCB3
-#define HERMES_RID_CNFSUPPORTEDRATES           0xFCB4
-#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE  0xFCB4
-#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE        0xFCB5
-#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE  0xFCB6
-#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE   0xFCB7
-#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE   0xFCB8
-#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
-#define HERMES_RID_CNFCACHEDPMKADDRESS         0xFCBA
-#define HERMES_RID_CNFREMOVEPMKADDRESS         0xFCBB
-#define HERMES_RID_CNFSCANCHANNELS2GHZ         0xFCC2
-#define HERMES_RID_CNFDISASSOCIATE             0xFCC8
-#define HERMES_RID_CNFTICKTIME                 0xFCE0
-#define HERMES_RID_CNFSCANREQUEST              0xFCE1
-#define HERMES_RID_CNFJOINREQUEST              0xFCE2
-#define HERMES_RID_CNFAUTHENTICATESTATION      0xFCE3
-#define HERMES_RID_CNFCHANNELINFOREQUEST       0xFCE4
-#define HERMES_RID_CNFHOSTSCAN                 0xFCE5
-
-/*
- * Information RIDs
- */
-#define HERMES_RID_MAXLOADTIME                 0xFD00
-#define HERMES_RID_DOWNLOADBUFFER              0xFD01
-#define HERMES_RID_PRIID                       0xFD02
-#define HERMES_RID_PRISUPRANGE                 0xFD03
-#define HERMES_RID_CFIACTRANGES                        0xFD04
-#define HERMES_RID_NICSERNUM                   0xFD0A
-#define HERMES_RID_NICID                       0xFD0B
-#define HERMES_RID_MFISUPRANGE                 0xFD0C
-#define HERMES_RID_CFISUPRANGE                 0xFD0D
-#define HERMES_RID_CHANNELLIST                 0xFD10
-#define HERMES_RID_REGULATORYDOMAINS           0xFD11
-#define HERMES_RID_TEMPTYPE                    0xFD12
-#define HERMES_RID_CIS                         0xFD13
-#define HERMES_RID_STAID                       0xFD20
-#define HERMES_RID_STASUPRANGE                 0xFD21
-#define HERMES_RID_MFIACTRANGES                        0xFD22
-#define HERMES_RID_CFIACTRANGES2               0xFD23
-#define HERMES_RID_SECONDARYVERSION_SYMBOL     0xFD24
-#define HERMES_RID_PORTSTATUS                  0xFD40
-#define HERMES_RID_CURRENTSSID                 0xFD41
-#define HERMES_RID_CURRENTBSSID                        0xFD42
-#define HERMES_RID_COMMSQUALITY                        0xFD43
-#define HERMES_RID_CURRENTTXRATE               0xFD44
-#define HERMES_RID_CURRENTBEACONINTERVAL       0xFD45
-#define HERMES_RID_CURRENTSCALETHRESHOLDS      0xFD46
-#define HERMES_RID_PROTOCOLRSPTIME             0xFD47
-#define HERMES_RID_SHORTRETRYLIMIT             0xFD48
-#define HERMES_RID_LONGRETRYLIMIT              0xFD49
-#define HERMES_RID_MAXTRANSMITLIFETIME         0xFD4A
-#define HERMES_RID_MAXRECEIVELIFETIME          0xFD4B
-#define HERMES_RID_CFPOLLABLE                  0xFD4C
-#define HERMES_RID_AUTHENTICATIONALGORITHMS    0xFD4D
-#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED    0xFD4F
-#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL    0xFD51
-#define HERMES_RID_CURRENTTXRATE1              0xFD80
-#define HERMES_RID_CURRENTTXRATE2              0xFD81
-#define HERMES_RID_CURRENTTXRATE3              0xFD82
-#define HERMES_RID_CURRENTTXRATE4              0xFD83
-#define HERMES_RID_CURRENTTXRATE5              0xFD84
-#define HERMES_RID_CURRENTTXRATE6              0xFD85
-#define HERMES_RID_OWNMACADDR                  0xFD86
-#define HERMES_RID_SCANRESULTSTABLE            0xFD88
-#define HERMES_RID_CURRENT_COUNTRY_INFO                0xFD89
-#define HERMES_RID_CURRENT_WPA_IE              0xFD8A
-#define HERMES_RID_CURRENT_TKIP_IV             0xFD8B
-#define HERMES_RID_CURRENT_ASSOC_REQ_INFO      0xFD8C
-#define HERMES_RID_CURRENT_ASSOC_RESP_INFO     0xFD8D
-#define HERMES_RID_TXQUEUEEMPTY                        0xFD91
-#define HERMES_RID_PHYTYPE                     0xFDC0
-#define HERMES_RID_CURRENTCHANNEL              0xFDC1
-#define HERMES_RID_CURRENTPOWERSTATE           0xFDC2
-#define HERMES_RID_CCAMODE                     0xFDC3
-#define HERMES_RID_SUPPORTEDDATARATES          0xFDC6
-#define HERMES_RID_BUILDSEQ                    0xFFFE
-#define HERMES_RID_FWID                                0xFFFF
-
-#endif
index 592c5958723b4ef03aa523c7d8bf4453e8836543..7187925bd0d5cce04f4cd0d4866beea80624f2da 100644 (file)
@@ -828,8 +828,6 @@ struct iwl3945_priv {
        unsigned long last_statistics_time;
 
        /* context information */
-       u8 essid[IW_ESSID_MAX_SIZE];
-       u8 essid_len;
        u16 rates_mask;
 
        u32 power_mode;
index 0953a9c568070ba95135059003c62f28725b0600..157cad4e9da038bb78fac200fffa406d4c7abea7 100644 (file)
@@ -2323,7 +2323,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .reset = iwl4965_apm_reset,
                .stop = iwl4965_apm_stop,
                .config = iwl4965_nic_config,
-               .set_pwr_src = iwl4965_set_pwr_src,
+               .set_pwr_src = iwl_set_pwr_src,
        },
        .eeprom_ops = {
                .regulatory_bands = {
@@ -2342,7 +2342,7 @@ static struct iwl_lib_ops iwl4965_lib = {
                .query_addr = iwlcore_eeprom_query_addr,
        },
        .send_tx_power  = iwl4965_send_tx_power,
-       .update_chain_flags = iwl4965_update_chain_flags,
+       .update_chain_flags = iwl_update_chain_flags,
        .temperature = iwl4965_temperature_calib,
 };
 
index 4348c7db3d1f64a9ab1389586f9f58549ae65d23..31e62a838ad40696236ce9ebaef4ea2b94d1d979 100644 (file)
@@ -535,7 +535,7 @@ static int iwl5000_load_section(struct iwl_priv *priv,
        iwl_write_direct32(priv,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
        iwl_release_nic_access(priv);
@@ -549,14 +549,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv,
 {
        int ret = 0;
 
-       ret = iwl5000_load_section(
-               priv, inst_image, RTC_INST_LOWER_BOUND);
+       ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND);
        if (ret)
                return ret;
 
        IWL_DEBUG_INFO("INST uCode section being loaded...\n");
        ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-                               priv->ucode_write_complete, 5 * HZ);
+                                       priv->ucode_write_complete, 5 * HZ);
        if (ret == -ERESTARTSYS) {
                IWL_ERROR("Could not load the INST uCode section due "
                        "to interrupt\n");
@@ -753,6 +752,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv)
        priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
        iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
        /* map qos queues to fifos one-to-one */
        for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
                int ac = iwl5000_default_queue_to_tx_fifo[i];
@@ -1474,13 +1474,13 @@ static struct iwl_lib_ops iwl5000_lib = {
        .alive_notify = iwl5000_alive_notify,
        .send_tx_power = iwl5000_send_tx_power,
        .temperature = iwl5000_temperature,
-       .update_chain_flags = iwl4965_update_chain_flags,
+       .update_chain_flags = iwl_update_chain_flags,
        .apm_ops = {
                .init = iwl5000_apm_init,
                .reset = iwl5000_apm_reset,
                .stop = iwl5000_apm_stop,
                .config = iwl5000_nic_config,
-               .set_pwr_src = iwl4965_set_pwr_src,
+               .set_pwr_src = iwl_set_pwr_src,
        },
        .eeprom_ops = {
                .regulatory_bands = {
index f5e94b65a7f6d61ac476d5e935c9227a74feff85..0332805cc6306e9d06ea101ad9b1d866a2db0863 100644 (file)
@@ -2071,15 +2071,13 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        if ((i < 0) || (i >= IWL_RATE_COUNT))
                i = 0;
 
-       /* FIXME:RS: This is also wrong in 4965 */
        rate = iwl_rates[i].plcp;
-       rate |= RATE_MCS_ANT_B_MSK;
-       rate &= ~RATE_MCS_ANT_A_MSK;
+       tbl->ant_type = first_antenna(valid_tx_ant);
+       rate |= tbl->ant_type << RATE_MCS_ANT_POS;
 
        if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
                rate |= RATE_MCS_CCK_MSK;
 
-       tbl->ant_type = ANT_B;
        rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
        if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
            rs_toggle_antenna(valid_tx_ant, &rate, tbl);
index ccfafcfa47671b47f3a7a8535cc719baec0d55da..adcbf538ed54054321f5f56e48dab3a73382d1c4 100644 (file)
@@ -294,7 +294,7 @@ static inline u8 first_antenna(u8 mask)
 }
 
 
-static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
 {
        u8 rate = iwl_rates[rate_index].prev_ieee;
 
@@ -304,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 }
 
 /**
- * iwl4965_rate_control_register - Register the rate control algorithm callbacks
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl4965_rate_control_register in order to register the rate control callbacks
+ * iwl_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
@@ -316,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 extern int iwlagn_rate_control_register(void);
 
 /**
- * iwl4965_rate_control_unregister - Unregister the rate control callbacks
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
index 2c35a017e5f63648e7dd58f66b8fb1a001c3c391..8264d3742d0881c28cd079276a9794f60fac8e10 100644 (file)
@@ -96,7 +96,7 @@ MODULE_ALIAS("iwl4965");
 
 
 
-static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 {
        struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
@@ -108,13 +108,13 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 }
 
 /**
- * iwl4965_check_rxon_cmd - validate RXON structure is valid
+ * iwl_check_rxon_cmd - validate RXON structure is valid
  *
  * NOTE:  This is really only useful during development and can eventually
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
 {
        int error = 0;
        int counter = 1;
@@ -174,7 +174,7 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
                            le16_to_cpu(rxon->channel));
 
        if (error) {
-               IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
+               IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
                return -1;
        }
        return 0;
@@ -228,14 +228,14 @@ static int iwl_full_rxon_required(struct iwl_priv *priv)
 }
 
 /**
- * iwl4965_commit_rxon - commit staging_rxon to hardware
+ * iwl_commit_rxon - commit staging_rxon to hardware
  *
  * The RXON command in staging_rxon is committed to the hardware and
  * the active_rxon structure is updated with the new data.  This
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl4965_commit_rxon(struct iwl_priv *priv)
+static int iwl_commit_rxon(struct iwl_priv *priv)
 {
        /* cast away the const for active_rxon in this function */
        struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
@@ -252,14 +252,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
         * 5000, but will not damage 4965 */
        priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
 
-       ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
+       ret = iwl_check_rxon_cmd(&priv->staging_rxon);
        if (ret) {
                IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
                return -EINVAL;
        }
 
        /* If we don't need to send a full RXON, we can use
-        * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
+        * iwl_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
        if (!iwl_full_rxon_required(priv)) {
                ret = iwl_send_rxon_assoc(priv);
@@ -304,7 +304,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
                       le16_to_cpu(priv->staging_rxon.channel),
                       priv->staging_rxon.bssid_addr);
 
-       iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+       iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
 
        /* Apply the new configuration
         * RXON unassoc clears the station table in uCode, send it before
@@ -374,14 +374,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
        return 0;
 }
 
-void iwl4965_update_chain_flags(struct iwl_priv *priv)
+void iwl_update_chain_flags(struct iwl_priv *priv)
 {
 
        iwl_set_rxon_chain(priv);
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 }
 
-static int iwl4965_send_bt_config(struct iwl_priv *priv)
+static int iwl_send_bt_config(struct iwl_priv *priv)
 {
        struct iwl4965_bt_cmd bt_cmd = {
                .flags = 3,
@@ -459,7 +459,7 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
        return priv->ibss_beacon->len;
 }
 
-static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
+static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
 {
        int i;
        int rate_mask;
@@ -484,7 +484,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
                return IWL_RATE_6M_PLCP;
 }
 
-static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
                                       struct iwl_frame *frame, u8 rate)
 {
        struct iwl_tx_beacon_cmd *tx_beacon_cmd;
@@ -516,7 +516,7 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
 
        return sizeof(*tx_beacon_cmd) + frame_size;
 }
-static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
 {
        struct iwl_frame *frame;
        unsigned int frame_size;
@@ -531,9 +531,9 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
                return -ENOMEM;
        }
 
-       rate = iwl4965_rate_get_lowest_plcp(priv);
+       rate = iwl_rate_get_lowest_plcp(priv);
 
-       frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
+       frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
 
        rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
                              &frame->u.cmd[0]);
@@ -549,7 +549,7 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void iwl4965_ht_conf(struct iwl_priv *priv,
+static void iwl_ht_conf(struct iwl_priv *priv,
                            struct ieee80211_bss_conf *bss_conf)
 {
        struct ieee80211_sta_ht_cap *ht_conf;
@@ -708,7 +708,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
                      | RXON_FLG_CCK_MSK);
                priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
-               /* Copied from iwl4965_post_associate() */
+               /* Copied from iwl_post_associate() */
                if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
@@ -726,13 +726,13 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
 /*
  * initialize rxon structure with default values from eeprom
  */
-static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
+static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
 {
        const struct iwl_channel_info *ch_info;
 
        memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-       switch (priv->iw_mode) {
+       switch (mode) {
        case NL80211_IFTYPE_AP:
                priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
                break;
@@ -755,7 +755,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
                    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
                break;
        default:
-               IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+               IWL_ERROR("Unsupported interface type %d\n", mode);
                break;
        }
 
@@ -801,11 +801,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
        iwl_set_rxon_chain(priv);
 }
 
-static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
 {
-       priv->iw_mode = mode;
-
-       iwl4965_connection_init_rx_config(priv);
+       iwl_connection_init_rx_config(priv, mode);
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
        iwl_clear_stations_table(priv);
@@ -821,12 +819,12 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
                return -EAGAIN;
        }
 
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 
        return 0;
 }
 
-static void iwl4965_set_rate(struct iwl_priv *priv)
+static void iwl_set_rate(struct iwl_priv *priv)
 {
        const struct ieee80211_supported_band *hw = NULL;
        struct ieee80211_rate *rate;
@@ -888,7 +886,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
  * the lower 3 bytes is the time in usec within one beacon interval
  */
 
-static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
 {
        u32 quot;
        u32 rem;
@@ -907,7 +905,7 @@ static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
  * the same as HW timer counter counting down
  */
 
-static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 {
        u32 base_low = base & BEACON_TIME_MASK_LOW;
        u32 addon_low = addon & BEACON_TIME_MASK_LOW;
@@ -926,7 +924,7 @@ static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
        return cpu_to_le32(res);
 }
 
-static int iwl4965_get_measurement(struct iwl_priv *priv,
+static int iwl_get_measurement(struct iwl_priv *priv,
                               struct ieee80211_measurement_params *params,
                               u8 type)
 {
@@ -944,7 +942,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv,
 
        if (iwl_is_associated(priv))
                add_time =
-                   iwl4965_usecs_to_beacons(
+                   iwl_usecs_to_beacons(
                        le64_to_cpu(params->start_time) - priv->last_tsf,
                        le16_to_cpu(priv->rxon_timing.beacon_interval));
 
@@ -959,7 +957,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv,
 
        if (iwl_is_associated(priv))
                spectrum.start_time =
-                   iwl4965_add_beacon_time(priv->last_beacon_time,
+                   iwl_add_beacon_time(priv->last_beacon_time,
                                add_time,
                                le16_to_cpu(priv->rxon_timing.beacon_interval));
        else
@@ -1047,7 +1045,7 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
                IWL_WARNING("uCode did not respond OK.\n");
 }
 
-static void iwl4965_rx_reply_error(struct iwl_priv *priv,
+static void iwl_rx_reply_error(struct iwl_priv *priv,
                                   struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1063,7 +1061,7 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv,
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
@@ -1074,7 +1072,7 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        priv->staging_rxon.channel = csa->channel;
 }
 
-static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
                                          struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
@@ -1092,7 +1090,7 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
 #endif
 }
 
-static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
                                      struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1103,7 +1101,7 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
 #endif
 }
 
-static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
                                             struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1113,7 +1111,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
        iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 
-static void iwl4965_bg_beacon_update(struct work_struct *work)
+static void iwl_bg_beacon_update(struct work_struct *work)
 {
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, beacon_update);
@@ -1135,11 +1133,11 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
        priv->ibss_beacon = beacon;
        mutex_unlock(&priv->mutex);
 
-       iwl4965_send_beacon_cmd(priv);
+       iwl_send_beacon_cmd(priv);
 }
 
 /**
- * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ * iwl_bg_statistics_periodic - Timer callback to queue statistics
  *
  * This callback is provided in order to send a statistics request.
  *
@@ -1148,17 +1146,21 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
  * was received.  We need to ensure we receive the statistics in order
  * to update the temperature used for calibrating the TXPOWER.
  */
-static void iwl4965_bg_statistics_periodic(unsigned long data)
+static void iwl_bg_statistics_periodic(unsigned long data)
 {
        struct iwl_priv *priv = (struct iwl_priv *)data;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
+       /* dont send host command if rf-kill is on */
+       if (!iwl_is_ready_rf(priv))
+               return;
+
        iwl_send_statistics_request(priv, CMD_ASYNC);
 }
 
-static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1182,7 +1184,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                                    struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
@@ -1251,7 +1253,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
                wake_up_interruptible(&priv->wait_command_queue);
 }
 
-int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
+int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
        int ret;
        unsigned long flags;
@@ -1283,7 +1285,7 @@ err:
 }
 
 /**
- * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
  * Setup the RX handlers for each of the reply types sent from the uCode
  * to the host.
@@ -1294,14 +1296,14 @@ err:
 static void iwl_setup_rx_handlers(struct iwl_priv *priv)
 {
        priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
-       priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
-       priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
+       priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+       priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
        priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-           iwl4965_rx_spectrum_measure_notif;
-       priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif;
+           iwl_rx_spectrum_measure_notif;
+       priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
        priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-           iwl4965_rx_pm_debug_statistics_notif;
-       priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
+           iwl_rx_pm_debug_statistics_notif;
+       priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
 
        /*
         * The same handler is used for both the REPLY to a discrete
@@ -1314,7 +1316,7 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
        iwl_setup_rx_scan_handlers(priv);
 
        /* status change handler */
-       priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
+       priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
 
        priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
            iwl_rx_missed_beacon_notif;
@@ -1398,7 +1400,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
 
                /* Based on type of command response or notification,
                 *   handle those that need handling via function in
-                *   rx_handlers table.  See iwl4965_setup_rx_handlers() */
+                *   rx_handlers table.  See iwl_setup_rx_handlers() */
                if (priv->rx_handlers[pkt->hdr.cmd]) {
                        IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r,
                                i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
@@ -1455,7 +1457,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
+static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
 {
        struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
@@ -1475,7 +1477,7 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
 }
 #endif
 
-static void iwl4965_enable_interrupts(struct iwl_priv *priv)
+static void iwl_enable_interrupts(struct iwl_priv *priv)
 {
        IWL_DEBUG_ISR("Enabling interrupts\n");
        set_bit(STATUS_INT_ENABLED, &priv->status);
@@ -1490,7 +1492,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
        tasklet_kill(&priv->irq_tasklet);
 }
 
-static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
 {
        clear_bit(STATUS_INT_ENABLED, &priv->status);
 
@@ -1506,11 +1508,11 @@ static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
 
 
 /**
- * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
  */
-static void iwl4965_irq_handle_error(struct iwl_priv *priv)
+static void iwl_irq_handle_error(struct iwl_priv *priv)
 {
-       /* Set the FW error flag -- cleared on iwl4965_down */
+       /* Set the FW error flag -- cleared on iwl_down */
        set_bit(STATUS_FW_ERROR, &priv->status);
 
        /* Cancel currently queued command. */
@@ -1520,7 +1522,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
        if (priv->debug_level & IWL_DL_FW_ERRORS) {
                iwl_dump_nic_error_log(priv);
                iwl_dump_nic_event_log(priv);
-               iwl4965_print_rx_config_cmd(priv);
+               iwl_print_rx_config_cmd(priv);
        }
 #endif
 
@@ -1544,14 +1546,14 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
        }
 }
 
-static void iwl4965_error_recovery(struct iwl_priv *priv)
+static void iwl_error_recovery(struct iwl_priv *priv)
 {
        unsigned long flags;
 
        memcpy(&priv->staging_rxon, &priv->recovery_rxon,
               sizeof(priv->staging_rxon));
        priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 
        iwl_rxon_add_station(priv, priv->bssid, 1);
 
@@ -1561,7 +1563,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl4965_irq_tasklet(struct iwl_priv *priv)
+static void iwl_irq_tasklet(struct iwl_priv *priv)
 {
        u32 inta, handled = 0;
        u32 inta_fh;
@@ -1607,9 +1609,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                IWL_ERROR("Microcode HW error detected.  Restarting.\n");
 
                /* Tell the device to stop sending interrupts */
-               iwl4965_disable_interrupts(priv);
+               iwl_disable_interrupts(priv);
 
-               iwl4965_irq_handle_error(priv);
+               iwl_irq_handle_error(priv);
 
                handled |= CSR_INT_BIT_HW_ERR;
 
@@ -1663,7 +1665,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        if (inta & CSR_INT_BIT_SW_ERR) {
                IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
                          inta);
-               iwl4965_irq_handle_error(priv);
+               iwl_irq_handle_error(priv);
                handled |= CSR_INT_BIT_SW_ERR;
        }
 
@@ -1709,7 +1711,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        /* Re-enable all interrupts */
        /* only Re-enable if diabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
-               iwl4965_enable_interrupts(priv);
+               iwl_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (priv->debug_level & (IWL_DL_ISR)) {
@@ -1723,7 +1725,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl4965_isr(int irq, void *data)
+static irqreturn_t iwl_isr(int irq, void *data)
 {
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
@@ -1764,7 +1766,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
 
        inta &= ~CSR_INT_BIT_SCD;
 
-       /* iwl4965_irq_tasklet() will service interrupts and re-enable them */
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
        if (likely(inta || inta_fh))
                tasklet_schedule(&priv->irq_tasklet);
 
@@ -1776,7 +1778,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
        /* re-enable interrupts here since we don't have anything to service. */
        /* only Re-enable if diabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
-               iwl4965_enable_interrupts(priv);
+               iwl_enable_interrupts(priv);
        spin_unlock(&priv->lock);
        return IRQ_NONE;
 }
@@ -1787,7 +1789,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
  *
  ******************************************************************************/
 
-static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
 {
        iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
        iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
@@ -1797,7 +1799,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
        iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
-static void iwl4965_nic_start(struct iwl_priv *priv)
+static void iwl_nic_start(struct iwl_priv *priv)
 {
        /* Remove all resets to allow NIC to operate */
        iwl_write32(priv, CSR_RESET, 0);
@@ -1805,11 +1807,11 @@ static void iwl4965_nic_start(struct iwl_priv *priv)
 
 
 /**
- * iwl4965_read_ucode - Read uCode images from disk file.
+ * iwl_read_ucode - Read uCode images from disk file.
  *
  * Copy into buffers for card to fetch via bus-mastering
  */
-static int iwl4965_read_ucode(struct iwl_priv *priv)
+static int iwl_read_ucode(struct iwl_priv *priv)
 {
        struct iwl_ucode *ucode;
        int ret;
@@ -1953,7 +1955,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
        /* Runtime data (2nd block)
-        * NOTE:  Copy into backup buffer will be done in iwl4965_up()  */
+        * NOTE:  Copy into backup buffer will be done in iwl_up()  */
        src = &ucode->data[inst_size];
        len = priv->ucode_data.len;
        IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
@@ -1991,7 +1993,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
  err_pci_alloc:
        IWL_ERROR("failed to allocate pci memory\n");
        ret = -ENOMEM;
-       iwl4965_dealloc_ucode_pci(priv);
+       iwl_dealloc_ucode_pci(priv);
 
  err_release:
        release_firmware(ucode_raw);
@@ -2036,7 +2038,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       /* After the ALIVE response, we can send host commands to 4965 uCode */
+       /* After the ALIVE response, we can send host commands to the uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
        if (iwl_is_rfkill(priv))
@@ -2056,17 +2058,17 @@ static void iwl_alive_start(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl4965_connection_init_rx_config(priv);
+               iwl_connection_init_rx_config(priv, priv->iw_mode);
                memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
        }
 
        /* Configure Bluetooth device coexistence support */
-       iwl4965_send_bt_config(priv);
+       iwl_send_bt_config(priv);
 
        iwl_reset_run_time_calib(priv);
 
        /* Configure the adapter for unassociated operation */
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 
        /* At this point, the NIC is initialized and operational */
        iwl_rf_kill_ct_config(priv);
@@ -2078,12 +2080,12 @@ static void iwl_alive_start(struct iwl_priv *priv)
        wake_up_interruptible(&priv->wait_command_queue);
 
        if (priv->error_recovering)
-               iwl4965_error_recovery(priv);
+               iwl_error_recovery(priv);
 
        iwl_power_update_mode(priv, 1);
 
        if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
-               iwl4965_set_mode(priv, priv->iw_mode);
+               iwl_set_mode(priv, priv->iw_mode);
 
        return;
 
@@ -2093,7 +2095,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
-static void __iwl4965_down(struct iwl_priv *priv)
+static void __iwl_down(struct iwl_priv *priv)
 {
        unsigned long flags;
        int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -2120,14 +2122,14 @@ static void __iwl4965_down(struct iwl_priv *priv)
 
        /* tell the device to stop sending interrupts */
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
        iwl_synchronize_irq(priv);
 
        if (priv->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
 
-       /* If we have not previously called iwl4965_init() then
+       /* If we have not previously called iwl_init() then
         * clear all bits but the RF Kill and SUSPEND bits and return */
        if (!iwl_is_init(priv)) {
                priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
@@ -2194,10 +2196,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl_clear_free_frames(priv);
 }
 
-static void iwl4965_down(struct iwl_priv *priv)
+static void iwl_down(struct iwl_priv *priv)
 {
        mutex_lock(&priv->mutex);
-       __iwl4965_down(priv);
+       __iwl_down(priv);
        mutex_unlock(&priv->mutex);
 
        iwl_cancel_deferred_work(priv);
@@ -2205,7 +2207,7 @@ static void iwl4965_down(struct iwl_priv *priv)
 
 #define MAX_HW_RESTARTS 5
 
-static int __iwl4965_up(struct iwl_priv *priv)
+static int __iwl_up(struct iwl_priv *priv)
 {
        int i;
        int ret;
@@ -2227,7 +2229,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
                set_bit(STATUS_RF_KILL_HW, &priv->status);
 
        if (iwl_is_rfkill(priv)) {
-               iwl4965_enable_interrupts(priv);
+               iwl_enable_interrupts(priv);
                IWL_WARNING("Radio disabled by %s RF Kill switch\n",
                    test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
                return 0;
@@ -2254,7 +2256,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
 
        /* clear (again), then enable host interrupts */
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-       iwl4965_enable_interrupts(priv);
+       iwl_enable_interrupts(priv);
 
        /* really make sure rfkill handshake bits are cleared */
        iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
@@ -2284,7 +2286,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
                clear_bit(STATUS_FW_ERROR, &priv->status);
 
                /* start card; "initialize" will load runtime ucode */
-               iwl4965_nic_start(priv);
+               iwl_nic_start(priv);
 
                IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
@@ -2292,7 +2294,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
        }
 
        set_bit(STATUS_EXIT_PENDING, &priv->status);
-       __iwl4965_down(priv);
+       __iwl_down(priv);
        clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
        /* tried to restart and config the device for as long as our
@@ -2335,7 +2337,7 @@ static void iwl_bg_alive_start(struct work_struct *data)
        ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC);
 }
 
-static void iwl4965_bg_rf_kill(struct work_struct *work)
+static void iwl_bg_rf_kill(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
 
@@ -2369,7 +2371,7 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
        iwl_rfkill_set_hw_state(priv);
 }
 
-static void iwl4965_bg_set_monitor(struct work_struct *work)
+static void iwl_bg_set_monitor(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work,
                                struct iwl_priv, set_monitor);
@@ -2379,16 +2381,16 @@ static void iwl4965_bg_set_monitor(struct work_struct *work)
 
        mutex_lock(&priv->mutex);
 
-       ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR);
-
+       ret = iwl_set_mode(priv, NL80211_IFTYPE_MONITOR);
        if (ret) {
                if (ret == -EAGAIN)
                        IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
                else
-                       IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret);
+                       IWL_ERROR("iwl_set_mode() failed ret = %d\n", ret);
        }
 
        mutex_unlock(&priv->mutex);
+       ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC);
 }
 
 static void iwl_bg_run_time_calib_work(struct work_struct *work)
@@ -2414,7 +2416,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        return;
 }
 
-static void iwl4965_bg_up(struct work_struct *data)
+static void iwl_bg_up(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
 
@@ -2422,23 +2424,23 @@ static void iwl4965_bg_up(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       __iwl4965_up(priv);
+       __iwl_up(priv);
        mutex_unlock(&priv->mutex);
        iwl_rfkill_set_hw_state(priv);
 }
 
-static void iwl4965_bg_restart(struct work_struct *data)
+static void iwl_bg_restart(struct work_struct *data)
 {
        struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       iwl4965_down(priv);
+       iwl_down(priv);
        queue_work(priv->workqueue, &priv->up);
 }
 
-static void iwl4965_bg_rx_replenish(struct work_struct *data)
+static void iwl_bg_rx_replenish(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, rx_replenish);
@@ -2453,7 +2455,7 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-static void iwl4965_post_associate(struct iwl_priv *priv)
+static void iwl_post_associate(struct iwl_priv *priv)
 {
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
@@ -2481,7 +2483,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
        conf = ieee80211_get_hw_conf(priv->hw);
 
        priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 
        iwl_setup_rxon_timing(priv);
        ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
@@ -2516,7 +2518,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 
        }
 
-       iwl4965_commit_rxon(priv);
+       iwl_commit_rxon(priv);
 
        switch (priv->iw_mode) {
        case NL80211_IFTYPE_STATION:
@@ -2528,7 +2530,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
                priv->assoc_id = 1;
 
                iwl_rxon_add_station(priv, priv->bssid, 0);
-               iwl4965_send_beacon_cmd(priv);
+               iwl_send_beacon_cmd(priv);
 
                break;
 
@@ -2565,7 +2567,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 
 #define UCODE_READY_TIMEOUT    (4 * HZ)
 
-static int iwl4965_mac_start(struct ieee80211_hw *hw)
+static int iwl_mac_start(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
        int ret;
@@ -2587,7 +2589,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
                pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
        }
 
-       ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+       ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
                          DRV_NAME, priv);
        if (ret) {
                IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -2602,7 +2604,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
         * ucode filename and max sizes are card-specific. */
 
        if (!priv->ucode_code.len) {
-               ret = iwl4965_read_ucode(priv);
+               ret = iwl_read_ucode(priv);
                if (ret) {
                        IWL_ERROR("Could not read microcode: %d\n", ret);
                        mutex_unlock(&priv->mutex);
@@ -2610,7 +2612,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
                }
        }
 
-       ret = __iwl4965_up(priv);
+       ret = __iwl_up(priv);
 
        mutex_unlock(&priv->mutex);
 
@@ -2656,7 +2658,7 @@ out_disable_msi:
        return ret;
 }
 
-static void iwl4965_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
 
@@ -2678,7 +2680,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
                mutex_unlock(&priv->mutex);
        }
 
-       iwl4965_down(priv);
+       iwl_down(priv);
 
        flush_workqueue(priv->workqueue);
        free_irq(priv->pci_dev->irq, priv);
@@ -2689,7 +2691,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl_priv *priv = hw->priv;
 
@@ -2705,7 +2707,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return 0;
 }
 
-static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
                                 struct ieee80211_if_init_conf *conf)
 {
        struct iwl_priv *priv = hw->priv;
@@ -2720,6 +2722,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
 
        spin_lock_irqsave(&priv->lock, flags);
        priv->vif = conf->vif;
+       priv->iw_mode = conf->type;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2730,7 +2733,7 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
                memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
        }
 
-       if (iwl4965_set_mode(priv, conf->type) == -EAGAIN)
+       if (iwl_set_mode(priv, conf->type) == -EAGAIN)
                /* we are not ready, will run again when ready */
                set_bit(STATUS_MODE_PENDING, &priv->status);
 
@@ -2741,13 +2744,13 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
 }
 
 /**
- * iwl4965_mac_config - mac80211 config callback
+ * iwl_mac_config - mac80211 config callback
  *
  * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
+static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct iwl_priv *priv = hw->priv;
        const struct iwl_channel_info *ch_info;
@@ -2818,13 +2821,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
        /* The list of supported rates and rate mask can be different
         * for each band; since the band may have changed, reset
         * the rate mask to what mac80211 lists */
-       iwl4965_set_rate(priv);
+       iwl_set_rate(priv);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
        if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
-               iwl4965_hw_channel_switch(priv, conf->channel);
+               iwl_hw_channel_switch(priv, conf->channel);
                goto out;
        }
 #endif
@@ -2852,11 +2855,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
 
        iwl_set_tx_power(priv, conf->power_level, false);
 
-       iwl4965_set_rate(priv);
+       iwl_set_rate(priv);
 
        if (memcmp(&priv->active_rxon,
                   &priv->staging_rxon, sizeof(priv->staging_rxon)))
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
        else
                IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
 
@@ -2867,7 +2870,7 @@ out:
        return ret;
 }
 
-static void iwl4965_config_ap(struct iwl_priv *priv)
+static void iwl_config_ap(struct iwl_priv *priv)
 {
        int ret = 0;
        unsigned long flags;
@@ -2880,7 +2883,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 
                /* RXON - unassoc (to set timing command) */
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
 
                /* RXON Timing */
                iwl_setup_rxon_timing(priv);
@@ -2916,13 +2919,13 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
                spin_lock_irqsave(&priv->lock, flags);
                iwl_activate_qos(priv, 1);
                spin_unlock_irqrestore(&priv->lock, flags);
                iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
        }
-       iwl4965_send_beacon_cmd(priv);
+       iwl_send_beacon_cmd(priv);
 
        /* FIXME - we need to add code here to detect a totally new
         * configuration, reset the AP, unassoc, rxon timing, assoc,
@@ -2930,14 +2933,13 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
 }
 
 /* temporary */
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
 
-static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+static int iwl_mac_config_interface(struct ieee80211_hw *hw,
                                        struct ieee80211_vif *vif,
                                    struct ieee80211_if_conf *conf)
 {
        struct iwl_priv *priv = hw->priv;
-       unsigned long flags;
        int rc;
 
        if (conf == NULL)
@@ -2953,18 +2955,11 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
                if (!beacon)
                        return -ENOMEM;
-               rc = iwl4965_mac_beacon_update(hw, beacon);
+               rc = iwl_mac_beacon_update(hw, beacon);
                if (rc)
                        return rc;
        }
 
-       if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-           (!conf->ssid_len)) {
-               IWL_DEBUG_MAC80211
-                   ("Leaving in AP mode because HostAPD is not ready.\n");
-               return 0;
-       }
-
        if (!iwl_is_alive(priv))
                return -EAGAIN;
 
@@ -3016,9 +3011,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
                if (priv->iw_mode == NL80211_IFTYPE_AP)
-                       iwl4965_config_ap(priv);
+                       iwl_config_ap(priv);
                else {
-                       rc = iwl4965_commit_rxon(priv);
+                       rc = iwl_commit_rxon(priv);
                        if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc)
                                iwl_rxon_add_station(
                                        priv, priv->active_rxon.bssid_addr, 1);
@@ -3027,26 +3022,17 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
        } else {
                iwl_scan_cancel_timeout(priv, 100);
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
        }
 
  done:
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!conf->ssid_len)
-               memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-       else
-               memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-       priv->essid_len = conf->ssid_len;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        IWL_DEBUG_MAC80211("leave\n");
        mutex_unlock(&priv->mutex);
 
        return 0;
 }
 
-static void iwl4965_configure_filter(struct ieee80211_hw *hw,
+static void iwl_configure_filter(struct ieee80211_hw *hw,
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
                                 int mc_count, struct dev_addr_list *mc_list)
@@ -3065,7 +3051,7 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw,
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
-static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_if_init_conf *conf)
 {
        struct iwl_priv *priv = hw->priv;
@@ -3077,13 +3063,11 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
        if (iwl_is_ready_rf(priv)) {
                iwl_scan_cancel_timeout(priv, 100);
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
        }
        if (priv->vif == conf->vif) {
                priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
-               memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-               priv->essid_len = 0;
        }
        mutex_unlock(&priv->mutex);
 
@@ -3092,7 +3076,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
 }
 
 #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
-static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+static void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
                                     u32 changes)
@@ -3119,7 +3103,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changes & BSS_CHANGED_HT) {
-               iwl4965_ht_conf(priv, bss_conf);
+               iwl_ht_conf(priv, bss_conf);
                iwl_set_rxon_chain(priv);
        }
 
@@ -3142,7 +3126,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
                        priv->next_scan_jiffies = jiffies +
                                        IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
                        mutex_lock(&priv->mutex);
-                       iwl4965_post_associate(priv);
+                       iwl_post_associate(priv);
                        mutex_unlock(&priv->mutex);
                } else {
                        priv->assoc_id = 0;
@@ -3218,7 +3202,7 @@ out_unlock:
        return ret;
 }
 
-static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
+static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
                        struct ieee80211_key_conf *keyconf, const u8 *addr,
                        u32 iv32, u16 *phase1key)
 {
@@ -3269,7 +3253,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           const u8 *local_addr, const u8 *addr,
                           struct ieee80211_key_conf *key)
 {
@@ -3340,7 +3324,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        return ret;
 }
 
-static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                           const struct ieee80211_tx_queue_params *params)
 {
        struct iwl_priv *priv = hw->priv;
@@ -3388,7 +3372,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return 0;
 }
 
-static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                             enum ieee80211_ampdu_mlme_action action,
                             struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
@@ -3420,7 +3404,7 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
        }
        return 0;
 }
-static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
                                struct ieee80211_tx_queue_stats *stats)
 {
        struct iwl_priv *priv = hw->priv;
@@ -3455,7 +3439,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
                             struct ieee80211_low_level_stats *stats)
 {
        struct iwl_priv *priv = hw->priv;
@@ -3467,7 +3451,7 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
@@ -3511,7 +3495,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        if (priv->iw_mode != NL80211_IFTYPE_AP) {
                iwl_scan_cancel_timeout(priv, 100);
                priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwl4965_commit_rxon(priv);
+               iwl_commit_rxon(priv);
        }
 
        iwl_power_update_mode(priv, 0);
@@ -3534,14 +3518,14 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
                return;
        }
 
-       iwl4965_set_rate(priv);
+       iwl_set_rate(priv);
 
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
@@ -3578,7 +3562,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 
        iwl_reset_qos(priv);
 
-       iwl4965_post_associate(priv);
+       iwl_post_associate(priv);
 
        mutex_unlock(&priv->mutex);
 
@@ -3732,7 +3716,7 @@ static ssize_t store_flags(struct device *d,
                else {
                        IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags);
                        priv->staging_rxon.flags = cpu_to_le32(flags);
-                       iwl4965_commit_rxon(priv);
+                       iwl_commit_rxon(priv);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3773,7 +3757,7 @@ static ssize_t store_filter_flags(struct device *d,
                                       "0x%04X\n", filter_flags);
                        priv->staging_rxon.filter_flags =
                                cpu_to_le32(filter_flags);
-                       iwl4965_commit_rxon(priv);
+                       iwl_commit_rxon(priv);
                }
        }
        mutex_unlock(&priv->mutex);
@@ -3848,7 +3832,7 @@ static ssize_t store_measurement(struct device *d,
 
        IWL_DEBUG_INFO("Invoking measurement of type %d on "
                       "channel %d (for '%s')\n", type, params.channel, buf);
-       iwl4965_get_measurement(priv, &params, type);
+       iwl_get_measurement(priv, &params, type);
 
        return count;
 }
@@ -4068,12 +4052,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 
        init_waitqueue_head(&priv->wait_command_queue);
 
-       INIT_WORK(&priv->up, iwl4965_bg_up);
-       INIT_WORK(&priv->restart, iwl4965_bg_restart);
-       INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish);
-       INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
-       INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
-       INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
+       INIT_WORK(&priv->up, iwl_bg_up);
+       INIT_WORK(&priv->restart, iwl_bg_restart);
+       INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+       INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+       INIT_WORK(&priv->set_monitor, iwl_bg_set_monitor);
        INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -4086,10 +4070,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
 
        init_timer(&priv->statistics_periodic);
        priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-                    iwl4965_irq_tasklet, (unsigned long)priv);
+                    iwl_irq_tasklet, (unsigned long)priv);
 }
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -4105,7 +4089,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        del_timer_sync(&priv->statistics_periodic);
 }
 
-static struct attribute *iwl4965_sysfs_entries[] = {
+static struct attribute *iwl_sysfs_entries[] = {
        &dev_attr_channels.attr,
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
@@ -4126,32 +4110,32 @@ static struct attribute *iwl4965_sysfs_entries[] = {
        NULL
 };
 
-static struct attribute_group iwl4965_attribute_group = {
+static struct attribute_group iwl_attribute_group = {
        .name = NULL,           /* put in device directory */
-       .attrs = iwl4965_sysfs_entries,
+       .attrs = iwl_sysfs_entries,
 };
 
-static struct ieee80211_ops iwl4965_hw_ops = {
-       .tx = iwl4965_mac_tx,
-       .start = iwl4965_mac_start,
-       .stop = iwl4965_mac_stop,
-       .add_interface = iwl4965_mac_add_interface,
-       .remove_interface = iwl4965_mac_remove_interface,
-       .config = iwl4965_mac_config,
-       .config_interface = iwl4965_mac_config_interface,
-       .configure_filter = iwl4965_configure_filter,
-       .set_key = iwl4965_mac_set_key,
-       .update_tkip_key = iwl4965_mac_update_tkip_key,
-       .get_stats = iwl4965_mac_get_stats,
-       .get_tx_stats = iwl4965_mac_get_tx_stats,
-       .conf_tx = iwl4965_mac_conf_tx,
-       .reset_tsf = iwl4965_mac_reset_tsf,
-       .bss_info_changed = iwl4965_bss_info_changed,
-       .ampdu_action = iwl4965_mac_ampdu_action,
+static struct ieee80211_ops iwl_hw_ops = {
+       .tx = iwl_mac_tx,
+       .start = iwl_mac_start,
+       .stop = iwl_mac_stop,
+       .add_interface = iwl_mac_add_interface,
+       .remove_interface = iwl_mac_remove_interface,
+       .config = iwl_mac_config,
+       .config_interface = iwl_mac_config_interface,
+       .configure_filter = iwl_configure_filter,
+       .set_key = iwl_mac_set_key,
+       .update_tkip_key = iwl_mac_update_tkip_key,
+       .get_stats = iwl_mac_get_stats,
+       .get_tx_stats = iwl_mac_get_tx_stats,
+       .conf_tx = iwl_mac_conf_tx,
+       .reset_tsf = iwl_mac_reset_tsf,
+       .bss_info_changed = iwl_bss_info_changed,
+       .ampdu_action = iwl_mac_ampdu_action,
        .hw_scan = iwl_mac_hw_scan
 };
 
-static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = 0;
        struct iwl_priv *priv;
@@ -4169,10 +4153,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                if (cfg->mod_params->debug & IWL_DL_INFO)
                        dev_printk(KERN_DEBUG, &(pdev->dev),
                                   "Disabling hw_scan\n");
-               iwl4965_hw_ops.hw_scan = NULL;
+               iwl_hw_ops.hw_scan = NULL;
        }
 
-       hw = iwl_alloc_all(cfg, &iwl4965_hw_ops);
+       hw = iwl_alloc_all(cfg, &iwl_hw_ops);
        if (!hw) {
                err = -ENOMEM;
                goto out;
@@ -4300,10 +4284,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * 8. Setup services
         ********************/
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+       err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
        if (err) {
                IWL_ERROR("failed to create sysfs device attributes\n");
                goto out_uninit_drv;
@@ -4339,7 +4323,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        return 0;
 
  out_remove_sysfs:
-       sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+       sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
  out_uninit_drv:
        iwl_uninit_drv(priv);
  out_free_eeprom:
@@ -4357,7 +4341,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        return err;
 }
 
-static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
+static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 {
        struct iwl_priv *priv = pci_get_drvdata(pdev);
        unsigned long flags;
@@ -4368,10 +4352,10 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
 
        iwl_dbgfs_unregister(priv);
-       sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+       sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
 
-       /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
-        * to be called and iwl4965_down since we are removing the device
+       /* ieee80211_unregister_hw call wil cause iwl_mac_stop to
+        * to be called and iwl_down since we are removing the device
         * we need to set STATUS_EXIT_PENDING bit.
         */
        set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -4379,20 +4363,20 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
                ieee80211_unregister_hw(priv->hw);
                priv->mac80211_registered = 0;
        } else {
-               iwl4965_down(priv);
+               iwl_down(priv);
        }
 
        /* make sure we flush any pending irq or
         * tasklet for the driver
         */
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        iwl_synchronize_irq(priv);
 
        iwl_rfkill_unregister(priv);
-       iwl4965_dealloc_ucode_pci(priv);
+       iwl_dealloc_ucode_pci(priv);
 
        if (priv->rxq.bd)
                iwl_rx_queue_free(priv, &priv->rxq);
@@ -4405,7 +4389,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
 
-       /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes
+       /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
         * priv->workqueue... so we can't take down the workqueue
         * until now... */
        destroy_workqueue(priv->workqueue);
@@ -4426,13 +4410,13 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
-static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct iwl_priv *priv = pci_get_drvdata(pdev);
 
        if (priv->is_open) {
                set_bit(STATUS_IN_SUSPEND, &priv->status);
-               iwl4965_mac_stop(priv->hw);
+               iwl_mac_stop(priv->hw);
                priv->is_open = 1;
        }
 
@@ -4441,14 +4425,14 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int iwl4965_pci_resume(struct pci_dev *pdev)
+static int iwl_pci_resume(struct pci_dev *pdev)
 {
        struct iwl_priv *priv = pci_get_drvdata(pdev);
 
        pci_set_power_state(pdev, PCI_D0);
 
        if (priv->is_open)
-               iwl4965_mac_start(priv->hw);
+               iwl_mac_start(priv->hw);
 
        clear_bit(STATUS_IN_SUSPEND, &priv->status);
        return 0;
@@ -4491,15 +4475,15 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 static struct pci_driver iwl_driver = {
        .name = DRV_NAME,
        .id_table = iwl_hw_card_ids,
-       .probe = iwl4965_pci_probe,
-       .remove = __devexit_p(iwl4965_pci_remove),
+       .probe = iwl_pci_probe,
+       .remove = __devexit_p(iwl_pci_remove),
 #ifdef CONFIG_PM
-       .suspend = iwl4965_pci_suspend,
-       .resume = iwl4965_pci_resume,
+       .suspend = iwl_pci_suspend,
+       .resume = iwl_pci_resume,
 #endif
 };
 
-static int __init iwl4965_init(void)
+static int __init iwl_init(void)
 {
 
        int ret;
@@ -4525,11 +4509,11 @@ error_register:
        return ret;
 }
 
-static void __exit iwl4965_exit(void)
+static void __exit iwl_exit(void)
 {
        pci_unregister_driver(&iwl_driver);
        iwlagn_rate_control_unregister();
 }
 
-module_exit(iwl4965_exit);
-module_init(iwl4965_init);
+module_exit(iwl_exit);
+module_init(iwl_init);
index 5ab74fc0fd10374b98a4ed58fa423dfb602af49a..8aade00e165a5c1c1dd8e0d8d724b15e3252f737 100644 (file)
@@ -66,8 +66,8 @@
  * Please use iwl-dev.h for driver implementation definitions.
  */
 
-#ifndef __iwl4965_commands_h__
-#define __iwl4965_commands_h__
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
 
 enum {
        REPLY_ALIVE = 0x1,
@@ -3064,4 +3064,4 @@ struct iwl_rx_packet {
 
 #define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
 
-#endif                         /* __iwl4965_commands_h__ */
+#endif                         /* __iwl_commands_h__ */
index b58fcdef5432ea22400ed278bab47aa342d57c39..eb396f26730cbd416cb3bde06b56ba2bd35336c4 100644 (file)
@@ -576,8 +576,8 @@ extern int iwl_send_add_sta(struct iwl_priv *priv,
                            struct iwl_addsta_cmd *sta, u8 flags);
 extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
                        int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
-extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
-extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern void iwl_update_chain_flags(struct iwl_priv *priv);
+extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
 extern const u8 iwl_bcast_addr[ETH_ALEN];
 extern int iwl_rxq_stop(struct iwl_priv *priv);
 extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
@@ -926,8 +926,6 @@ struct iwl_priv {
        unsigned long last_statistics_time;
 
        /* context information */
-       u8 essid[IW_ESSID_MAX_SIZE];
-       u8 essid_len;
        u16 rates_mask;
 
        u32 power_mode;
index f2688d551830c42a42078e13c9b264a6b05e4311..97e2cf41258d278109fd811619d06f5c8cfc9354 100644 (file)
 #define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
 
 /* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-       (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+#define FH49_TCSR_CHNL_NUM                            (7)
+#define FH50_TCSR_CHNL_NUM                            (8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl)      \
+               (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl))
+#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl)      \
+               (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl)     \
+               (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF         (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV         (0x00000001)
 
-#define FH_TCSR_CHNL_NUM                            (7)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE   (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE    (0x00000008)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT      (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD     (0x00100000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD      (0x00200000)
 
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
-#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT       (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD      (0x00400000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD       (0x00800000)
 
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM      (20)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX      (12)
-#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-       (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
-         (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
-#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
-        (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE       (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF   (0x40000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE      (0x80000000)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY     (0x00000000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT      (0x00002000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID     (0x00000003)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM         (20)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX         (12)
 
 /**
  * Tx Shared Status Registers (TSSR)
 #define FH_TSSR_LOWER_BOUND            (FH_MEM_LOWER_BOUND + 0xEA0)
 #define FH_TSSR_UPPER_BOUND            (FH_MEM_LOWER_BOUND + 0xEC0)
 
-#define FH_TSSR_TX_STATUS_REG  (FH_TSSR_LOWER_BOUND + 0x010)
+#define FH_TSSR_TX_STATUS_REG          (FH_TSSR_LOWER_BOUND + 0x010)
 
 #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
 #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
index 6c5654f70a068429d9fa61407d9e7a1dfb7d4f13..c4b90301e9a12c1337322eee9530b0342cd68e3f 100644 (file)
@@ -743,13 +743,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
                memcpy(scan->direct_scan[0].ssid,
                       priv->direct_ssid, priv->direct_ssid_len);
                n_probes++;
-       } else if (!iwl_is_associated(priv) && priv->essid_len) {
-               IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
-                               print_ssid(ssid, priv->essid, priv->essid_len));
-               scan->direct_scan[0].id = WLAN_EID_SSID;
-               scan->direct_scan[0].len = priv->essid_len;
-               memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-               n_probes++;
        } else {
                IWL_DEBUG_SCAN("Start indirect scan.\n");
        }
index bfc009ce8a9423fb0882774aff1005a16cb77ef1..0c5f1221b8f3ef7f4a7b655a592d3457c42fa4b1 100644 (file)
@@ -870,7 +870,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
 
                link_cmd.rs_table[i].rate_n_flags =
                        iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-               r = iwl4965_get_prev_ieee_rate(r);
+               r = iwl_get_prev_ieee_rate(r);
        }
 
        link_cmd.general_params.single_stream_ant_msk =
index 6008c0cce214b0e683903d3db1c7ef656e5b67ec..7d8b4e2d509473cad53300ecc2bfab3c3f1b3210 100644 (file)
@@ -431,8 +431,8 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
 
        /* Enable DMA channel, using same id as for TFD queue */
        iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+                       FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                       FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
 
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
index f675b2993a3df7c8be03600f247a1fc34a883d79..119185fb1e2625ab0e0be7bfbf5fac90753309f2 100644 (file)
@@ -1593,7 +1593,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate,
  */
 static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
                              struct ieee80211_mgmt *frame,
-                             int left, int is_direct)
+                             int left)
 {
        int len = 0;
        u8 *pos = NULL;
@@ -1623,20 +1623,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
        *pos++ = WLAN_EID_SSID;
        *pos++ = 0;
 
-       /* fill in our direct SSID IE... */
-       if (is_direct) {
-               /* ...next IE... */
-               left -= 2 + priv->essid_len;
-               if (left < 0)
-                       return 0;
-               /* ... fill it in... */
-               *pos++ = WLAN_EID_SSID;
-               *pos++ = priv->essid_len;
-               memcpy(pos, priv->essid, priv->essid_len);
-               pos += priv->essid_len;
-               len += 2 + priv->essid_len;
-       }
-
        /* fill in supported rate */
        /* ...next IE... */
        left -= 2;
@@ -2189,13 +2175,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv,
 /*
  * initialize rxon structure with default values from eeprom
  */
-static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv,
+                                             int mode)
 {
        const struct iwl3945_channel_info *ch_info;
 
        memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-       switch (priv->iw_mode) {
+       switch (mode) {
        case NL80211_IFTYPE_AP:
                priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
                break;
@@ -2218,7 +2205,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
                    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
                break;
        default:
-               IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+               IWL_ERROR("Unsupported interface type %d\n", mode);
                break;
        }
 
@@ -2241,8 +2228,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
         * in some case A channels are all non IBSS
         * in this case force B/G channel
         */
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-           !(is_channel_ibss(ch_info)))
+       if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info)))
                ch_info = &priv->channel_info[0];
 
        priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
@@ -2275,9 +2261,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
                }
        }
 
-       priv->iw_mode = mode;
-
-       iwl3945_connection_init_rx_config(priv);
+       iwl3945_connection_init_rx_config(priv, mode);
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
        iwl3945_clear_stations_table(priv);
@@ -5699,7 +5683,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl3945_connection_init_rx_config(priv);
+               iwl3945_connection_init_rx_config(priv, priv->iw_mode);
                memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
        }
 
@@ -6015,6 +5999,7 @@ static void iwl3945_bg_set_monitor(struct work_struct *work)
                        IWL_ERROR("iwl3945_set_mode() failed\n");
 
        mutex_unlock(&priv->mutex);
+       ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC);
 }
 
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
@@ -6162,14 +6147,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                memcpy(scan->direct_scan[0].ssid,
                       priv->direct_ssid, priv->direct_ssid_len);
                n_probes++;
-       } else if (!iwl3945_is_associated(priv) && priv->essid_len) {
-               IWL_DEBUG_SCAN
-                 ("Kicking off one direct scan for '%s' when not associated\n",
-                  print_ssid(ssid, priv->essid, priv->essid_len));
-               scan->direct_scan[0].id = WLAN_EID_SSID;
-               scan->direct_scan[0].len = priv->essid_len;
-               memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
-               n_probes++;
        } else
                IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
 
@@ -6177,7 +6154,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
         * that based on the direct_mask added to each channel entry */
        scan->tx_cmd.len = cpu_to_le16(
                iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
-                       IWL_MAX_SCAN_SIZE - sizeof(*scan), 0));
+                       IWL_MAX_SCAN_SIZE - sizeof(*scan)));
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
        scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
@@ -6566,6 +6543,7 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
 
        spin_lock_irqsave(&priv->lock, flags);
        priv->vif = conf->vif;
+       priv->iw_mode = conf->type;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -6742,7 +6720,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
                                    struct ieee80211_if_conf *conf)
 {
        struct iwl3945_priv *priv = hw->priv;
-       unsigned long flags;
        int rc;
 
        if (conf == NULL)
@@ -6764,15 +6741,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
                        return rc;
        }
 
-       /* XXX: this MUST use conf->mac_addr */
-
-       if ((priv->iw_mode == NL80211_IFTYPE_AP) &&
-           (!conf->ssid_len)) {
-               IWL_DEBUG_MAC80211
-                   ("Leaving in AP mode because HostAPD is not ready.\n");
-               return 0;
-       }
-
        if (!iwl3945_is_alive(priv))
                return -EAGAIN;
 
@@ -6839,15 +6807,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
        }
 
  done:
-       spin_lock_irqsave(&priv->lock, flags);
-       if (!conf->ssid_len)
-               memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-       else
-               memcpy(priv->essid, conf->ssid, conf->ssid_len);
-
-       priv->essid_len = conf->ssid_len;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        IWL_DEBUG_MAC80211("leave\n");
        mutex_unlock(&priv->mutex);
 
@@ -6890,8 +6849,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
        if (priv->vif == conf->vif) {
                priv->vif = NULL;
                memset(priv->bssid, 0, ETH_ALEN);
-               memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-               priv->essid_len = 0;
        }
        mutex_unlock(&priv->mutex);
 
index 92863780286fb8569e4738ec112f13f6c06cf9be..a0e440cd8967ec55c53ae17b948d678d6c5b7959 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <linux/if_arp.h>
 #include <net/lib80211.h>
 
 #include "assoc.h"
@@ -341,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv,
        WARN_ON(!assoc_req->channel);
 
        /* set Physical parameter set */
-       cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET;
+       cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
        cmd.phyparamset.dsparamset.len = 1;
        cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
 
        /* set IBSS parameter set */
-       cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET;
+       cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
        cmd.ssparamset.ibssparamset.len = 2;
        cmd.ssparamset.ibssparamset.atimwindow = 0;
 
@@ -430,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
 {
        if (!secinfo->wep_enabled  && !secinfo->WPAenabled
            && !secinfo->WPA2enabled
-           && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
-           && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+           && match_bss->wpa_ie[0] != WLAN_EID_GENERIC
+           && match_bss->rsn_ie[0] != WLAN_EID_RSN
            && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY))
                return 1;
        else
@@ -453,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
                                struct bss_descriptor *match_bss)
 {
        if (!secinfo->wep_enabled && secinfo->WPAenabled
-           && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
+           && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC)
            /* privacy bit may NOT be set in some APs like LinkSys WRT54G
            && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
           )
@@ -466,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
                                 struct bss_descriptor *match_bss)
 {
        if (!secinfo->wep_enabled && secinfo->WPA2enabled &&
-           (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
+           (match_bss->rsn_ie[0] == WLAN_EID_RSN)
            /* privacy bit may NOT be set in some APs like LinkSys WRT54G
            (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */
           )
@@ -480,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
 {
        if (!secinfo->wep_enabled && !secinfo->WPAenabled
            && !secinfo->WPA2enabled
-           && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
-           && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+           && (match_bss->wpa_ie[0] != WLAN_EID_GENERIC)
+           && (match_bss->rsn_ie[0] != WLAN_EID_RSN)
            && (match_bss->capability & WLAN_CAPABILITY_PRIVACY))
                return 1;
        else
index 38843c8b919cc033a5f94c102a54612d6300721c..957fd5a10a8d30a1b7b8aaca68460865ef6fa5dd 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <net/iw_handler.h>
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
@@ -1071,7 +1070,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
 
        switch (action) {
        case CMD_ACT_MESH_CONFIG_START:
-               ie->hdr.id = MFIE_TYPE_GENERIC;
+               ie->id = WLAN_EID_GENERIC;
                ie->val.oui[0] = 0x00;
                ie->val.oui[1] = 0x50;
                ie->val.oui[2] = 0x43;
@@ -1083,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
                ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
                ie->val.mesh_id_len = priv->mesh_ssid_len;
                memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
-               ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+               ie->len = sizeof(struct mrvl_meshie_val) -
                        IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
                cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
                break;
index f6f3753da303d80f26bc95d0f51ca52f03106814..dd682c4cfde816929425b3f68417de552e62b0b6 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/wireless.h>
 #include <linux/ethtool.h>
 #include <linux/debugfs.h>
-#include <net/ieee80211.h>
 
 #include "defs.h"
 #include "hostcmd.h"
@@ -278,6 +277,12 @@ struct lbs_private {
        struct enc_key wpa_mcast_key;
        struct enc_key wpa_unicast_key;
 
+/*
+ * In theory, the IE is limited to the IE length, 255,
+ * but in practice 64 bytes are enough.
+ */
+#define MAX_WPA_IE_LEN 64
+
        /** WPA Information Elements*/
        u8 wpa_ie[MAX_WPA_IE_LEN];
        u8 wpa_ie_len;
index e9d23f68174f7049161efc55876d73d5c2122f0e..241af7fe44bb6320485899f1ccca561f1a08ca60 100644 (file)
@@ -12,9 +12,8 @@
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
 #include <linux/stddef.h>
-
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 
 #include "host.h"
 #include "decl.h"
@@ -223,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 static ssize_t lbs_anycast_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
        struct cmd_ds_mesh_access mesh_access;
        int ret;
 
@@ -242,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev,
 static ssize_t lbs_anycast_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
        struct cmd_ds_mesh_access mesh_access;
        uint32_t datum;
        int ret;
@@ -270,7 +269,7 @@ static void lbs_remove_mesh(struct lbs_private *priv);
 static ssize_t lbs_rtap_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
        return snprintf(buf, 5, "0x%X\n", priv->monitormode);
 }
 
@@ -281,7 +280,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
        int monitor_mode;
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
 
        sscanf(buf, "%x", &monitor_mode);
        if (monitor_mode) {
@@ -332,7 +331,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
 static ssize_t lbs_mesh_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
        return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 }
 
@@ -342,7 +341,7 @@ static ssize_t lbs_mesh_get(struct device *dev,
 static ssize_t lbs_mesh_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
-       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
        int enable;
        int ret, action = CMD_ACT_MESH_CONFIG_STOP;
 
@@ -393,7 +392,7 @@ static struct attribute_group lbs_mesh_attr_group = {
  */
 static int lbs_dev_open(struct net_device *dev)
 {
-       struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+       struct lbs_private *priv = netdev_priv(dev) ;
        int ret = 0;
 
        lbs_deb_enter(LBS_DEB_NET);
@@ -435,7 +434,7 @@ static int lbs_dev_open(struct net_device *dev)
  */
 static int lbs_mesh_stop(struct net_device *dev)
 {
-       struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_MESH);
        spin_lock_irq(&priv->driver_lock);
@@ -462,7 +461,7 @@ static int lbs_mesh_stop(struct net_device *dev)
  */
 static int lbs_eth_stop(struct net_device *dev)
 {
-       struct lbs_private *priv = (struct lbs_private *) dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
 
        lbs_deb_enter(LBS_DEB_NET);
 
@@ -479,7 +478,7 @@ static int lbs_eth_stop(struct net_device *dev)
 
 static void lbs_tx_timeout(struct net_device *dev)
 {
-       struct lbs_private *priv = (struct lbs_private *) dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
 
        lbs_deb_enter(LBS_DEB_TX);
 
@@ -531,7 +530,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
  */
 static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 {
-       struct lbs_private *priv = (struct lbs_private *) dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
 
        lbs_deb_enter(LBS_DEB_NET);
        return &priv->stats;
@@ -540,7 +539,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 static int lbs_set_mac_address(struct net_device *dev, void *addr)
 {
        int ret = 0;
-       struct lbs_private *priv = (struct lbs_private *) dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
        struct sockaddr *phwaddr = addr;
        struct cmd_ds_802_11_mac_address cmd;
 
@@ -673,7 +672,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
 
 static void lbs_set_multicast_list(struct net_device *dev)
 {
-       struct lbs_private *priv = dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
 
        schedule_work(&priv->mcast_work);
 }
@@ -689,7 +688,7 @@ static void lbs_set_multicast_list(struct net_device *dev)
 static int lbs_thread(void *data)
 {
        struct net_device *dev = data;
-       struct lbs_private *priv = dev->priv;
+       struct lbs_private *priv = netdev_priv(dev);
        wait_queue_t wait;
 
        lbs_deb_enter(LBS_DEB_THREAD);
@@ -1124,7 +1123,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
                lbs_pr_err("init ethX device failed\n");
                goto done;
        }
-       priv = dev->priv;
+       priv = netdev_priv(dev);
 
        if (lbs_init_adapter(priv)) {
                lbs_pr_err("failed to initialize adapter structure.\n");
@@ -1377,7 +1376,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
                ret = -ENOMEM;
                goto done;
        }
-       mesh_dev->priv = priv;
+       mesh_dev->ml_priv = priv;
        priv->mesh_dev = mesh_dev;
 
        mesh_dev->open = lbs_dev_open;
@@ -1590,7 +1589,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
 {
-       struct lbs_private *priv = dev->priv;
+       struct lbs_private *priv = dev->ml_priv;
        lbs_deb_enter(LBS_DEB_NET);
        return &priv->stats;
 }
@@ -1631,7 +1630,7 @@ static int lbs_add_rtap(struct lbs_private *priv)
        rtap_dev->stop = lbs_rtap_stop;
        rtap_dev->get_stats = lbs_rtap_get_stats;
        rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
-       rtap_dev->priv = priv;
+       rtap_dev->ml_priv = priv;
        SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
 
        ret = register_netdev(rtap_dev);
index 3309a9c3cfef3f66c84f5f1cb67388dda176c5e6..56e2401cc76803db0d39ef49bb48c4a567de9ff1 100644 (file)
@@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
        /* SSID len */
        ie->val.mesh_id_len = len;
        /* IE len */
-       ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+       ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
 
        ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
                                   CMD_TYPE_MESH_SET_MESH_IE);
index 5c34ac588189147234afc9e81087756a30d488a9..93f74763a01005b0a2d5e070ed85763740516e2c 100644 (file)
@@ -6,8 +6,8 @@
   */
 #include <linux/types.h>
 #include <linux/etherdevice.h>
+#include <linux/if_arp.h>
 #include <asm/unaligned.h>
-
 #include <net/lib80211.h>
 
 #include "host.h"
@@ -55,6 +55,8 @@
 //! Scan time specified in the channel TLV for each channel for active scans
 #define MRVDRV_ACTIVE_SCAN_CHAN_TIME   100
 
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+
 static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
                              struct cmd_header *resp);
 
@@ -591,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 
        /* process variable IE */
        while (pos <= end - 2) {
-               struct ieee80211_info_element * elem = (void *)pos;
-
-               if (pos + elem->len > end) {
+               if (pos + pos[1] > end) {
                        lbs_deb_scan("process_bss: error in processing IE, "
                                     "bytes left < IE length\n");
                        break;
                }
 
-               switch (elem->id) {
-               case MFIE_TYPE_SSID:
-                       bss->ssid_len = min_t(int, 32, elem->len);
-                       memcpy(bss->ssid, elem->data, bss->ssid_len);
+               switch (pos[0]) {
+               case WLAN_EID_SSID:
+                       bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);
+                       memcpy(bss->ssid, pos + 2, bss->ssid_len);
                        lbs_deb_scan("got SSID IE: '%s', len %u\n",
                                     print_ssid(ssid, bss->ssid, bss->ssid_len),
                                     bss->ssid_len);
                        break;
 
-               case MFIE_TYPE_RATES:
-                       n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len);
-                       memcpy(bss->rates, elem->data, n_basic_rates);
+               case WLAN_EID_SUPP_RATES:
+                       n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);
+                       memcpy(bss->rates, pos + 2, n_basic_rates);
                        got_basic_rates = 1;
                        lbs_deb_scan("got RATES IE\n");
                        break;
 
-               case MFIE_TYPE_FH_SET:
+               case WLAN_EID_FH_PARAMS:
                        pFH = (struct ieeetypes_fhparamset *) pos;
                        memmove(&bss->phyparamset.fhparamset, pFH,
                                sizeof(struct ieeetypes_fhparamset));
                        lbs_deb_scan("got FH IE\n");
                        break;
 
-               case MFIE_TYPE_DS_SET:
+               case WLAN_EID_DS_PARAMS:
                        pDS = (struct ieeetypes_dsparamset *) pos;
                        bss->channel = pDS->currentchan;
                        memcpy(&bss->phyparamset.dsparamset, pDS,
@@ -630,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss,
                        lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
                        break;
 
-               case MFIE_TYPE_CF_SET:
+               case WLAN_EID_CF_PARAMS:
                        pCF = (struct ieeetypes_cfparamset *) pos;
                        memcpy(&bss->ssparamset.cfparamset, pCF,
                               sizeof(struct ieeetypes_cfparamset));
                        lbs_deb_scan("got CF IE\n");
                        break;
 
-               case MFIE_TYPE_IBSS_SET:
+               case WLAN_EID_IBSS_PARAMS:
                        pibss = (struct ieeetypes_ibssparamset *) pos;
                        bss->atimwindow = le16_to_cpu(pibss->atimwindow);
                        memmove(&bss->ssparamset.ibssparamset, pibss,
@@ -645,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
                        lbs_deb_scan("got IBSS IE\n");
                        break;
 
-               case MFIE_TYPE_COUNTRY:
+               case WLAN_EID_COUNTRY:
                        pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
                        lbs_deb_scan("got COUNTRY IE\n");
                        if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
@@ -662,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss,
                                    (int) (pcountryinfo->len + 2));
                        break;
 
-               case MFIE_TYPE_RATES_EX:
+               case WLAN_EID_EXT_SUPP_RATES:
                        /* only process extended supported rate if data rate is
                         * already found. Data rate IE should come before
                         * extended supported rate IE
@@ -673,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss,
                                break;
                        }
 
-                       n_ex_rates = elem->len;
+                       n_ex_rates = pos[1];
                        if (n_basic_rates + n_ex_rates > MAX_RATES)
                                n_ex_rates = MAX_RATES - n_basic_rates;
 
                        p = bss->rates + n_basic_rates;
-                       memcpy(p, elem->data, n_ex_rates);
+                       memcpy(p, pos + 2, n_ex_rates);
                        break;
 
-               case MFIE_TYPE_GENERIC:
-                       if (elem->len >= 4 &&
-                           elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-                           elem->data[2] == 0xf2 && elem->data[3] == 0x01) {
-                               bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-                               memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+               case WLAN_EID_GENERIC:
+                       if (pos[1] >= 4 &&
+                           pos[2] == 0x00 && pos[3] == 0x50 &&
+                           pos[4] == 0xf2 && pos[5] == 0x01) {
+                               bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+                               memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);
                                lbs_deb_scan("got WPA IE\n");
-                               lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len);
-                       } else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
-                                  elem->data[0] == 0x00 && elem->data[1] == 0x50 &&
-                                  elem->data[2] == 0x43 && elem->data[3] == 0x04) {
+                               lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
+                                           bss->wpa_ie_len);
+                       } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&
+                                  pos[2] == 0x00 && pos[3] == 0x50 &&
+                                  pos[4] == 0x43 && pos[4] == 0x04) {
                                lbs_deb_scan("got mesh IE\n");
                                bss->mesh = 1;
                        } else {
                                lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",
-                                       elem->data[0], elem->data[1],
-                                       elem->data[2], elem->data[3],
-                                       elem->len);
+                                       pos[2], pos[3],
+                                       pos[4], pos[5],
+                                       pos[1]);
                        }
                        break;
 
-               case MFIE_TYPE_RSN:
+               case WLAN_EID_RSN:
                        lbs_deb_scan("got RSN IE\n");
-                       bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
-                       memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+                       bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);
+                       memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);
                        lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
-                                   bss->rsn_ie, elem->len);
+                                   bss->rsn_ie, bss->rsn_ie_len);
                        break;
 
                default:
                        lbs_deb_scan("got IE 0x%04x, len %d\n",
-                                    elem->id, elem->len);
+                                    pos[0], pos[1]);
                        break;
                }
 
-               pos += elem->len + 2;
+               pos += pos[1] + 2;
        }
 
        /* Timestamp */
index 9e07b0464a8e1e432d82cb787f9e34ec95afe68f..fab7d5d097fc73f5241117e35b4adc32b30a6c1c 100644 (file)
@@ -7,6 +7,10 @@
 #ifndef _LBS_SCAN_H
 #define _LBS_SCAN_H
 
+#include <net/iw_handler.h>
+
+#define MAX_NETWORK_COUNT 128
+
 /**
  *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
  */
index e0c2599da92f182c2e3a31b616d04fd9c2ac4323..fb7a2d1a2525e5efae1d78c9dcf0edec7ab1a76c 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
 #include <linux/wireless.h>
-#include <net/ieee80211.h>
 
 struct ieeetypes_cfparamset {
        u8 elementid;
@@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv {
  * Note that the len member of the ieee80211_info_element varies depending on
  * the mesh_id_len */
 struct mrvl_meshie_val {
-       uint8_t oui[P80211_OUI_LEN];
+       uint8_t oui[3];
        uint8_t type;
        uint8_t subtype;
        uint8_t version;
@@ -270,7 +269,7 @@ struct mrvl_meshie_val {
 } __attribute__ ((packed));
 
 struct mrvl_meshie {
-       struct ieee80211_info_element hdr;
+       u8 id, len;
        struct mrvl_meshie_val val;
 } __attribute__ ((packed));
 
index d4c6a659b5622596618aea20d9ae284f6922e6f0..fe7498f12147b5be4e16058aae48f34bf8029702 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/bitops.h>
 
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <net/iw_handler.h>
 
 #include "host.h"
index 1cc03a8dd67acdfaca7c93a09c39b02428565c1f..59634c33b1f9194f4e10ed8fc36e2d9aed30ef4e 100644 (file)
@@ -331,7 +331,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
        /* Fill the receive configuration URB and initialise the Rx call back */
        usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
                          usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
-                         (void *) (skb->tail),
+                         skb_tail_pointer(skb),
                          MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp);
 
        cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
index c57652325286932f24828b518e398d96c6b8186e..b9230da925ee7a6d98a02d1d5d5b39b38a374138 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/etherdevice.h>
+#include <linux/debugfs.h>
 
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
@@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios");
 
 struct hwsim_vif_priv {
        u32 magic;
+       u8 bssid[ETH_ALEN];
+       bool assoc;
+       u16 aid;
 };
 
 #define HWSIM_VIF_MAGIC        0x69537748
@@ -132,6 +136,12 @@ struct mac80211_hwsim_data {
        unsigned int rx_filter;
        int started;
        struct timer_list beacon_timer;
+       enum ps_mode {
+               PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
+       } ps;
+       bool ps_poll_pending;
+       struct dentry *debugfs;
+       struct dentry *debugfs_ps;
 };
 
 
@@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
 }
 
 
+static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
+                          struct sk_buff *skb)
+{
+       switch (data->ps) {
+       case PS_DISABLED:
+               return true;
+       case PS_ENABLED:
+               return false;
+       case PS_AUTO_POLL:
+               /* TODO: accept (some) Beacons by default and other frames only
+                * if pending PS-Poll has been sent */
+               return true;
+       case PS_MANUAL_POLL:
+               /* Allow unicast frames to own address if there is a pending
+                * PS-Poll */
+               if (data->ps_poll_pending &&
+                   memcmp(data->hw->wiphy->perm_addr, skb->data + 4,
+                          ETH_ALEN) == 0) {
+                       data->ps_poll_pending = false;
+                       return true;
+               }
+               return false;
+       }
+
+       return true;
+}
+
+
 static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                                    struct sk_buff *skb)
 {
@@ -212,6 +250,9 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
        rx_status.rate_idx = info->control.rates[0].idx;
        /* TODO: simulate signal strength (and optional packet drop) */
 
+       if (data->ps != PS_DISABLED)
+               hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+
        /* Copy skb to all enabled radios that are on the current frequency */
        spin_lock(&hwsim_radio_lock);
        list_for_each_entry(data2, &hwsim_radios, list) {
@@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                        continue;
 
                if (!data2->started || !data2->radio_enabled ||
+                   !hwsim_ps_rx_ok(data2, skb) ||
                    data->channel->center_freq != data2->channel->center_freq)
                        continue;
 
@@ -290,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        data->started = 0;
+       del_timer(&data->beacon_timer);
        printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__);
 }
 
@@ -403,7 +446,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif,
                                           struct ieee80211_if_conf *conf)
 {
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
        hwsim_check_magic(vif);
+       if (conf->changed & IEEE80211_IFCC_BSSID) {
+               DECLARE_MAC_BUF(mac);
+               printk(KERN_DEBUG "%s:%s: BSSID changed: %s\n",
+                      wiphy_name(hw->wiphy), __func__,
+                      print_mac(mac, conf->bssid));
+               memcpy(vp->bssid, conf->bssid, ETH_ALEN);
+       }
        return 0;
 }
 
@@ -412,7 +464,48 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
                                            struct ieee80211_bss_conf *info,
                                            u32 changed)
 {
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+
        hwsim_check_magic(vif);
+
+       printk(KERN_DEBUG "%s:%s(changed=0x%x)\n",
+              wiphy_name(hw->wiphy), __func__, changed);
+
+       if (changed & BSS_CHANGED_ASSOC) {
+               printk(KERN_DEBUG "  %s: ASSOC: assoc=%d aid=%d\n",
+                      wiphy_name(hw->wiphy), info->assoc, info->aid);
+               vp->assoc = info->assoc;
+               vp->aid = info->aid;
+       }
+
+       if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+               printk(KERN_DEBUG "  %s: ERP_CTS_PROT: %d\n",
+                      wiphy_name(hw->wiphy), info->use_cts_prot);
+       }
+
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               printk(KERN_DEBUG "  %s: ERP_PREAMBLE: %d\n",
+                      wiphy_name(hw->wiphy), info->use_short_preamble);
+       }
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               printk(KERN_DEBUG "  %s: ERP_SLOT: %d\n",
+                      wiphy_name(hw->wiphy), info->use_short_slot);
+       }
+
+       if (changed & BSS_CHANGED_HT) {
+               printk(KERN_DEBUG "  %s: HT: sec_ch_offs=%d width_40_ok=%d "
+                      "op_mode=%d\n",
+                      wiphy_name(hw->wiphy),
+                      info->ht.secondary_channel_offset,
+                      info->ht.width_40_ok, info->ht.operation_mode);
+       }
+
+       if (changed & BSS_CHANGED_BASIC_RATES) {
+               printk(KERN_DEBUG "  %s: BASIC_RATES: 0x%llx\n",
+                      wiphy_name(hw->wiphy),
+                      (unsigned long long) info->basic_rates);
+       }
 }
 
 static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw,
@@ -439,6 +532,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw,
        return 0;
 }
 
+static int mac80211_hwsim_conf_tx(
+       struct ieee80211_hw *hw, u16 queue,
+       const struct ieee80211_tx_queue_params *params)
+{
+       printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d "
+              "aifs=%d)\n",
+              wiphy_name(hw->wiphy), __func__, queue,
+              params->txop, params->cw_min, params->cw_max, params->aifs);
+       return 0;
+}
+
 static const struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -452,6 +556,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
        .bss_info_changed = mac80211_hwsim_bss_info_changed,
        .sta_notify = mac80211_hwsim_sta_notify,
        .set_tim = mac80211_hwsim_set_tim,
+       .conf_tx = mac80211_hwsim_conf_tx,
 };
 
 
@@ -468,6 +573,8 @@ static void mac80211_hwsim_free(void)
        spin_unlock_bh(&hwsim_radio_lock);
 
        list_for_each_entry(data, &tmplist, list) {
+               debugfs_remove(data->debugfs_ps);
+               debugfs_remove(data->debugfs);
                ieee80211_unregister_hw(data->hw);
                device_unregister(data->dev);
                ieee80211_free_hw(data->hw);
@@ -493,6 +600,127 @@ static void hwsim_mon_setup(struct net_device *dev)
 }
 
 
+static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_data *data = dat;
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+       DECLARE_MAC_BUF(buf);
+       struct sk_buff *skb;
+       struct ieee80211_pspoll *pspoll;
+
+       if (!vp->assoc)
+               return;
+
+       printk(KERN_DEBUG "%s:%s: send PS-Poll to %s for aid %d\n",
+              wiphy_name(data->hw->wiphy), __func__,
+              print_mac(buf, vp->bssid), vp->aid);
+
+       skb = dev_alloc_skb(sizeof(*pspoll));
+       if (!skb)
+               return;
+       pspoll = (void *) skb_put(skb, sizeof(*pspoll));
+       pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
+                                           IEEE80211_STYPE_PSPOLL |
+                                           IEEE80211_FCTL_PM);
+       pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
+       memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
+       memcpy(pspoll->ta, mac, ETH_ALEN);
+       if (data->radio_enabled &&
+           !mac80211_hwsim_tx_frame(data->hw, skb))
+               printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
+       dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
+                               struct ieee80211_vif *vif, int ps)
+{
+       struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
+       DECLARE_MAC_BUF(buf);
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+
+       if (!vp->assoc)
+               return;
+
+       printk(KERN_DEBUG "%s:%s: send data::nullfunc to %s ps=%d\n",
+              wiphy_name(data->hw->wiphy), __func__,
+              print_mac(buf, vp->bssid), ps);
+
+       skb = dev_alloc_skb(sizeof(*hdr));
+       if (!skb)
+               return;
+       hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN);
+       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                        IEEE80211_STYPE_NULLFUNC |
+                                        (ps ? IEEE80211_FCTL_PM : 0));
+       hdr->duration_id = cpu_to_le16(0);
+       memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
+       memcpy(hdr->addr2, mac, ETH_ALEN);
+       memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
+       if (data->radio_enabled &&
+           !mac80211_hwsim_tx_frame(data->hw, skb))
+               printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
+       dev_kfree_skb(skb);
+}
+
+
+static void hwsim_send_nullfunc_ps(void *dat, u8 *mac,
+                                  struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_data *data = dat;
+       hwsim_send_nullfunc(data, mac, vif, 1);
+}
+
+
+static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac,
+                                     struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_data *data = dat;
+       hwsim_send_nullfunc(data, mac, vif, 0);
+}
+
+
+static int hwsim_fops_ps_read(void *dat, u64 *val)
+{
+       struct mac80211_hwsim_data *data = dat;
+       *val = data->ps;
+       return 0;
+}
+
+static int hwsim_fops_ps_write(void *dat, u64 val)
+{
+       struct mac80211_hwsim_data *data = dat;
+       enum ps_mode old_ps;
+
+       if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL &&
+           val != PS_MANUAL_POLL)
+               return -EINVAL;
+
+       old_ps = data->ps;
+       data->ps = val;
+
+       if (val == PS_MANUAL_POLL) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   hwsim_send_ps_poll, data);
+               data->ps_poll_pending = true;
+       } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   hwsim_send_nullfunc_ps,
+                                                   data);
+       } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
+               ieee80211_iterate_active_interfaces(data->hw,
+                                                   hwsim_send_nullfunc_no_ps,
+                                                   data);
+       }
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write,
+                       "%llu\n");
+
+
 static int __init init_mac80211_hwsim(void)
 {
        int i, err = 0;
@@ -584,6 +812,12 @@ static int __init init_mac80211_hwsim(void)
                       wiphy_name(hw->wiphy),
                       hw->wiphy->perm_addr);
 
+               data->debugfs = debugfs_create_dir("hwsim",
+                                                  hw->wiphy->debugfsdir);
+               data->debugfs_ps = debugfs_create_file("ps", 0666,
+                                                      data->debugfs, data,
+                                                      &hwsim_fops_ps);
+
                setup_timer(&data->beacon_timer, mac80211_hwsim_beacon,
                            (unsigned long) hw);
 
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
deleted file mode 100644 (file)
index b657a91..0000000
+++ /dev/null
@@ -1,6030 +0,0 @@
-/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c)
- *
- * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
- * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
- *
- * Current maintainers (as of 29 September 2003) are:
- *     Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corporation 2001-2003.
- * Copyright (C) 2000 David Gibson, Linuxcare Australia.
- *     With some help from :
- * Copyright (C) 2001 Jean Tourrilhes, HP Labs
- * Copyright (C) 2001 Benjamin Herrenschmidt
- *
- * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
- *
- * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
- * AT fasta.fh-dortmund.de>
- *      http://www.stud.fh-dortmund.de/~andy/wvlan/
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds AT users.sourceforge.net>.  Portions created by David
- * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
- * Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.  */
-
-/*
- * TODO
- *     o Handle de-encapsulation within network layer, provide 802.11
- *       headers (patch from Thomas 'Dent' Mirlacher)
- *     o Fix possible races in SPY handling.
- *     o Disconnect wireless extensions from fundamental configuration.
- *     o (maybe) Software WEP support (patch from Stano Meduna).
- *     o (maybe) Use multiple Tx buffers - driver handling queue
- *       rather than firmware.
- */
-
-/* Locking and synchronization:
- *
- * The basic principle is that everything is serialized through a
- * single spinlock, priv->lock.  The lock is used in user, bh and irq
- * context, so when taken outside hardirq context it should always be
- * taken with interrupts disabled.  The lock protects both the
- * hardware and the struct orinoco_private.
- *
- * Another flag, priv->hw_unavailable indicates that the hardware is
- * unavailable for an extended period of time (e.g. suspended, or in
- * the middle of a hard reset).  This flag is protected by the
- * spinlock.  All code which touches the hardware should check the
- * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again.  The orinoco_lock()
- * function handles this (it unlocks and returns -EBUSY if
- * hw_unavailable is non-zero).
- */
-
-#define DRIVER_NAME "orinoco"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/firmware.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/ieee80211.h>
-
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
-
-#include "hermes_rid.h"
-#include "hermes_dld.h"
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module information                                               */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Level of debugging. Used in the macros in orinoco.h */
-#ifdef ORINOCO_DEBUG
-int orinoco_debug = ORINOCO_DEBUG;
-module_param(orinoco_debug, int, 0644);
-MODULE_PARM_DESC(orinoco_debug, "Debug level");
-EXPORT_SYMBOL(orinoco_debug);
-#endif
-
-static int suppress_linkstatus; /* = 0 */
-module_param(suppress_linkstatus, bool, 0644);
-MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
-static int ignore_disconnect; /* = 0 */
-module_param(ignore_disconnect, int, 0644);
-MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
-
-static int force_monitor; /* = 0 */
-module_param(force_monitor, int, 0644);
-MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
-
-/********************************************************************/
-/* Compile time configuration and compatibility stuff               */
-/********************************************************************/
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv)       (priv->spy_data.spy_number)
-#else
-#define SPY_NUMBER(priv)       0
-#endif /* WIRELESS_SPY */
-
-/********************************************************************/
-/* Internal constants                                               */
-/********************************************************************/
-
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
-
-#define ORINOCO_MIN_MTU                256
-#define ORINOCO_MAX_MTU                (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD)
-
-#define SYMBOL_MAX_VER_LEN     (14)
-#define USER_BAP               0
-#define IRQ_BAP                        1
-#define MAX_IRQLOOPS_PER_IRQ   10
-#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
-                                           * how many events the
-                                           * device could
-                                           * legitimately generate */
-#define SMALL_KEY_SIZE         5
-#define LARGE_KEY_SIZE         13
-#define TX_NICBUF_SIZE_BUG     1585            /* Bug in Symbol firmware */
-
-#define DUMMY_FID              0xFFFF
-
-/*#define MAX_MULTICAST(priv)  (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
-  HERMES_MAX_MULTICAST : 0)*/
-#define MAX_MULTICAST(priv)    (HERMES_MAX_MULTICAST)
-
-#define ORINOCO_INTEN          (HERMES_EV_RX | HERMES_EV_ALLOC \
-                                | HERMES_EV_TX | HERMES_EV_TXEXC \
-                                | HERMES_EV_WTERR | HERMES_EV_INFO \
-                                | HERMES_EV_INFDROP )
-
-#define MAX_RID_LEN 1024
-
-static const struct iw_handler_def orinoco_handler_def;
-static const struct ethtool_ops orinoco_ethtool_ops;
-
-/********************************************************************/
-/* Data tables                                                      */
-/********************************************************************/
-
-/* The frequency of each channel in MHz */
-static const long channel_frequency[] = {
-       2412, 2417, 2422, 2427, 2432, 2437, 2442,
-       2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-#define NUM_CHANNELS ARRAY_SIZE(channel_frequency)
-
-/* This tables gives the actual meanings of the bitrate IDs returned
- * by the firmware. */
-static struct {
-       int bitrate; /* in 100s of kilobits */
-       int automatic;
-       u16 agere_txratectrl;
-       u16 intersil_txratectrl;
-} bitrate_table[] = {
-       {110, 1,  3, 15}, /* Entry 0 is the default */
-       {10,  0,  1,  1},
-       {10,  1,  1,  1},
-       {20,  0,  2,  2},
-       {20,  1,  6,  3},
-       {55,  0,  4,  4},
-       {55,  1,  7,  7},
-       {110, 0,  5,  8},
-};
-#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
-
-/********************************************************************/
-/* Data types                                                       */
-/********************************************************************/
-
-/* Beginning of the Tx descriptor, used in TxExc handling */
-struct hermes_txexc_data {
-       struct hermes_tx_descriptor desc;
-       __le16 frame_ctl;
-       __le16 duration_id;
-       u8 addr1[ETH_ALEN];
-} __attribute__ ((packed));
-
-/* Rx frame header except compatibility 802.3 header */
-struct hermes_rx_descriptor {
-       /* Control */
-       __le16 status;
-       __le32 time;
-       u8 silence;
-       u8 signal;
-       u8 rate;
-       u8 rxflow;
-       __le32 reserved;
-
-       /* 802.11 header */
-       __le16 frame_ctl;
-       __le16 duration_id;
-       u8 addr1[ETH_ALEN];
-       u8 addr2[ETH_ALEN];
-       u8 addr3[ETH_ALEN];
-       __le16 seq_ctl;
-       u8 addr4[ETH_ALEN];
-
-       /* Data length */
-       __le16 data_len;
-} __attribute__ ((packed));
-
-/********************************************************************/
-/* Function prototypes                                              */
-/********************************************************************/
-
-static int __orinoco_program_rids(struct net_device *dev);
-static void __orinoco_set_multicast_list(struct net_device *dev);
-
-/********************************************************************/
-/* Michael MIC crypto setup                                         */
-/********************************************************************/
-#define MICHAEL_MIC_LEN 8
-static int orinoco_mic_init(struct orinoco_private *priv)
-{
-       priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
-       if (IS_ERR(priv->tx_tfm_mic)) {
-               printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
-                      "crypto API michael_mic\n");
-               priv->tx_tfm_mic = NULL;
-               return -ENOMEM;
-       }
-
-       priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
-       if (IS_ERR(priv->rx_tfm_mic)) {
-               printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
-                      "crypto API michael_mic\n");
-               priv->rx_tfm_mic = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void orinoco_mic_free(struct orinoco_private *priv)
-{
-       if (priv->tx_tfm_mic)
-               crypto_free_hash(priv->tx_tfm_mic);
-       if (priv->rx_tfm_mic)
-               crypto_free_hash(priv->rx_tfm_mic);
-}
-
-static int michael_mic(struct crypto_hash *tfm_michael, u8 *key,
-                      u8 *da, u8 *sa, u8 priority,
-                      u8 *data, size_t data_len, u8 *mic)
-{
-       struct hash_desc desc;
-       struct scatterlist sg[2];
-       u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
-
-       if (tfm_michael == NULL) {
-               printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
-               return -1;
-       }
-
-       /* Copy header into buffer. We need the padding on the end zeroed */
-       memcpy(&hdr[0], da, ETH_ALEN);
-       memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
-       hdr[ETH_ALEN*2] = priority;
-       hdr[ETH_ALEN*2+1] = 0;
-       hdr[ETH_ALEN*2+2] = 0;
-       hdr[ETH_ALEN*2+3] = 0;
-
-       /* Use scatter gather to MIC header and data in one go */
-       sg_init_table(sg, 2);
-       sg_set_buf(&sg[0], hdr, sizeof(hdr));
-       sg_set_buf(&sg[1], data, data_len);
-
-       if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
-               return -1;
-
-       desc.tfm = tfm_michael;
-       desc.flags = 0;
-       return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
-                                 mic);
-}
-
-/********************************************************************/
-/* Internal helper functions                                        */
-/********************************************************************/
-
-static inline void set_port_type(struct orinoco_private *priv)
-{
-       switch (priv->iw_mode) {
-       case IW_MODE_INFRA:
-               priv->port_type = 1;
-               priv->createibss = 0;
-               break;
-       case IW_MODE_ADHOC:
-               if (priv->prefer_port3) {
-                       priv->port_type = 3;
-                       priv->createibss = 0;
-               } else {
-                       priv->port_type = priv->ibss_port;
-                       priv->createibss = 1;
-               }
-               break;
-       case IW_MODE_MONITOR:
-               priv->port_type = 3;
-               priv->createibss = 0;
-               break;
-       default:
-               printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
-                      priv->ndev->name);
-       }
-}
-
-#define ORINOCO_MAX_BSS_COUNT  64
-static int orinoco_bss_data_allocate(struct orinoco_private *priv)
-{
-       if (priv->bss_xbss_data)
-               return 0;
-
-       if (priv->has_ext_scan)
-               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-                                             sizeof(struct xbss_element),
-                                             GFP_KERNEL);
-       else
-               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
-                                             sizeof(struct bss_element),
-                                             GFP_KERNEL);
-
-       if (!priv->bss_xbss_data) {
-               printk(KERN_WARNING "Out of memory allocating beacons");
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-static void orinoco_bss_data_free(struct orinoco_private *priv)
-{
-       kfree(priv->bss_xbss_data);
-       priv->bss_xbss_data = NULL;
-}
-
-#define PRIV_BSS       ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS      ((struct xbss_element *)priv->bss_xbss_data)
-static void orinoco_bss_data_init(struct orinoco_private *priv)
-{
-       int i;
-
-       INIT_LIST_HEAD(&priv->bss_free_list);
-       INIT_LIST_HEAD(&priv->bss_list);
-       if (priv->has_ext_scan)
-               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-                       list_add_tail(&(PRIV_XBSS[i].list),
-                                     &priv->bss_free_list);
-       else
-               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
-                       list_add_tail(&(PRIV_BSS[i].list),
-                                     &priv->bss_free_list);
-
-}
-
-static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-                                enum ieee80211_mfie eid)
-{
-       u8 *p = data;
-       while ((p + 2) < (data + len)) {
-               if (p[0] == eid)
-                       return p;
-               p += p[1] + 2;
-       }
-       return NULL;
-}
-
-#define WPA_OUI_TYPE   "\x00\x50\xF2\x01"
-#define WPA_SELECTOR_LEN 4
-static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
-{
-       u8 *p = data;
-       while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
-               if ((p[0] == MFIE_TYPE_GENERIC) &&
-                   (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
-                       return p;
-               p += p[1] + 2;
-       }
-       return NULL;
-}
-
-
-/********************************************************************/
-/* Download functionality                                           */
-/********************************************************************/
-
-struct fw_info {
-       char *pri_fw;
-       char *sta_fw;
-       char *ap_fw;
-       u32 pda_addr;
-       u16 pda_size;
-};
-
-const static struct fw_info orinoco_fw[] = {
-       { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
-       { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
-       { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
-};
-
-/* Structure used to access fields in FW
- * Make sure LE decoding macros are used
- */
-struct orinoco_fw_header {
-       char hdr_vers[6];       /* ASCII string for header version */
-       __le16 headersize;      /* Total length of header */
-       __le32 entry_point;     /* NIC entry point */
-       __le32 blocks;          /* Number of blocks to program */
-       __le32 block_offset;    /* Offset of block data from eof header */
-       __le32 pdr_offset;      /* Offset to PDR data from eof header */
-       __le32 pri_offset;      /* Offset to primary plug data */
-       __le32 compat_offset;   /* Offset to compatibility data*/
-       char signature[0];      /* FW signature length headersize-20 */
-} __attribute__ ((packed));
-
-/* Download either STA or AP firmware into the card. */
-static int
-orinoco_dl_firmware(struct orinoco_private *priv,
-                   const struct fw_info *fw,
-                   int ap)
-{
-       /* Plug Data Area (PDA) */
-       __le16 *pda;
-
-       hermes_t *hw = &priv->hw;
-       const struct firmware *fw_entry;
-       const struct orinoco_fw_header *hdr;
-       const unsigned char *first_block;
-       const unsigned char *end;
-       const char *firmware;
-       struct net_device *dev = priv->ndev;
-       int err = 0;
-
-       pda = kzalloc(fw->pda_size, GFP_KERNEL);
-       if (!pda)
-               return -ENOMEM;
-
-       if (ap)
-               firmware = fw->ap_fw;
-       else
-               firmware = fw->sta_fw;
-
-       printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
-              dev->name, firmware);
-
-       /* Read current plug data */
-       err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
-       printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
-       if (err)
-               goto free;
-
-       if (priv->cached_fw)
-               fw_entry = priv->cached_fw;
-       else {
-               err = request_firmware(&fw_entry, firmware, priv->dev);
-               if (err) {
-                       printk(KERN_ERR "%s: Cannot find firmware %s\n",
-                              dev->name, firmware);
-                       err = -ENOENT;
-                       goto free;
-               }
-               priv->cached_fw = fw_entry;
-       }
-
-       hdr = (const struct orinoco_fw_header *) fw_entry->data;
-
-       /* Enable aux port to allow programming */
-       err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
-       printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
-       if (err != 0)
-               goto abort;
-
-       /* Program data */
-       first_block = (fw_entry->data +
-                      le16_to_cpu(hdr->headersize) +
-                      le32_to_cpu(hdr->block_offset));
-       end = fw_entry->data + fw_entry->size;
-
-       err = hermes_program(hw, first_block, end);
-       printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
-       if (err != 0)
-               goto abort;
-
-       /* Update production data */
-       first_block = (fw_entry->data +
-                      le16_to_cpu(hdr->headersize) +
-                      le32_to_cpu(hdr->pdr_offset));
-
-       err = hermes_apply_pda_with_defaults(hw, first_block, pda);
-       printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
-       if (err)
-               goto abort;
-
-       /* Tell card we've finished */
-       err = hermesi_program_end(hw);
-       printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
-       if (err != 0)
-               goto abort;
-
-       /* Check if we're running */
-       printk(KERN_DEBUG "%s: hermes_present returned %d\n",
-              dev->name, hermes_present(hw));
-
-abort:
-       /* In case of error, assume firmware was bogus and release it */
-       if (err) {
-               priv->cached_fw = NULL;
-               release_firmware(fw_entry);
-       }
-
-free:
-       kfree(pda);
-       return err;
-}
-
-/* End markers */
-#define TEXT_END       0x1A            /* End of text header */
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds.  For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
-static int
-symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
-               const unsigned char *image, const unsigned char *end,
-               int secondary)
-{
-       hermes_t *hw = &priv->hw;
-       int ret = 0;
-       const unsigned char *ptr;
-       const unsigned char *first_block;
-
-       /* Plug Data Area (PDA) */
-       __le16 *pda = NULL;
-
-       /* Binary block begins after the 0x1A marker */
-       ptr = image;
-       while (*ptr++ != TEXT_END);
-       first_block = ptr;
-
-       /* Read the PDA from EEPROM */
-       if (secondary) {
-               pda = kzalloc(fw->pda_size, GFP_KERNEL);
-               if (!pda)
-                       return -ENOMEM;
-
-               ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
-               if (ret)
-                       goto free;
-       }
-
-       /* Stop the firmware, so that it can be safely rewritten */
-       if (priv->stop_fw) {
-               ret = priv->stop_fw(priv, 1);
-               if (ret)
-                       goto free;
-       }
-
-       /* Program the adapter with new firmware */
-       ret = hermes_program(hw, first_block, end);
-       if (ret)
-               goto free;
-
-       /* Write the PDA to the adapter */
-       if (secondary) {
-               size_t len = hermes_blocks_length(first_block);
-               ptr = first_block + len;
-               ret = hermes_apply_pda(hw, ptr, pda);
-               kfree(pda);
-               if (ret)
-                       return ret;
-       }
-
-       /* Run the firmware */
-       if (priv->stop_fw) {
-               ret = priv->stop_fw(priv, 0);
-               if (ret)
-                       return ret;
-       }
-
-       /* Reset hermes chip and make sure it responds */
-       ret = hermes_init(hw);
-
-       /* hermes_reset() should return 0 with the secondary firmware */
-       if (secondary && ret != 0)
-               return -ENODEV;
-
-       /* And this should work with any firmware */
-       if (!hermes_present(hw))
-               return -ENODEV;
-
-       return 0;
-
-free:
-       kfree(pda);
-       return ret;
-}
-
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
-static int
-symbol_dl_firmware(struct orinoco_private *priv,
-                  const struct fw_info *fw)
-{
-       struct net_device *dev = priv->ndev;
-       int ret;
-       const struct firmware *fw_entry;
-
-       if (request_firmware(&fw_entry, fw->pri_fw,
-                            priv->dev) != 0) {
-               printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-                      dev->name, fw->pri_fw);
-               return -ENOENT;
-       }
-
-       /* Load primary firmware */
-       ret = symbol_dl_image(priv, fw, fw_entry->data,
-                             fw_entry->data + fw_entry->size, 0);
-       release_firmware(fw_entry);
-       if (ret) {
-               printk(KERN_ERR "%s: Primary firmware download failed\n",
-                      dev->name);
-               return ret;
-       }
-
-       if (request_firmware(&fw_entry, fw->sta_fw,
-                            priv->dev) != 0) {
-               printk(KERN_ERR "%s: Cannot find firmware: %s\n",
-                      dev->name, fw->sta_fw);
-               return -ENOENT;
-       }
-
-       /* Load secondary firmware */
-       ret = symbol_dl_image(priv, fw, fw_entry->data,
-                             fw_entry->data + fw_entry->size, 1);
-       release_firmware(fw_entry);
-       if (ret) {
-               printk(KERN_ERR "%s: Secondary firmware download failed\n",
-                      dev->name);
-       }
-
-       return ret;
-}
-
-static int orinoco_download(struct orinoco_private *priv)
-{
-       int err = 0;
-       /* Reload firmware */
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               /* case FIRMWARE_TYPE_INTERSIL: */
-               err = orinoco_dl_firmware(priv,
-                                         &orinoco_fw[priv->firmware_type], 0);
-               break;
-
-       case FIRMWARE_TYPE_SYMBOL:
-               err = symbol_dl_firmware(priv,
-                                        &orinoco_fw[priv->firmware_type]);
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-               break;
-       }
-       /* TODO: if we fail we probably need to reinitialise
-        * the driver */
-
-       return err;
-}
-
-/********************************************************************/
-/* Device methods                                                   */
-/********************************************************************/
-
-static int orinoco_open(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = __orinoco_up(dev);
-
-       if (! err)
-               priv->open = 1;
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_stop(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-
-       /* We mustn't use orinoco_lock() here, because we need to be
-          able to close the interface even if hw_unavailable is set
-          (e.g. as we're released after a PC Card removal) */
-       spin_lock_irq(&priv->lock);
-
-       priv->open = 0;
-
-       err = __orinoco_down(dev);
-
-       spin_unlock_irq(&priv->lock);
-
-       return err;
-}
-
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       
-       return &priv->stats;
-}
-
-static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       struct iw_statistics *wstats = &priv->wstats;
-       int err;
-       unsigned long flags;
-
-       if (! netif_device_present(dev)) {
-               printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
-                      dev->name);
-               return NULL; /* FIXME: Can we do better than this? */
-       }
-
-       /* If busy, return the old stats.  Returning NULL may cause
-        * the interface to disappear from /proc/net/wireless */
-       if (orinoco_lock(priv, &flags) != 0)
-               return wstats;
-
-       /* We can't really wait for the tallies inquiry command to
-        * complete, so we just use the previous results and trigger
-        * a new tallies inquiry command for next time - Jean II */
-       /* FIXME: Really we should wait for the inquiry to come back -
-        * as it is the stats we give don't make a whole lot of sense.
-        * Unfortunately, it's not clear how to do that within the
-        * wireless extensions framework: I think we're in user
-        * context, but a lock seems to be held by the time we get in
-        * here so we're not safe to sleep here. */
-       hermes_inquire(hw, HERMES_INQ_TALLIES);
-
-       if (priv->iw_mode == IW_MODE_ADHOC) {
-               memset(&wstats->qual, 0, sizeof(wstats->qual));
-               /* If a spy address is defined, we report stats of the
-                * first spy address - Jean II */
-               if (SPY_NUMBER(priv)) {
-                       wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
-                       wstats->qual.level = priv->spy_data.spy_stat[0].level;
-                       wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
-                       wstats->qual.updated = priv->spy_data.spy_stat[0].updated;
-               }
-       } else {
-               struct {
-                       __le16 qual, signal, noise, unused;
-               } __attribute__ ((packed)) cq;
-
-               err = HERMES_READ_RECORD(hw, USER_BAP,
-                                        HERMES_RID_COMMSQUALITY, &cq);
-
-               if (!err) {
-                       wstats->qual.qual = (int)le16_to_cpu(cq.qual);
-                       wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
-                       wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
-                       wstats->qual.updated = 7;
-               }
-       }
-
-       orinoco_unlock(priv, &flags);
-       return wstats;
-}
-
-static void orinoco_set_multicast_list(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0) {
-               printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
-                      "called when hw_unavailable\n", dev->name);
-               return;
-       }
-
-       __orinoco_set_multicast_list(dev);
-       orinoco_unlock(priv, &flags);
-}
-
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
-               return -EINVAL;
-
-       if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) >
-            (priv->nicbuf_size - ETH_HLEN) )
-               return -EINVAL;
-
-       dev->mtu = new_mtu;
-
-       return 0;
-}
-
-/********************************************************************/
-/* Tx path                                                          */
-/********************************************************************/
-
-static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u16 txfid = priv->txfid;
-       struct ethhdr *eh;
-       int tx_control;
-       unsigned long flags;
-
-       if (! netif_running(dev)) {
-               printk(KERN_ERR "%s: Tx on stopped device!\n",
-                      dev->name);
-               return NETDEV_TX_BUSY;
-       }
-       
-       if (netif_queue_stopped(dev)) {
-               printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", 
-                      dev->name);
-               return NETDEV_TX_BUSY;
-       }
-       
-       if (orinoco_lock(priv, &flags) != 0) {
-               printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
-                      dev->name);
-               return NETDEV_TX_BUSY;
-       }
-
-       if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
-               /* Oops, the firmware hasn't established a connection,
-                   silently drop the packet (this seems to be the
-                   safest approach). */
-               goto drop;
-       }
-
-       /* Check packet length */
-       if (skb->len < ETH_HLEN)
-               goto drop;
-
-       tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
-
-       if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
-               tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
-                       HERMES_TXCTRL_MIC;
-
-       if (priv->has_alt_txcntl) {
-               /* WPA enabled firmwares have tx_cntl at the end of
-                * the 802.11 header.  So write zeroed descriptor and
-                * 802.11 header at the same time
-                */
-               char desc[HERMES_802_3_OFFSET];
-               __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
-
-               memset(&desc, 0, sizeof(desc));
-
-               *txcntl = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
-               if (err) {
-                       if (net_ratelimit())
-                               printk(KERN_ERR "%s: Error %d writing Tx "
-                                      "descriptor to BAP\n", dev->name, err);
-                       goto busy;
-               }
-       } else {
-               struct hermes_tx_descriptor desc;
-
-               memset(&desc, 0, sizeof(desc));
-
-               desc.tx_control = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
-               if (err) {
-                       if (net_ratelimit())
-                               printk(KERN_ERR "%s: Error %d writing Tx "
-                                      "descriptor to BAP\n", dev->name, err);
-                       goto busy;
-               }
-
-               /* Clear the 802.11 header and data length fields - some
-                * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
-                * if this isn't done. */
-               hermes_clear_words(hw, HERMES_DATA0,
-                                  HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
-       }
-
-       eh = (struct ethhdr *)skb->data;
-
-       /* Encapsulate Ethernet-II frames */
-       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-               struct header_struct {
-                       struct ethhdr eth;      /* 802.3 header */
-                       u8 encap[6];            /* 802.2 header */
-               } __attribute__ ((packed)) hdr;
-
-               /* Strip destination and source from the data */
-               skb_pull(skb, 2 * ETH_ALEN);
-
-               /* And move them to a separate header */
-               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
-               /* Insert the SNAP header */
-               if (skb_headroom(skb) < sizeof(hdr)) {
-                       printk(KERN_ERR
-                              "%s: Not enough headroom for 802.2 headers %d\n",
-                              dev->name, skb_headroom(skb));
-                       goto drop;
-               }
-               eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
-               memcpy(eh, &hdr, sizeof(hdr));
-       }
-
-       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-                               txfid, HERMES_802_3_OFFSET);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
-                      dev->name, err);
-               goto busy;
-       }
-
-       /* Calculate Michael MIC */
-       if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
-               u8 mic_buf[MICHAEL_MIC_LEN + 1];
-               u8 *mic;
-               size_t offset;
-               size_t len;
-
-               if (skb->len % 2) {
-                       /* MIC start is on an odd boundary */
-                       mic_buf[0] = skb->data[skb->len - 1];
-                       mic = &mic_buf[1];
-                       offset = skb->len - 1;
-                       len = MICHAEL_MIC_LEN + 1;
-               } else {
-                       mic = &mic_buf[0];
-                       offset = skb->len;
-                       len = MICHAEL_MIC_LEN;
-               }
-
-               michael_mic(priv->tx_tfm_mic,
-                           priv->tkip_key[priv->tx_key].tx_mic,
-                           eh->h_dest, eh->h_source, 0 /* priority */,
-                           skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
-
-               /* Write the MIC */
-               err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-                                       txfid, HERMES_802_3_OFFSET + offset);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
-                              dev->name, err);
-                       goto busy;
-               }
-       }
-
-       /* Finally, we actually initiate the send */
-       netif_stop_queue(dev);
-
-       err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
-                               txfid, NULL);
-       if (err) {
-               netif_start_queue(dev);
-               if (net_ratelimit())
-                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
-                               dev->name, err);
-               goto busy;
-       }
-
-       dev->trans_start = jiffies;
-       stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
-       goto ok;
-
- drop:
-       stats->tx_errors++;
-       stats->tx_dropped++;
-
- ok:
-       orinoco_unlock(priv, &flags);
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-
- busy:
-       if (err == -EIO)
-               schedule_work(&priv->reset_work);
-       orinoco_unlock(priv, &flags);
-       return NETDEV_TX_BUSY;
-}
-
-static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       u16 fid = hermes_read_regn(hw, ALLOCFID);
-
-       if (fid != priv->txfid) {
-               if (fid != DUMMY_FID)
-                       printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
-                              dev->name, fid);
-               return;
-       }
-
-       hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-
-       stats->tx_packets++;
-
-       netif_wake_queue(dev);
-
-       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       u16 fid = hermes_read_regn(hw, TXCOMPLFID);
-       u16 status;
-       struct hermes_txexc_data hdr;
-       int err = 0;
-
-       if (fid == DUMMY_FID)
-               return; /* Nothing's really happened */
-
-       /* Read part of the frame header - we need status and addr1 */
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_txexc_data),
-                              fid, 0);
-
-       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-       stats->tx_errors++;
-
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
-                      "(FID=%04X error %d)\n",
-                      dev->name, fid, err);
-               return;
-       }
-       
-       DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
-             err, fid);
-    
-       /* We produce a TXDROP event only for retry or lifetime
-        * exceeded, because that's the only status that really mean
-        * that this particular node went away.
-        * Other errors means that *we* screwed up. - Jean II */
-       status = le16_to_cpu(hdr.desc.status);
-       if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
-               union iwreq_data        wrqu;
-
-               /* Copy 802.11 dest address.
-                * We use the 802.11 header because the frame may
-                * not be 802.3 or may be mangled...
-                * In Ad-Hoc mode, it will be the node address.
-                * In managed mode, it will be most likely the AP addr
-                * User space will figure out how to convert it to
-                * whatever it needs (IP address or else).
-                * - Jean II */
-               memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
-               wrqu.addr.sa_family = ARPHRD_ETHER;
-
-               /* Send event to user space */
-               wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
-       }
-
-       netif_wake_queue(dev);
-}
-
-static void orinoco_tx_timeout(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       struct hermes *hw = &priv->hw;
-
-       printk(KERN_WARNING "%s: Tx timeout! "
-              "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
-              dev->name, hermes_read_regn(hw, ALLOCFID),
-              hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
-
-       stats->tx_errors++;
-
-       schedule_work(&priv->reset_work);
-}
-
-/********************************************************************/
-/* Rx path (data frames)                                            */
-/********************************************************************/
-
-/* Does the frame have a SNAP header indicating it should be
- * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(void *_hdr)
-{
-       u8 *hdr = _hdr;
-
-       /* We de-encapsulate all packets which, a) have SNAP headers
-        * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
-        * and where b) the OUI of the SNAP header is 00:00:00 or
-        * 00:00:f8 - we need both because different APs appear to use
-        * different OUIs for some reason */
-       return (memcmp(hdr, &encaps_hdr, 5) == 0)
-               && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) );
-}
-
-static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
-                                     int level, int noise)
-{
-       struct iw_quality wstats;
-       wstats.level = level - 0x95;
-       wstats.noise = noise - 0x95;
-       wstats.qual = (level > noise) ? (level - noise) : 0;
-       wstats.updated = 7;
-       /* Update spy records */
-       wireless_spy_update(dev, mac, &wstats);
-}
-
-static void orinoco_stat_gather(struct net_device *dev,
-                               struct sk_buff *skb,
-                               struct hermes_rx_descriptor *desc)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       /* Using spy support with lots of Rx packets, like in an
-        * infrastructure (AP), will really slow down everything, because
-        * the MAC address must be compared to each entry of the spy list.
-        * If the user really asks for it (set some address in the
-        * spy list), we do it, but he will pay the price.
-        * Note that to get here, you need both WIRELESS_SPY
-        * compiled in AND some addresses in the list !!!
-        */
-       /* Note : gcc will optimise the whole section away if
-        * WIRELESS_SPY is not defined... - Jean II */
-       if (SPY_NUMBER(priv)) {
-               orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
-                                  desc->signal, desc->silence);
-       }
-}
-
-/*
- * orinoco_rx_monitor - handle received monitor frames.
- *
- * Arguments:
- *     dev             network device
- *     rxfid           received FID
- *     desc            rx descriptor of the frame
- *
- * Call context: interrupt
- */
-static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
-                              struct hermes_rx_descriptor *desc)
-{
-       u32 hdrlen = 30;        /* return full header by default */
-       u32 datalen = 0;
-       u16 fc;
-       int err;
-       int len;
-       struct sk_buff *skb;
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       hermes_t *hw = &priv->hw;
-
-       len = le16_to_cpu(desc->data_len);
-
-       /* Determine the size of the header and the data */
-       fc = le16_to_cpu(desc->frame_ctl);
-       switch (fc & IEEE80211_FCTL_FTYPE) {
-       case IEEE80211_FTYPE_DATA:
-               if ((fc & IEEE80211_FCTL_TODS)
-                   && (fc & IEEE80211_FCTL_FROMDS))
-                       hdrlen = 30;
-               else
-                       hdrlen = 24;
-               datalen = len;
-               break;
-       case IEEE80211_FTYPE_MGMT:
-               hdrlen = 24;
-               datalen = len;
-               break;
-       case IEEE80211_FTYPE_CTL:
-               switch (fc & IEEE80211_FCTL_STYPE) {
-               case IEEE80211_STYPE_PSPOLL:
-               case IEEE80211_STYPE_RTS:
-               case IEEE80211_STYPE_CFEND:
-               case IEEE80211_STYPE_CFENDACK:
-                       hdrlen = 16;
-                       break;
-               case IEEE80211_STYPE_CTS:
-               case IEEE80211_STYPE_ACK:
-                       hdrlen = 10;
-                       break;
-               }
-               break;
-       default:
-               /* Unknown frame type */
-               break;
-       }
-
-       /* sanity check the length */
-       if (datalen > IEEE80211_DATA_LEN + 12) {
-               printk(KERN_DEBUG "%s: oversized monitor frame, "
-                      "data length = %d\n", dev->name, datalen);
-               stats->rx_length_errors++;
-               goto update_stats;
-       }
-
-       skb = dev_alloc_skb(hdrlen + datalen);
-       if (!skb) {
-               printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
-                      dev->name);
-               goto update_stats;
-       }
-
-       /* Copy the 802.11 header to the skb */
-       memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
-       skb_reset_mac_header(skb);
-
-       /* If any, copy the data from the card to the skb */
-       if (datalen > 0) {
-               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-                                      ALIGN(datalen, 2), rxfid,
-                                      HERMES_802_2_OFFSET);
-               if (err) {
-                       printk(KERN_ERR "%s: error %d reading monitor frame\n",
-                              dev->name, err);
-                       goto drop;
-               }
-       }
-
-       skb->dev = dev;
-       skb->ip_summed = CHECKSUM_NONE;
-       skb->pkt_type = PACKET_OTHERHOST;
-       skb->protocol = __constant_htons(ETH_P_802_2);
-       
-       stats->rx_packets++;
-       stats->rx_bytes += skb->len;
-
-       netif_rx(skb);
-       return;
-
- drop:
-       dev_kfree_skb_irq(skb);
- update_stats:
-       stats->rx_errors++;
-       stats->rx_dropped++;
-}
-
-/* Get tsc from the firmware */
-static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key,
-                                 u8 *tsc)
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
-
-       if ((key < 0) || (key > 4))
-               return -EINVAL;
-
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
-                             sizeof(tsc_arr), NULL, &tsc_arr);
-       if (!err)
-               memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
-
-       return err;
-}
-
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       struct iw_statistics *wstats = &priv->wstats;
-       struct sk_buff *skb = NULL;
-       u16 rxfid, status;
-       int length;
-       struct hermes_rx_descriptor *desc;
-       struct orinoco_rx_data *rx_data;
-       int err;
-
-       desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
-       if (!desc) {
-               printk(KERN_WARNING
-                      "%s: Can't allocate space for RX descriptor\n",
-                      dev->name);
-               goto update_stats;
-       }
-
-       rxfid = hermes_read_regn(hw, RXFID);
-
-       err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-                              rxfid, 0);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading Rx descriptor. "
-                      "Frame dropped.\n", dev->name, err);
-               goto update_stats;
-       }
-
-       status = le16_to_cpu(desc->status);
-
-       if (status & HERMES_RXSTAT_BADCRC) {
-               DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
-                     dev->name);
-               stats->rx_crc_errors++;
-               goto update_stats;
-       }
-
-       /* Handle frames in monitor mode */
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               orinoco_rx_monitor(dev, rxfid, desc);
-               goto out;
-       }
-
-       if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
-               DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
-                     dev->name);
-               wstats->discard.code++;
-               goto update_stats;
-       }
-
-       length = le16_to_cpu(desc->data_len);
-
-       /* Sanity checks */
-       if (length < 3) { /* No for even an 802.2 LLC header */
-               /* At least on Symbol firmware with PCF we get quite a
-                   lot of these legitimately - Poll frames with no
-                   data. */
-               goto out;
-       }
-       if (length > IEEE80211_DATA_LEN) {
-               printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
-                      dev->name, length);
-               stats->rx_length_errors++;
-               goto update_stats;
-       }
-
-       /* Payload size does not include Michael MIC. Increase payload
-        * size to read it together with the data. */
-       if (status & HERMES_RXSTAT_MIC)
-               length += MICHAEL_MIC_LEN;
-
-       /* We need space for the packet data itself, plus an ethernet
-          header, plus 2 bytes so we can align the IP header on a
-          32bit boundary, plus 1 byte so we can read in odd length
-          packets from the card, which has an IO granularity of 16
-          bits */  
-       skb = dev_alloc_skb(length+ETH_HLEN+2+1);
-       if (!skb) {
-               printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
-                      dev->name);
-               goto update_stats;
-       }
-
-       /* We'll prepend the header, so reserve space for it.  The worst
-          case is no decapsulation, when 802.3 header is prepended and
-          nothing is removed.  2 is for aligning the IP header.  */
-       skb_reserve(skb, ETH_HLEN + 2);
-
-       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-                              ALIGN(length, 2), rxfid,
-                              HERMES_802_2_OFFSET);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading frame. "
-                      "Frame dropped.\n", dev->name, err);
-               goto drop;
-       }
-
-       /* Add desc and skb to rx queue */
-       rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
-       if (!rx_data) {
-               printk(KERN_WARNING "%s: Can't allocate RX packet\n",
-                       dev->name);
-               goto drop;
-       }
-       rx_data->desc = desc;
-       rx_data->skb = skb;
-       list_add_tail(&rx_data->list, &priv->rx_list);
-       tasklet_schedule(&priv->rx_tasklet);
-
-       return;
-
-drop:
-       dev_kfree_skb_irq(skb);
-update_stats:
-       stats->rx_errors++;
-       stats->rx_dropped++;
-out:
-       kfree(desc);
-}
-
-static void orinoco_rx(struct net_device *dev,
-                      struct hermes_rx_descriptor *desc,
-                      struct sk_buff *skb)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &priv->stats;
-       u16 status, fc;
-       int length;
-       struct ethhdr *hdr;
-
-       status = le16_to_cpu(desc->status);
-       length = le16_to_cpu(desc->data_len);
-       fc = le16_to_cpu(desc->frame_ctl);
-
-       /* Calculate and check MIC */
-       if (status & HERMES_RXSTAT_MIC) {
-               int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
-                             HERMES_MIC_KEY_ID_SHIFT);
-               u8 mic[MICHAEL_MIC_LEN];
-               u8 *rxmic;
-               u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
-                       desc->addr3 : desc->addr2;
-
-               /* Extract Michael MIC from payload */
-               rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
-
-               skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
-               length -= MICHAEL_MIC_LEN;
-
-               michael_mic(priv->rx_tfm_mic,
-                           priv->tkip_key[key_id].rx_mic,
-                           desc->addr1,
-                           src,
-                           0, /* priority or QoS? */
-                           skb->data,
-                           skb->len,
-                           &mic[0]);
-
-               if (memcmp(mic, rxmic,
-                          MICHAEL_MIC_LEN)) {
-                       union iwreq_data wrqu;
-                       struct iw_michaelmicfailure wxmic;
-
-                       printk(KERN_WARNING "%s: "
-                              "Invalid Michael MIC in data frame from %pM, "
-                              "using key %i\n",
-                              dev->name, src, key_id);
-
-                       /* TODO: update stats */
-
-                       /* Notify userspace */
-                       memset(&wxmic, 0, sizeof(wxmic));
-                       wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
-                       wxmic.flags |= (desc->addr1[0] & 1) ?
-                               IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
-                       wxmic.src_addr.sa_family = ARPHRD_ETHER;
-                       memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
-
-                       (void) orinoco_hw_get_tkip_iv(priv, key_id,
-                                                     &wxmic.tsc[0]);
-
-                       memset(&wrqu, 0, sizeof(wrqu));
-                       wrqu.data.length = sizeof(wxmic);
-                       wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
-                                           (char *) &wxmic);
-
-                       goto drop;
-               }
-       }
-
-       /* Handle decapsulation
-        * In most cases, the firmware tell us about SNAP frames.
-        * For some reason, the SNAP frames sent by LinkSys APs
-        * are not properly recognised by most firmwares.
-        * So, check ourselves */
-       if (length >= ENCAPS_OVERHEAD &&
-           (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
-            ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-            is_ethersnap(skb->data))) {
-               /* These indicate a SNAP within 802.2 LLC within
-                  802.11 frame which we'll need to de-encapsulate to
-                  the original EthernetII frame. */
-               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
-       } else {
-               /* 802.3 frame - prepend 802.3 header as is */
-               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
-               hdr->h_proto = htons(length);
-       }
-       memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
-       if (fc & IEEE80211_FCTL_FROMDS)
-               memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
-       else
-               memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
-
-       skb->protocol = eth_type_trans(skb, dev);
-       skb->ip_summed = CHECKSUM_NONE;
-       if (fc & IEEE80211_FCTL_TODS)
-               skb->pkt_type = PACKET_OTHERHOST;
-       
-       /* Process the wireless stats if needed */
-       orinoco_stat_gather(dev, skb, desc);
-
-       /* Pass the packet to the networking stack */
-       netif_rx(skb);
-       stats->rx_packets++;
-       stats->rx_bytes += length;
-
-       return;
-
- drop:
-       dev_kfree_skb(skb);
-       stats->rx_errors++;
-       stats->rx_dropped++;
-}
-
-static void orinoco_rx_isr_tasklet(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *) data;
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_rx_data *rx_data, *temp;
-       struct hermes_rx_descriptor *desc;
-       struct sk_buff *skb;
-
-       /* extract desc and skb from queue */
-       list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
-               desc = rx_data->desc;
-               skb = rx_data->skb;
-               list_del(&rx_data->list);
-               kfree(rx_data);
-
-               orinoco_rx(dev, desc, skb);
-
-               kfree(desc);
-       }
-}
-
-/********************************************************************/
-/* Rx path (info frames)                                            */
-/********************************************************************/
-
-static void print_linkstatus(struct net_device *dev, u16 status)
-{
-       char * s;
-
-       if (suppress_linkstatus)
-               return;
-
-       switch (status) {
-       case HERMES_LINKSTATUS_NOT_CONNECTED:
-               s = "Not Connected";
-               break;
-       case HERMES_LINKSTATUS_CONNECTED:
-               s = "Connected";
-               break;
-       case HERMES_LINKSTATUS_DISCONNECTED:
-               s = "Disconnected";
-               break;
-       case HERMES_LINKSTATUS_AP_CHANGE:
-               s = "AP Changed";
-               break;
-       case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
-               s = "AP Out of Range";
-               break;
-       case HERMES_LINKSTATUS_AP_IN_RANGE:
-               s = "AP In Range";
-               break;
-       case HERMES_LINKSTATUS_ASSOC_FAILED:
-               s = "Association Failed";
-               break;
-       default:
-               s = "UNKNOWN";
-       }
-       
-       printk(KERN_INFO "%s: New link status: %s (%04x)\n",
-              dev->name, s, status);
-}
-
-/* Search scan results for requested BSSID, join it if found */
-static void orinoco_join_ap(struct work_struct *work)
-{
-       struct orinoco_private *priv =
-               container_of(work, struct orinoco_private, join_work);
-       struct net_device *dev = priv->ndev;
-       struct hermes *hw = &priv->hw;
-       int err;
-       unsigned long flags;
-       struct join_req {
-               u8 bssid[ETH_ALEN];
-               __le16 channel;
-       } __attribute__ ((packed)) req;
-       const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
-       struct prism2_scan_apinfo *atom = NULL;
-       int offset = 4;
-       int found = 0;
-       u8 *buf;
-       u16 len;
-
-       /* Allocate buffer for scan results */
-       buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
-       if (! buf)
-               return;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               goto fail_lock;
-
-       /* Sanity checks in case user changed something in the meantime */
-       if (! priv->bssid_fixed)
-               goto out;
-
-       if (strlen(priv->desired_essid) == 0)
-               goto out;
-
-       /* Read scan results from the firmware */
-       err = hermes_read_ltv(hw, USER_BAP,
-                             HERMES_RID_SCANRESULTSTABLE,
-                             MAX_SCAN_LEN, &len, buf);
-       if (err) {
-               printk(KERN_ERR "%s: Cannot read scan results\n",
-                      dev->name);
-               goto out;
-       }
-
-       len = HERMES_RECLEN_TO_BYTES(len);
-
-       /* Go through the scan results looking for the channel of the AP
-        * we were requested to join */
-       for (; offset + atom_len <= len; offset += atom_len) {
-               atom = (struct prism2_scan_apinfo *) (buf + offset);
-               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (! found) {
-               DEBUG(1, "%s: Requested AP not found in scan results\n",
-                     dev->name);
-               goto out;
-       }
-
-       memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
-       req.channel = atom->channel;    /* both are little-endian */
-       err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
-                                 &req);
-       if (err)
-               printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
-
- out:
-       orinoco_unlock(priv, &flags);
-
- fail_lock:
-       kfree(buf);
-}
-
-/* Send new BSSID to userspace */
-static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
-{
-       struct net_device *dev = priv->ndev;
-       struct hermes *hw = &priv->hw;
-       union iwreq_data wrqu;
-       int err;
-
-       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
-       if (err != 0)
-               return;
-
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
-       /* Send event to user space */
-       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
-{
-       struct net_device *dev = priv->ndev;
-       struct hermes *hw = &priv->hw;
-       union iwreq_data wrqu;
-       int err;
-       u8 buf[88];
-       u8 *ie;
-
-       if (!priv->has_wpa)
-               return;
-
-       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-                             sizeof(buf), NULL, &buf);
-       if (err != 0)
-               return;
-
-       ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-       if (ie) {
-               int rem = sizeof(buf) - (ie - &buf[0]);
-               wrqu.data.length = ie[1] + 2;
-               if (wrqu.data.length > rem)
-                       wrqu.data.length = rem;
-
-               if (wrqu.data.length)
-                       /* Send event to user space */
-                       wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
-       }
-}
-
-static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
-{
-       struct net_device *dev = priv->ndev;
-       struct hermes *hw = &priv->hw;
-       union iwreq_data wrqu;
-       int err;
-       u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
-       u8 *ie;
-
-       if (!priv->has_wpa)
-               return;
-
-       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-                             sizeof(buf), NULL, &buf);
-       if (err != 0)
-               return;
-
-       ie = orinoco_get_wpa_ie(buf, sizeof(buf));
-       if (ie) {
-               int rem = sizeof(buf) - (ie - &buf[0]);
-               wrqu.data.length = ie[1] + 2;
-               if (wrqu.data.length > rem)
-                       wrqu.data.length = rem;
-
-               if (wrqu.data.length)
-                       /* Send event to user space */
-                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
-       }
-}
-
-static void orinoco_send_wevents(struct work_struct *work)
-{
-       struct orinoco_private *priv =
-               container_of(work, struct orinoco_private, wevent_work);
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return;
-
-       orinoco_send_assocreqie_wevent(priv);
-       orinoco_send_assocrespie_wevent(priv);
-       orinoco_send_bssid_wevent(priv);
-
-       orinoco_unlock(priv, &flags);
-}
-
-static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
-                                             unsigned long scan_age)
-{
-       if (priv->has_ext_scan) {
-               struct xbss_element *bss;
-               struct xbss_element *tmp_bss;
-
-               /* Blow away current list of scan results */
-               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-                       if (!scan_age ||
-                           time_after(jiffies, bss->last_scanned + scan_age)) {
-                               list_move_tail(&bss->list,
-                                              &priv->bss_free_list);
-                               /* Don't blow away ->list, just BSS data */
-                               memset(&bss->bss, 0, sizeof(bss->bss));
-                               bss->last_scanned = 0;
-                       }
-               }
-       } else {
-               struct bss_element *bss;
-               struct bss_element *tmp_bss;
-
-               /* Blow away current list of scan results */
-               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
-                       if (!scan_age ||
-                           time_after(jiffies, bss->last_scanned + scan_age)) {
-                               list_move_tail(&bss->list,
-                                              &priv->bss_free_list);
-                               /* Don't blow away ->list, just BSS data */
-                               memset(&bss->bss, 0, sizeof(bss->bss));
-                               bss->last_scanned = 0;
-                       }
-               }
-       }
-}
-
-static void orinoco_add_ext_scan_result(struct orinoco_private *priv,
-                                       struct agere_ext_scan_info *atom)
-{
-       struct xbss_element *bss = NULL;
-       int found = 0;
-
-       /* Try to update an existing bss first */
-       list_for_each_entry(bss, &priv->bss_list, list) {
-               if (compare_ether_addr(bss->bss.bssid, atom->bssid))
-                       continue;
-               /* ESSID lengths */
-               if (bss->bss.data[1] != atom->data[1])
-                       continue;
-               if (memcmp(&bss->bss.data[2], &atom->data[2],
-                          atom->data[1]))
-                       continue;
-               found = 1;
-               break;
-       }
-
-       /* Grab a bss off the free list */
-       if (!found && !list_empty(&priv->bss_free_list)) {
-               bss = list_entry(priv->bss_free_list.next,
-                                struct xbss_element, list);
-               list_del(priv->bss_free_list.next);
-
-               list_add_tail(&bss->list, &priv->bss_list);
-       }
-
-       if (bss) {
-               /* Always update the BSS to get latest beacon info */
-               memcpy(&bss->bss, atom, sizeof(bss->bss));
-               bss->last_scanned = jiffies;
-       }
-}
-
-static int orinoco_process_scan_results(struct net_device *dev,
-                                       unsigned char *buf,
-                                       int len)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int                     offset;         /* In the scan data */
-       union hermes_scan_info *atom;
-       int                     atom_len;
-
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               atom_len = sizeof(struct agere_scan_apinfo);
-               offset = 0;
-               break;
-       case FIRMWARE_TYPE_SYMBOL:
-               /* Lack of documentation necessitates this hack.
-                * Different firmwares have 68 or 76 byte long atoms.
-                * We try modulo first.  If the length divides by both,
-                * we check what would be the channel in the second
-                * frame for a 68-byte atom.  76-byte atoms have 0 there.
-                * Valid channel cannot be 0.  */
-               if (len % 76)
-                       atom_len = 68;
-               else if (len % 68)
-                       atom_len = 76;
-               else if (len >= 1292 && buf[68] == 0)
-                       atom_len = 76;
-               else
-                       atom_len = 68;
-               offset = 0;
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-               offset = 4;
-               if (priv->has_hostscan) {
-                       atom_len = le16_to_cpup((__le16 *)buf);
-                       /* Sanity check for atom_len */
-                       if (atom_len < sizeof(struct prism2_scan_apinfo)) {
-                               printk(KERN_ERR "%s: Invalid atom_len in scan "
-                                      "data: %d\n", dev->name, atom_len);
-                               return -EIO;
-                       }
-               } else
-                       atom_len = offsetof(struct prism2_scan_apinfo, atim);
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       /* Check that we got an whole number of atoms */
-       if ((len - offset) % atom_len) {
-               printk(KERN_ERR "%s: Unexpected scan data length %d, "
-                      "atom_len %d, offset %d\n", dev->name, len,
-                      atom_len, offset);
-               return -EIO;
-       }
-
-       orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
-       /* Read the entries one by one */
-       for (; offset + atom_len <= len; offset += atom_len) {
-               int found = 0;
-               struct bss_element *bss = NULL;
-
-               /* Get next atom */
-               atom = (union hermes_scan_info *) (buf + offset);
-
-               /* Try to update an existing bss first */
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
-                               continue;
-                       if (le16_to_cpu(bss->bss.a.essid_len) !=
-                             le16_to_cpu(atom->a.essid_len))
-                               continue;
-                       if (memcmp(bss->bss.a.essid, atom->a.essid,
-                             le16_to_cpu(atom->a.essid_len)))
-                               continue;
-                       found = 1;
-                       break;
-               }
-
-               /* Grab a bss off the free list */
-               if (!found && !list_empty(&priv->bss_free_list)) {
-                       bss = list_entry(priv->bss_free_list.next,
-                                        struct bss_element, list);
-                       list_del(priv->bss_free_list.next);
-
-                       list_add_tail(&bss->list, &priv->bss_list);
-               }
-
-               if (bss) {
-                       /* Always update the BSS to get latest beacon info */
-                       memcpy(&bss->bss, atom, sizeof(bss->bss));
-                       bss->last_scanned = jiffies;
-               }
-       }
-
-       return 0;
-}
-
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       u16 infofid;
-       struct {
-               __le16 len;
-               __le16 type;
-       } __attribute__ ((packed)) info;
-       int len, type;
-       int err;
-
-       /* This is an answer to an INQUIRE command that we did earlier,
-        * or an information "event" generated by the card
-        * The controller return to us a pseudo frame containing
-        * the information in question - Jean II */
-       infofid = hermes_read_regn(hw, INFOFID);
-
-       /* Read the info frame header - don't try too hard */
-       err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-                              infofid, 0);
-       if (err) {
-               printk(KERN_ERR "%s: error %d reading info frame. "
-                      "Frame dropped.\n", dev->name, err);
-               return;
-       }
-       
-       len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
-       type = le16_to_cpu(info.type);
-
-       switch (type) {
-       case HERMES_INQ_TALLIES: {
-               struct hermes_tallies_frame tallies;
-               struct iw_statistics *wstats = &priv->wstats;
-               
-               if (len > sizeof(tallies)) {
-                       printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
-                              dev->name, len);
-                       len = sizeof(tallies);
-               }
-               
-               err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-                                      infofid, sizeof(info));
-               if (err)
-                       break;
-               
-               /* Increment our various counters */
-               /* wstats->discard.nwid - no wrong BSSID stuff */
-               wstats->discard.code +=
-                       le16_to_cpu(tallies.RxWEPUndecryptable);
-               if (len == sizeof(tallies))  
-                       wstats->discard.code +=
-                               le16_to_cpu(tallies.RxDiscards_WEPICVError) +
-                               le16_to_cpu(tallies.RxDiscards_WEPExcluded);
-               wstats->discard.misc +=
-                       le16_to_cpu(tallies.TxDiscardsWrongSA);
-               wstats->discard.fragment +=
-                       le16_to_cpu(tallies.RxMsgInBadMsgFragments);
-               wstats->discard.retries +=
-                       le16_to_cpu(tallies.TxRetryLimitExceeded);
-               /* wstats->miss.beacon - no match */
-       }
-       break;
-       case HERMES_INQ_LINKSTATUS: {
-               struct hermes_linkstatus linkstatus;
-               u16 newstatus;
-               int connected;
-
-               if (priv->iw_mode == IW_MODE_MONITOR)
-                       break;
-
-               if (len != sizeof(linkstatus)) {
-                       printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
-                              dev->name, len);
-                       break;
-               }
-
-               err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-                                      infofid, sizeof(info));
-               if (err)
-                       break;
-               newstatus = le16_to_cpu(linkstatus.linkstatus);
-
-               /* Symbol firmware uses "out of range" to signal that
-                * the hostscan frame can be requested.  */
-               if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
-                   priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
-                   priv->has_hostscan && priv->scan_inprogress) {
-                       hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
-                       break;
-               }
-
-               connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
-                       || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
-                       || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
-
-               if (connected)
-                       netif_carrier_on(dev);
-               else if (!ignore_disconnect)
-                       netif_carrier_off(dev);
-
-               if (newstatus != priv->last_linkstatus) {
-                       priv->last_linkstatus = newstatus;
-                       print_linkstatus(dev, newstatus);
-                       /* The info frame contains only one word which is the
-                        * status (see hermes.h). The status is pretty boring
-                        * in itself, that's why we export the new BSSID...
-                        * Jean II */
-                       schedule_work(&priv->wevent_work);
-               }
-       }
-       break;
-       case HERMES_INQ_SCAN:
-               if (!priv->scan_inprogress && priv->bssid_fixed &&
-                   priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
-                       schedule_work(&priv->join_work);
-                       break;
-               }
-               /* fall through */
-       case HERMES_INQ_HOSTSCAN:
-       case HERMES_INQ_HOSTSCAN_SYMBOL: {
-               /* Result of a scanning. Contains information about
-                * cells in the vicinity - Jean II */
-               union iwreq_data        wrqu;
-               unsigned char *buf;
-
-               /* Scan is no longer in progress */
-               priv->scan_inprogress = 0;
-
-               /* Sanity check */
-               if (len > 4096) {
-                       printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
-                              dev->name, len);
-                       break;
-               }
-
-               /* Allocate buffer for results */
-               buf = kmalloc(len, GFP_ATOMIC);
-               if (buf == NULL)
-                       /* No memory, so can't printk()... */
-                       break;
-
-               /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-                                      infofid, sizeof(info));
-               if (err) {
-                       kfree(buf);
-                       break;
-               }
-
-#ifdef ORINOCO_DEBUG
-               {
-                       int     i;
-                       printk(KERN_DEBUG "Scan result [%02X", buf[0]);
-                       for(i = 1; i < (len * 2); i++)
-                               printk(":%02X", buf[i]);
-                       printk("]\n");
-               }
-#endif /* ORINOCO_DEBUG */
-
-               if (orinoco_process_scan_results(dev, buf, len) == 0) {
-                       /* Send an empty event to user space.
-                        * We don't send the received data on the event because
-                        * it would require us to do complex transcoding, and
-                        * we want to minimise the work done in the irq handler
-                        * Use a request to extract the data - Jean II */
-                       wrqu.data.length = 0;
-                       wrqu.data.flags = 0;
-                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-               }
-               kfree(buf);
-       }
-       break;
-       case HERMES_INQ_CHANNELINFO:
-       {
-               struct agere_ext_scan_info *bss;
-
-               if (!priv->scan_inprogress) {
-                       printk(KERN_DEBUG "%s: Got chaninfo without scan, "
-                              "len=%d\n", dev->name, len);
-                       break;
-               }
-
-               /* An empty result indicates that the scan is complete */
-               if (len == 0) {
-                       union iwreq_data        wrqu;
-
-                       /* Scan is no longer in progress */
-                       priv->scan_inprogress = 0;
-
-                       wrqu.data.length = 0;
-                       wrqu.data.flags = 0;
-                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-                       break;
-               }
-
-               /* Sanity check */
-               else if (len > sizeof(*bss)) {
-                       printk(KERN_WARNING
-                              "%s: Ext scan results too large (%d bytes). "
-                              "Truncating results to %zd bytes.\n",
-                              dev->name, len, sizeof(*bss));
-                       len = sizeof(*bss);
-               } else if (len < (offsetof(struct agere_ext_scan_info,
-                                          data) + 2)) {
-                       /* Drop this result now so we don't have to
-                        * keep checking later */
-                       printk(KERN_WARNING
-                              "%s: Ext scan results too short (%d bytes)\n",
-                              dev->name, len);
-                       break;
-               }
-
-               bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
-               if (bss == NULL)
-                       break;
-
-               /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-                                      infofid, sizeof(info));
-               if (err) {
-                       kfree(bss);
-                       break;
-               }
-
-               orinoco_add_ext_scan_result(priv, bss);
-
-               kfree(bss);
-               break;
-       }
-       case HERMES_INQ_SEC_STAT_AGERE:
-               /* Security status (Agere specific) */
-               /* Ignore this frame for now */
-               if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
-                       break;
-               /* fall through */
-       default:
-               printk(KERN_DEBUG "%s: Unknown information frame received: "
-                      "type 0x%04x, length %d\n", dev->name, type, len);
-               /* We don't actually do anything about it */
-               break;
-       }
-}
-
-static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
-{
-       if (net_ratelimit())
-               printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
-}
-
-/********************************************************************/
-/* Internal hardware control routines                               */
-/********************************************************************/
-
-int __orinoco_up(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       netif_carrier_off(dev); /* just to make sure */
-
-       err = __orinoco_program_rids(dev);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d configuring card\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Fire things up again */
-       hermes_set_irqmask(hw, ORINOCO_INTEN);
-       err = hermes_enable_port(hw, 0);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d enabling MAC port\n",
-                      dev->name, err);
-               return err;
-       }
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-int __orinoco_down(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       netif_stop_queue(dev);
-
-       if (! priv->hw_unavailable) {
-               if (! priv->broken_disableport) {
-                       err = hermes_disable_port(hw, 0);
-                       if (err) {
-                               /* Some firmwares (e.g. Intersil 1.3.x) seem
-                                * to have problems disabling the port, oh
-                                * well, too bad. */
-                               printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
-                                      dev->name, err);
-                               priv->broken_disableport = 1;
-                       }
-               }
-               hermes_set_irqmask(hw, 0);
-               hermes_write_regn(hw, EVACK, 0xffff);
-       }
-       
-       /* firmware will have to reassociate */
-       netif_carrier_off(dev);
-       priv->last_linkstatus = 0xffff;
-
-       return 0;
-}
-
-static int orinoco_allocate_fid(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-       if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
-               /* Try workaround for old Symbol firmware bug */
-               printk(KERN_WARNING "%s: firmware ALLOC bug detected "
-                      "(old Symbol firmware?). Trying to work around... ",
-                      dev->name);
-               
-               priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-               if (err)
-                       printk("failed!\n");
-               else
-                       printk("ok.\n");
-       }
-
-       return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       int err;
-
-       err = hermes_init(hw);
-       if (priv->do_fw_download && !err) {
-               err = orinoco_download(priv);
-               if (err)
-                       priv->do_fw_download = 0;
-       }
-       if (!err)
-               err = orinoco_allocate_fid(dev);
-
-       return err;
-}
-
-static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-
-       if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
-               printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
-                      priv->ndev->name, priv->bitratemode);
-               return -EINVAL;
-       }
-
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFTXRATECONTROL,
-                                          bitrate_table[priv->bitratemode].agere_txratectrl);
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-       case FIRMWARE_TYPE_SYMBOL:
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFTXRATECONTROL,
-                                          bitrate_table[priv->bitratemode].intersil_txratectrl);
-               break;
-       default:
-               BUG();
-       }
-
-       return err;
-}
-
-/* Set fixed AP address */
-static int __orinoco_hw_set_wap(struct orinoco_private *priv)
-{
-       int roaming_flag;
-       int err = 0;
-       hermes_t *hw = &priv->hw;
-
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               /* not supported */
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-               if (priv->bssid_fixed)
-                       roaming_flag = 2;
-               else
-                       roaming_flag = 1;
-
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFROAMINGMODE,
-                                          roaming_flag);
-               break;
-       case FIRMWARE_TYPE_SYMBOL:
-               err = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                         HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
-                                         &priv->desired_bssid);
-               break;
-       }
-       return err;
-}
-
-/* Change the WEP keys and/or the current keys.  Can be called
- * either from __orinoco_hw_setup_enc() or directly from
- * orinoco_ioctl_setiwencode().  In the later case the association
- * with the AP is not broken (if the firmware can handle it),
- * which is needed for 802.1x implementations. */
-static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               err = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                         HERMES_RID_CNFWEPKEYS_AGERE,
-                                         &priv->keys);
-               if (err)
-                       return err;
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFTXKEY_AGERE,
-                                          priv->tx_key);
-               if (err)
-                       return err;
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-       case FIRMWARE_TYPE_SYMBOL:
-               {
-                       int keylen;
-                       int i;
-
-                       /* Force uniform key length to work around firmware bugs */
-                       keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
-                       
-                       if (keylen > LARGE_KEY_SIZE) {
-                               printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
-                                      priv->ndev->name, priv->tx_key, keylen);
-                               return -E2BIG;
-                       }
-
-                       /* Write all 4 keys */
-                       for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
-                               err = hermes_write_ltv(hw, USER_BAP,
-                                                      HERMES_RID_CNFDEFAULTKEY0 + i,
-                                                      HERMES_BYTES_TO_RECLEN(keylen),
-                                                      priv->keys[i].data);
-                               if (err)
-                                       return err;
-                       }
-
-                       /* Write the index of the key used in transmission */
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFWEPDEFAULTKEYID,
-                                                  priv->tx_key);
-                       if (err)
-                               return err;
-               }
-               break;
-       }
-
-       return 0;
-}
-
-static int __orinoco_hw_setup_enc(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       int master_wep_flag;
-       int auth_flag;
-       int enc_flag;
-
-       /* Setup WEP keys for WEP and WPA */
-       if (priv->encode_alg)
-               __orinoco_hw_setup_wepkeys(priv);
-
-       if (priv->wep_restrict)
-               auth_flag = HERMES_AUTH_SHARED_KEY;
-       else
-               auth_flag = HERMES_AUTH_OPEN;
-
-       if (priv->wpa_enabled)
-               enc_flag = 2;
-       else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
-               enc_flag = 1;
-       else
-               enc_flag = 0;
-
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
-               if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
-                       /* Enable the shared-key authentication. */
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFAUTHENTICATION_AGERE,
-                                                  auth_flag);
-               }
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFWEPENABLED_AGERE,
-                                          enc_flag);
-               if (err)
-                       return err;
-
-               if (priv->has_wpa) {
-                       /* Set WPA key management */
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                 HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
-                                 priv->key_mgmt);
-                       if (err)
-                               return err;
-               }
-
-               break;
-
-       case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
-       case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-               if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
-                       if (priv->wep_restrict ||
-                           (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
-                               master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
-                                                 HERMES_WEP_EXCL_UNENCRYPTED;
-                       else
-                               master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
-
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFAUTHENTICATION,
-                                                  auth_flag);
-                       if (err)
-                               return err;
-               } else
-                       master_wep_flag = 0;
-
-               if (priv->iw_mode == IW_MODE_MONITOR)
-                       master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
-
-               /* Master WEP setting : on/off */
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFWEPFLAGS_INTERSIL,
-                                          master_wep_flag);
-               if (err)
-                       return err;     
-
-               break;
-       }
-
-       return 0;
-}
-
-/* key must be 32 bytes, including the tx and rx MIC keys.
- * rsc must be 8 bytes
- * tsc must be 8 bytes or NULL
- */
-static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
-                                    u8 *key, u8 *rsc, u8 *tsc)
-{
-       struct {
-               __le16 idx;
-               u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
-               u8 key[TKIP_KEYLEN];
-               u8 tx_mic[MIC_KEYLEN];
-               u8 rx_mic[MIC_KEYLEN];
-               u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
-       } __attribute__ ((packed)) buf;
-       int ret;
-       int err;
-       int k;
-       u16 xmitting;
-
-       key_idx &= 0x3;
-
-       if (set_tx)
-               key_idx |= 0x8000;
-
-       buf.idx = cpu_to_le16(key_idx);
-       memcpy(buf.key, key,
-              sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
-
-       if (rsc == NULL)
-               memset(buf.rsc, 0, sizeof(buf.rsc));
-       else
-               memcpy(buf.rsc, rsc, sizeof(buf.rsc));
-
-       if (tsc == NULL) {
-               memset(buf.tsc, 0, sizeof(buf.tsc));
-               buf.tsc[4] = 0x10;
-       } else {
-               memcpy(buf.tsc, tsc, sizeof(buf.tsc));
-       }
-
-       /* Wait upto 100ms for tx queue to empty */
-       k = 100;
-       do {
-               k--;
-               udelay(1000);
-               ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
-                                         &xmitting);
-               if (ret)
-                       break;
-       } while ((k > 0) && xmitting);
-
-       if (k == 0)
-               ret = -ETIMEDOUT;
-
-       err = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                 HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
-                                 &buf);
-
-       return ret ? ret : err;
-}
-
-static int orinoco_clear_tkip_key(struct orinoco_private *priv,
-                                 int key_idx)
-{
-       hermes_t *hw = &priv->hw;
-       int err;
-
-       memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
-       err = hermes_write_wordrec(hw, USER_BAP,
-                                  HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
-                                  key_idx);
-       if (err)
-               printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
-                      priv->ndev->name, err, key_idx);
-       return err;
-}
-
-static int __orinoco_program_rids(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       struct hermes_idstring idbuf;
-
-       /* Set the MAC address */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting MAC address\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set up the link mode */
-       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
-                                  priv->port_type);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting port type\n",
-                      dev->name, err);
-               return err;
-       }
-       /* Set the channel/frequency */
-       if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFOWNCHANNEL,
-                                          priv->channel);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting channel %d\n",
-                              dev->name, err, priv->channel);
-                       return err;
-               }
-       }
-
-       if (priv->has_ibss) {
-               u16 createibss;
-
-               if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
-                       printk(KERN_WARNING "%s: This firmware requires an "
-                              "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
-                       /* With wvlan_cs, in this case, we would crash.
-                        * hopefully, this driver will behave better...
-                        * Jean II */
-                       createibss = 0;
-               } else {
-                       createibss = priv->createibss;
-               }
-               
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFCREATEIBSS,
-                                          createibss);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set the desired BSSID */
-       err = __orinoco_hw_set_wap(priv);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting AP address\n",
-                      dev->name, err);
-               return err;
-       }
-       /* Set the desired ESSID */
-       idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
-       memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
-       /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-                              &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
-                      dev->name, err);
-               return err;
-       }
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-                              &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set the station name */
-       idbuf.len = cpu_to_le16(strlen(priv->nick));
-       memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-                              &idbuf);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting nickname\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set AP density */
-       if (priv->has_sensitivity) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFSYSTEMSCALE,
-                                          priv->ap_density);
-               if (err) {
-                       printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE.  "
-                              "Disabling sensitivity control\n",
-                              dev->name, err);
-
-                       priv->has_sensitivity = 0;
-               }
-       }
-
-       /* Set RTS threshold */
-       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-                                  priv->rts_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set fragmentation threshold or MWO robustness */
-       if (priv->has_mwo)
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMWOROBUST_AGERE,
-                                          priv->mwo_robust);
-       else
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                          priv->frag_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting fragmentation\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set bitrate */
-       err = __orinoco_hw_set_bitrate(priv);
-       if (err) {
-               printk(KERN_ERR "%s: Error %d setting bitrate\n",
-                      dev->name, err);
-               return err;
-       }
-
-       /* Set power management */
-       if (priv->has_pm) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPMENABLED,
-                                          priv->pm_on);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMULTICASTRECEIVE,
-                                          priv->pm_mcast);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFMAXSLEEPDURATION,
-                                          priv->pm_period);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPMHOLDOVERDURATION,
-                                          priv->pm_timeout);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting up PM\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set preamble - only for Symbol so far... */
-       if (priv->has_preamble) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
-                                          priv->preamble);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting preamble\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       /* Set up encryption */
-       if (priv->has_wep || priv->has_wpa) {
-               err = __orinoco_hw_setup_enc(priv);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d activating encryption\n",
-                              dev->name, err);
-                       return err;
-               }
-       }
-
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               /* Enable monitor mode */
-               dev->type = ARPHRD_IEEE80211;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
-                                           HERMES_TEST_MONITOR, 0, NULL);
-       } else {
-               /* Disable monitor mode */
-               dev->type = ARPHRD_ETHER;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-                                           HERMES_TEST_STOP, 0, NULL);
-       }
-       if (err)
-               return err;
-
-       /* Set promiscuity / multicast*/
-       priv->promiscuous = 0;
-       priv->mc_count = 0;
-
-       /* FIXME: what about netif_tx_lock */
-       __orinoco_set_multicast_list(dev);
-
-       return 0;
-}
-
-/* FIXME: return int? */
-static void
-__orinoco_set_multicast_list(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       int promisc, mc_count;
-
-       /* The Hermes doesn't seem to have an allmulti mode, so we go
-        * into promiscuous mode and let the upper levels deal. */
-       if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
-            (dev->mc_count > MAX_MULTICAST(priv)) ) {
-               promisc = 1;
-               mc_count = 0;
-       } else {
-               promisc = 0;
-               mc_count = dev->mc_count;
-       }
-
-       if (promisc != priv->promiscuous) {
-               err = hermes_write_wordrec(hw, USER_BAP,
-                                          HERMES_RID_CNFPROMISCUOUSMODE,
-                                          promisc);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
-                              dev->name, err);
-               } else 
-                       priv->promiscuous = promisc;
-       }
-
-       /* If we're not in promiscuous mode, then we need to set the
-        * group address if either we want to multicast, or if we were
-        * multicasting and want to stop */
-       if (! promisc && (mc_count || priv->mc_count) ) {
-               struct dev_mc_list *p = dev->mc_list;
-               struct hermes_multicast mclist;
-               int i;
-
-               for (i = 0; i < mc_count; i++) {
-                       /* paranoia: is list shorter than mc_count? */
-                       BUG_ON(! p);
-                       /* paranoia: bad address size in list? */
-                       BUG_ON(p->dmi_addrlen != ETH_ALEN);
-                       
-                       memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
-                       p = p->next;
-               }
-               
-               if (p)
-                       printk(KERN_WARNING "%s: Multicast list is "
-                              "longer than mc_count\n", dev->name);
-
-               err = hermes_write_ltv(hw, USER_BAP,
-                                  HERMES_RID_CNFGROUPADDRESSES,
-                                  HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
-                                  &mclist);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-                              dev->name, err);
-               else
-                       priv->mc_count = mc_count;
-       }
-}
-
-/* This must be called from user context, without locks held - use
- * schedule_work() */
-static void orinoco_reset(struct work_struct *work)
-{
-       struct orinoco_private *priv =
-               container_of(work, struct orinoco_private, reset_work);
-       struct net_device *dev = priv->ndev;
-       struct hermes *hw = &priv->hw;
-       int err;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               /* When the hardware becomes available again, whatever
-                * detects that is responsible for re-initializing
-                * it. So no need for anything further */
-               return;
-
-       netif_stop_queue(dev);
-
-       /* Shut off interrupts.  Depending on what state the hardware
-        * is in, this might not work, but we'll try anyway */
-       hermes_set_irqmask(hw, 0);
-       hermes_write_regn(hw, EVACK, 0xffff);
-
-       priv->hw_unavailable++;
-       priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
-       netif_carrier_off(dev);
-
-       orinoco_unlock(priv, &flags);
-
-       /* Scanning support: Cleanup of driver struct */
-       orinoco_clear_scan_results(priv, 0);
-       priv->scan_inprogress = 0;
-
-       if (priv->hard_reset) {
-               err = (*priv->hard_reset)(priv);
-               if (err) {
-                       printk(KERN_ERR "%s: orinoco_reset: Error %d "
-                              "performing hard reset\n", dev->name, err);
-                       goto disable;
-               }
-       }
-
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
-                      dev->name, err);
-               goto disable;
-       }
-
-       spin_lock_irq(&priv->lock); /* This has to be called from user context */
-
-       priv->hw_unavailable--;
-
-       /* priv->open or priv->hw_unavailable might have changed while
-        * we dropped the lock */
-       if (priv->open && (! priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
-               if (err) {
-                       printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
-                              dev->name, err);
-               } else
-                       dev->trans_start = jiffies;
-       }
-
-       spin_unlock_irq(&priv->lock);
-
-       return;
- disable:
-       hermes_set_irqmask(hw, 0);
-       netif_device_detach(dev);
-       printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
-}
-
-/********************************************************************/
-/* Interrupt handler                                                */
-/********************************************************************/
-
-static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
-{
-       printk(KERN_DEBUG "%s: TICK\n", dev->name);
-}
-
-static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
-{
-       /* This seems to happen a fair bit under load, but ignoring it
-          seems to work fine...*/
-       printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
-              dev->name);
-}
-
-irqreturn_t orinoco_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int count = MAX_IRQLOOPS_PER_IRQ;
-       u16 evstat, events;
-       /* These are used to detect a runaway interrupt situation */
-       /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
-        * we panic and shut down the hardware */
-       static int last_irq_jiffy = 0; /* jiffies value the last time
-                                       * we were called */
-       static int loops_this_jiffy = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0) {
-               /* If hw is unavailable - we don't know if the irq was
-                * for us or not */
-               return IRQ_HANDLED;
-       }
-
-       evstat = hermes_read_regn(hw, EVSTAT);
-       events = evstat & hw->inten;
-       if (! events) {
-               orinoco_unlock(priv, &flags);
-               return IRQ_NONE;
-       }
-       
-       if (jiffies != last_irq_jiffy)
-               loops_this_jiffy = 0;
-       last_irq_jiffy = jiffies;
-
-       while (events && count--) {
-               if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
-                       printk(KERN_WARNING "%s: IRQ handler is looping too "
-                              "much! Resetting.\n", dev->name);
-                       /* Disable interrupts for now */
-                       hermes_set_irqmask(hw, 0);
-                       schedule_work(&priv->reset_work);
-                       break;
-               }
-
-               /* Check the card hasn't been removed */
-               if (! hermes_present(hw)) {
-                       DEBUG(0, "orinoco_interrupt(): card removed\n");
-                       break;
-               }
-
-               if (events & HERMES_EV_TICK)
-                       __orinoco_ev_tick(dev, hw);
-               if (events & HERMES_EV_WTERR)
-                       __orinoco_ev_wterr(dev, hw);
-               if (events & HERMES_EV_INFDROP)
-                       __orinoco_ev_infdrop(dev, hw);
-               if (events & HERMES_EV_INFO)
-                       __orinoco_ev_info(dev, hw);
-               if (events & HERMES_EV_RX)
-                       __orinoco_ev_rx(dev, hw);
-               if (events & HERMES_EV_TXEXC)
-                       __orinoco_ev_txexc(dev, hw);
-               if (events & HERMES_EV_TX)
-                       __orinoco_ev_tx(dev, hw);
-               if (events & HERMES_EV_ALLOC)
-                       __orinoco_ev_alloc(dev, hw);
-               
-               hermes_write_regn(hw, EVACK, evstat);
-
-               evstat = hermes_read_regn(hw, EVSTAT);
-               events = evstat & hw->inten;
-       };
-
-       orinoco_unlock(priv, &flags);
-       return IRQ_HANDLED;
-}
-
-/********************************************************************/
-/* Initialization                                                   */
-/********************************************************************/
-
-struct comp_id {
-       u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
-       if (nic_id->id < 0x8000)
-               return FIRMWARE_TYPE_AGERE;
-       else if (nic_id->id == 0x8000 && nic_id->major == 0)
-               return FIRMWARE_TYPE_SYMBOL;
-       else
-               return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       struct comp_id nic_id, sta_id;
-       unsigned int firmver;
-       char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
-       /* Get the hardware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
-       if (err) {
-               printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
-                      dev->name, err);
-               return err;
-       }
-
-       le16_to_cpus(&nic_id.id);
-       le16_to_cpus(&nic_id.variant);
-       le16_to_cpus(&nic_id.major);
-       le16_to_cpus(&nic_id.minor);
-       printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
-              dev->name, nic_id.id, nic_id.variant,
-              nic_id.major, nic_id.minor);
-
-       priv->firmware_type = determine_firmware_type(&nic_id);
-
-       /* Get the firmware version */
-       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
-       if (err) {
-               printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
-                      dev->name, err);
-               return err;
-       }
-
-       le16_to_cpus(&sta_id.id);
-       le16_to_cpus(&sta_id.variant);
-       le16_to_cpus(&sta_id.major);
-       le16_to_cpus(&sta_id.minor);
-       printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
-              dev->name, sta_id.id, sta_id.variant,
-              sta_id.major, sta_id.minor);
-
-       switch (sta_id.id) {
-       case 0x15:
-               printk(KERN_ERR "%s: Primary firmware is active\n",
-                      dev->name);
-               return -ENODEV;
-       case 0x14b:
-               printk(KERN_ERR "%s: Tertiary firmware is active\n",
-                      dev->name);
-               return -ENODEV;
-       case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
-       case 0x21:      /* Symbol Spectrum24 Trilogy */
-               break;
-       default:
-               printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
-                      dev->name);
-               break;
-       }
-
-       /* Default capabilities */
-       priv->has_sensitivity = 1;
-       priv->has_mwo = 0;
-       priv->has_preamble = 0;
-       priv->has_port3 = 1;
-       priv->has_ibss = 1;
-       priv->has_wep = 0;
-       priv->has_big_wep = 0;
-       priv->has_alt_txcntl = 0;
-       priv->has_ext_scan = 0;
-       priv->has_wpa = 0;
-       priv->do_fw_download = 0;
-
-       /* Determine capabilities from the firmware version */
-       switch (priv->firmware_type) {
-       case FIRMWARE_TYPE_AGERE:
-               /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-                  ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
-               firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
-               priv->has_ibss = (firmver >= 0x60006);
-               priv->has_wep = (firmver >= 0x40020);
-               priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
-                                         Gold cards from the others? */
-               priv->has_mwo = (firmver >= 0x60000);
-               priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
-               priv->ibss_port = 1;
-               priv->has_hostscan = (firmver >= 0x8000a);
-               priv->do_fw_download = 1;
-               priv->broken_monitor = (firmver >= 0x80000);
-               priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
-               priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
-               priv->has_wpa = (firmver >= 0x9002a);
-               /* Tested with Agere firmware :
-                *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
-                * Tested CableTron firmware : 4.32 => Anton */
-               break;
-       case FIRMWARE_TYPE_SYMBOL:
-               /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
-               /* Intel MAC : 00:02:B3:* */
-               /* 3Com MAC : 00:50:DA:* */
-               memset(tmp, 0, sizeof(tmp));
-               /* Get the Symbol firmware version */
-               err = hermes_read_ltv(hw, USER_BAP,
-                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
-                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
-               if (err) {
-                       printk(KERN_WARNING
-                              "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n",
-                              dev->name, err);
-                       firmver = 0;
-                       tmp[0] = '\0';
-               } else {
-                       /* The firmware revision is a string, the format is
-                        * something like : "V2.20-01".
-                        * Quick and dirty parsing... - Jean II
-                        */
-                       firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12)
-                               | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4)
-                               | (tmp[7] - '0');
-
-                       tmp[SYMBOL_MAX_VER_LEN] = '\0';
-               }
-
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Symbol %s", tmp);
-
-               priv->has_ibss = (firmver >= 0x20000);
-               priv->has_wep = (firmver >= 0x15012);
-               priv->has_big_wep = (firmver >= 0x20000);
-               priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
-                              (firmver >= 0x29000 && firmver < 0x30000) ||
-                              firmver >= 0x31000;
-               priv->has_preamble = (firmver >= 0x20000);
-               priv->ibss_port = 4;
-
-               /* Symbol firmware is found on various cards, but
-                * there has been no attempt to check firmware
-                * download on non-spectrum_cs based cards.
-                *
-                * Given that the Agere firmware download works
-                * differently, we should avoid doing a firmware
-                * download with the Symbol algorithm on non-spectrum
-                * cards.
-                *
-                * For now we can identify a spectrum_cs based card
-                * because it has a firmware reset function.
-                */
-               priv->do_fw_download = (priv->stop_fw != NULL);
-
-               priv->broken_disableport = (firmver == 0x25013) ||
-                                          (firmver >= 0x30000 && firmver <= 0x31000);
-               priv->has_hostscan = (firmver >= 0x31001) ||
-                                    (firmver >= 0x29057 && firmver < 0x30000);
-               /* Tested with Intel firmware : 0x20015 => Jean II */
-               /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
-               break;
-       case FIRMWARE_TYPE_INTERSIL:
-               /* D-Link, Linksys, Adtron, ZoomAir, and many others...
-                * Samsung, Compaq 100/200 and Proxim are slightly
-                * different and less well tested */
-               /* D-Link MAC : 00:40:05:* */
-               /* Addtron MAC : 00:90:D1:* */
-               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
-                        "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
-                        sta_id.variant);
-
-               firmver = ((unsigned long)sta_id.major << 16) |
-                       ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
-               priv->has_ibss = (firmver >= 0x000700); /* FIXME */
-               priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
-               priv->has_pm = (firmver >= 0x000700);
-               priv->has_hostscan = (firmver >= 0x010301);
-
-               if (firmver >= 0x000800)
-                       priv->ibss_port = 0;
-               else {
-                       printk(KERN_NOTICE "%s: Intersil firmware earlier "
-                              "than v0.8.x - several features not supported\n",
-                              dev->name);
-                       priv->ibss_port = 1;
-               }
-               break;
-       }
-       printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
-              priv->fw_name);
-
-       return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       struct hermes_idstring nickbuf;
-       u16 reclen;
-       int len;
-
-       /* No need to lock, the hw_unavailable flag is already set in
-        * alloc_orinocodev() */
-       priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN;
-
-       /* Initialize the firmware */
-       err = hermes_init(hw);
-       if (err != 0) {
-               printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
-                      dev->name, err);
-               goto out;
-       }
-
-       err = determine_firmware(dev);
-       if (err != 0) {
-               printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-                      dev->name);
-               goto out;
-       }
-
-       if (priv->do_fw_download) {
-               err = orinoco_download(priv);
-               if (err)
-                       priv->do_fw_download = 0;
-
-               /* Check firmware version again */
-               err = determine_firmware(dev);
-               if (err != 0) {
-                       printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
-                              dev->name);
-                       goto out;
-               }
-       }
-
-       if (priv->has_port3)
-               printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
-       if (priv->has_ibss)
-               printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
-                      dev->name);
-       if (priv->has_wep) {
-               printk(KERN_DEBUG "%s: WEP supported, ", dev->name);
-               if (priv->has_big_wep)
-                       printk("104-bit key\n");
-               else
-                       printk("40-bit key\n");
-       }
-       if (priv->has_wpa) {
-               printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
-               if (orinoco_mic_init(priv)) {
-                       printk(KERN_ERR "%s: Failed to setup MIC crypto "
-                              "algorithm. Disabling WPA support\n", dev->name);
-                       priv->has_wpa = 0;
-               }
-       }
-
-       /* Now we have the firmware capabilities, allocate appropiate
-        * sized scan buffers */
-       if (orinoco_bss_data_allocate(priv))
-               goto out;
-       orinoco_bss_data_init(priv);
-
-       /* Get the MAC address */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                             ETH_ALEN, NULL, dev->dev_addr);
-       if (err) {
-               printk(KERN_WARNING "%s: failed to read MAC address!\n",
-                      dev->name);
-               goto out;
-       }
-
-       printk(KERN_DEBUG "%s: MAC address %pM\n",
-              dev->name, dev->dev_addr);
-
-       /* Get the station name */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                             sizeof(nickbuf), &reclen, &nickbuf);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read station name\n",
-                      dev->name);
-               goto out;
-       }
-       if (nickbuf.len)
-               len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
-       else
-               len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
-       memcpy(priv->nick, &nickbuf.val, len);
-       priv->nick[len] = '\0';
-
-       printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
-       err = orinoco_allocate_fid(dev);
-       if (err) {
-               printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Get allowed channels */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
-                                 &priv->channel_mask);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read channel list!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Get initial AP density */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
-                                 &priv->ap_density);
-       if (err || priv->ap_density < 1 || priv->ap_density > 3) {
-               priv->has_sensitivity = 0;
-       }
-
-       /* Get initial RTS threshold */
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
-                                 &priv->rts_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read RTS threshold!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Get initial fragmentation settings */
-       if (priv->has_mwo)
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMWOROBUST_AGERE,
-                                         &priv->mwo_robust);
-       else
-               err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                         &priv->frag_thresh);
-       if (err) {
-               printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
-                      dev->name);
-               goto out;
-       }
-
-       /* Power management setup */
-       if (priv->has_pm) {
-               priv->pm_on = 0;
-               priv->pm_mcast = 1;
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMAXSLEEPDURATION,
-                                         &priv->pm_period);
-               if (err) {
-                       printk(KERN_ERR "%s: failed to read power management period!\n",
-                              dev->name);
-                       goto out;
-               }
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFPMHOLDOVERDURATION,
-                                         &priv->pm_timeout);
-               if (err) {
-                       printk(KERN_ERR "%s: failed to read power management timeout!\n",
-                              dev->name);
-                       goto out;
-               }
-       }
-
-       /* Preamble setup */
-       if (priv->has_preamble) {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFPREAMBLE_SYMBOL,
-                                         &priv->preamble);
-               if (err)
-                       goto out;
-       }
-               
-       /* Set up the default configuration */
-       priv->iw_mode = IW_MODE_INFRA;
-       /* By default use IEEE/IBSS ad-hoc mode if we have it */
-       priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
-       set_port_type(priv);
-       priv->channel = 0; /* use firmware default */
-
-       priv->promiscuous = 0;
-       priv->encode_alg = IW_ENCODE_ALG_NONE;
-       priv->tx_key = 0;
-       priv->wpa_enabled = 0;
-       priv->tkip_cm_active = 0;
-       priv->key_mgmt = 0;
-       priv->wpa_ie_len = 0;
-       priv->wpa_ie = NULL;
-
-       /* Make the hardware available, as long as it hasn't been
-        * removed elsewhere (e.g. by PCMCIA hot unplug) */
-       spin_lock_irq(&priv->lock);
-       priv->hw_unavailable--;
-       spin_unlock_irq(&priv->lock);
-
-       printk(KERN_DEBUG "%s: ready\n", dev->name);
-
- out:
-       return err;
-}
-
-struct net_device
-*alloc_orinocodev(int sizeof_card,
-                 struct device *device,
-                 int (*hard_reset)(struct orinoco_private *),
-                 int (*stop_fw)(struct orinoco_private *, int))
-{
-       struct net_device *dev;
-       struct orinoco_private *priv;
-
-       dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
-       if (! dev)
-               return NULL;
-       priv = netdev_priv(dev);
-       priv->ndev = dev;
-       if (sizeof_card)
-               priv->card = (void *)((unsigned long)priv
-                                     + sizeof(struct orinoco_private));
-       else
-               priv->card = NULL;
-       priv->dev = device;
-
-       /* Setup / override net_device fields */
-       dev->init = orinoco_init;
-       dev->hard_start_xmit = orinoco_xmit;
-       dev->tx_timeout = orinoco_tx_timeout;
-       dev->watchdog_timeo = HZ; /* 1 second timeout */
-       dev->get_stats = orinoco_get_stats;
-       dev->ethtool_ops = &orinoco_ethtool_ops;
-       dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
-#ifdef WIRELESS_SPY
-       priv->wireless_data.spy_data = &priv->spy_data;
-       dev->wireless_data = &priv->wireless_data;
-#endif
-       dev->change_mtu = orinoco_change_mtu;
-       dev->set_multicast_list = orinoco_set_multicast_list;
-       /* we use the default eth_mac_addr for setting the MAC addr */
-
-       /* Reserve space in skb for the SNAP header */
-       dev->hard_header_len += ENCAPS_OVERHEAD;
-
-       /* Set up default callbacks */
-       dev->open = orinoco_open;
-       dev->stop = orinoco_stop;
-       priv->hard_reset = hard_reset;
-       priv->stop_fw = stop_fw;
-
-       spin_lock_init(&priv->lock);
-       priv->open = 0;
-       priv->hw_unavailable = 1; /* orinoco_init() must clear this
-                                  * before anything else touches the
-                                  * hardware */
-       INIT_WORK(&priv->reset_work, orinoco_reset);
-       INIT_WORK(&priv->join_work, orinoco_join_ap);
-       INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
-
-       INIT_LIST_HEAD(&priv->rx_list);
-       tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
-                    (unsigned long) dev);
-
-       netif_carrier_off(dev);
-       priv->last_linkstatus = 0xffff;
-
-       priv->cached_fw = NULL;
-
-       return dev;
-}
-
-void free_orinocodev(struct net_device *dev)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       /* No need to empty priv->rx_list: if the tasklet is scheduled
-        * when we call tasklet_kill it will run one final time,
-        * emptying the list */
-       tasklet_kill(&priv->rx_tasklet);
-       if (priv->cached_fw)
-               release_firmware(priv->cached_fw);
-       priv->cached_fw = NULL;
-       priv->wpa_ie_len = 0;
-       kfree(priv->wpa_ie);
-       orinoco_mic_free(priv);
-       orinoco_bss_data_free(priv);
-       free_netdev(dev);
-}
-
-/********************************************************************/
-/* Wireless extensions                                              */
-/********************************************************************/
-
-/* Return : < 0 -> error code ; >= 0 -> length */
-static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-                               char buf[IW_ESSID_MAX_SIZE+1])
-{
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       struct hermes_idstring essidbuf;
-       char *p = (char *)(&essidbuf.val);
-       int len;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (strlen(priv->desired_essid) > 0) {
-               /* We read the desired SSID from the hardware rather
-                  than from priv->desired_essid, just in case the
-                  firmware is allowed to change it on us. I'm not
-                  sure about this */
-               /* My guess is that the OWNSSID should always be whatever
-                * we set to the card, whereas CURRENT_SSID is the one that
-                * may change... - Jean II */
-               u16 rid;
-
-               *active = 1;
-
-               rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
-                       HERMES_RID_CNFDESIREDSSID;
-               
-               err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-                                     NULL, &essidbuf);
-               if (err)
-                       goto fail_unlock;
-       } else {
-               *active = 0;
-
-               err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
-                                     sizeof(essidbuf), NULL, &essidbuf);
-               if (err)
-                       goto fail_unlock;
-       }
-
-       len = le16_to_cpu(essidbuf.len);
-       BUG_ON(len > IW_ESSID_MAX_SIZE);
-
-       memset(buf, 0, IW_ESSID_MAX_SIZE);
-       memcpy(buf, p, len);
-       err = len;
-
- fail_unlock:
-       orinoco_unlock(priv, &flags);
-
-       return err;       
-}
-
-static long orinoco_hw_get_freq(struct orinoco_private *priv)
-{
-       
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u16 channel;
-       long freq = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
-       if (err)
-               goto out;
-
-       /* Intersil firmware 1.3.5 returns 0 when the interface is down */
-       if (channel == 0) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-               printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
-                      priv->ndev->name, channel);
-               err = -EBUSY;
-               goto out;
-
-       }
-       freq = channel_frequency[channel-1] * 100000;
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       if (err > 0)
-               err = -EBUSY;
-       return err ? err : freq;
-}
-
-static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
-                                     int *numrates, s32 *rates, int max)
-{
-       hermes_t *hw = &priv->hw;
-       struct hermes_idstring list;
-       unsigned char *p = (unsigned char *)&list.val;
-       int err = 0;
-       int num;
-       int i;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
-                             sizeof(list), NULL, &list);
-       orinoco_unlock(priv, &flags);
-
-       if (err)
-               return err;
-       
-       num = le16_to_cpu(list.len);
-       *numrates = num;
-       num = min(num, max);
-
-       for (i = 0; i < num; i++) {
-               rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
-       }
-
-       return 0;
-}
-
-static int orinoco_ioctl_getname(struct net_device *dev,
-                                struct iw_request_info *info,
-                                char *name,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int numrates;
-       int err;
-
-       err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
-       if (!err && (numrates > 2))
-               strcpy(name, "IEEE 802.11b");
-       else
-               strcpy(name, "IEEE 802.11-DS");
-
-       return 0;
-}
-
-static int orinoco_ioctl_setwap(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct sockaddr *ap_addr,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-       static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-       static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* Enable automatic roaming - no sanity checks are needed */
-       if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
-           memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
-               priv->bssid_fixed = 0;
-               memset(priv->desired_bssid, 0, ETH_ALEN);
-
-               /* "off" means keep existing connection */
-               if (ap_addr->sa_data[0] == 0) {
-                       __orinoco_hw_set_wap(priv);
-                       err = 0;
-               }
-               goto out;
-       }
-
-       if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
-               printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
-                      "support manual roaming\n",
-                      dev->name);
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (priv->iw_mode != IW_MODE_INFRA) {
-               printk(KERN_WARNING "%s: Manual roaming supported only in "
-                      "managed mode\n", dev->name);
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       /* Intersil firmware hangs without Desired ESSID */
-       if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
-           strlen(priv->desired_essid) == 0) {
-               printk(KERN_WARNING "%s: Desired ESSID must be set for "
-                      "manual roaming\n", dev->name);
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       /* Finally, enable manual roaming */
-       priv->bssid_fixed = 1;
-       memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct sockaddr *ap_addr,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       ap_addr->sa_family = ARPHRD_ETHER;
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, ap_addr->sa_data);
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_setmode(struct net_device *dev,
-                                struct iw_request_info *info,
-                                u32 *mode,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (priv->iw_mode == *mode)
-               return 0;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (*mode) {
-       case IW_MODE_ADHOC:
-               if (!priv->has_ibss && !priv->has_port3)
-                       err = -EOPNOTSUPP;
-               break;
-
-       case IW_MODE_INFRA:
-               break;
-
-       case IW_MODE_MONITOR:
-               if (priv->broken_monitor && !force_monitor) {
-                       printk(KERN_WARNING "%s: Monitor mode support is "
-                              "buggy in this firmware, not enabling\n",
-                              dev->name);
-                       err = -EOPNOTSUPP;
-               }
-               break;
-
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       if (err == -EINPROGRESS) {
-               priv->iw_mode = *mode;
-               set_port_type(priv);
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
-                                struct iw_request_info *info,
-                                u32 *mode,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       *mode = priv->iw_mode;
-       return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
-                                   struct iw_request_info *info,
-                                   struct iw_point *rrq,
-                                   char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       struct iw_range *range = (struct iw_range *) extra;
-       int numrates;
-       int i, k;
-
-       rrq->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 22;
-
-       /* Set available channels/frequencies */
-       range->num_channels = NUM_CHANNELS;
-       k = 0;
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               if (priv->channel_mask & (1 << i)) {
-                       range->freq[k].i = i + 1;
-                       range->freq[k].m = channel_frequency[i] * 100000;
-                       range->freq[k].e = 1;
-                       k++;
-               }
-               
-               if (k >= IW_MAX_FREQUENCIES)
-                       break;
-       }
-       range->num_frequency = k;
-       range->sensitivity = 3;
-
-       if (priv->has_wep) {
-               range->max_encoding_tokens = ORINOCO_MAX_KEYS;
-               range->encoding_size[0] = SMALL_KEY_SIZE;
-               range->num_encoding_sizes = 1;
-
-               if (priv->has_big_wep) {
-                       range->encoding_size[1] = LARGE_KEY_SIZE;
-                       range->num_encoding_sizes = 2;
-               }
-       }
-
-       if (priv->has_wpa)
-               range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
-       if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
-               /* Quality stats meaningless in ad-hoc mode */
-       } else {
-               range->max_qual.qual = 0x8b - 0x2f;
-               range->max_qual.level = 0x2f - 0x95 - 1;
-               range->max_qual.noise = 0x2f - 0x95 - 1;
-               /* Need to get better values */
-               range->avg_qual.qual = 0x24;
-               range->avg_qual.level = 0xC2;
-               range->avg_qual.noise = 0x9E;
-       }
-
-       err = orinoco_hw_get_bitratelist(priv, &numrates,
-                                        range->bitrate, IW_MAX_BITRATES);
-       if (err)
-               return err;
-       range->num_bitrates = numrates;
-
-       /* Set an indication of the max TCP throughput in bit/s that we can
-        * expect using this interface. May be use for QoS stuff...
-        * Jean II */
-       if (numrates > 2)
-               range->throughput = 5 * 1000 * 1000;    /* ~5 Mb/s */
-       else
-               range->throughput = 1.5 * 1000 * 1000;  /* ~1.5 Mb/s */
-
-       range->min_rts = 0;
-       range->max_rts = 2347;
-       range->min_frag = 256;
-       range->max_frag = 2346;
-
-       range->min_pmp = 0;
-       range->max_pmp = 65535000;
-       range->min_pmt = 0;
-       range->max_pmt = 65535 * 1000;  /* ??? */
-       range->pmp_flags = IW_POWER_PERIOD;
-       range->pmt_flags = IW_POWER_TIMEOUT;
-       range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-       range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-       range->retry_flags = IW_RETRY_LIMIT;
-       range->r_time_flags = IW_RETRY_LIFETIME;
-       range->min_retry = 0;
-       range->max_retry = 65535;       /* ??? */
-       range->min_r_time = 0;
-       range->max_r_time = 65535 * 1000;       /* ??? */
-
-       if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
-               range->scan_capa = IW_SCAN_CAPA_ESSID;
-       else
-               range->scan_capa = IW_SCAN_CAPA_NONE;
-
-       /* Event capability (kernel) */
-       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-       /* Event capability (driver) */
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-       IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
-       return 0;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    struct iw_point *erq,
-                                    char *keybuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-       int setindex = priv->tx_key;
-       int encode_alg = priv->encode_alg;
-       int restricted = priv->wep_restrict;
-       u16 xlen = 0;
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (! priv->has_wep)
-               return -EOPNOTSUPP;
-
-       if (erq->pointer) {
-               /* We actually have a key to set - check its length */
-               if (erq->length > LARGE_KEY_SIZE)
-                       return -E2BIG;
-
-               if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
-                       return -E2BIG;
-       }
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* Clear any TKIP key we have */
-       if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
-               (void) orinoco_clear_tkip_key(priv, setindex);
-
-       if (erq->length > 0) {
-               if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-                       index = priv->tx_key;
-
-               /* Adjust key length to a supported value */
-               if (erq->length > SMALL_KEY_SIZE) {
-                       xlen = LARGE_KEY_SIZE;
-               } else if (erq->length > 0) {
-                       xlen = SMALL_KEY_SIZE;
-               } else
-                       xlen = 0;
-
-               /* Switch on WEP if off */
-               if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
-                       setindex = index;
-                       encode_alg = IW_ENCODE_ALG_WEP;
-               }
-       } else {
-               /* Important note : if the user do "iwconfig eth0 enc off",
-                * we will arrive there with an index of -1. This is valid
-                * but need to be taken care off... Jean II */
-               if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
-                       if((index != -1) || (erq->flags == 0)) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-               } else {
-                       /* Set the index : Check that the key is valid */
-                       if(priv->keys[index].len == 0) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       setindex = index;
-               }
-       }
-
-       if (erq->flags & IW_ENCODE_DISABLED)
-               encode_alg = IW_ENCODE_ALG_NONE;
-       if (erq->flags & IW_ENCODE_OPEN)
-               restricted = 0;
-       if (erq->flags & IW_ENCODE_RESTRICTED)
-               restricted = 1;
-
-       if (erq->pointer && erq->length > 0) {
-               priv->keys[index].len = cpu_to_le16(xlen);
-               memset(priv->keys[index].data, 0,
-                      sizeof(priv->keys[index].data));
-               memcpy(priv->keys[index].data, keybuf, erq->length);
-       }
-       priv->tx_key = setindex;
-
-       /* Try fast key change if connected and only keys are changed */
-       if ((priv->encode_alg == encode_alg) &&
-           (priv->wep_restrict == restricted) &&
-           netif_carrier_ok(dev)) {
-               err = __orinoco_hw_setup_wepkeys(priv);
-               /* No need to commit if successful */
-               goto out;
-       }
-
-       priv->encode_alg = encode_alg;
-       priv->wep_restrict = restricted;
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    struct iw_point *erq,
-                                    char *keybuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-       u16 xlen = 0;
-       unsigned long flags;
-
-       if (! priv->has_wep)
-               return -EOPNOTSUPP;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
-               index = priv->tx_key;
-
-       erq->flags = 0;
-       if (!priv->encode_alg)
-               erq->flags |= IW_ENCODE_DISABLED;
-       erq->flags |= index + 1;
-
-       if (priv->wep_restrict)
-               erq->flags |= IW_ENCODE_RESTRICTED;
-       else
-               erq->flags |= IW_ENCODE_OPEN;
-
-       xlen = le16_to_cpu(priv->keys[index].len);
-
-       erq->length = xlen;
-
-       memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
-
-       orinoco_unlock(priv, &flags);
-       return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_point *erq,
-                                 char *essidbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
-        * anyway... - Jean II */
-
-       /* Hum... Should not use Wireless Extension constant (may change),
-        * should use our own... - Jean II */
-       if (erq->length > IW_ESSID_MAX_SIZE)
-               return -E2BIG;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
-       memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
-       /* If not ANY, get the new ESSID */
-       if (erq->flags) {
-               memcpy(priv->desired_essid, essidbuf, erq->length);
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_point *erq,
-                                 char *essidbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int active;
-       int err = 0;
-       unsigned long flags;
-
-       if (netif_running(dev)) {
-               err = orinoco_hw_get_essid(priv, &active, essidbuf);
-               if (err < 0)
-                       return err;
-               erq->length = err;
-       } else {
-               if (orinoco_lock(priv, &flags) != 0)
-                       return -EBUSY;
-               memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
-               erq->length = strlen(priv->desired_essid);
-               orinoco_unlock(priv, &flags);
-       }
-
-       erq->flags = 1;
-
-       return 0;
-}
-
-static int orinoco_ioctl_setnick(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *nrq,
-                                char *nickbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       if (nrq->length > IW_ESSID_MAX_SIZE)
-               return -E2BIG;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       memset(priv->nick, 0, sizeof(priv->nick));
-       memcpy(priv->nick, nickbuf, nrq->length);
-
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *nrq,
-                                char *nickbuf)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
-       orinoco_unlock(priv, &flags);
-
-       nrq->length = strlen(priv->nick);
-
-       return 0;
-}
-
-static int orinoco_ioctl_setfreq(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_freq *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int chan = -1;
-       unsigned long flags;
-       int err = -EINPROGRESS;         /* Call commit handler */
-
-       /* In infrastructure mode the AP sets the channel */
-       if (priv->iw_mode == IW_MODE_INFRA)
-               return -EBUSY;
-
-       if ( (frq->e == 0) && (frq->m <= 1000) ) {
-               /* Setting by channel number */
-               chan = frq->m;
-       } else {
-               /* Setting by frequency - search the table */
-               int mult = 1;
-               int i;
-
-               for (i = 0; i < (6 - frq->e); i++)
-                       mult *= 10;
-
-               for (i = 0; i < NUM_CHANNELS; i++)
-                       if (frq->m == (channel_frequency[i] * mult))
-                               chan = i+1;
-       }
-
-       if ( (chan < 1) || (chan > NUM_CHANNELS) ||
-            ! (priv->channel_mask & (1 << (chan-1)) ) )
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       priv->channel = chan;
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               /* Fast channel change - no commit if successful */
-               hermes_t *hw = &priv->hw;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
-                                           HERMES_TEST_SET_CHANNEL,
-                                       chan, NULL);
-       }
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getfreq(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_freq *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int tmp;
-
-       /* Locking done in there */
-       tmp = orinoco_hw_get_freq(priv);
-       if (tmp < 0) {
-               return tmp;
-       }
-
-       frq->m = tmp;
-       frq->e = 1;
-
-       return 0;
-}
-
-static int orinoco_ioctl_getsens(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       u16 val;
-       int err;
-       unsigned long flags;
-
-       if (!priv->has_sensitivity)
-               return -EOPNOTSUPP;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       err = hermes_read_wordrec(hw, USER_BAP,
-                                 HERMES_RID_CNFSYSTEMSCALE, &val);
-       orinoco_unlock(priv, &flags);
-
-       if (err)
-               return err;
-
-       srq->value = val;
-       srq->fixed = 0; /* auto */
-
-       return 0;
-}
-
-static int orinoco_ioctl_setsens(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int val = srq->value;
-       unsigned long flags;
-
-       if (!priv->has_sensitivity)
-               return -EOPNOTSUPP;
-
-       if ((val < 1) || (val > 3))
-               return -EINVAL;
-       
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       priv->ap_density = val;
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_setrts(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct iw_param *rrq,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int val = rrq->value;
-       unsigned long flags;
-
-       if (rrq->disabled)
-               val = 2347;
-
-       if ( (val < 0) || (val > 2347) )
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       priv->rts_thresh = val;
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getrts(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct iw_param *rrq,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       rrq->value = priv->rts_thresh;
-       rrq->disabled = (rrq->value == 2347);
-       rrq->fixed = 1;
-
-       return 0;
-}
-
-static int orinoco_ioctl_setfrag(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (priv->has_mwo) {
-               if (frq->disabled)
-                       priv->mwo_robust = 0;
-               else {
-                       if (frq->fixed)
-                               printk(KERN_WARNING "%s: Fixed fragmentation is "
-                                      "not supported on this firmware. "
-                                      "Using MWO robust instead.\n", dev->name);
-                       priv->mwo_robust = 1;
-               }
-       } else {
-               if (frq->disabled)
-                       priv->frag_thresh = 2346;
-               else {
-                       if ( (frq->value < 256) || (frq->value > 2346) )
-                               err = -EINVAL;
-                       else
-                               priv->frag_thresh = frq->value & ~0x1; /* must be even */
-               }
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getfrag(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       u16 val;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       
-       if (priv->has_mwo) {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMWOROBUST_AGERE,
-                                         &val);
-               if (err)
-                       val = 0;
-
-               frq->value = val ? 2347 : 0;
-               frq->disabled = ! val;
-               frq->fixed = 0;
-       } else {
-               err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                         &val);
-               if (err)
-                       val = 0;
-
-               frq->value = val;
-               frq->disabled = (val >= 2346);
-               frq->fixed = 1;
-       }
-
-       orinoco_unlock(priv, &flags);
-       
-       return err;
-}
-
-static int orinoco_ioctl_setrate(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *rrq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int ratemode = -1;
-       int bitrate; /* 100s of kilobits */
-       int i;
-       unsigned long flags;
-       
-       /* As the user space doesn't know our highest rate, it uses -1
-        * to ask us to set the highest rate.  Test it using "iwconfig
-        * ethX rate auto" - Jean II */
-       if (rrq->value == -1)
-               bitrate = 110;
-       else {
-               if (rrq->value % 100000)
-                       return -EINVAL;
-               bitrate = rrq->value / 100000;
-       }
-
-       if ( (bitrate != 10) && (bitrate != 20) &&
-            (bitrate != 55) && (bitrate != 110) )
-               return -EINVAL;
-
-       for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-               if ( (bitrate_table[i].bitrate == bitrate) &&
-                    (bitrate_table[i].automatic == ! rrq->fixed) ) {
-                       ratemode = i;
-                       break;
-               }
-       
-       if (ratemode == -1)
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       priv->bitratemode = ratemode;
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;
-}
-
-static int orinoco_ioctl_getrate(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *rrq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       int ratemode;
-       int i;
-       u16 val;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       ratemode = priv->bitratemode;
-
-       BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
-
-       rrq->value = bitrate_table[ratemode].bitrate * 100000;
-       rrq->fixed = ! bitrate_table[ratemode].automatic;
-       rrq->disabled = 0;
-
-       /* If the interface is running we try to find more about the
-          current mode */
-       if (netif_running(dev)) {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CURRENTTXRATE, &val);
-               if (err)
-                       goto out;
-               
-               switch (priv->firmware_type) {
-               case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
-                       /* Note : in Lucent firmware, the return value of
-                        * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
-                        * and therefore is totally different from the
-                        * encoding of HERMES_RID_CNFTXRATECONTROL.
-                        * Don't forget that 6Mb/s is really 5.5Mb/s */
-                       if (val == 6)
-                               rrq->value = 5500000;
-                       else
-                               rrq->value = val * 1000000;
-                       break;
-               case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
-               case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-                       for (i = 0; i < BITRATE_TABLE_SIZE; i++)
-                               if (bitrate_table[i].intersil_txratectrl == val) {
-                                       ratemode = i;
-                                       break;
-                               }
-                       if (i >= BITRATE_TABLE_SIZE)
-                               printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
-                                      dev->name, val);
-
-                       rrq->value = bitrate_table[ratemode].bitrate * 100000;
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_setpower(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *prq,
-                                 char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (prq->disabled) {
-               priv->pm_on = 0;
-       } else {
-               switch (prq->flags & IW_POWER_MODE) {
-               case IW_POWER_UNICAST_R:
-                       priv->pm_mcast = 0;
-                       priv->pm_on = 1;
-                       break;
-               case IW_POWER_ALL_R:
-                       priv->pm_mcast = 1;
-                       priv->pm_on = 1;
-                       break;
-               case IW_POWER_ON:
-                       /* No flags : but we may have a value - Jean II */
-                       break;
-               default:
-                       err = -EINVAL;
-                       goto out;
-               }
-               
-               if (prq->flags & IW_POWER_TIMEOUT) {
-                       priv->pm_on = 1;
-                       priv->pm_timeout = prq->value / 1000;
-               }
-               if (prq->flags & IW_POWER_PERIOD) {
-                       priv->pm_on = 1;
-                       priv->pm_period = prq->value / 1000;
-               }
-               /* It's valid to not have a value if we are just toggling
-                * the flags... Jean II */
-               if(!priv->pm_on) {
-                       err = -EINVAL;
-                       goto out;
-               }                       
-       }
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getpower(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *prq,
-                                 char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u16 enable, period, timeout, mcast;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP,
-                                 HERMES_RID_CNFMAXSLEEPDURATION, &period);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
-       if (err)
-               goto out;
-
-       prq->disabled = !enable;
-       /* Note : by default, display the period */
-       if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-               prq->flags = IW_POWER_TIMEOUT;
-               prq->value = timeout * 1000;
-       } else {
-               prq->flags = IW_POWER_PERIOD;
-               prq->value = period * 1000;
-       }
-       if (mcast)
-               prq->flags |= IW_POWER_ALL_R;
-       else
-               prq->flags |= IW_POWER_UNICAST_R;
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
-                                      struct iw_request_info *info,
-                                      union iwreq_data *wrqu,
-                                      char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct iw_point *encoding = &wrqu->encoding;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       int idx, alg = ext->alg, set_key = 1;
-       unsigned long flags;
-       int err = -EINVAL;
-       u16 key_len;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* Determine and validate the key index */
-       idx = encoding->flags & IW_ENCODE_INDEX;
-       if (idx) {
-               if ((idx < 1) || (idx > WEP_KEYS))
-                       goto out;
-               idx--;
-       } else
-               idx = priv->tx_key;
-
-       if (encoding->flags & IW_ENCODE_DISABLED)
-           alg = IW_ENCODE_ALG_NONE;
-
-       if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
-               /* Clear any TKIP TX key we had */
-               (void) orinoco_clear_tkip_key(priv, priv->tx_key);
-       }
-
-       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
-               priv->tx_key = idx;
-               set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
-                          (ext->key_len > 0)) ? 1 : 0;
-       }
-
-       if (set_key) {
-               /* Set the requested key first */
-               switch (alg) {
-               case IW_ENCODE_ALG_NONE:
-                       priv->encode_alg = alg;
-                       priv->keys[idx].len = 0;
-                       break;
-
-               case IW_ENCODE_ALG_WEP:
-                       if (ext->key_len > SMALL_KEY_SIZE)
-                               key_len = LARGE_KEY_SIZE;
-                       else if (ext->key_len > 0)
-                               key_len = SMALL_KEY_SIZE;
-                       else
-                               goto out;
-
-                       priv->encode_alg = alg;
-                       priv->keys[idx].len = cpu_to_le16(key_len);
-
-                       key_len = min(ext->key_len, key_len);
-
-                       memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
-                       memcpy(priv->keys[idx].data, ext->key, key_len);
-                       break;
-
-               case IW_ENCODE_ALG_TKIP:
-               {
-                       hermes_t *hw = &priv->hw;
-                       u8 *tkip_iv = NULL;
-
-                       if (!priv->has_wpa ||
-                           (ext->key_len > sizeof(priv->tkip_key[0])))
-                               goto out;
-
-                       priv->encode_alg = alg;
-                       memset(&priv->tkip_key[idx], 0,
-                              sizeof(priv->tkip_key[idx]));
-                       memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
-
-                       if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-                               tkip_iv = &ext->rx_seq[0];
-
-                       err = __orinoco_hw_set_tkip_key(hw, idx,
-                                ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
-                                (u8 *) &priv->tkip_key[idx],
-                                tkip_iv, NULL);
-                       if (err)
-                               printk(KERN_ERR "%s: Error %d setting TKIP key"
-                                      "\n", dev->name, err);
-
-                       goto out;
-               }
-               default:
-                       goto out;
-               }
-       }
-       err = -EINPROGRESS;
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
-                                      struct iw_request_info *info,
-                                      union iwreq_data *wrqu,
-                                      char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct iw_point *encoding = &wrqu->encoding;
-       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-       int idx, max_key_len;
-       unsigned long flags;
-       int err;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = -EINVAL;
-       max_key_len = encoding->length - sizeof(*ext);
-       if (max_key_len < 0)
-               goto out;
-
-       idx = encoding->flags & IW_ENCODE_INDEX;
-       if (idx) {
-               if ((idx < 1) || (idx > WEP_KEYS))
-                       goto out;
-               idx--;
-       } else
-               idx = priv->tx_key;
-
-       encoding->flags = idx + 1;
-       memset(ext, 0, sizeof(*ext));
-
-       ext->alg = priv->encode_alg;
-       switch (priv->encode_alg) {
-       case IW_ENCODE_ALG_NONE:
-               ext->key_len = 0;
-               encoding->flags |= IW_ENCODE_DISABLED;
-               break;
-       case IW_ENCODE_ALG_WEP:
-               ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
-                                    max_key_len);
-               memcpy(ext->key, priv->keys[idx].data, ext->key_len);
-               encoding->flags |= IW_ENCODE_ENABLED;
-               break;
-       case IW_ENCODE_ALG_TKIP:
-               ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
-                                    max_key_len);
-               memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
-               encoding->flags |= IW_ENCODE_ENABLED;
-               break;
-       }
-
-       err = 0;
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *wrqu, char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       struct iw_param *param = &wrqu->param;
-       unsigned long flags;
-       int ret = -EINPROGRESS;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (param->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-       case IW_AUTH_CIPHER_PAIRWISE:
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-       case IW_AUTH_PRIVACY_INVOKED:
-       case IW_AUTH_DROP_UNENCRYPTED:
-               /*
-                * orinoco does not use these parameters
-                */
-               break;
-
-       case IW_AUTH_KEY_MGMT:
-               /* wl_lkm implies value 2 == PSK for Hermes I
-                * which ties in with WEXT
-                * no other hints tho :(
-                */
-               priv->key_mgmt = param->value;
-               break;
-
-       case IW_AUTH_TKIP_COUNTERMEASURES:
-               /* When countermeasures are enabled, shut down the
-                * card; when disabled, re-enable the card. This must
-                * take effect immediately.
-                *
-                * TODO: Make sure that the EAPOL message is getting
-                *       out before card disabled
-                */
-               if (param->value) {
-                       priv->tkip_cm_active = 1;
-                       ret = hermes_enable_port(hw, 0);
-               } else {
-                       priv->tkip_cm_active = 0;
-                       ret = hermes_disable_port(hw, 0);
-               }
-               break;
-
-       case IW_AUTH_80211_AUTH_ALG:
-               if (param->value & IW_AUTH_ALG_SHARED_KEY)
-                       priv->wep_restrict = 1;
-               else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
-                       priv->wep_restrict = 0;
-               else
-                       ret = -EINVAL;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               if (priv->has_wpa) {
-                       priv->wpa_enabled = param->value ? 1 : 0;
-               } else {
-                       if (param->value)
-                               ret = -EOPNOTSUPP;
-                       /* else silently accept disable of WPA */
-                       priv->wpa_enabled = 0;
-               }
-               break;
-
-       default:
-               ret = -EOPNOTSUPP;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *wrqu, char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct iw_param *param = &wrqu->param;
-       unsigned long flags;
-       int ret = 0;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (param->flags & IW_AUTH_INDEX) {
-       case IW_AUTH_KEY_MGMT:
-               param->value = priv->key_mgmt;
-               break;
-
-       case IW_AUTH_TKIP_COUNTERMEASURES:
-               param->value = priv->tkip_cm_active;
-               break;
-
-       case IW_AUTH_80211_AUTH_ALG:
-               if (priv->wep_restrict)
-                       param->value = IW_AUTH_ALG_SHARED_KEY;
-               else
-                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
-               break;
-
-       case IW_AUTH_WPA_ENABLED:
-               param->value = priv->wpa_enabled;
-               break;
-
-       default:
-               ret = -EOPNOTSUPP;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  union iwreq_data *wrqu, char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       u8 *buf;
-       unsigned long flags;
-       int err = 0;
-
-       if ((wrqu->data.length > MAX_WPA_IE_LEN) ||
-           (wrqu->data.length && (extra == NULL)))
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (wrqu->data.length) {
-               buf = kmalloc(wrqu->data.length, GFP_KERNEL);
-               if (buf == NULL) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-
-               memcpy(buf, extra, wrqu->data.length);
-               kfree(priv->wpa_ie);
-               priv->wpa_ie = buf;
-               priv->wpa_ie_len = wrqu->data.length;
-       } else {
-               kfree(priv->wpa_ie);
-               priv->wpa_ie = NULL;
-               priv->wpa_ie_len = 0;
-       }
-
-       if (priv->wpa_ie) {
-               /* Looks like wl_lkm wants to check the auth alg, and
-                * somehow pass it to the firmware.
-                * Instead it just calls the key mgmt rid
-                *   - we do this in set auth.
-                */
-       }
-
-out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  union iwreq_data *wrqu, char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err = 0;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
-               wrqu->data.length = 0;
-               goto out;
-       }
-
-       if (wrqu->data.length < priv->wpa_ie_len) {
-               err = -E2BIG;
-               goto out;
-       }
-
-       wrqu->data.length = priv->wpa_ie_len;
-       memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 union iwreq_data *wrqu, char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       struct iw_mlme *mlme = (struct iw_mlme *)extra;
-       unsigned long flags;
-       int ret = 0;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (mlme->cmd) {
-       case IW_MLME_DEAUTH:
-               /* silently ignore */
-               break;
-
-       case IW_MLME_DISASSOC:
-       {
-               struct {
-                       u8 addr[ETH_ALEN];
-                       __le16 reason_code;
-               } __attribute__ ((packed)) buf;
-
-               memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
-               buf.reason_code = cpu_to_le16(mlme->reason_code);
-               ret = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                         HERMES_RID_CNFDISASSOCIATE,
-                                         &buf);
-               break;
-       }
-       default:
-               ret = -EOPNOTSUPP;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return ret;
-}
-
-static int orinoco_ioctl_getretry(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rrq,
-                                 char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u16 short_limit, long_limit, lifetime;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-       
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
-                                 &short_limit);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
-                                 &long_limit);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
-                                 &lifetime);
-       if (err)
-               goto out;
-
-       rrq->disabled = 0;              /* Can't be disabled */
-
-       /* Note : by default, display the retry number */
-       if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-               rrq->flags = IW_RETRY_LIFETIME;
-               rrq->value = lifetime * 1000;   /* ??? */
-       } else {
-               /* By default, display the min number */
-               if ((rrq->flags & IW_RETRY_LONG)) {
-                       rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-                       rrq->value = long_limit;
-               } else {
-                       rrq->flags = IW_RETRY_LIMIT;
-                       rrq->value = short_limit;
-                       if(short_limit != long_limit)
-                               rrq->flags |= IW_RETRY_SHORT;
-               }
-       }
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_reset(struct net_device *dev,
-                              struct iw_request_info *info,
-                              void *wrqu,
-                              char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       if (! capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
-               printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-
-               /* Firmware reset */
-               orinoco_reset(&priv->reset_work);
-       } else {
-               printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
-               schedule_work(&priv->reset_work);
-       }
-
-       return 0;
-}
-
-static int orinoco_ioctl_setibssport(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    void *wrqu,
-                                    char *extra)
-
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int val = *( (int *) extra );
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       priv->ibss_port = val ;
-
-       /* Actually update the mode we are using */
-       set_port_type(priv);
-
-       orinoco_unlock(priv, &flags);
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getibssport(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    void *wrqu,
-                                    char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int *val = (int *) extra;
-
-       *val = priv->ibss_port;
-       return 0;
-}
-
-static int orinoco_ioctl_setport3(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 void *wrqu,
-                                 char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int val = *( (int *) extra );
-       int err = 0;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       switch (val) {
-       case 0: /* Try to do IEEE ad-hoc mode */
-               if (! priv->has_ibss) {
-                       err = -EINVAL;
-                       break;
-               }
-               priv->prefer_port3 = 0;
-                       
-               break;
-
-       case 1: /* Try to do Lucent proprietary ad-hoc mode */
-               if (! priv->has_port3) {
-                       err = -EINVAL;
-                       break;
-               }
-               priv->prefer_port3 = 1;
-               break;
-
-       default:
-               err = -EINVAL;
-       }
-
-       if (! err) {
-               /* Actually update the mode we are using */
-               set_port_type(priv);
-               err = -EINPROGRESS;
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getport3(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 void *wrqu,
-                                 char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int *val = (int *) extra;
-
-       *val = priv->prefer_port3;
-       return 0;
-}
-
-static int orinoco_ioctl_setpreamble(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    void *wrqu,
-                                    char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int val;
-
-       if (! priv->has_preamble)
-               return -EOPNOTSUPP;
-
-       /* 802.11b has recently defined some short preamble.
-        * Basically, the Phy header has been reduced in size.
-        * This increase performance, especially at high rates
-        * (the preamble is transmitted at 1Mb/s), unfortunately
-        * this give compatibility troubles... - Jean II */
-       val = *( (int *) extra );
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (val)
-               priv->preamble = 1;
-       else
-               priv->preamble = 0;
-
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getpreamble(struct net_device *dev,
-                                    struct iw_request_info *info,
-                                    void *wrqu,
-                                    char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int *val = (int *) extra;
-
-       if (! priv->has_preamble)
-               return -EOPNOTSUPP;
-
-       *val = priv->preamble;
-       return 0;
-}
-
-/* ioctl interface to hermes_read_ltv()
- * To use with iwpriv, pass the RID as the token argument, e.g.
- * iwpriv get_rid [0xfc00]
- * At least Wireless Tools 25 is required to use iwpriv.
- * For Wireless Tools 25 and 26 append "dummy" are the end. */
-static int orinoco_ioctl_getrid(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct iw_point *data,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int rid = data->flags;
-       u16 length;
-       int err;
-       unsigned long flags;
-
-       /* It's a "get" function, but we don't want users to access the
-        * WEP key and other raw firmware data */
-       if (! capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       if (rid < 0xfc00 || rid > 0xffff)
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
-                             extra);
-       if (err)
-               goto out;
-
-       data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
-                            MAX_RID_LEN);
-
- out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       struct iw_scan_req *si = (struct iw_scan_req *) extra;
-       int err = 0;
-       unsigned long flags;
-
-       /* Note : you may have realised that, as this is a SET operation,
-        * this is privileged and therefore a normal user can't
-        * perform scanning.
-        * This is not an error, while the device perform scanning,
-        * traffic doesn't flow, so it's a perfect DoS...
-        * Jean II */
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       /* Scanning with port 0 disabled would fail */
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       /* In monitor mode, the scan results are always empty.
-        * Probe responses are passed to the driver as received
-        * frames and could be processed in software. */
-       if (priv->iw_mode == IW_MODE_MONITOR) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       /* Note : because we don't lock out the irq handler, the way
-        * we access scan variables in priv is critical.
-        *      o scan_inprogress : not touched by irq handler
-        *      o scan_mode : not touched by irq handler
-        * Before modifying anything on those variables, please think hard !
-        * Jean II */
-
-       /* Save flags */
-       priv->scan_mode = srq->flags;
-
-       /* Always trigger scanning, even if it's in progress.
-        * This way, if the info frame get lost, we will recover somewhat
-        * gracefully  - Jean II */
-
-       if (priv->has_hostscan) {
-               switch (priv->firmware_type) {
-               case FIRMWARE_TYPE_SYMBOL:
-                       err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFHOSTSCAN_SYMBOL,
-                                                  HERMES_HOSTSCAN_SYMBOL_ONCE |
-                                                  HERMES_HOSTSCAN_SYMBOL_BCAST);
-                       break;
-               case FIRMWARE_TYPE_INTERSIL: {
-                       __le16 req[3];
-
-                       req[0] = cpu_to_le16(0x3fff);   /* All channels */
-                       req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
-                       req[2] = 0;                     /* Any ESSID */
-                       err = HERMES_WRITE_RECORD(hw, USER_BAP,
-                                                 HERMES_RID_CNFHOSTSCAN, &req);
-               }
-               break;
-               case FIRMWARE_TYPE_AGERE:
-                       if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
-                               struct hermes_idstring idbuf;
-                               size_t len = min(sizeof(idbuf.val),
-                                                (size_t) si->essid_len);
-                               idbuf.len = cpu_to_le16(len);
-                               memcpy(idbuf.val, si->essid, len);
-
-                               err = hermes_write_ltv(hw, USER_BAP,
-                                              HERMES_RID_CNFSCANSSID_AGERE,
-                                              HERMES_BYTES_TO_RECLEN(len + 2),
-                                              &idbuf);
-                       } else
-                               err = hermes_write_wordrec(hw, USER_BAP,
-                                                  HERMES_RID_CNFSCANSSID_AGERE,
-                                                  0);  /* Any ESSID */
-                       if (err)
-                               break;
-
-                       if (priv->has_ext_scan) {
-                               /* Clear scan results at the start of
-                                * an extended scan */
-                               orinoco_clear_scan_results(priv,
-                                               msecs_to_jiffies(15000));
-
-                               /* TODO: Is this available on older firmware?
-                                *   Can we use it to scan specific channels
-                                *   for IW_SCAN_THIS_FREQ? */
-                               err = hermes_write_wordrec(hw, USER_BAP,
-                                               HERMES_RID_CNFSCANCHANNELS2GHZ,
-                                               0x7FFF);
-                               if (err)
-                                       goto out;
-
-                               err = hermes_inquire(hw,
-                                                    HERMES_INQ_CHANNELINFO);
-                       } else
-                               err = hermes_inquire(hw, HERMES_INQ_SCAN);
-                       break;
-               }
-       } else
-               err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
-       /* One more client */
-       if (! err)
-               priv->scan_inprogress = 1;
-
- out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
-                                          struct iw_request_info *info,
-                                          char *current_ev,
-                                          char *end_buf,
-                                          union hermes_scan_info *bss,
-                                          unsigned int last_scanned)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       u16                     capabilities;
-       u16                     channel;
-       struct iw_event         iwe;            /* Temporary buffer */
-       char custom[MAX_CUSTOM_LEN];
-
-       memset(&iwe, 0, sizeof(iwe));
-
-       /* First entry *MUST* be the AP MAC address */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_ADDR_LEN);
-
-       /* Other entries will be displayed in the order we give them */
-
-       /* Add the ESSID */
-       iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
-       if (iwe.u.data.length > 32)
-               iwe.u.data.length = 32;
-       iwe.cmd = SIOCGIWESSID;
-       iwe.u.data.flags = 1;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, bss->a.essid);
-
-       /* Add mode */
-       iwe.cmd = SIOCGIWMODE;
-       capabilities = le16_to_cpu(bss->a.capabilities);
-       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-               if (capabilities & WLAN_CAPABILITY_ESS)
-                       iwe.u.mode = IW_MODE_MASTER;
-               else
-                       iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_UINT_LEN);
-       }
-
-       channel = bss->s.channel;
-       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-               /* Add channel and frequency */
-               iwe.cmd = SIOCGIWFREQ;
-               iwe.u.freq.m = channel;
-               iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-
-               iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-               iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-       }
-
-       /* Add quality statistics. level and noise in dB. No link quality */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-       iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
-       iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
-       /* Wireless tools prior to 27.pre22 will show link quality
-        * anyway, so we provide a reasonable value. */
-       if (iwe.u.qual.level > iwe.u.qual.noise)
-               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-       else
-               iwe.u.qual.qual = 0;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_QUAL_LEN);
-
-       /* Add encryption capability */
-       iwe.cmd = SIOCGIWENCODE;
-       if (capabilities & WLAN_CAPABILITY_PRIVACY)
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       else
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, NULL);
-
-       /* Bit rate is not available in Lucent/Agere firmwares */
-       if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-               char *current_val = current_ev + iwe_stream_lcp_len(info);
-               int i;
-               int step;
-
-               if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-                       step = 2;
-               else
-                       step = 1;
-
-               iwe.cmd = SIOCGIWRATE;
-               /* Those two flags are ignored... */
-               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-               /* Max 10 values */
-               for (i = 0; i < 10; i += step) {
-                       /* NULL terminated */
-                       if (bss->p.rates[i] == 0x0)
-                               break;
-                       /* Bit rate given in 500 kb/s units (+ 0x80) */
-                       iwe.u.bitrate.value =
-                               ((bss->p.rates[i] & 0x7f) * 500000);
-                       current_val = iwe_stream_add_value(info, current_ev,
-                                                          current_val,
-                                                          end_buf, &iwe,
-                                                          IW_EV_PARAM_LEN);
-               }
-               /* Check if we added any event */
-               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
-                       current_ev = current_val;
-       }
-
-       /* Beacon interval */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "bcn_int=%d",
-                                    le16_to_cpu(bss->a.beacon_interv));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Capabilites */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "capab=0x%04x",
-                                    capabilities);
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Add EXTRA: Age to display seconds since last beacon/probe response
-        * for given network. */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    " Last beacon: %dms ago",
-                                    jiffies_to_msecs(jiffies - last_scanned));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
-                                              struct iw_request_info *info,
-                                              char *current_ev,
-                                              char *end_buf,
-                                              struct agere_ext_scan_info *bss,
-                                              unsigned int last_scanned)
-{
-       u16                     capabilities;
-       u16                     channel;
-       struct iw_event         iwe;            /* Temporary buffer */
-       char custom[MAX_CUSTOM_LEN];
-       u8 *ie;
-
-       memset(&iwe, 0, sizeof(iwe));
-
-       /* First entry *MUST* be the AP MAC address */
-       iwe.cmd = SIOCGIWAP;
-       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-       memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_ADDR_LEN);
-
-       /* Other entries will be displayed in the order we give them */
-
-       /* Add the ESSID */
-       ie = bss->data;
-       iwe.u.data.length = ie[1];
-       if (iwe.u.data.length) {
-               if (iwe.u.data.length > 32)
-                       iwe.u.data.length = 32;
-               iwe.cmd = SIOCGIWESSID;
-               iwe.u.data.flags = 1;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, &ie[2]);
-       }
-
-       /* Add mode */
-       capabilities = le16_to_cpu(bss->capabilities);
-       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
-               iwe.cmd = SIOCGIWMODE;
-               if (capabilities & WLAN_CAPABILITY_ESS)
-                       iwe.u.mode = IW_MODE_MASTER;
-               else
-                       iwe.u.mode = IW_MODE_ADHOC;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_UINT_LEN);
-       }
-
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET);
-       channel = ie ? ie[2] : 0;
-       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
-               /* Add channel and frequency */
-               iwe.cmd = SIOCGIWFREQ;
-               iwe.u.freq.m = channel;
-               iwe.u.freq.e = 0;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-
-               iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-               iwe.u.freq.e = 1;
-               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                                 &iwe, IW_EV_FREQ_LEN);
-       }
-
-       /* Add quality statistics. level and noise in dB. No link quality */
-       iwe.cmd = IWEVQUAL;
-       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
-       iwe.u.qual.level = bss->level - 0x95;
-       iwe.u.qual.noise = bss->noise - 0x95;
-       /* Wireless tools prior to 27.pre22 will show link quality
-        * anyway, so we provide a reasonable value. */
-       if (iwe.u.qual.level > iwe.u.qual.noise)
-               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-       else
-               iwe.u.qual.qual = 0;
-       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
-                                         &iwe, IW_EV_QUAL_LEN);
-
-       /* Add encryption capability */
-       iwe.cmd = SIOCGIWENCODE;
-       if (capabilities & WLAN_CAPABILITY_PRIVACY)
-               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
-       else
-               iwe.u.data.flags = IW_ENCODE_DISABLED;
-       iwe.u.data.length = 0;
-       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                         &iwe, NULL);
-
-       /* WPA IE */
-       ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
-       if (ie) {
-               iwe.cmd = IWEVGENIE;
-               iwe.u.data.length = ie[1] + 2;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, ie);
-       }
-
-       /* RSN IE */
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN);
-       if (ie) {
-               iwe.cmd = IWEVGENIE;
-               iwe.u.data.length = ie[1] + 2;
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, ie);
-       }
-
-       ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES);
-       if (ie) {
-               char *p = current_ev + iwe_stream_lcp_len(info);
-               int i;
-
-               iwe.cmd = SIOCGIWRATE;
-               /* Those two flags are ignored... */
-               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
-               for (i = 2; i < (ie[1] + 2); i++) {
-                       iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
-                       p = iwe_stream_add_value(info, current_ev, p, end_buf,
-                                                &iwe, IW_EV_PARAM_LEN);
-               }
-               /* Check if we added any event */
-               if (p > (current_ev + iwe_stream_lcp_len(info)))
-                       current_ev = p;
-       }
-
-       /* Timestamp */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length =
-               snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
-                        (unsigned long long) le64_to_cpu(bss->timestamp));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Beacon interval */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "bcn_int=%d",
-                                    le16_to_cpu(bss->beacon_interval));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Capabilites */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    "capab=0x%04x",
-                                    capabilities);
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       /* Add EXTRA: Age to display seconds since last beacon/probe response
-        * for given network. */
-       iwe.cmd = IWEVCUSTOM;
-       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
-                                    " Last beacon: %dms ago",
-                                    jiffies_to_msecs(jiffies - last_scanned));
-       if (iwe.u.data.length)
-               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
-                                                 &iwe, custom);
-
-       return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *srq,
-                                char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       int err = 0;
-       unsigned long flags;
-       char *current_ev = extra;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (priv->scan_inprogress) {
-               /* Important note : we don't want to block the caller
-                * until results are ready for various reasons.
-                * First, managing wait queues is complex and racy.
-                * Second, we grab some rtnetlink lock before comming
-                * here (in dev_ioctl()).
-                * Third, we generate an Wireless Event, so the
-                * caller can wait itself on that - Jean II */
-               err = -EAGAIN;
-               goto out;
-       }
-
-       if (priv->has_ext_scan) {
-               struct xbss_element *bss;
-
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       /* Translate this entry to WE format */
-                       current_ev =
-                               orinoco_translate_ext_scan(dev, info,
-                                                          current_ev,
-                                                          extra + srq->length,
-                                                          &bss->bss,
-                                                          bss->last_scanned);
-
-                       /* Check if there is space for one more entry */
-                       if ((extra + srq->length - current_ev)
-                           <= IW_EV_ADDR_LEN) {
-                               /* Ask user space to try again with a
-                                * bigger buffer */
-                               err = -E2BIG;
-                               goto out;
-                       }
-               }
-
-       } else {
-               struct bss_element *bss;
-
-               list_for_each_entry(bss, &priv->bss_list, list) {
-                       /* Translate this entry to WE format */
-                       current_ev = orinoco_translate_scan(dev, info,
-                                                           current_ev,
-                                                           extra + srq->length,
-                                                           &bss->bss,
-                                                           bss->last_scanned);
-
-                       /* Check if there is space for one more entry */
-                       if ((extra + srq->length - current_ev)
-                           <= IW_EV_ADDR_LEN) {
-                               /* Ask user space to try again with a
-                                * bigger buffer */
-                               err = -E2BIG;
-                               goto out;
-                       }
-               }
-       }
-
-       srq->length = (current_ev - extra);
-       srq->flags = (__u16) priv->scan_mode;
-
-out:
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-/* Commit handler, called after set operations */
-static int orinoco_ioctl_commit(struct net_device *dev,
-                               struct iw_request_info *info,
-                               void *wrqu,
-                               char *extra)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct hermes *hw = &priv->hw;
-       unsigned long flags;
-       int err = 0;
-
-       if (!priv->open)
-               return 0;
-
-       if (priv->broken_disableport) {
-               orinoco_reset(&priv->reset_work);
-               return 0;
-       }
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return err;
-
-       err = hermes_disable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to disable port "
-                      "while reconfiguring card\n", dev->name);
-               priv->broken_disableport = 1;
-               goto out;
-       }
-
-       err = __orinoco_program_rids(dev);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
-                      dev->name);
-               goto out;
-       }
-
-       err = hermes_enable_port(hw, 0);
-       if (err) {
-               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
-                      dev->name);
-               goto out;
-       }
-
- out:
-       if (err) {
-               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
-               schedule_work(&priv->reset_work);
-               err = 0;
-       }
-
-       orinoco_unlock(priv, &flags);
-       return err;
-}
-
-static const struct iw_priv_args orinoco_privtab[] = {
-       { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-       { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-       { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         0, "set_port3" },
-       { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         "get_port3" },
-       { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         0, "set_preamble" },
-       { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         "get_preamble" },
-       { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         0, "set_ibssport" },
-       { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-         "get_ibssport" },
-       { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
-         "get_rid" },
-};
-
-
-/*
- * Structures to export the Wireless Handlers
- */
-
-#define STD_IW_HANDLER(id, func) \
-       [IW_IOCTL_IDX(id)] = (iw_handler) func
-static const iw_handler        orinoco_handler[] = {
-       STD_IW_HANDLER(SIOCSIWCOMMIT,   orinoco_ioctl_commit),
-       STD_IW_HANDLER(SIOCGIWNAME,     orinoco_ioctl_getname),
-       STD_IW_HANDLER(SIOCSIWFREQ,     orinoco_ioctl_setfreq),
-       STD_IW_HANDLER(SIOCGIWFREQ,     orinoco_ioctl_getfreq),
-       STD_IW_HANDLER(SIOCSIWMODE,     orinoco_ioctl_setmode),
-       STD_IW_HANDLER(SIOCGIWMODE,     orinoco_ioctl_getmode),
-       STD_IW_HANDLER(SIOCSIWSENS,     orinoco_ioctl_setsens),
-       STD_IW_HANDLER(SIOCGIWSENS,     orinoco_ioctl_getsens),
-       STD_IW_HANDLER(SIOCGIWRANGE,    orinoco_ioctl_getiwrange),
-       STD_IW_HANDLER(SIOCSIWSPY,      iw_handler_set_spy),
-       STD_IW_HANDLER(SIOCGIWSPY,      iw_handler_get_spy),
-       STD_IW_HANDLER(SIOCSIWTHRSPY,   iw_handler_set_thrspy),
-       STD_IW_HANDLER(SIOCGIWTHRSPY,   iw_handler_get_thrspy),
-       STD_IW_HANDLER(SIOCSIWAP,       orinoco_ioctl_setwap),
-       STD_IW_HANDLER(SIOCGIWAP,       orinoco_ioctl_getwap),
-       STD_IW_HANDLER(SIOCSIWSCAN,     orinoco_ioctl_setscan),
-       STD_IW_HANDLER(SIOCGIWSCAN,     orinoco_ioctl_getscan),
-       STD_IW_HANDLER(SIOCSIWESSID,    orinoco_ioctl_setessid),
-       STD_IW_HANDLER(SIOCGIWESSID,    orinoco_ioctl_getessid),
-       STD_IW_HANDLER(SIOCSIWNICKN,    orinoco_ioctl_setnick),
-       STD_IW_HANDLER(SIOCGIWNICKN,    orinoco_ioctl_getnick),
-       STD_IW_HANDLER(SIOCSIWRATE,     orinoco_ioctl_setrate),
-       STD_IW_HANDLER(SIOCGIWRATE,     orinoco_ioctl_getrate),
-       STD_IW_HANDLER(SIOCSIWRTS,      orinoco_ioctl_setrts),
-       STD_IW_HANDLER(SIOCGIWRTS,      orinoco_ioctl_getrts),
-       STD_IW_HANDLER(SIOCSIWFRAG,     orinoco_ioctl_setfrag),
-       STD_IW_HANDLER(SIOCGIWFRAG,     orinoco_ioctl_getfrag),
-       STD_IW_HANDLER(SIOCGIWRETRY,    orinoco_ioctl_getretry),
-       STD_IW_HANDLER(SIOCSIWENCODE,   orinoco_ioctl_setiwencode),
-       STD_IW_HANDLER(SIOCGIWENCODE,   orinoco_ioctl_getiwencode),
-       STD_IW_HANDLER(SIOCSIWPOWER,    orinoco_ioctl_setpower),
-       STD_IW_HANDLER(SIOCGIWPOWER,    orinoco_ioctl_getpower),
-       STD_IW_HANDLER(SIOCSIWGENIE,    orinoco_ioctl_set_genie),
-       STD_IW_HANDLER(SIOCGIWGENIE,    orinoco_ioctl_get_genie),
-       STD_IW_HANDLER(SIOCSIWMLME,     orinoco_ioctl_set_mlme),
-       STD_IW_HANDLER(SIOCSIWAUTH,     orinoco_ioctl_set_auth),
-       STD_IW_HANDLER(SIOCGIWAUTH,     orinoco_ioctl_get_auth),
-       STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
-       STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
-};
-
-
-/*
-  Added typecasting since we no longer use iwreq_data -- Moustafa
- */
-static const iw_handler        orinoco_private_handler[] = {
-       [0] = (iw_handler) orinoco_ioctl_reset,
-       [1] = (iw_handler) orinoco_ioctl_reset,
-       [2] = (iw_handler) orinoco_ioctl_setport3,
-       [3] = (iw_handler) orinoco_ioctl_getport3,
-       [4] = (iw_handler) orinoco_ioctl_setpreamble,
-       [5] = (iw_handler) orinoco_ioctl_getpreamble,
-       [6] = (iw_handler) orinoco_ioctl_setibssport,
-       [7] = (iw_handler) orinoco_ioctl_getibssport,
-       [9] = (iw_handler) orinoco_ioctl_getrid,
-};
-
-static const struct iw_handler_def orinoco_handler_def = {
-       .num_standard = ARRAY_SIZE(orinoco_handler),
-       .num_private = ARRAY_SIZE(orinoco_private_handler),
-       .num_private_args = ARRAY_SIZE(orinoco_privtab),
-       .standard = orinoco_handler,
-       .private = orinoco_private_handler,
-       .private_args = orinoco_privtab,
-       .get_wireless_stats = orinoco_get_wireless_stats,
-};
-
-static void orinoco_get_drvinfo(struct net_device *dev,
-                               struct ethtool_drvinfo *info)
-{
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
-       strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
-       strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
-       if (dev->dev.parent)
-               strncpy(info->bus_info, dev->dev.parent->bus_id,
-                       sizeof(info->bus_info) - 1);
-       else
-               snprintf(info->bus_info, sizeof(info->bus_info) - 1,
-                        "PCMCIA %p", priv->hw.iobase);
-}
-
-static const struct ethtool_ops orinoco_ethtool_ops = {
-       .get_drvinfo = orinoco_get_drvinfo,
-       .get_link = ethtool_op_get_link,
-};
-
-/********************************************************************/
-/* Module initialization                                            */
-/********************************************************************/
-
-EXPORT_SYMBOL(alloc_orinocodev);
-EXPORT_SYMBOL(free_orinocodev);
-
-EXPORT_SYMBOL(__orinoco_up);
-EXPORT_SYMBOL(__orinoco_down);
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-EXPORT_SYMBOL(orinoco_interrupt);
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (David Gibson <hermes@gibson.dropbear.id.au>, "
-       "Pavel Roskin <proski@gnu.org>, et al)";
-
-static int __init init_orinoco(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-       return 0;
-}
-
-static void __exit exit_orinoco(void)
-{
-}
-
-module_init(init_orinoco);
-module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
deleted file mode 100644 (file)
index 8c29538..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/* orinoco.h
- * 
- * Common definitions to all pieces of the various orinoco
- * drivers
- */
-
-#ifndef _ORINOCO_H
-#define _ORINOCO_H
-
-#define DRIVER_VERSION "0.15"
-
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include "hermes.h"
-
-/* To enable debug messages */
-//#define ORINOCO_DEBUG                3
-
-#define WIRELESS_SPY           // enable iwspy support
-
-#define MAX_SCAN_LEN           4096
-
-#define ORINOCO_MAX_KEY_SIZE   14
-#define ORINOCO_MAX_KEYS       4
-
-struct orinoco_key {
-       __le16 len;     /* always stored as little-endian */
-       char data[ORINOCO_MAX_KEY_SIZE];
-} __attribute__ ((packed));
-
-#define TKIP_KEYLEN    16
-#define MIC_KEYLEN     8
-
-struct orinoco_tkip_key {
-       u8 tkip[TKIP_KEYLEN];
-       u8 tx_mic[MIC_KEYLEN];
-       u8 rx_mic[MIC_KEYLEN];
-};
-
-typedef enum {
-       FIRMWARE_TYPE_AGERE,
-       FIRMWARE_TYPE_INTERSIL,
-       FIRMWARE_TYPE_SYMBOL
-} fwtype_t;
-
-struct bss_element {
-       union hermes_scan_info bss;
-       unsigned long last_scanned;
-       struct list_head list;
-};
-
-struct xbss_element {
-       struct agere_ext_scan_info bss;
-       unsigned long last_scanned;
-       struct list_head list;
-};
-
-struct hermes_rx_descriptor;
-
-struct orinoco_rx_data {
-       struct hermes_rx_descriptor *desc;
-       struct sk_buff *skb;
-       struct list_head list;
-};
-
-struct firmware;
-
-struct orinoco_private {
-       void *card;     /* Pointer to card dependent structure */
-       struct device *dev;
-       int (*hard_reset)(struct orinoco_private *);
-       int (*stop_fw)(struct orinoco_private *, int);
-
-       /* Synchronisation stuff */
-       spinlock_t lock;
-       int hw_unavailable;
-       struct work_struct reset_work;
-
-       /* Interrupt tasklets */
-       struct tasklet_struct rx_tasklet;
-       struct list_head rx_list;
-       struct orinoco_rx_data *rx_data;
-
-       /* driver state */
-       int open;
-       u16 last_linkstatus;
-       struct work_struct join_work;
-       struct work_struct wevent_work;
-
-       /* Net device stuff */
-       struct net_device *ndev;
-       struct net_device_stats stats;
-       struct iw_statistics wstats;
-
-       /* Hardware control variables */
-       hermes_t hw;
-       u16 txfid;
-
-       /* Capabilities of the hardware/firmware */
-       fwtype_t firmware_type;
-       char fw_name[32];
-       int ibss_port;
-       int nicbuf_size;
-       u16 channel_mask;
-
-       /* Boolean capabilities */
-       unsigned int has_ibss:1;
-       unsigned int has_port3:1;
-       unsigned int has_wep:1;
-       unsigned int has_big_wep:1;
-       unsigned int has_mwo:1;
-       unsigned int has_pm:1;
-       unsigned int has_preamble:1;
-       unsigned int has_sensitivity:1;
-       unsigned int has_hostscan:1;
-       unsigned int has_alt_txcntl:1;
-       unsigned int has_ext_scan:1;
-       unsigned int has_wpa:1;
-       unsigned int do_fw_download:1;
-       unsigned int broken_disableport:1;
-       unsigned int broken_monitor:1;
-
-       /* Configuration paramaters */
-       u32 iw_mode;
-       int prefer_port3;
-       u16 encode_alg, wep_restrict, tx_key;
-       struct orinoco_key keys[ORINOCO_MAX_KEYS];
-       int bitratemode;
-       char nick[IW_ESSID_MAX_SIZE+1];
-       char desired_essid[IW_ESSID_MAX_SIZE+1];
-       char desired_bssid[ETH_ALEN];
-       int bssid_fixed;
-       u16 frag_thresh, mwo_robust;
-       u16 channel;
-       u16 ap_density, rts_thresh;
-       u16 pm_on, pm_mcast, pm_period, pm_timeout;
-       u16 preamble;
-#ifdef WIRELESS_SPY
-       struct iw_spy_data spy_data; /* iwspy support */
-       struct iw_public_data   wireless_data;
-#endif
-
-       /* Configuration dependent variables */
-       int port_type, createibss;
-       int promiscuous, mc_count;
-
-       /* Scanning support */
-       struct list_head bss_list;
-       struct list_head bss_free_list;
-       void *bss_xbss_data;
-
-       int     scan_inprogress;        /* Scan pending... */
-       u32     scan_mode;              /* Type of scan done */
-
-       /* WPA support */
-       u8 *wpa_ie;
-       int wpa_ie_len;
-
-       struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
-       struct crypto_hash *rx_tfm_mic;
-       struct crypto_hash *tx_tfm_mic;
-
-       unsigned int wpa_enabled:1;
-       unsigned int tkip_cm_active:1;
-       unsigned int key_mgmt:3;
-
-       /* Cached in memory firmware to use in ->resume */
-       const struct firmware *cached_fw;
-};
-
-#ifdef ORINOCO_DEBUG
-extern int orinoco_debug;
-#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0)
-#else
-#define DEBUG(n, args...) do { } while (0)
-#endif /* ORINOCO_DEBUG */
-
-/********************************************************************/
-/* Exported prototypes                                              */
-/********************************************************************/
-
-extern struct net_device *alloc_orinocodev(
-       int sizeof_card, struct device *device,
-       int (*hard_reset)(struct orinoco_private *),
-       int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
-extern irqreturn_t orinoco_interrupt(int irq, void * dev_id);
-
-/********************************************************************/
-/* Locking and synchronization functions                            */
-/********************************************************************/
-
-static inline int orinoco_lock(struct orinoco_private *priv,
-                              unsigned long *flags)
-{
-       spin_lock_irqsave(&priv->lock, *flags);
-       if (priv->hw_unavailable) {
-               DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
-                      priv->ndev);
-               spin_unlock_irqrestore(&priv->lock, *flags);
-               return -EBUSY;
-       }
-       return 0;
-}
-
-static inline void orinoco_unlock(struct orinoco_private *priv,
-                                 unsigned long *flags)
-{
-       spin_unlock_irqrestore(&priv->lock, *flags);
-}
-
-#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
new file mode 100644 (file)
index 0000000..791366e
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the orinoco wireless device drivers.
+#
+
+obj-$(CONFIG_HERMES)           += orinoco.o hermes.o hermes_dld.o
+obj-$(CONFIG_PCMCIA_HERMES)    += orinoco_cs.o
+obj-$(CONFIG_APPLE_AIRPORT)    += airport.o
+obj-$(CONFIG_PLX_HERMES)       += orinoco_plx.o
+obj-$(CONFIG_PCI_HERMES)       += orinoco_pci.o
+obj-$(CONFIG_TMD_HERMES)       += orinoco_tmd.o
+obj-$(CONFIG_NORTEL_HERMES)    += orinoco_nortel.o
+obj-$(CONFIG_PCMCIA_SPECTRUM)  += spectrum_cs.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
new file mode 100644 (file)
index 0000000..ce03a2e
--- /dev/null
@@ -0,0 +1,286 @@
+/* airport.c
+ *
+ * A driver for "Hermes" chipset based Apple Airport wireless
+ * card.
+ *
+ * Copyright notice & release notes in file orinoco.c
+ * 
+ * Note specific to airport stub:
+ * 
+ *  0.05 : first version of the new split driver
+ *  0.06 : fix possible hang on powerup, add sleep support
+ */
+
+#define DRIVER_NAME "airport"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/pmac_feature.h>
+
+#include "orinoco.h"
+
+#define AIRPORT_IO_LEN (0x1000)        /* one page */
+
+struct airport {
+       struct macio_dev *mdev;
+       void __iomem *vaddr;
+       int irq_requested;
+       int ndev_registered;
+};
+
+static int
+airport_suspend(struct macio_dev *mdev, pm_message_t state)
+{
+       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err;
+
+       printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
+
+       err = orinoco_lock(priv, &flags);
+       if (err) {
+               printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
+                      dev->name);
+               return 0;
+       }
+
+       err = __orinoco_down(dev);
+       if (err)
+               printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
+                      dev->name, err);
+
+       netif_device_detach(dev);
+
+       priv->hw_unavailable++;
+
+       orinoco_unlock(priv, &flags);
+
+       disable_irq(dev->irq);
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
+
+       return 0;
+}
+
+static int
+airport_resume(struct macio_dev *mdev)
+{
+       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err;
+
+       printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
+
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
+       msleep(200);
+
+       enable_irq(dev->irq);
+
+       err = orinoco_reinit_firmware(dev);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
+                      dev->name, err);
+               return 0;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       netif_device_attach(dev);
+
+       priv->hw_unavailable--;
+
+       if (priv->open && (! priv->hw_unavailable)) {
+               err = __orinoco_up(dev);
+               if (err)
+                       printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
+                              dev->name, err);
+       }
+
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int
+airport_detach(struct macio_dev *mdev)
+{
+       struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct airport *card = priv->card;
+
+       if (card->ndev_registered)
+               unregister_netdev(dev);
+       card->ndev_registered = 0;
+
+       if (card->irq_requested)
+               free_irq(dev->irq, dev);
+       card->irq_requested = 0;
+
+       if (card->vaddr)
+               iounmap(card->vaddr);
+       card->vaddr = NULL;
+
+       macio_release_resource(mdev, 0);
+
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
+       ssleep(1);
+
+       macio_set_drvdata(mdev, NULL);
+       free_orinocodev(dev);
+
+       return 0;
+}
+
+static int airport_hard_reset(struct orinoco_private *priv)
+{
+       /* It would be nice to power cycle the Airport for a real hard
+        * reset, but for some reason although it appears to
+        * re-initialize properly, it falls in a screaming heap
+        * shortly afterwards. */
+#if 0
+       struct net_device *dev = priv->ndev;
+       struct airport *card = priv->card;
+
+       /* Vitally important.  If we don't do this it seems we get an
+        * interrupt somewhere during the power cycle, since
+        * hw_unavailable is already set it doesn't get ACKed, we get
+        * into an interrupt loop and the PMU decides to turn us
+        * off. */
+       disable_irq(dev->irq);
+
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
+       ssleep(1);
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
+       ssleep(1);
+
+       enable_irq(dev->irq);
+       ssleep(1);
+#endif
+
+       return 0;
+}
+
+static int
+airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+       struct orinoco_private *priv;
+       struct net_device *dev;
+       struct airport *card;
+       unsigned long phys_addr;
+       hermes_t *hw;
+
+       if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
+               printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
+               return -ENODEV;
+       }
+
+       /* Allocate space for private device-specific data */
+       dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+                              airport_hard_reset, NULL);
+       if (! dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               return -ENODEV;
+       }
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       hw = &priv->hw;
+       card->mdev = mdev;
+
+       if (macio_request_resource(mdev, 0, "airport")) {
+               printk(KERN_ERR PFX "can't request IO resource !\n");
+               free_orinocodev(dev);
+               return -EBUSY;
+       }
+
+       SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
+
+       macio_set_drvdata(mdev, dev);
+
+       /* Setup interrupts & base address */
+       dev->irq = macio_irq(mdev, 0);
+       phys_addr = macio_resource_start(mdev, 0);  /* Physical address */
+       printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
+       dev->base_addr = phys_addr;
+       card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
+       if (!card->vaddr) {
+               printk(KERN_ERR PFX "ioremap() failed\n");
+               goto failed;
+       }
+
+       hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
+               
+       /* Power up card */
+       pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
+       ssleep(1);
+
+       /* Reset it before we get the interrupt */
+       hermes_init(hw);
+
+       if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
+               printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+               goto failed;
+       }
+       card->irq_requested = 1;
+
+       /* Tell the stack we exist */
+       if (register_netdev(dev) != 0) {
+               printk(KERN_ERR PFX "register_netdev() failed\n");
+               goto failed;
+       }
+       printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
+       card->ndev_registered = 1;
+       return 0;
+ failed:
+       airport_detach(mdev);
+       return -ENODEV;
+}                              /* airport_attach */
+
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static struct of_device_id airport_match[] = 
+{
+       {
+       .name           = "radio",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE (of, airport_match);
+
+static struct macio_driver airport_driver = 
+{
+       .name           = DRIVER_NAME,
+       .match_table    = airport_match,
+       .probe          = airport_attach,
+       .remove         = airport_detach,
+       .suspend        = airport_suspend,
+       .resume         = airport_resume,
+};
+
+static int __init
+init_airport(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+
+       return macio_register_driver(&airport_driver);
+}
+
+static void __exit
+exit_airport(void)
+{
+       return macio_unregister_driver(&airport_driver);
+}
+
+module_init(init_airport);
+module_exit(exit_airport);
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
new file mode 100644 (file)
index 0000000..bfa3753
--- /dev/null
@@ -0,0 +1,544 @@
+/* hermes.c
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
+ * particular order).
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia.
+ * (C) Copyright David Gibson, IBM Corp. 2001-2003.
+ * 
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "hermes.h"
+
+MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
+       " & David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* These are maximum timeouts. Most often, card wil react much faster */
+#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
+#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
+#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
+#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
+
+/*
+ * Debugging helpers
+ */
+
+#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
+                       printk(stuff);} while (0)
+
+#undef HERMES_DEBUG
+#ifdef HERMES_DEBUG
+#include <stdarg.h>
+
+#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
+
+#else /* ! HERMES_DEBUG */
+
+#define DEBUG(lvl, stuff...) do { } while (0)
+
+#endif /* ! HERMES_DEBUG */
+
+
+/*
+ * Internal functions
+ */
+
+/* Issue a command to the chip. Waiting for it to complete is the caller's
+   problem.
+
+   Returns -EBUSY if the command register is busy, 0 on success.
+
+   Callable from any context.
+*/
+static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
+                           u16 param1, u16 param2)
+{
+       int k = CMD_BUSY_TIMEOUT;
+       u16 reg;
+
+       /* First wait for the command register to unbusy */
+       reg = hermes_read_regn(hw, CMD);
+       while ( (reg & HERMES_CMD_BUSY) && k ) {
+               k--;
+               udelay(1);
+               reg = hermes_read_regn(hw, CMD);
+       }
+       if (reg & HERMES_CMD_BUSY) {
+               return -EBUSY;
+       }
+
+       hermes_write_regn(hw, PARAM2, param2);
+       hermes_write_regn(hw, PARAM1, param1);
+       hermes_write_regn(hw, PARAM0, param0);
+       hermes_write_regn(hw, CMD, cmd);
+       
+       return 0;
+}
+
+/*
+ * Function definitions
+ */
+
+/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
+int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+                      u16 parm0, u16 parm1, u16 parm2,
+                      struct hermes_response *resp)
+{
+       int err = 0;
+       int k;
+       u16 status, reg;
+
+       err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
+       if (err)
+               return err;
+
+       reg = hermes_read_regn(hw, EVSTAT);
+       k = CMD_INIT_TIMEOUT;
+       while ((!(reg & HERMES_EV_CMD)) && k) {
+               k--;
+               udelay(10);
+               reg = hermes_read_regn(hw, EVSTAT);
+       }
+
+       hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+
+       if (!hermes_present(hw)) {
+               DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
+                      hw->iobase);
+               err = -ENODEV;
+               goto out;
+       }
+
+       if (!(reg & HERMES_EV_CMD)) {
+               printk(KERN_ERR "hermes @ %p: "
+                      "Timeout waiting for card to reset (reg=0x%04x)!\n",
+                      hw->iobase, reg);
+               err = -ETIMEDOUT;
+               goto out;
+       }
+
+       status = hermes_read_regn(hw, STATUS);
+       if (resp) {
+               resp->status = status;
+               resp->resp0 = hermes_read_regn(hw, RESP0);
+               resp->resp1 = hermes_read_regn(hw, RESP1);
+               resp->resp2 = hermes_read_regn(hw, RESP2);
+       }
+
+       hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+       if (status & HERMES_STATUS_RESULT)
+               err = -EIO;
+out:
+       return err;
+}
+EXPORT_SYMBOL(hermes_doicmd_wait);
+
+void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
+{
+       hw->iobase = address;
+       hw->reg_spacing = reg_spacing;
+       hw->inten = 0x0;
+}
+EXPORT_SYMBOL(hermes_struct_init);
+
+int hermes_init(hermes_t *hw)
+{
+       u16 reg;
+       int err = 0;
+       int k;
+
+       /* We don't want to be interrupted while resetting the chipset */
+       hw->inten = 0x0;
+       hermes_write_regn(hw, INTEN, 0);
+       hermes_write_regn(hw, EVACK, 0xffff);
+
+       /* Normally it's a "can't happen" for the command register to
+           be busy when we go to issue a command because we are
+           serializing all commands.  However we want to have some
+           chance of resetting the card even if it gets into a stupid
+           state, so we actually wait to see if the command register
+           will unbusy itself here. */
+       k = CMD_BUSY_TIMEOUT;
+       reg = hermes_read_regn(hw, CMD);
+       while (k && (reg & HERMES_CMD_BUSY)) {
+               if (reg == 0xffff) /* Special case - the card has probably been removed,
+                                     so don't wait for the timeout */
+                       return -ENODEV;
+
+               k--;
+               udelay(1);
+               reg = hermes_read_regn(hw, CMD);
+       }
+       
+       /* No need to explicitly handle the timeout - if we've timed
+          out hermes_issue_cmd() will probably return -EBUSY below */
+
+       /* According to the documentation, EVSTAT may contain
+          obsolete event occurrence information.  We have to acknowledge
+          it by writing EVACK. */
+       reg = hermes_read_regn(hw, EVSTAT);
+       hermes_write_regn(hw, EVACK, reg);
+
+       /* We don't use hermes_docmd_wait here, because the reset wipes
+          the magic constant in SWSUPPORT0 away, and it gets confused */
+       err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
+
+       return err;
+}
+EXPORT_SYMBOL(hermes_init);
+
+/* Issue a command to the chip, and (busy!) wait for it to
+ * complete.
+ *
+ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
+ *
+ * Callable from any context, but locking is your problem. */
+int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                     struct hermes_response *resp)
+{
+       int err;
+       int k;
+       u16 reg;
+       u16 status;
+
+       err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
+       if (err) {
+               if (! hermes_present(hw)) {
+                       if (net_ratelimit())
+                               printk(KERN_WARNING "hermes @ %p: "
+                                      "Card removed while issuing command "
+                                      "0x%04x.\n", hw->iobase, cmd);
+                       err = -ENODEV;
+               } else 
+                       if (net_ratelimit())
+                               printk(KERN_ERR "hermes @ %p: "
+                                      "Error %d issuing command 0x%04x.\n",
+                                      hw->iobase, err, cmd);
+               goto out;
+       }
+
+       reg = hermes_read_regn(hw, EVSTAT);
+       k = CMD_COMPL_TIMEOUT;
+       while ( (! (reg & HERMES_EV_CMD)) && k) {
+               k--;
+               udelay(10);
+               reg = hermes_read_regn(hw, EVSTAT);
+       }
+
+       if (! hermes_present(hw)) {
+               printk(KERN_WARNING "hermes @ %p: Card removed "
+                      "while waiting for command 0x%04x completion.\n",
+                      hw->iobase, cmd);
+               err = -ENODEV;
+               goto out;
+       }
+               
+       if (! (reg & HERMES_EV_CMD)) {
+               printk(KERN_ERR "hermes @ %p: Timeout waiting for "
+                      "command 0x%04x completion.\n", hw->iobase, cmd);
+               err = -ETIMEDOUT;
+               goto out;
+       }
+
+       status = hermes_read_regn(hw, STATUS);
+       if (resp) {
+               resp->status = status;
+               resp->resp0 = hermes_read_regn(hw, RESP0);
+               resp->resp1 = hermes_read_regn(hw, RESP1);
+               resp->resp2 = hermes_read_regn(hw, RESP2);
+       }
+
+       hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+       if (status & HERMES_STATUS_RESULT)
+               err = -EIO;
+
+ out:
+       return err;
+}
+EXPORT_SYMBOL(hermes_docmd_wait);
+
+int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+{
+       int err = 0;
+       int k;
+       u16 reg;
+       
+       if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
+               return -EINVAL;
+
+       err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
+       if (err) {
+               return err;
+       }
+
+       reg = hermes_read_regn(hw, EVSTAT);
+       k = ALLOC_COMPL_TIMEOUT;
+       while ( (! (reg & HERMES_EV_ALLOC)) && k) {
+               k--;
+               udelay(10);
+               reg = hermes_read_regn(hw, EVSTAT);
+       }
+       
+       if (! hermes_present(hw)) {
+               printk(KERN_WARNING "hermes @ %p: "
+                      "Card removed waiting for frame allocation.\n",
+                      hw->iobase);
+               return -ENODEV;
+       }
+               
+       if (! (reg & HERMES_EV_ALLOC)) {
+               printk(KERN_ERR "hermes @ %p: "
+                      "Timeout waiting for frame allocation\n",
+                      hw->iobase);
+               return -ETIMEDOUT;
+       }
+
+       *fid = hermes_read_regn(hw, ALLOCFID);
+       hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
+       
+       return 0;
+}
+EXPORT_SYMBOL(hermes_allocate);
+
+/* Set up a BAP to read a particular chunk of data from card's internal buffer.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
+ * from firmware
+ *
+ * Callable from any context */
+static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
+{
+       int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
+       int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
+       int k;
+       u16 reg;
+
+       /* Paranoia.. */
+       if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
+               return -EINVAL;
+
+       k = HERMES_BAP_BUSY_TIMEOUT;
+       reg = hermes_read_reg(hw, oreg);
+       while ((reg & HERMES_OFFSET_BUSY) && k) {
+               k--;
+               udelay(1);
+               reg = hermes_read_reg(hw, oreg);
+       }
+
+       if (reg & HERMES_OFFSET_BUSY)
+               return -ETIMEDOUT;
+
+       /* Now we actually set up the transfer */
+       hermes_write_reg(hw, sreg, id);
+       hermes_write_reg(hw, oreg, offset);
+
+       /* Wait for the BAP to be ready */
+       k = HERMES_BAP_BUSY_TIMEOUT;
+       reg = hermes_read_reg(hw, oreg);
+       while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
+               k--;
+               udelay(1);
+               reg = hermes_read_reg(hw, oreg);
+       }
+
+       if (reg != offset) {
+               printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
+                      "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
+                      (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
+                      reg, id, offset);
+
+               if (reg & HERMES_OFFSET_BUSY) {
+                       return -ETIMEDOUT;
+               }
+
+               return -EIO;            /* error or wrong offset */
+       }
+
+       return 0;
+}
+
+/* Read a block of data from the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem.  len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+                    u16 id, u16 offset)
+{
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+
+       if ( (len < 0) || (len % 2) )
+               return -EINVAL;
+
+       err = hermes_bap_seek(hw, bap, id, offset);
+       if (err)
+               goto out;
+
+       /* Actually do the transfer */
+       hermes_read_words(hw, dreg, buf, len/2);
+
+ out:
+       return err;
+}
+EXPORT_SYMBOL(hermes_bap_pread);
+
+/* Write a block of data to the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+                     u16 id, u16 offset)
+{
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+
+       if (len < 0)
+               return -EINVAL;
+
+       err = hermes_bap_seek(hw, bap, id, offset);
+       if (err)
+               goto out;
+       
+       /* Actually do the transfer */
+       hermes_write_bytes(hw, dreg, buf, len);
+
+ out:  
+       return err;
+}
+EXPORT_SYMBOL(hermes_bap_pwrite);
+
+/* Read a Length-Type-Value record from the card.
+ *
+ * If length is NULL, we ignore the length read from the card, and
+ * read the entire buffer regardless. This is useful because some of
+ * the configuration records appear to have incorrect lengths in
+ * practice.
+ *
+ * Callable from user or bh context.  */
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
+                   u16 *length, void *buf)
+{
+       int err = 0;
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       u16 rlength, rtype;
+       unsigned nwords;
+
+       if ( (bufsize < 0) || (bufsize % 2) )
+               return -EINVAL;
+
+       err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
+       if (err)
+               return err;
+
+       err = hermes_bap_seek(hw, bap, rid, 0);
+       if (err)
+               return err;
+
+       rlength = hermes_read_reg(hw, dreg);
+
+       if (! rlength)
+               return -ENODATA;
+
+       rtype = hermes_read_reg(hw, dreg);
+
+       if (length)
+               *length = rlength;
+
+       if (rtype != rid)
+               printk(KERN_WARNING "hermes @ %p: %s(): "
+                      "rid (0x%04x) does not match type (0x%04x)\n",
+                      hw->iobase, __func__, rid, rtype);
+       if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
+               printk(KERN_WARNING "hermes @ %p: "
+                      "Truncating LTV record from %d to %d bytes. "
+                      "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
+                      HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
+
+       nwords = min((unsigned)rlength - 1, bufsize / 2);
+       hermes_read_words(hw, dreg, buf, nwords);
+
+       return 0;
+}
+EXPORT_SYMBOL(hermes_read_ltv);
+
+int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
+                    u16 length, const void *value)
+{
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+       unsigned count;
+
+       if (length == 0)
+               return -EINVAL;
+
+       err = hermes_bap_seek(hw, bap, rid, 0);
+       if (err)
+               return err;
+
+       hermes_write_reg(hw, dreg, length);
+       hermes_write_reg(hw, dreg, rid);
+
+       count = length - 1;
+
+       hermes_write_bytes(hw, dreg, value, count << 1);
+
+       err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
+                               rid, NULL);
+
+       return err;
+}
+EXPORT_SYMBOL(hermes_write_ltv);
+
+static int __init init_hermes(void)
+{
+       return 0;
+}
+
+static void __exit exit_hermes(void)
+{
+}
+
+module_init(init_hermes);
+module_exit(exit_hermes);
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
new file mode 100644 (file)
index 0000000..8b13c8f
--- /dev/null
@@ -0,0 +1,494 @@
+/* hermes.h
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism I & II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver.
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia.
+ * (C) Copyright David Gibson, IBM Corp. 2001-2003.
+ *
+ * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ *
+ * This file distributed under the GPL, version 2.
+ */
+
+#ifndef _HERMES_H
+#define _HERMES_H
+
+/* Notes on locking:
+ *
+ * As a module of low level hardware access routines, there is no
+ * locking. Users of this module should ensure that they serialize
+ * access to the hermes_t structure, and to the hardware
+*/
+
+#include <linux/if_ether.h>
+#include <asm/io.h>
+
+/*
+ * Limits and constants
+ */
+#define                HERMES_ALLOC_LEN_MIN            (4)
+#define                HERMES_ALLOC_LEN_MAX            (2400)
+#define                HERMES_LTV_LEN_MAX              (34)
+#define                HERMES_BAP_DATALEN_MAX          (4096)
+#define                HERMES_BAP_OFFSET_MAX           (4096)
+#define                HERMES_PORTID_MAX               (7)
+#define                HERMES_NUMPORTS_MAX             (HERMES_PORTID_MAX+1)
+#define                HERMES_PDR_LEN_MAX              (260)   /* in bytes, from EK */
+#define                HERMES_PDA_RECS_MAX             (200)   /* a guess */
+#define                HERMES_PDA_LEN_MAX              (1024)  /* in bytes, from EK */
+#define                HERMES_SCANRESULT_MAX           (35)
+#define                HERMES_CHINFORESULT_MAX         (8)
+#define                HERMES_MAX_MULTICAST            (16)
+#define                HERMES_MAGIC                    (0x7d1f)
+
+/*
+ * Hermes register offsets
+ */
+#define                HERMES_CMD                      (0x00)
+#define                HERMES_PARAM0                   (0x02)
+#define                HERMES_PARAM1                   (0x04)
+#define                HERMES_PARAM2                   (0x06)
+#define                HERMES_STATUS                   (0x08)
+#define                HERMES_RESP0                    (0x0A)
+#define                HERMES_RESP1                    (0x0C)
+#define                HERMES_RESP2                    (0x0E)
+#define                HERMES_INFOFID                  (0x10)
+#define                HERMES_RXFID                    (0x20)
+#define                HERMES_ALLOCFID                 (0x22)
+#define                HERMES_TXCOMPLFID               (0x24)
+#define                HERMES_SELECT0                  (0x18)
+#define                HERMES_OFFSET0                  (0x1C)
+#define                HERMES_DATA0                    (0x36)
+#define                HERMES_SELECT1                  (0x1A)
+#define                HERMES_OFFSET1                  (0x1E)
+#define                HERMES_DATA1                    (0x38)
+#define                HERMES_EVSTAT                   (0x30)
+#define                HERMES_INTEN                    (0x32)
+#define                HERMES_EVACK                    (0x34)
+#define                HERMES_CONTROL                  (0x14)
+#define                HERMES_SWSUPPORT0               (0x28)
+#define                HERMES_SWSUPPORT1               (0x2A)
+#define                HERMES_SWSUPPORT2               (0x2C)
+#define                HERMES_AUXPAGE                  (0x3A)
+#define                HERMES_AUXOFFSET                (0x3C)
+#define                HERMES_AUXDATA                  (0x3E)
+
+/*
+ * CMD register bitmasks
+ */
+#define                HERMES_CMD_BUSY                 (0x8000)
+#define                HERMES_CMD_AINFO                (0x7f00)
+#define                HERMES_CMD_MACPORT              (0x0700)
+#define                HERMES_CMD_RECL                 (0x0100)
+#define                HERMES_CMD_WRITE                (0x0100)
+#define                HERMES_CMD_PROGMODE             (0x0300)
+#define                HERMES_CMD_CMDCODE              (0x003f)
+
+/*
+ * STATUS register bitmasks
+ */
+#define                HERMES_STATUS_RESULT            (0x7f00)
+#define                HERMES_STATUS_CMDCODE           (0x003f)
+
+/*
+ * OFFSET register bitmasks
+ */
+#define                HERMES_OFFSET_BUSY              (0x8000)
+#define                HERMES_OFFSET_ERR               (0x4000)
+#define                HERMES_OFFSET_DATAOFF           (0x0ffe)
+
+/*
+ * Event register bitmasks (INTEN, EVSTAT, EVACK)
+ */
+#define                HERMES_EV_TICK                  (0x8000)
+#define                HERMES_EV_WTERR                 (0x4000)
+#define                HERMES_EV_INFDROP               (0x2000)
+#define                HERMES_EV_INFO                  (0x0080)
+#define                HERMES_EV_DTIM                  (0x0020)
+#define                HERMES_EV_CMD                   (0x0010)
+#define                HERMES_EV_ALLOC                 (0x0008)
+#define                HERMES_EV_TXEXC                 (0x0004)
+#define                HERMES_EV_TX                    (0x0002)
+#define                HERMES_EV_RX                    (0x0001)
+
+/*
+ * Command codes
+ */
+/*--- Controller Commands ----------------------------*/
+#define                HERMES_CMD_INIT                 (0x0000)
+#define                HERMES_CMD_ENABLE               (0x0001)
+#define                HERMES_CMD_DISABLE              (0x0002)
+#define                HERMES_CMD_DIAG                 (0x0003)
+
+/*--- Buffer Mgmt Commands ---------------------------*/
+#define                HERMES_CMD_ALLOC                (0x000A)
+#define                HERMES_CMD_TX                   (0x000B)
+
+/*--- Regulate Commands ------------------------------*/
+#define                HERMES_CMD_NOTIFY               (0x0010)
+#define                HERMES_CMD_INQUIRE              (0x0011)
+
+/*--- Configure Commands -----------------------------*/
+#define                HERMES_CMD_ACCESS               (0x0021)
+#define                HERMES_CMD_DOWNLD               (0x0022)
+
+/*--- Serial I/O Commands ----------------------------*/
+#define                HERMES_CMD_READMIF              (0x0030)
+#define                HERMES_CMD_WRITEMIF             (0x0031)
+
+/*--- Debugging Commands -----------------------------*/
+#define        HERMES_CMD_TEST                 (0x0038)
+
+
+/* Test command arguments */
+#define                HERMES_TEST_SET_CHANNEL         0x0800
+#define                HERMES_TEST_MONITOR             0x0b00
+#define                HERMES_TEST_STOP                0x0f00
+
+/* Authentication algorithms */
+#define                HERMES_AUTH_OPEN                1
+#define                HERMES_AUTH_SHARED_KEY          2
+
+/* WEP settings */
+#define                HERMES_WEP_PRIVACY_INVOKED      0x0001
+#define                HERMES_WEP_EXCL_UNENCRYPTED     0x0002
+#define                HERMES_WEP_HOST_ENCRYPT         0x0010
+#define                HERMES_WEP_HOST_DECRYPT         0x0080
+
+/* Symbol hostscan options */
+#define                HERMES_HOSTSCAN_SYMBOL_5SEC     0x0001
+#define                HERMES_HOSTSCAN_SYMBOL_ONCE     0x0002
+#define                HERMES_HOSTSCAN_SYMBOL_PASSIVE  0x0040
+#define                HERMES_HOSTSCAN_SYMBOL_BCAST    0x0080
+
+/*
+ * Frame structures and constants
+ */
+
+#define HERMES_DESCRIPTOR_OFFSET       0
+#define HERMES_802_11_OFFSET           (14)
+#define HERMES_802_3_OFFSET            (14+32)
+#define HERMES_802_2_OFFSET            (14+32+14)
+#define HERMES_TXCNTL2_OFFSET          (HERMES_802_3_OFFSET - 2)
+
+#define HERMES_RXSTAT_ERR              (0x0003)
+#define        HERMES_RXSTAT_BADCRC            (0x0001)
+#define        HERMES_RXSTAT_UNDECRYPTABLE     (0x0002)
+#define        HERMES_RXSTAT_MIC               (0x0010)        /* Frame contains MIC */
+#define        HERMES_RXSTAT_MACPORT           (0x0700)
+#define HERMES_RXSTAT_PCF              (0x1000)        /* Frame was received in CF period */
+#define        HERMES_RXSTAT_MIC_KEY_ID        (0x1800)        /* MIC key used */
+#define        HERMES_RXSTAT_MSGTYPE           (0xE000)
+#define        HERMES_RXSTAT_1042              (0x2000)        /* RFC-1042 frame */
+#define        HERMES_RXSTAT_TUNNEL            (0x4000)        /* bridge-tunnel encoded frame */
+#define        HERMES_RXSTAT_WMP               (0x6000)        /* Wavelan-II Management Protocol frame */
+
+/* Shift amount for key ID in RXSTAT and TXCTRL */
+#define        HERMES_MIC_KEY_ID_SHIFT         11
+
+struct hermes_tx_descriptor {
+       __le16 status;
+       __le16 reserved1;
+       __le16 reserved2;
+       __le32 sw_support;
+       u8 retry_count;
+       u8 tx_rate;
+       __le16 tx_control;      
+} __attribute__ ((packed));
+
+#define HERMES_TXSTAT_RETRYERR         (0x0001)
+#define HERMES_TXSTAT_AGEDERR          (0x0002)
+#define HERMES_TXSTAT_DISCON           (0x0004)
+#define HERMES_TXSTAT_FORMERR          (0x0008)
+
+#define HERMES_TXCTRL_TX_OK            (0x0002)        /* ?? interrupt on Tx complete */
+#define HERMES_TXCTRL_TX_EX            (0x0004)        /* ?? interrupt on Tx exception */
+#define HERMES_TXCTRL_802_11           (0x0008)        /* We supply 802.11 header */
+#define HERMES_TXCTRL_MIC              (0x0010)        /* 802.3 + TKIP */
+#define HERMES_TXCTRL_MIC_KEY_ID       (0x1800)        /* MIC Key ID mask */
+#define HERMES_TXCTRL_ALT_RTRY         (0x0020)
+
+/* Inquiry constants and data types */
+
+#define HERMES_INQ_TALLIES             (0xF100)
+#define HERMES_INQ_SCAN                        (0xF101)
+#define HERMES_INQ_CHANNELINFO         (0xF102)
+#define HERMES_INQ_HOSTSCAN            (0xF103)
+#define HERMES_INQ_HOSTSCAN_SYMBOL     (0xF104)
+#define HERMES_INQ_LINKSTATUS          (0xF200)
+#define HERMES_INQ_SEC_STAT_AGERE      (0xF202)
+
+struct hermes_tallies_frame {
+       __le16 TxUnicastFrames;
+       __le16 TxMulticastFrames;
+       __le16 TxFragments;
+       __le16 TxUnicastOctets;
+       __le16 TxMulticastOctets;
+       __le16 TxDeferredTransmissions;
+       __le16 TxSingleRetryFrames;
+       __le16 TxMultipleRetryFrames;
+       __le16 TxRetryLimitExceeded;
+       __le16 TxDiscards;
+       __le16 RxUnicastFrames;
+       __le16 RxMulticastFrames;
+       __le16 RxFragments;
+       __le16 RxUnicastOctets;
+       __le16 RxMulticastOctets;
+       __le16 RxFCSErrors;
+       __le16 RxDiscards_NoBuffer;
+       __le16 TxDiscardsWrongSA;
+       __le16 RxWEPUndecryptable;
+       __le16 RxMsgInMsgFragments;
+       __le16 RxMsgInBadMsgFragments;
+       /* Those last are probably not available in very old firmwares */
+       __le16 RxDiscards_WEPICVError;
+       __le16 RxDiscards_WEPExcluded;
+} __attribute__ ((packed));
+
+/* Grabbed from wlan-ng - Thanks Mark... - Jean II
+ * This is the result of a scan inquiry command */
+/* Structure describing info about an Access Point */
+struct prism2_scan_apinfo {
+       __le16 channel;         /* Channel where the AP sits */
+       __le16 noise;           /* Noise level */
+       __le16 level;           /* Signal level */
+       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
+       __le16 beacon_interv;   /* Beacon interval */
+       __le16 capabilities;    /* Capabilities */
+       __le16 essid_len;       /* ESSID length */
+       u8 essid[32];           /* ESSID of the network */
+       u8 rates[10];           /* Bit rate supported */
+       __le16 proberesp_rate;  /* Data rate of the response frame */
+       __le16 atim;            /* ATIM window time, Kus (hostscan only) */
+} __attribute__ ((packed));
+
+/* Same stuff for the Lucent/Agere card.
+ * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
+struct agere_scan_apinfo {
+       __le16 channel;         /* Channel where the AP sits */
+       __le16 noise;           /* Noise level */
+       __le16 level;           /* Signal level */
+       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
+       __le16 beacon_interv;   /* Beacon interval */
+       __le16 capabilities;    /* Capabilities */
+       /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
+       __le16 essid_len;       /* ESSID length */
+       u8 essid[32];           /* ESSID of the network */
+} __attribute__ ((packed));
+
+/* Moustafa: Scan structure for Symbol cards */
+struct symbol_scan_apinfo {
+       u8 channel;             /* Channel where the AP sits */
+       u8 unknown1;            /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
+       __le16 noise;           /* Noise level */
+       __le16 level;           /* Signal level */
+       u8 bssid[ETH_ALEN];     /* MAC address of the Access Point */
+       __le16 beacon_interv;   /* Beacon interval */
+       __le16 capabilities;    /* Capabilities */
+       /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
+       __le16 essid_len;       /* ESSID length */
+       u8 essid[32];           /* ESSID of the network */
+       __le16 rates[5];        /* Bit rate supported */
+       __le16 basic_rates;     /* Basic rates bitmask */
+       u8 unknown2[6];         /* Always FF:FF:FF:FF:00:00 */
+       u8 unknown3[8];         /* Always 0, appeared in f/w 3.91-68 */
+} __attribute__ ((packed));
+
+union hermes_scan_info {
+       struct agere_scan_apinfo        a;
+       struct prism2_scan_apinfo       p;
+       struct symbol_scan_apinfo       s;
+};
+
+/* Extended scan struct for HERMES_INQ_CHANNELINFO.
+ * wl_lkm calls this an ACS scan (Automatic Channel Select).
+ * Keep out of union hermes_scan_info because it is much bigger than
+ * the older scan structures. */
+struct agere_ext_scan_info {
+       __le16  reserved0;
+
+       u8      noise;
+       u8      level;
+       u8      rx_flow;
+       u8      rate;
+       __le16  reserved1[2];
+
+       __le16  frame_control;
+       __le16  dur_id;
+       u8      addr1[ETH_ALEN];
+       u8      addr2[ETH_ALEN];
+       u8      bssid[ETH_ALEN];
+       __le16  sequence;
+       u8      addr4[ETH_ALEN];
+
+       __le16  data_length;
+
+       /* Next 3 fields do not get filled in. */
+       u8      daddr[ETH_ALEN];
+       u8      saddr[ETH_ALEN];
+       __le16  len_type;
+
+       __le64  timestamp;
+       __le16  beacon_interval;
+       __le16  capabilities;
+       u8      data[316];
+} __attribute__ ((packed));
+
+#define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
+#define HERMES_LINKSTATUS_CONNECTED       (0x0001)
+#define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
+#define HERMES_LINKSTATUS_AP_CHANGE       (0x0003)
+#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
+#define HERMES_LINKSTATUS_AP_IN_RANGE     (0x0005)
+#define HERMES_LINKSTATUS_ASSOC_FAILED    (0x0006)
+  
+struct hermes_linkstatus {
+       __le16 linkstatus;         /* Link status */
+} __attribute__ ((packed));
+
+struct hermes_response {
+       u16 status, resp0, resp1, resp2;
+};
+
+/* "ID" structure - used for ESSID and station nickname */
+struct hermes_idstring {
+       __le16 len;
+       __le16 val[16];
+} __attribute__ ((packed));
+
+struct hermes_multicast {
+       u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
+} __attribute__ ((packed));
+
+/* Timeouts */
+#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
+
+/* Basic control structure */
+typedef struct hermes {
+       void __iomem *iobase;
+       int reg_spacing;
+#define HERMES_16BIT_REGSPACING        0
+#define HERMES_32BIT_REGSPACING        1
+       u16 inten; /* Which interrupts should be enabled? */
+} hermes_t;
+
+/* Register access convenience macros */
+#define hermes_read_reg(hw, off) \
+       (ioread16((hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#define hermes_write_reg(hw, off, val) \
+       (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
+#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
+#define hermes_write_regn(hw, name, val) hermes_write_reg((hw), HERMES_##name, (val))
+
+/* Function prototypes */
+void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
+int hermes_init(hermes_t *hw);
+int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                     struct hermes_response *resp);
+int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+                      u16 parm0, u16 parm1, u16 parm2,
+                      struct hermes_response *resp);
+int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
+
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+                      u16 id, u16 offset);
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+                       u16 id, u16 offset);
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
+                   u16 *length, void *buf);
+int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+                     u16 length, const void *value);
+
+/* Inline functions */
+
+static inline int hermes_present(hermes_t *hw)
+{
+       return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
+}
+
+static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
+{
+       hw->inten = events;
+       hermes_write_regn(hw, INTEN, events);
+}
+
+static inline int hermes_enable_port(hermes_t *hw, int port)
+{
+       return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+                                0, NULL);
+}
+
+static inline int hermes_disable_port(hermes_t *hw, int port)
+{
+       return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8), 
+                                0, NULL);
+}
+
+/* Initiate an INQUIRE command (tallies or scan).  The result will come as an
+ * information frame in __orinoco_ev_info() */
+static inline int hermes_inquire(hermes_t *hw, u16 rid)
+{
+       return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
+}
+
+#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 )
+#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
+
+/* Note that for the next two, the count is in 16-bit words, not bytes */
+static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
+{
+       off = off << hw->reg_spacing;
+       ioread16_rep(hw->iobase + off, buf, count);
+}
+
+static inline void hermes_write_bytes(struct hermes *hw, int off,
+                                     const char *buf, unsigned count)
+{
+       off = off << hw->reg_spacing;
+       iowrite16_rep(hw->iobase + off, buf, count >> 1);
+       if (unlikely(count & 1))
+               iowrite8(buf[count - 1], hw->iobase + off);
+}
+
+static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
+{
+       unsigned i;
+
+       off = off << hw->reg_spacing;
+
+       for (i = 0; i < count; i++)
+               iowrite16(0, hw->iobase + off);
+}
+
+#define HERMES_READ_RECORD(hw, bap, rid, buf) \
+       (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
+#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
+       (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
+
+static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
+{
+       __le16 rec;
+       int err;
+
+       err = HERMES_READ_RECORD(hw, bap, rid, &rec);
+       *word = le16_to_cpu(rec);
+       return err;
+}
+
+static inline int hermes_write_wordrec(hermes_t *hw, int bap, u16 rid, u16 word)
+{
+       __le16 rec = cpu_to_le16(word);
+       return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
+}
+
+#endif  /* _HERMES_H */
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
new file mode 100644 (file)
index 0000000..d8c626e
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * Hermes download helper driver.
+ *
+ * This could be entirely merged into hermes.c.
+ *
+ * I'm keeping it separate to minimise the amount of merging between
+ * kernel upgrades. It also means the memory overhead for drivers that
+ * don't need firmware download low.
+ *
+ * This driver:
+ *  - is capable of writing to the volatile area of the hermes device
+ *  - is currently not capable of writing to non-volatile areas
+ *  - provide helpers to identify and update plugin data
+ *  - is not capable of interpreting a fw image directly. That is up to
+ *    the main card driver.
+ *  - deals with Hermes I devices. It can probably be modified to deal
+ *    with Hermes II devices
+ *
+ * Copyright (C) 2007, David Kilroy
+ *
+ * Plug data code slightly modified from spectrum_cs driver
+ *    Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
+ * Portions based on information in wl_lkm_718 Agere driver
+ *    COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "hermes.h"
+#include "hermes_dld.h"
+
+MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
+MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define PFX "hermes_dld: "
+
+/*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
+#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
+
+/* End markers used in dblocks */
+#define PDI_END                0x00000000      /* End of PDA */
+#define BLOCK_END      0xFFFFFFFF      /* Last image block */
+#define TEXT_END       0x1A            /* End of text header */
+
+/*
+ * PDA == Production Data Area
+ *
+ * In principle, the max. size of the PDA is is 4096 words. Currently,
+ * however, only about 500 bytes of this area are used.
+ *
+ * Some USB implementations can't handle sizes in excess of 1016. Note
+ * that PDA is not actually used in those USB environments, but may be
+ * retrieved by common code.
+ */
+#define MAX_PDA_SIZE   1000
+
+/* Limit the amout we try to download in a single shot.
+ * Size is in bytes.
+ */
+#define MAX_DL_SIZE 1024
+#define LIMIT_PROGRAM_SIZE 0
+
+/*
+ * The following structures have little-endian fields denoted by
+ * the leading underscore.  Don't access them directly - use inline
+ * functions defined below.
+ */
+
+/*
+ * The binary image to be downloaded consists of series of data blocks.
+ * Each block has the following structure.
+ */
+struct dblock {
+       __le32 addr;            /* adapter address where to write the block */
+       __le16 len;             /* length of the data only, in bytes */
+       char data[0];           /* data to be written */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data References are located in in the image after the last data
+ * block.  They refer to areas in the adapter memory where the plug data
+ * items with matching ID should be written.
+ */
+struct pdr {
+       __le32 id;              /* record ID */
+       __le32 addr;            /* adapter address where to write the data */
+       __le32 len;             /* expected length of the data, in bytes */
+       char next[0];           /* next PDR starts here */
+} __attribute__ ((packed));
+
+/*
+ * Plug Data Items are located in the EEPROM read from the adapter by
+ * primary firmware.  They refer to the device-specific data that should
+ * be plugged into the secondary firmware.
+ */
+struct pdi {
+       __le16 len;             /* length of ID and data, in words */
+       __le16 id;              /* record ID */
+       char data[0];           /* plug data */
+} __attribute__ ((packed));
+
+/*** FW data block access functions ***/
+
+static inline u32
+dblock_addr(const struct dblock *blk)
+{
+       return le32_to_cpu(blk->addr);
+}
+
+static inline u32
+dblock_len(const struct dblock *blk)
+{
+       return le16_to_cpu(blk->len);
+}
+
+/*** PDR Access functions ***/
+
+static inline u32
+pdr_id(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->id);
+}
+
+static inline u32
+pdr_addr(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->addr);
+}
+
+static inline u32
+pdr_len(const struct pdr *pdr)
+{
+       return le32_to_cpu(pdr->len);
+}
+
+/*** PDI Access functions ***/
+
+static inline u32
+pdi_id(const struct pdi *pdi)
+{
+       return le16_to_cpu(pdi->id);
+}
+
+/* Return length of the data only, in bytes */
+static inline u32
+pdi_len(const struct pdi *pdi)
+{
+       return 2 * (le16_to_cpu(pdi->len) - 1);
+}
+
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+       int i;
+
+       /* Already open? */
+       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+               return 0;
+
+       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+       hermes_write_reg(hw, HERMES_CONTROL, action);
+
+       for (i = 0; i < 20; i++) {
+               udelay(10);
+               if (hermes_read_reg(hw, HERMES_CONTROL) ==
+                   desired_state)
+                       return 0;
+       }
+
+       return -EBUSY;
+}
+
+/*** Plug Data Functions ***/
+
+/*
+ * Scan PDR for the record with the specified RECORD_ID.
+ * If it's not found, return NULL.
+ */
+static struct pdr *
+hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
+{
+       struct pdr *pdr = first_pdr;
+       void *end = (void *)first_pdr + MAX_PDA_SIZE;
+
+       while (((void *)pdr < end) &&
+              (pdr_id(pdr) != PDI_END)) {
+               /*
+                * PDR area is currently not terminated by PDI_END.
+                * It's followed by CRC records, which have the type
+                * field where PDR has length.  The type can be 0 or 1.
+                */
+               if (pdr_len(pdr) < 2)
+                       return NULL;
+
+               /* If the record ID matches, we are done */
+               if (pdr_id(pdr) == record_id)
+                       return pdr;
+
+               pdr = (struct pdr *) pdr->next;
+       }
+       return NULL;
+}
+
+/* Scan production data items for a particular entry */
+static struct pdi *
+hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
+{
+       struct pdi *pdi = first_pdi;
+
+       while (pdi_id(pdi) != PDI_END) {
+
+               /* If the record ID matches, we are done */
+               if (pdi_id(pdi) == record_id)
+                       return pdi;
+
+               pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
+       }
+       return NULL;
+}
+
+/* Process one Plug Data Item - find corresponding PDR and plug it */
+static int
+hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
+{
+       struct pdr *pdr;
+
+       /* Find the PDR corresponding to this PDI */
+       pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
+
+       /* No match is found, safe to ignore */
+       if (!pdr)
+               return 0;
+
+       /* Lengths of the data in PDI and PDR must match */
+       if (pdi_len(pdi) != pdr_len(pdr))
+               return -EINVAL;
+
+       /* do the actual plugging */
+       hermes_aux_setaddr(hw, pdr_addr(pdr));
+       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
+
+       return 0;
+}
+
+/* Read PDA from the adapter */
+int hermes_read_pda(hermes_t *hw,
+                   __le16 *pda,
+                   u32 pda_addr,
+                   u16 pda_len,
+                   int use_eeprom) /* can we get this into hw? */
+{
+       int ret;
+       u16 pda_size;
+       u16 data_len = pda_len;
+       __le16 *data = pda;
+
+       if (use_eeprom) {
+               /* PDA of spectrum symbol is in eeprom */
+
+               /* Issue command to read EEPROM */
+               ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+               if (ret)
+                       return ret;
+       } else {
+               /* wl_lkm does not include PDA size in the PDA area.
+                * We will pad the information into pda, so other routines
+                * don't have to be modified */
+               pda[0] = cpu_to_le16(pda_len - 2);
+                       /* Includes CFG_PROD_DATA but not itself */
+               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+               data_len = pda_len - 4;
+               data = pda + 2;
+       }
+
+       /* Open auxiliary port */
+       ret = hermes_aux_control(hw, 1);
+       printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+       if (ret)
+               return ret;
+
+       /* read PDA from EEPROM */
+       hermes_aux_setaddr(hw, pda_addr);
+       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+       /* Close aux port */
+       ret = hermes_aux_control(hw, 0);
+       printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+
+       /* Check PDA length */
+       pda_size = le16_to_cpu(pda[0]);
+       printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
+              pda_size, pda_len);
+       if (pda_size > pda_len)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(hermes_read_pda);
+
+/* Parse PDA and write the records into the adapter
+ *
+ * Attempt to write every records that is in the specified pda
+ * which also has a valid production data record for the firmware.
+ */
+int hermes_apply_pda(hermes_t *hw,
+                    const char *first_pdr,
+                    const __le16 *pda)
+{
+       int ret;
+       const struct pdi *pdi;
+       struct pdr *pdr;
+
+       pdr = (struct pdr *) first_pdr;
+
+       /* Go through every PDI and plug them into the adapter */
+       pdi = (const struct pdi *) (pda + 2);
+       while (pdi_id(pdi) != PDI_END) {
+               ret = hermes_plug_pdi(hw, pdr, pdi);
+               if (ret)
+                       return ret;
+
+               /* Increment to the next PDI */
+               pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
+       }
+       return 0;
+}
+EXPORT_SYMBOL(hermes_apply_pda);
+
+/* Identify the total number of bytes in all blocks
+ * including the header data.
+ */
+size_t
+hermes_blocks_length(const char *first_block)
+{
+       const struct dblock *blk = (const struct dblock *) first_block;
+       int total_len = 0;
+       int len;
+
+       /* Skip all blocks to locate Plug Data References
+        * (Spectrum CS) */
+       while (dblock_addr(blk) != BLOCK_END) {
+               len = dblock_len(blk);
+               total_len += sizeof(*blk) + len;
+               blk = (struct dblock *) &blk->data[len];
+       }
+
+       return total_len;
+}
+EXPORT_SYMBOL(hermes_blocks_length);
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+       int err;
+
+       /* Disable interrupts?*/
+       /*hw->inten = 0x0;*/
+       /*hermes_write_regn(hw, INTEN, 0);*/
+       /*hermes_set_irqmask(hw, 0);*/
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Using doicmd_wait rather than docmd_wait */
+       err = hermes_doicmd_wait(hw,
+                                0x0100 | HERMES_CMD_INIT,
+                                0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hermes_doicmd_wait(hw,
+                                0x0000 | HERMES_CMD_INIT,
+                                0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hermes_aux_control(hw, 1);
+       printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+
+       if (err)
+               return err;
+
+       printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+       err = hermes_doicmd_wait(hw,
+                                HERMES_PROGRAM_ENABLE_VOLATILE,
+                                offset & 0xFFFFu,
+                                offset >> 16,
+                                0,
+                                NULL);
+       printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
+              err);
+
+       return err;
+}
+EXPORT_SYMBOL(hermesi_program_init);
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+int hermesi_program_end(hermes_t *hw)
+{
+       struct hermes_response resp;
+       int rc = 0;
+       int err;
+
+       rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+       printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
+              "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+              rc, resp.resp0, resp.resp1, resp.resp2);
+
+       if ((rc == 0) &&
+           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+               rc = -EIO;
+
+       err = hermes_aux_control(hw, 0);
+       printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Reinitialise, ignoring return */
+       (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+                                 0, 0, 0, NULL);
+
+       return rc ? rc : err;
+}
+EXPORT_SYMBOL(hermesi_program_end);
+
+/* Program the data blocks */
+int hermes_program(hermes_t *hw, const char *first_block, const char *end)
+{
+       const struct dblock *blk;
+       u32 blkaddr;
+       u32 blklen;
+#if LIMIT_PROGRAM_SIZE
+       u32 addr;
+       u32 len;
+#endif
+
+       blk = (const struct dblock *) first_block;
+
+       if ((const char *) blk > (end - sizeof(*blk)))
+               return -EIO;
+
+       blkaddr = dblock_addr(blk);
+       blklen = dblock_len(blk);
+
+       while ((blkaddr != BLOCK_END) &&
+              (((const char *) blk + blklen) <= end)) {
+               printk(KERN_DEBUG PFX
+                      "Programming block of length %d to address 0x%08x\n",
+                      blklen, blkaddr);
+
+#if !LIMIT_PROGRAM_SIZE
+               /* wl_lkm driver splits this into writes of 2000 bytes */
+               hermes_aux_setaddr(hw, blkaddr);
+               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
+                                  blklen);
+#else
+               len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
+               addr = blkaddr;
+
+               while (addr < (blkaddr + blklen)) {
+                       printk(KERN_DEBUG PFX
+                              "Programming subblock of length %d "
+                              "to address 0x%08x. Data @ %p\n",
+                              len, addr, &blk->data[addr - blkaddr]);
+
+                       hermes_aux_setaddr(hw, addr);
+                       hermes_write_bytes(hw, HERMES_AUXDATA,
+                                          &blk->data[addr - blkaddr],
+                                          len);
+
+                       addr += len;
+                       len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
+                               (blkaddr + blklen - addr) : MAX_DL_SIZE;
+               }
+#endif
+               blk = (const struct dblock *) &blk->data[blklen];
+
+               if ((const char *) blk > (end - sizeof(*blk)))
+                       return -EIO;
+
+               blkaddr = dblock_addr(blk);
+               blklen = dblock_len(blk);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(hermes_program);
+
+static int __init init_hermes_dld(void)
+{
+       return 0;
+}
+
+static void __exit exit_hermes_dld(void)
+{
+}
+
+module_init(init_hermes_dld);
+module_exit(exit_hermes_dld);
+
+/*** Default plugging data for Hermes I ***/
+/* Values from wl_lkm_718/hcf/dhf.c */
+
+#define DEFINE_DEFAULT_PDR(pid, length, data)                          \
+static const struct {                                                  \
+       __le16 len;                                                     \
+       __le16 id;                                                      \
+       u8 val[length];                                                 \
+} __attribute__ ((packed)) default_pdr_data_##pid = {                  \
+       __constant_cpu_to_le16((sizeof(default_pdr_data_##pid)/         \
+                               sizeof(__le16)) - 1),                   \
+       __constant_cpu_to_le16(pid),                                    \
+       data                                                            \
+}
+
+#define DEFAULT_PDR(pid) default_pdr_data_##pid
+
+/*  HWIF Compatiblity */
+DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
+
+/* PPPPSign */
+DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
+
+/* PPPPProf */
+DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
+
+/* Antenna diversity */
+DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
+
+/* Modem VCO band Set-up */
+DEFINE_DEFAULT_PDR(0x0160, 28,
+                  "\x00\x00\x00\x00\x00\x00\x00\x00"
+                  "\x00\x00\x00\x00\x00\x00\x00\x00"
+                  "\x00\x00\x00\x00\x00\x00\x00\x00"
+                  "\x00\x00\x00\x00");
+
+/* Modem Rx Gain Table Values */
+DEFINE_DEFAULT_PDR(0x0161, 256,
+                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+                  "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
+                  "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
+                  "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
+                  "\x3B\x01\x3A\01\x3A\x01\x39\x01"
+                  "\x39\x01\x38\01\x38\x01\x37\x01"
+                  "\x37\x01\x36\01\x36\x01\x35\x01"
+                  "\x35\x01\x34\01\x34\x01\x33\x01"
+                  "\x33\x01\x32\x01\x32\x01\x31\x01"
+                  "\x31\x01\x30\x01\x30\x01\x7B\x01"
+                  "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
+                  "\x79\x01\x78\x01\x78\x01\x77\x01"
+                  "\x77\x01\x76\x01\x76\x01\x75\x01"
+                  "\x75\x01\x74\x01\x74\x01\x73\x01"
+                  "\x73\x01\x72\x01\x72\x01\x71\x01"
+                  "\x71\x01\x70\x01\x70\x01\x68\x01"
+                  "\x68\x01\x67\x01\x67\x01\x66\x01"
+                  "\x66\x01\x65\x01\x65\x01\x57\x01"
+                  "\x57\x01\x56\x01\x56\x01\x55\x01"
+                  "\x55\x01\x54\x01\x54\x01\x53\x01"
+                  "\x53\x01\x52\x01\x52\x01\x51\x01"
+                  "\x51\x01\x50\x01\x50\x01\x48\x01"
+                  "\x48\x01\x47\x01\x47\x01\x46\x01"
+                  "\x46\x01\x45\x01\x45\x01\x44\x01"
+                  "\x44\x01\x43\x01\x43\x01\x42\x01"
+                  "\x42\x01\x41\x01\x41\x01\x40\x01"
+                  "\x40\x01\x40\x01\x40\x01\x40\x01"
+                  "\x40\x01\x40\x01\x40\x01\x40\x01"
+                  "\x40\x01\x40\x01\x40\x01\x40\x01"
+                  "\x40\x01\x40\x01\x40\x01\x40\x01");
+
+/* Write PDA according to certain rules.
+ *
+ * For every production data record, look for a previous setting in
+ * the pda, and use that.
+ *
+ * For certain records, use defaults if they are not found in pda.
+ */
+int hermes_apply_pda_with_defaults(hermes_t *hw,
+                                  const char *first_pdr,
+                                  const __le16 *pda)
+{
+       const struct pdr *pdr = (const struct pdr *) first_pdr;
+       struct pdi *first_pdi = (struct pdi *) &pda[2];
+       struct pdi *pdi;
+       struct pdi *default_pdi = NULL;
+       struct pdi *outdoor_pdi;
+       void *end = (void *)first_pdr + MAX_PDA_SIZE;
+       int record_id;
+
+       while (((void *)pdr < end) &&
+              (pdr_id(pdr) != PDI_END)) {
+               /*
+                * For spectrum_cs firmwares,
+                * PDR area is currently not terminated by PDI_END.
+                * It's followed by CRC records, which have the type
+                * field where PDR has length.  The type can be 0 or 1.
+                */
+               if (pdr_len(pdr) < 2)
+                       break;
+               record_id = pdr_id(pdr);
+
+               pdi = hermes_find_pdi(first_pdi, record_id);
+               if (pdi)
+                       printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
+                              record_id, pdi);
+
+               switch (record_id) {
+               case 0x110: /* Modem REFDAC values */
+               case 0x120: /* Modem VGDAC values */
+                       outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
+                       default_pdi = NULL;
+                       if (outdoor_pdi) {
+                               pdi = outdoor_pdi;
+                               printk(KERN_DEBUG PFX
+                                      "Using outdoor record 0x%04x at %p\n",
+                                      record_id + 1, pdi);
+                       }
+                       break;
+               case 0x5: /*  HWIF Compatiblity */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
+                       break;
+               case 0x108: /* PPPPSign */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
+                       break;
+               case 0x109: /* PPPPProf */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
+                       break;
+               case 0x150: /* Antenna diversity */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
+                       break;
+               case 0x160: /* Modem VCO band Set-up */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
+                       break;
+               case 0x161: /* Modem Rx Gain Table Values */
+                       default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
+                       break;
+               default:
+                       default_pdi = NULL;
+                       break;
+               }
+               if (!pdi && default_pdi) {
+                       /* Use default */
+                       pdi = default_pdi;
+                       printk(KERN_DEBUG PFX
+                              "Using default record 0x%04x at %p\n",
+                              record_id, pdi);
+               }
+
+               if (pdi) {
+                       /* Lengths of the data in PDI and PDR must match */
+                       if (pdi_len(pdi) == pdr_len(pdr)) {
+                               /* do the actual plugging */
+                               hermes_aux_setaddr(hw, pdr_addr(pdr));
+                               hermes_write_bytes(hw, HERMES_AUXDATA,
+                                                  pdi->data, pdi_len(pdi));
+                       }
+               }
+
+               pdr++;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(hermes_apply_pda_with_defaults);
diff --git a/drivers/net/wireless/orinoco/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h
new file mode 100644 (file)
index 0000000..6fcb262
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007, David Kilroy
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+#ifndef _HERMES_DLD_H
+#define _HERMES_DLD_H
+
+#include "hermes.h"
+
+int hermesi_program_init(hermes_t *hw, u32 offset);
+int hermesi_program_end(hermes_t *hw);
+int hermes_program(hermes_t *hw, const char *first_block, const char *end);
+
+int hermes_read_pda(hermes_t *hw,
+                   __le16 *pda,
+                   u32 pda_addr,
+                   u16 pda_len,
+                   int use_eeprom);
+int hermes_apply_pda(hermes_t *hw,
+                    const char *first_pdr,
+                    const __le16 *pda);
+int hermes_apply_pda_with_defaults(hermes_t *hw,
+                                  const char *first_pdr,
+                                  const __le16 *pda);
+
+size_t hermes_blocks_length(const char *first_block);
+
+#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/orinoco/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h
new file mode 100644 (file)
index 0000000..42eb67d
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef _HERMES_RID_H
+#define _HERMES_RID_H
+
+/*
+ * Configuration RIDs
+ */
+#define HERMES_RID_CNFPORTTYPE                 0xFC00
+#define HERMES_RID_CNFOWNMACADDR               0xFC01
+#define HERMES_RID_CNFDESIREDSSID              0xFC02
+#define HERMES_RID_CNFOWNCHANNEL               0xFC03
+#define HERMES_RID_CNFOWNSSID                  0xFC04
+#define HERMES_RID_CNFOWNATIMWINDOW            0xFC05
+#define HERMES_RID_CNFSYSTEMSCALE              0xFC06
+#define HERMES_RID_CNFMAXDATALEN               0xFC07
+#define HERMES_RID_CNFWDSADDRESS               0xFC08
+#define HERMES_RID_CNFPMENABLED                        0xFC09
+#define HERMES_RID_CNFPMEPS                    0xFC0A
+#define HERMES_RID_CNFMULTICASTRECEIVE         0xFC0B
+#define HERMES_RID_CNFMAXSLEEPDURATION         0xFC0C
+#define HERMES_RID_CNFPMHOLDOVERDURATION       0xFC0D
+#define HERMES_RID_CNFOWNNAME                  0xFC0E
+#define HERMES_RID_CNFOWNDTIMPERIOD            0xFC10
+#define HERMES_RID_CNFWDSADDRESS1              0xFC11
+#define HERMES_RID_CNFWDSADDRESS2              0xFC12
+#define HERMES_RID_CNFWDSADDRESS3              0xFC13
+#define HERMES_RID_CNFWDSADDRESS4              0xFC14
+#define HERMES_RID_CNFWDSADDRESS5              0xFC15
+#define HERMES_RID_CNFWDSADDRESS6              0xFC16
+#define HERMES_RID_CNFMULTICASTPMBUFFERING     0xFC17
+#define HERMES_RID_CNFWEPENABLED_AGERE         0xFC20
+#define HERMES_RID_CNFAUTHENTICATION_AGERE     0xFC21
+#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL    0xFC21
+#define HERMES_RID_CNFDROPUNENCRYPTED          0xFC22
+#define HERMES_RID_CNFWEPDEFAULTKEYID          0xFC23
+#define HERMES_RID_CNFDEFAULTKEY0              0xFC24
+#define HERMES_RID_CNFDEFAULTKEY1              0xFC25
+#define HERMES_RID_CNFMWOROBUST_AGERE          0xFC25
+#define HERMES_RID_CNFDEFAULTKEY2              0xFC26
+#define HERMES_RID_CNFDEFAULTKEY3              0xFC27
+#define HERMES_RID_CNFWEPFLAGS_INTERSIL                0xFC28
+#define HERMES_RID_CNFWEPKEYMAPPINGTABLE       0xFC29
+#define HERMES_RID_CNFAUTHENTICATION           0xFC2A
+#define HERMES_RID_CNFMAXASSOCSTA              0xFC2B
+#define        HERMES_RID_CNFKEYLENGTH_SYMBOL          0xFC2B
+#define HERMES_RID_CNFTXCONTROL                        0xFC2C
+#define HERMES_RID_CNFROAMINGMODE              0xFC2D
+#define HERMES_RID_CNFHOSTAUTHENTICATION       0xFC2E
+#define HERMES_RID_CNFRCVCRCERROR              0xFC30
+#define HERMES_RID_CNFMMLIFE                   0xFC31
+#define HERMES_RID_CNFALTRETRYCOUNT            0xFC32
+#define HERMES_RID_CNFBEACONINT                        0xFC33
+#define HERMES_RID_CNFAPPCFINFO                        0xFC34
+#define HERMES_RID_CNFSTAPCFINFO               0xFC35
+#define HERMES_RID_CNFPRIORITYQUSAGE           0xFC37
+#define HERMES_RID_CNFTIMCTRL                  0xFC40
+#define HERMES_RID_CNFTHIRTY2TALLY             0xFC42
+#define HERMES_RID_CNFENHSECURITY              0xFC43
+#define HERMES_RID_CNFGROUPADDRESSES           0xFC80
+#define HERMES_RID_CNFCREATEIBSS               0xFC81
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD   0xFC82
+#define HERMES_RID_CNFRTSTHRESHOLD             0xFC83
+#define HERMES_RID_CNFTXRATECONTROL            0xFC84
+#define HERMES_RID_CNFPROMISCUOUSMODE          0xFC85
+#define HERMES_RID_CNFBASICRATES_SYMBOL                0xFC8A
+#define HERMES_RID_CNFPREAMBLE_SYMBOL          0xFC8C
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0  0xFC90
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1  0xFC91
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2  0xFC92
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3  0xFC93
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4  0xFC94
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5  0xFC95
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6  0xFC96
+#define HERMES_RID_CNFRTSTHRESHOLD0            0xFC97
+#define HERMES_RID_CNFRTSTHRESHOLD1            0xFC98
+#define HERMES_RID_CNFRTSTHRESHOLD2            0xFC99
+#define HERMES_RID_CNFRTSTHRESHOLD3            0xFC9A
+#define HERMES_RID_CNFRTSTHRESHOLD4            0xFC9B
+#define HERMES_RID_CNFRTSTHRESHOLD5            0xFC9C
+#define HERMES_RID_CNFRTSTHRESHOLD6            0xFC9D
+#define HERMES_RID_CNFHOSTSCAN_SYMBOL          0xFCAB
+#define HERMES_RID_CNFSHORTPREAMBLE            0xFCB0
+#define HERMES_RID_CNFWEPKEYS_AGERE            0xFCB0
+#define HERMES_RID_CNFEXCLUDELONGPREAMBLE      0xFCB1
+#define HERMES_RID_CNFTXKEY_AGERE              0xFCB1
+#define HERMES_RID_CNFAUTHENTICATIONRSPTO      0xFCB2
+#define HERMES_RID_CNFSCANSSID_AGERE           0xFCB2
+#define HERMES_RID_CNFBASICRATES               0xFCB3
+#define HERMES_RID_CNFSUPPORTEDRATES           0xFCB4
+#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE  0xFCB4
+#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE        0xFCB5
+#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE  0xFCB6
+#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE   0xFCB7
+#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE   0xFCB8
+#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
+#define HERMES_RID_CNFCACHEDPMKADDRESS         0xFCBA
+#define HERMES_RID_CNFREMOVEPMKADDRESS         0xFCBB
+#define HERMES_RID_CNFSCANCHANNELS2GHZ         0xFCC2
+#define HERMES_RID_CNFDISASSOCIATE             0xFCC8
+#define HERMES_RID_CNFTICKTIME                 0xFCE0
+#define HERMES_RID_CNFSCANREQUEST              0xFCE1
+#define HERMES_RID_CNFJOINREQUEST              0xFCE2
+#define HERMES_RID_CNFAUTHENTICATESTATION      0xFCE3
+#define HERMES_RID_CNFCHANNELINFOREQUEST       0xFCE4
+#define HERMES_RID_CNFHOSTSCAN                 0xFCE5
+
+/*
+ * Information RIDs
+ */
+#define HERMES_RID_MAXLOADTIME                 0xFD00
+#define HERMES_RID_DOWNLOADBUFFER              0xFD01
+#define HERMES_RID_PRIID                       0xFD02
+#define HERMES_RID_PRISUPRANGE                 0xFD03
+#define HERMES_RID_CFIACTRANGES                        0xFD04
+#define HERMES_RID_NICSERNUM                   0xFD0A
+#define HERMES_RID_NICID                       0xFD0B
+#define HERMES_RID_MFISUPRANGE                 0xFD0C
+#define HERMES_RID_CFISUPRANGE                 0xFD0D
+#define HERMES_RID_CHANNELLIST                 0xFD10
+#define HERMES_RID_REGULATORYDOMAINS           0xFD11
+#define HERMES_RID_TEMPTYPE                    0xFD12
+#define HERMES_RID_CIS                         0xFD13
+#define HERMES_RID_STAID                       0xFD20
+#define HERMES_RID_STASUPRANGE                 0xFD21
+#define HERMES_RID_MFIACTRANGES                        0xFD22
+#define HERMES_RID_CFIACTRANGES2               0xFD23
+#define HERMES_RID_SECONDARYVERSION_SYMBOL     0xFD24
+#define HERMES_RID_PORTSTATUS                  0xFD40
+#define HERMES_RID_CURRENTSSID                 0xFD41
+#define HERMES_RID_CURRENTBSSID                        0xFD42
+#define HERMES_RID_COMMSQUALITY                        0xFD43
+#define HERMES_RID_CURRENTTXRATE               0xFD44
+#define HERMES_RID_CURRENTBEACONINTERVAL       0xFD45
+#define HERMES_RID_CURRENTSCALETHRESHOLDS      0xFD46
+#define HERMES_RID_PROTOCOLRSPTIME             0xFD47
+#define HERMES_RID_SHORTRETRYLIMIT             0xFD48
+#define HERMES_RID_LONGRETRYLIMIT              0xFD49
+#define HERMES_RID_MAXTRANSMITLIFETIME         0xFD4A
+#define HERMES_RID_MAXRECEIVELIFETIME          0xFD4B
+#define HERMES_RID_CFPOLLABLE                  0xFD4C
+#define HERMES_RID_AUTHENTICATIONALGORITHMS    0xFD4D
+#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED    0xFD4F
+#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL    0xFD51
+#define HERMES_RID_CURRENTTXRATE1              0xFD80
+#define HERMES_RID_CURRENTTXRATE2              0xFD81
+#define HERMES_RID_CURRENTTXRATE3              0xFD82
+#define HERMES_RID_CURRENTTXRATE4              0xFD83
+#define HERMES_RID_CURRENTTXRATE5              0xFD84
+#define HERMES_RID_CURRENTTXRATE6              0xFD85
+#define HERMES_RID_OWNMACADDR                  0xFD86
+#define HERMES_RID_SCANRESULTSTABLE            0xFD88
+#define HERMES_RID_CURRENT_COUNTRY_INFO                0xFD89
+#define HERMES_RID_CURRENT_WPA_IE              0xFD8A
+#define HERMES_RID_CURRENT_TKIP_IV             0xFD8B
+#define HERMES_RID_CURRENT_ASSOC_REQ_INFO      0xFD8C
+#define HERMES_RID_CURRENT_ASSOC_RESP_INFO     0xFD8D
+#define HERMES_RID_TXQUEUEEMPTY                        0xFD91
+#define HERMES_RID_PHYTYPE                     0xFDC0
+#define HERMES_RID_CURRENTCHANNEL              0xFDC1
+#define HERMES_RID_CURRENTPOWERSTATE           0xFDC2
+#define HERMES_RID_CCAMODE                     0xFDC3
+#define HERMES_RID_SUPPORTEDDATARATES          0xFDC6
+#define HERMES_RID_BUILDSEQ                    0xFFFE
+#define HERMES_RID_FWID                                0xFFFF
+
+#endif
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
new file mode 100644 (file)
index 0000000..f4ea08f
--- /dev/null
@@ -0,0 +1,6032 @@
+/* orinoco.c - (formerly known as dldwd_cs.c and orinoco_cs.c)
+ *
+ * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
+ * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
+ *
+ * Current maintainers (as of 29 September 2003) are:
+ *     Pavel Roskin <proski AT gnu.org>
+ * and David Gibson <hermes AT gibson.dropbear.id.au>
+ *
+ * (C) Copyright David Gibson, IBM Corporation 2001-2003.
+ * Copyright (C) 2000 David Gibson, Linuxcare Australia.
+ *     With some help from :
+ * Copyright (C) 2001 Jean Tourrilhes, HP Labs
+ * Copyright (C) 2001 Benjamin Herrenschmidt
+ *
+ * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
+ *
+ * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
+ * AT fasta.fh-dortmund.de>
+ *      http://www.stud.fh-dortmund.de/~andy/wvlan/
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds AT users.sourceforge.net>.  Portions created by David
+ * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
+ * Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.  */
+
+/*
+ * TODO
+ *     o Handle de-encapsulation within network layer, provide 802.11
+ *       headers (patch from Thomas 'Dent' Mirlacher)
+ *     o Fix possible races in SPY handling.
+ *     o Disconnect wireless extensions from fundamental configuration.
+ *     o (maybe) Software WEP support (patch from Stano Meduna).
+ *     o (maybe) Use multiple Tx buffers - driver handling queue
+ *       rather than firmware.
+ */
+
+/* Locking and synchronization:
+ *
+ * The basic principle is that everything is serialized through a
+ * single spinlock, priv->lock.  The lock is used in user, bh and irq
+ * context, so when taken outside hardirq context it should always be
+ * taken with interrupts disabled.  The lock protects both the
+ * hardware and the struct orinoco_private.
+ *
+ * Another flag, priv->hw_unavailable indicates that the hardware is
+ * unavailable for an extended period of time (e.g. suspended, or in
+ * the middle of a hard reset).  This flag is protected by the
+ * spinlock.  All code which touches the hardware should check the
+ * flag after taking the lock, and if it is set, give up on whatever
+ * they are doing and drop the lock again.  The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+ * hw_unavailable is non-zero).
+ */
+
+#define DRIVER_NAME "orinoco"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/firmware.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+
+#include "hermes_rid.h"
+#include "hermes_dld.h"
+#include "orinoco.h"
+
+/********************************************************************/
+/* Module information                                               */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Level of debugging. Used in the macros in orinoco.h */
+#ifdef ORINOCO_DEBUG
+int orinoco_debug = ORINOCO_DEBUG;
+module_param(orinoco_debug, int, 0644);
+MODULE_PARM_DESC(orinoco_debug, "Debug level");
+EXPORT_SYMBOL(orinoco_debug);
+#endif
+
+static int suppress_linkstatus; /* = 0 */
+module_param(suppress_linkstatus, bool, 0644);
+MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
+static int ignore_disconnect; /* = 0 */
+module_param(ignore_disconnect, int, 0644);
+MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
+
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
+/********************************************************************/
+/* Compile time configuration and compatibility stuff               */
+/********************************************************************/
+
+/* We do this this way to avoid ifdefs in the actual code */
+#ifdef WIRELESS_SPY
+#define SPY_NUMBER(priv)       (priv->spy_data.spy_number)
+#else
+#define SPY_NUMBER(priv)       0
+#endif /* WIRELESS_SPY */
+
+/********************************************************************/
+/* Internal constants                                               */
+/********************************************************************/
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
+
+#define ORINOCO_MIN_MTU                256
+#define ORINOCO_MAX_MTU                (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
+
+#define SYMBOL_MAX_VER_LEN     (14)
+#define USER_BAP               0
+#define IRQ_BAP                        1
+#define MAX_IRQLOOPS_PER_IRQ   10
+#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
+                                           * how many events the
+                                           * device could
+                                           * legitimately generate */
+#define SMALL_KEY_SIZE         5
+#define LARGE_KEY_SIZE         13
+#define TX_NICBUF_SIZE_BUG     1585            /* Bug in Symbol firmware */
+
+#define DUMMY_FID              0xFFFF
+
+/*#define MAX_MULTICAST(priv)  (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
+  HERMES_MAX_MULTICAST : 0)*/
+#define MAX_MULTICAST(priv)    (HERMES_MAX_MULTICAST)
+
+#define ORINOCO_INTEN          (HERMES_EV_RX | HERMES_EV_ALLOC \
+                                | HERMES_EV_TX | HERMES_EV_TXEXC \
+                                | HERMES_EV_WTERR | HERMES_EV_INFO \
+                                | HERMES_EV_INFDROP )
+
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static const struct ethtool_ops orinoco_ethtool_ops;
+
+/********************************************************************/
+/* Data tables                                                      */
+/********************************************************************/
+
+/* The frequency of each channel in MHz */
+static const long channel_frequency[] = {
+       2412, 2417, 2422, 2427, 2432, 2437, 2442,
+       2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequency)
+
+/* This tables gives the actual meanings of the bitrate IDs returned
+ * by the firmware. */
+static struct {
+       int bitrate; /* in 100s of kilobits */
+       int automatic;
+       u16 agere_txratectrl;
+       u16 intersil_txratectrl;
+} bitrate_table[] = {
+       {110, 1,  3, 15}, /* Entry 0 is the default */
+       {10,  0,  1,  1},
+       {10,  1,  1,  1},
+       {20,  0,  2,  2},
+       {20,  1,  6,  3},
+       {55,  0,  4,  4},
+       {55,  1,  7,  7},
+       {110, 0,  5,  8},
+};
+#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+
+/********************************************************************/
+/* Data types                                                       */
+/********************************************************************/
+
+/* Beginning of the Tx descriptor, used in TxExc handling */
+struct hermes_txexc_data {
+       struct hermes_tx_descriptor desc;
+       __le16 frame_ctl;
+       __le16 duration_id;
+       u8 addr1[ETH_ALEN];
+} __attribute__ ((packed));
+
+/* Rx frame header except compatibility 802.3 header */
+struct hermes_rx_descriptor {
+       /* Control */
+       __le16 status;
+       __le32 time;
+       u8 silence;
+       u8 signal;
+       u8 rate;
+       u8 rxflow;
+       __le32 reserved;
+
+       /* 802.11 header */
+       __le16 frame_ctl;
+       __le16 duration_id;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       __le16 seq_ctl;
+       u8 addr4[ETH_ALEN];
+
+       /* Data length */
+       __le16 data_len;
+} __attribute__ ((packed));
+
+/********************************************************************/
+/* Function prototypes                                              */
+/********************************************************************/
+
+static int __orinoco_program_rids(struct net_device *dev);
+static void __orinoco_set_multicast_list(struct net_device *dev);
+
+/********************************************************************/
+/* Michael MIC crypto setup                                         */
+/********************************************************************/
+#define MICHAEL_MIC_LEN 8
+static int orinoco_mic_init(struct orinoco_private *priv)
+{
+       priv->tx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+       if (IS_ERR(priv->tx_tfm_mic)) {
+               printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+                      "crypto API michael_mic\n");
+               priv->tx_tfm_mic = NULL;
+               return -ENOMEM;
+       }
+
+       priv->rx_tfm_mic = crypto_alloc_hash("michael_mic", 0, 0);
+       if (IS_ERR(priv->rx_tfm_mic)) {
+               printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
+                      "crypto API michael_mic\n");
+               priv->rx_tfm_mic = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void orinoco_mic_free(struct orinoco_private *priv)
+{
+       if (priv->tx_tfm_mic)
+               crypto_free_hash(priv->tx_tfm_mic);
+       if (priv->rx_tfm_mic)
+               crypto_free_hash(priv->rx_tfm_mic);
+}
+
+static int michael_mic(struct crypto_hash *tfm_michael, u8 *key,
+                      u8 *da, u8 *sa, u8 priority,
+                      u8 *data, size_t data_len, u8 *mic)
+{
+       struct hash_desc desc;
+       struct scatterlist sg[2];
+       u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
+
+       if (tfm_michael == NULL) {
+               printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
+               return -1;
+       }
+
+       /* Copy header into buffer. We need the padding on the end zeroed */
+       memcpy(&hdr[0], da, ETH_ALEN);
+       memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
+       hdr[ETH_ALEN*2] = priority;
+       hdr[ETH_ALEN*2+1] = 0;
+       hdr[ETH_ALEN*2+2] = 0;
+       hdr[ETH_ALEN*2+3] = 0;
+
+       /* Use scatter gather to MIC header and data in one go */
+       sg_init_table(sg, 2);
+       sg_set_buf(&sg[0], hdr, sizeof(hdr));
+       sg_set_buf(&sg[1], data, data_len);
+
+       if (crypto_hash_setkey(tfm_michael, key, MIC_KEYLEN))
+               return -1;
+
+       desc.tfm = tfm_michael;
+       desc.flags = 0;
+       return crypto_hash_digest(&desc, sg, data_len + sizeof(hdr),
+                                 mic);
+}
+
+/********************************************************************/
+/* Internal helper functions                                        */
+/********************************************************************/
+
+static inline void set_port_type(struct orinoco_private *priv)
+{
+       switch (priv->iw_mode) {
+       case IW_MODE_INFRA:
+               priv->port_type = 1;
+               priv->createibss = 0;
+               break;
+       case IW_MODE_ADHOC:
+               if (priv->prefer_port3) {
+                       priv->port_type = 3;
+                       priv->createibss = 0;
+               } else {
+                       priv->port_type = priv->ibss_port;
+                       priv->createibss = 1;
+               }
+               break;
+       case IW_MODE_MONITOR:
+               priv->port_type = 3;
+               priv->createibss = 0;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+                      priv->ndev->name);
+       }
+}
+
+#define ORINOCO_MAX_BSS_COUNT  64
+static int orinoco_bss_data_allocate(struct orinoco_private *priv)
+{
+       if (priv->bss_xbss_data)
+               return 0;
+
+       if (priv->has_ext_scan)
+               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+                                             sizeof(struct xbss_element),
+                                             GFP_KERNEL);
+       else
+               priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
+                                             sizeof(struct bss_element),
+                                             GFP_KERNEL);
+
+       if (!priv->bss_xbss_data) {
+               printk(KERN_WARNING "Out of memory allocating beacons");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void orinoco_bss_data_free(struct orinoco_private *priv)
+{
+       kfree(priv->bss_xbss_data);
+       priv->bss_xbss_data = NULL;
+}
+
+#define PRIV_BSS       ((struct bss_element *)priv->bss_xbss_data)
+#define PRIV_XBSS      ((struct xbss_element *)priv->bss_xbss_data)
+static void orinoco_bss_data_init(struct orinoco_private *priv)
+{
+       int i;
+
+       INIT_LIST_HEAD(&priv->bss_free_list);
+       INIT_LIST_HEAD(&priv->bss_list);
+       if (priv->has_ext_scan)
+               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+                       list_add_tail(&(PRIV_XBSS[i].list),
+                                     &priv->bss_free_list);
+       else
+               for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+                       list_add_tail(&(PRIV_BSS[i].list),
+                                     &priv->bss_free_list);
+
+}
+
+static inline u8 *orinoco_get_ie(u8 *data, size_t len,
+                                enum ieee80211_eid eid)
+{
+       u8 *p = data;
+       while ((p + 2) < (data + len)) {
+               if (p[0] == eid)
+                       return p;
+               p += p[1] + 2;
+       }
+       return NULL;
+}
+
+#define WPA_OUI_TYPE   "\x00\x50\xF2\x01"
+#define WPA_SELECTOR_LEN 4
+static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
+{
+       u8 *p = data;
+       while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
+               if ((p[0] == WLAN_EID_GENERIC) &&
+                   (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
+                       return p;
+               p += p[1] + 2;
+       }
+       return NULL;
+}
+
+
+/********************************************************************/
+/* Download functionality                                           */
+/********************************************************************/
+
+struct fw_info {
+       char *pri_fw;
+       char *sta_fw;
+       char *ap_fw;
+       u32 pda_addr;
+       u16 pda_size;
+};
+
+const static struct fw_info orinoco_fw[] = {
+       { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
+       { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
+       { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
+};
+
+/* Structure used to access fields in FW
+ * Make sure LE decoding macros are used
+ */
+struct orinoco_fw_header {
+       char hdr_vers[6];       /* ASCII string for header version */
+       __le16 headersize;      /* Total length of header */
+       __le32 entry_point;     /* NIC entry point */
+       __le32 blocks;          /* Number of blocks to program */
+       __le32 block_offset;    /* Offset of block data from eof header */
+       __le32 pdr_offset;      /* Offset to PDR data from eof header */
+       __le32 pri_offset;      /* Offset to primary plug data */
+       __le32 compat_offset;   /* Offset to compatibility data*/
+       char signature[0];      /* FW signature length headersize-20 */
+} __attribute__ ((packed));
+
+/* Download either STA or AP firmware into the card. */
+static int
+orinoco_dl_firmware(struct orinoco_private *priv,
+                   const struct fw_info *fw,
+                   int ap)
+{
+       /* Plug Data Area (PDA) */
+       __le16 *pda;
+
+       hermes_t *hw = &priv->hw;
+       const struct firmware *fw_entry;
+       const struct orinoco_fw_header *hdr;
+       const unsigned char *first_block;
+       const unsigned char *end;
+       const char *firmware;
+       struct net_device *dev = priv->ndev;
+       int err = 0;
+
+       pda = kzalloc(fw->pda_size, GFP_KERNEL);
+       if (!pda)
+               return -ENOMEM;
+
+       if (ap)
+               firmware = fw->ap_fw;
+       else
+               firmware = fw->sta_fw;
+
+       printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
+              dev->name, firmware);
+
+       /* Read current plug data */
+       err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+       printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+       if (err)
+               goto free;
+
+       if (priv->cached_fw)
+               fw_entry = priv->cached_fw;
+       else {
+               err = request_firmware(&fw_entry, firmware, priv->dev);
+               if (err) {
+                       printk(KERN_ERR "%s: Cannot find firmware %s\n",
+                              dev->name, firmware);
+                       err = -ENOENT;
+                       goto free;
+               }
+               priv->cached_fw = fw_entry;
+       }
+
+       hdr = (const struct orinoco_fw_header *) fw_entry->data;
+
+       /* Enable aux port to allow programming */
+       err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+       printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+       if (err != 0)
+               goto abort;
+
+       /* Program data */
+       first_block = (fw_entry->data +
+                      le16_to_cpu(hdr->headersize) +
+                      le32_to_cpu(hdr->block_offset));
+       end = fw_entry->data + fw_entry->size;
+
+       err = hermes_program(hw, first_block, end);
+       printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+       if (err != 0)
+               goto abort;
+
+       /* Update production data */
+       first_block = (fw_entry->data +
+                      le16_to_cpu(hdr->headersize) +
+                      le32_to_cpu(hdr->pdr_offset));
+
+       err = hermes_apply_pda_with_defaults(hw, first_block, pda);
+       printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+       if (err)
+               goto abort;
+
+       /* Tell card we've finished */
+       err = hermesi_program_end(hw);
+       printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+       if (err != 0)
+               goto abort;
+
+       /* Check if we're running */
+       printk(KERN_DEBUG "%s: hermes_present returned %d\n",
+              dev->name, hermes_present(hw));
+
+abort:
+       /* In case of error, assume firmware was bogus and release it */
+       if (err) {
+               priv->cached_fw = NULL;
+               release_firmware(fw_entry);
+       }
+
+free:
+       kfree(pda);
+       return err;
+}
+
+/* End markers */
+#define TEXT_END       0x1A            /* End of text header */
+
+/*
+ * Process a firmware image - stop the card, load the firmware, reset
+ * the card and make sure it responds.  For the secondary firmware take
+ * care of the PDA - read it and then write it on top of the firmware.
+ */
+static int
+symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
+               const unsigned char *image, const unsigned char *end,
+               int secondary)
+{
+       hermes_t *hw = &priv->hw;
+       int ret = 0;
+       const unsigned char *ptr;
+       const unsigned char *first_block;
+
+       /* Plug Data Area (PDA) */
+       __le16 *pda = NULL;
+
+       /* Binary block begins after the 0x1A marker */
+       ptr = image;
+       while (*ptr++ != TEXT_END);
+       first_block = ptr;
+
+       /* Read the PDA from EEPROM */
+       if (secondary) {
+               pda = kzalloc(fw->pda_size, GFP_KERNEL);
+               if (!pda)
+                       return -ENOMEM;
+
+               ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+               if (ret)
+                       goto free;
+       }
+
+       /* Stop the firmware, so that it can be safely rewritten */
+       if (priv->stop_fw) {
+               ret = priv->stop_fw(priv, 1);
+               if (ret)
+                       goto free;
+       }
+
+       /* Program the adapter with new firmware */
+       ret = hermes_program(hw, first_block, end);
+       if (ret)
+               goto free;
+
+       /* Write the PDA to the adapter */
+       if (secondary) {
+               size_t len = hermes_blocks_length(first_block);
+               ptr = first_block + len;
+               ret = hermes_apply_pda(hw, ptr, pda);
+               kfree(pda);
+               if (ret)
+                       return ret;
+       }
+
+       /* Run the firmware */
+       if (priv->stop_fw) {
+               ret = priv->stop_fw(priv, 0);
+               if (ret)
+                       return ret;
+       }
+
+       /* Reset hermes chip and make sure it responds */
+       ret = hermes_init(hw);
+
+       /* hermes_reset() should return 0 with the secondary firmware */
+       if (secondary && ret != 0)
+               return -ENODEV;
+
+       /* And this should work with any firmware */
+       if (!hermes_present(hw))
+               return -ENODEV;
+
+       return 0;
+
+free:
+       kfree(pda);
+       return ret;
+}
+
+
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+symbol_dl_firmware(struct orinoco_private *priv,
+                  const struct fw_info *fw)
+{
+       struct net_device *dev = priv->ndev;
+       int ret;
+       const struct firmware *fw_entry;
+
+       if (request_firmware(&fw_entry, fw->pri_fw,
+                            priv->dev) != 0) {
+               printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+                      dev->name, fw->pri_fw);
+               return -ENOENT;
+       }
+
+       /* Load primary firmware */
+       ret = symbol_dl_image(priv, fw, fw_entry->data,
+                             fw_entry->data + fw_entry->size, 0);
+       release_firmware(fw_entry);
+       if (ret) {
+               printk(KERN_ERR "%s: Primary firmware download failed\n",
+                      dev->name);
+               return ret;
+       }
+
+       if (request_firmware(&fw_entry, fw->sta_fw,
+                            priv->dev) != 0) {
+               printk(KERN_ERR "%s: Cannot find firmware: %s\n",
+                      dev->name, fw->sta_fw);
+               return -ENOENT;
+       }
+
+       /* Load secondary firmware */
+       ret = symbol_dl_image(priv, fw, fw_entry->data,
+                             fw_entry->data + fw_entry->size, 1);
+       release_firmware(fw_entry);
+       if (ret) {
+               printk(KERN_ERR "%s: Secondary firmware download failed\n",
+                      dev->name);
+       }
+
+       return ret;
+}
+
+static int orinoco_download(struct orinoco_private *priv)
+{
+       int err = 0;
+       /* Reload firmware */
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* case FIRMWARE_TYPE_INTERSIL: */
+               err = orinoco_dl_firmware(priv,
+                                         &orinoco_fw[priv->firmware_type], 0);
+               break;
+
+       case FIRMWARE_TYPE_SYMBOL:
+               err = symbol_dl_firmware(priv,
+                                        &orinoco_fw[priv->firmware_type]);
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               break;
+       }
+       /* TODO: if we fail we probably need to reinitialise
+        * the driver */
+
+       return err;
+}
+
+/********************************************************************/
+/* Device methods                                                   */
+/********************************************************************/
+
+static int orinoco_open(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       err = __orinoco_up(dev);
+
+       if (! err)
+               priv->open = 1;
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_stop(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+
+       /* We mustn't use orinoco_lock() here, because we need to be
+          able to close the interface even if hw_unavailable is set
+          (e.g. as we're released after a PC Card removal) */
+       spin_lock_irq(&priv->lock);
+
+       priv->open = 0;
+
+       err = __orinoco_down(dev);
+
+       spin_unlock_irq(&priv->lock);
+
+       return err;
+}
+
+static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       
+       return &priv->stats;
+}
+
+static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       struct iw_statistics *wstats = &priv->wstats;
+       int err;
+       unsigned long flags;
+
+       if (! netif_device_present(dev)) {
+               printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
+                      dev->name);
+               return NULL; /* FIXME: Can we do better than this? */
+       }
+
+       /* If busy, return the old stats.  Returning NULL may cause
+        * the interface to disappear from /proc/net/wireless */
+       if (orinoco_lock(priv, &flags) != 0)
+               return wstats;
+
+       /* We can't really wait for the tallies inquiry command to
+        * complete, so we just use the previous results and trigger
+        * a new tallies inquiry command for next time - Jean II */
+       /* FIXME: Really we should wait for the inquiry to come back -
+        * as it is the stats we give don't make a whole lot of sense.
+        * Unfortunately, it's not clear how to do that within the
+        * wireless extensions framework: I think we're in user
+        * context, but a lock seems to be held by the time we get in
+        * here so we're not safe to sleep here. */
+       hermes_inquire(hw, HERMES_INQ_TALLIES);
+
+       if (priv->iw_mode == IW_MODE_ADHOC) {
+               memset(&wstats->qual, 0, sizeof(wstats->qual));
+               /* If a spy address is defined, we report stats of the
+                * first spy address - Jean II */
+               if (SPY_NUMBER(priv)) {
+                       wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
+                       wstats->qual.level = priv->spy_data.spy_stat[0].level;
+                       wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
+                       wstats->qual.updated = priv->spy_data.spy_stat[0].updated;
+               }
+       } else {
+               struct {
+                       __le16 qual, signal, noise, unused;
+               } __attribute__ ((packed)) cq;
+
+               err = HERMES_READ_RECORD(hw, USER_BAP,
+                                        HERMES_RID_COMMSQUALITY, &cq);
+
+               if (!err) {
+                       wstats->qual.qual = (int)le16_to_cpu(cq.qual);
+                       wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
+                       wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
+                       wstats->qual.updated = 7;
+               }
+       }
+
+       orinoco_unlock(priv, &flags);
+       return wstats;
+}
+
+static void orinoco_set_multicast_list(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0) {
+               printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
+                      "called when hw_unavailable\n", dev->name);
+               return;
+       }
+
+       __orinoco_set_multicast_list(dev);
+       orinoco_unlock(priv, &flags);
+}
+
+static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
+               return -EINVAL;
+
+       /* MTU + encapsulation + header length */
+       if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
+            (priv->nicbuf_size - ETH_HLEN) )
+               return -EINVAL;
+
+       dev->mtu = new_mtu;
+
+       return 0;
+}
+
+/********************************************************************/
+/* Tx path                                                          */
+/********************************************************************/
+
+static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       u16 txfid = priv->txfid;
+       struct ethhdr *eh;
+       int tx_control;
+       unsigned long flags;
+
+       if (! netif_running(dev)) {
+               printk(KERN_ERR "%s: Tx on stopped device!\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+       
+       if (netif_queue_stopped(dev)) {
+               printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", 
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+       
+       if (orinoco_lock(priv, &flags) != 0) {
+               printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+               /* Oops, the firmware hasn't established a connection,
+                   silently drop the packet (this seems to be the
+                   safest approach). */
+               goto drop;
+       }
+
+       /* Check packet length */
+       if (skb->len < ETH_HLEN)
+               goto drop;
+
+       tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
+
+       if (priv->encode_alg == IW_ENCODE_ALG_TKIP)
+               tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+                       HERMES_TXCTRL_MIC;
+
+       if (priv->has_alt_txcntl) {
+               /* WPA enabled firmwares have tx_cntl at the end of
+                * the 802.11 header.  So write zeroed descriptor and
+                * 802.11 header at the same time
+                */
+               char desc[HERMES_802_3_OFFSET];
+               __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
+
+               memset(&desc, 0, sizeof(desc));
+
+               *txcntl = cpu_to_le16(tx_control);
+               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                       txfid, 0);
+               if (err) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: Error %d writing Tx "
+                                      "descriptor to BAP\n", dev->name, err);
+                       goto busy;
+               }
+       } else {
+               struct hermes_tx_descriptor desc;
+
+               memset(&desc, 0, sizeof(desc));
+
+               desc.tx_control = cpu_to_le16(tx_control);
+               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                       txfid, 0);
+               if (err) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR "%s: Error %d writing Tx "
+                                      "descriptor to BAP\n", dev->name, err);
+                       goto busy;
+               }
+
+               /* Clear the 802.11 header and data length fields - some
+                * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
+                * if this isn't done. */
+               hermes_clear_words(hw, HERMES_DATA0,
+                                  HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+       }
+
+       eh = (struct ethhdr *)skb->data;
+
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
+               struct header_struct {
+                       struct ethhdr eth;      /* 802.3 header */
+                       u8 encap[6];            /* 802.2 header */
+               } __attribute__ ((packed)) hdr;
+
+               /* Strip destination and source from the data */
+               skb_pull(skb, 2 * ETH_ALEN);
+
+               /* And move them to a separate header */
+               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
+               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+
+               /* Insert the SNAP header */
+               if (skb_headroom(skb) < sizeof(hdr)) {
+                       printk(KERN_ERR
+                              "%s: Not enough headroom for 802.2 headers %d\n",
+                              dev->name, skb_headroom(skb));
+                       goto drop;
+               }
+               eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
+               memcpy(eh, &hdr, sizeof(hdr));
+       }
+
+       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+                               txfid, HERMES_802_3_OFFSET);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
+                      dev->name, err);
+               goto busy;
+       }
+
+       /* Calculate Michael MIC */
+       if (priv->encode_alg == IW_ENCODE_ALG_TKIP) {
+               u8 mic_buf[MICHAEL_MIC_LEN + 1];
+               u8 *mic;
+               size_t offset;
+               size_t len;
+
+               if (skb->len % 2) {
+                       /* MIC start is on an odd boundary */
+                       mic_buf[0] = skb->data[skb->len - 1];
+                       mic = &mic_buf[1];
+                       offset = skb->len - 1;
+                       len = MICHAEL_MIC_LEN + 1;
+               } else {
+                       mic = &mic_buf[0];
+                       offset = skb->len;
+                       len = MICHAEL_MIC_LEN;
+               }
+
+               michael_mic(priv->tx_tfm_mic,
+                           priv->tkip_key[priv->tx_key].tx_mic,
+                           eh->h_dest, eh->h_source, 0 /* priority */,
+                           skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
+
+               /* Write the MIC */
+               err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+                                       txfid, HERMES_802_3_OFFSET + offset);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
+                              dev->name, err);
+                       goto busy;
+               }
+       }
+
+       /* Finally, we actually initiate the send */
+       netif_stop_queue(dev);
+
+       err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+                               txfid, NULL);
+       if (err) {
+               netif_start_queue(dev);
+               if (net_ratelimit())
+                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
+                               dev->name, err);
+               goto busy;
+       }
+
+       dev->trans_start = jiffies;
+       stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
+       goto ok;
+
+ drop:
+       stats->tx_errors++;
+       stats->tx_dropped++;
+
+ ok:
+       orinoco_unlock(priv, &flags);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+
+ busy:
+       if (err == -EIO)
+               schedule_work(&priv->reset_work);
+       orinoco_unlock(priv, &flags);
+       return NETDEV_TX_BUSY;
+}
+
+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       u16 fid = hermes_read_regn(hw, ALLOCFID);
+
+       if (fid != priv->txfid) {
+               if (fid != DUMMY_FID)
+                       printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
+                              dev->name, fid);
+               return;
+       }
+
+       hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
+}
+
+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+
+       stats->tx_packets++;
+
+       netif_wake_queue(dev);
+
+       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+}
+
+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       u16 fid = hermes_read_regn(hw, TXCOMPLFID);
+       u16 status;
+       struct hermes_txexc_data hdr;
+       int err = 0;
+
+       if (fid == DUMMY_FID)
+               return; /* Nothing's really happened */
+
+       /* Read part of the frame header - we need status and addr1 */
+       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+                              sizeof(struct hermes_txexc_data),
+                              fid, 0);
+
+       hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+       stats->tx_errors++;
+
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
+                      "(FID=%04X error %d)\n",
+                      dev->name, fid, err);
+               return;
+       }
+       
+       DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+             err, fid);
+    
+       /* We produce a TXDROP event only for retry or lifetime
+        * exceeded, because that's the only status that really mean
+        * that this particular node went away.
+        * Other errors means that *we* screwed up. - Jean II */
+       status = le16_to_cpu(hdr.desc.status);
+       if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+               union iwreq_data        wrqu;
+
+               /* Copy 802.11 dest address.
+                * We use the 802.11 header because the frame may
+                * not be 802.3 or may be mangled...
+                * In Ad-Hoc mode, it will be the node address.
+                * In managed mode, it will be most likely the AP addr
+                * User space will figure out how to convert it to
+                * whatever it needs (IP address or else).
+                * - Jean II */
+               memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+               wrqu.addr.sa_family = ARPHRD_ETHER;
+
+               /* Send event to user space */
+               wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+       }
+
+       netif_wake_queue(dev);
+}
+
+static void orinoco_tx_timeout(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       struct hermes *hw = &priv->hw;
+
+       printk(KERN_WARNING "%s: Tx timeout! "
+              "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
+              dev->name, hermes_read_regn(hw, ALLOCFID),
+              hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
+
+       stats->tx_errors++;
+
+       schedule_work(&priv->reset_work);
+}
+
+/********************************************************************/
+/* Rx path (data frames)                                            */
+/********************************************************************/
+
+/* Does the frame have a SNAP header indicating it should be
+ * de-encapsulated to Ethernet-II? */
+static inline int is_ethersnap(void *_hdr)
+{
+       u8 *hdr = _hdr;
+
+       /* We de-encapsulate all packets which, a) have SNAP headers
+        * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
+        * and where b) the OUI of the SNAP header is 00:00:00 or
+        * 00:00:f8 - we need both because different APs appear to use
+        * different OUIs for some reason */
+       return (memcmp(hdr, &encaps_hdr, 5) == 0)
+               && ( (hdr[5] == 0x00) || (hdr[5] == 0xf8) );
+}
+
+static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
+                                     int level, int noise)
+{
+       struct iw_quality wstats;
+       wstats.level = level - 0x95;
+       wstats.noise = noise - 0x95;
+       wstats.qual = (level > noise) ? (level - noise) : 0;
+       wstats.updated = 7;
+       /* Update spy records */
+       wireless_spy_update(dev, mac, &wstats);
+}
+
+static void orinoco_stat_gather(struct net_device *dev,
+                               struct sk_buff *skb,
+                               struct hermes_rx_descriptor *desc)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       /* Using spy support with lots of Rx packets, like in an
+        * infrastructure (AP), will really slow down everything, because
+        * the MAC address must be compared to each entry of the spy list.
+        * If the user really asks for it (set some address in the
+        * spy list), we do it, but he will pay the price.
+        * Note that to get here, you need both WIRELESS_SPY
+        * compiled in AND some addresses in the list !!!
+        */
+       /* Note : gcc will optimise the whole section away if
+        * WIRELESS_SPY is not defined... - Jean II */
+       if (SPY_NUMBER(priv)) {
+               orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
+                                  desc->signal, desc->silence);
+       }
+}
+
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ *     dev             network device
+ *     rxfid           received FID
+ *     desc            rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+                              struct hermes_rx_descriptor *desc)
+{
+       u32 hdrlen = 30;        /* return full header by default */
+       u32 datalen = 0;
+       u16 fc;
+       int err;
+       int len;
+       struct sk_buff *skb;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       hermes_t *hw = &priv->hw;
+
+       len = le16_to_cpu(desc->data_len);
+
+       /* Determine the size of the header and the data */
+       fc = le16_to_cpu(desc->frame_ctl);
+       switch (fc & IEEE80211_FCTL_FTYPE) {
+       case IEEE80211_FTYPE_DATA:
+               if ((fc & IEEE80211_FCTL_TODS)
+                   && (fc & IEEE80211_FCTL_FROMDS))
+                       hdrlen = 30;
+               else
+                       hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_MGMT:
+               hdrlen = 24;
+               datalen = len;
+               break;
+       case IEEE80211_FTYPE_CTL:
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_PSPOLL:
+               case IEEE80211_STYPE_RTS:
+               case IEEE80211_STYPE_CFEND:
+               case IEEE80211_STYPE_CFENDACK:
+                       hdrlen = 16;
+                       break;
+               case IEEE80211_STYPE_CTS:
+               case IEEE80211_STYPE_ACK:
+                       hdrlen = 10;
+                       break;
+               }
+               break;
+       default:
+               /* Unknown frame type */
+               break;
+       }
+
+       /* sanity check the length */
+       if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
+               printk(KERN_DEBUG "%s: oversized monitor frame, "
+                      "data length = %d\n", dev->name, datalen);
+               stats->rx_length_errors++;
+               goto update_stats;
+       }
+
+       skb = dev_alloc_skb(hdrlen + datalen);
+       if (!skb) {
+               printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+                      dev->name);
+               goto update_stats;
+       }
+
+       /* Copy the 802.11 header to the skb */
+       memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+       skb_reset_mac_header(skb);
+
+       /* If any, copy the data from the card to the skb */
+       if (datalen > 0) {
+               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                      ALIGN(datalen, 2), rxfid,
+                                      HERMES_802_2_OFFSET);
+               if (err) {
+                       printk(KERN_ERR "%s: error %d reading monitor frame\n",
+                              dev->name, err);
+                       goto drop;
+               }
+       }
+
+       skb->dev = dev;
+       skb->ip_summed = CHECKSUM_NONE;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = __constant_htons(ETH_P_802_2);
+       
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+       netif_rx(skb);
+       return;
+
+ drop:
+       dev_kfree_skb_irq(skb);
+ update_stats:
+       stats->rx_errors++;
+       stats->rx_dropped++;
+}
+
+/* Get tsc from the firmware */
+static int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key,
+                                 u8 *tsc)
+{
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       u8 tsc_arr[4][IW_ENCODE_SEQ_MAX_SIZE];
+
+       if ((key < 0) || (key > 4))
+               return -EINVAL;
+
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+                             sizeof(tsc_arr), NULL, &tsc_arr);
+       if (!err)
+               memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
+
+       return err;
+}
+
+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       struct iw_statistics *wstats = &priv->wstats;
+       struct sk_buff *skb = NULL;
+       u16 rxfid, status;
+       int length;
+       struct hermes_rx_descriptor *desc;
+       struct orinoco_rx_data *rx_data;
+       int err;
+
+       desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
+       if (!desc) {
+               printk(KERN_WARNING
+                      "%s: Can't allocate space for RX descriptor\n",
+                      dev->name);
+               goto update_stats;
+       }
+
+       rxfid = hermes_read_regn(hw, RXFID);
+
+       err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+                              rxfid, 0);
+       if (err) {
+               printk(KERN_ERR "%s: error %d reading Rx descriptor. "
+                      "Frame dropped.\n", dev->name, err);
+               goto update_stats;
+       }
+
+       status = le16_to_cpu(desc->status);
+
+       if (status & HERMES_RXSTAT_BADCRC) {
+               DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+                     dev->name);
+               stats->rx_crc_errors++;
+               goto update_stats;
+       }
+
+       /* Handle frames in monitor mode */
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               orinoco_rx_monitor(dev, rxfid, desc);
+               goto out;
+       }
+
+       if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+               DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+                     dev->name);
+               wstats->discard.code++;
+               goto update_stats;
+       }
+
+       length = le16_to_cpu(desc->data_len);
+
+       /* Sanity checks */
+       if (length < 3) { /* No for even an 802.2 LLC header */
+               /* At least on Symbol firmware with PCF we get quite a
+                   lot of these legitimately - Poll frames with no
+                   data. */
+               goto out;
+       }
+       if (length > IEEE80211_MAX_DATA_LEN) {
+               printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
+                      dev->name, length);
+               stats->rx_length_errors++;
+               goto update_stats;
+       }
+
+       /* Payload size does not include Michael MIC. Increase payload
+        * size to read it together with the data. */
+       if (status & HERMES_RXSTAT_MIC)
+               length += MICHAEL_MIC_LEN;
+
+       /* We need space for the packet data itself, plus an ethernet
+          header, plus 2 bytes so we can align the IP header on a
+          32bit boundary, plus 1 byte so we can read in odd length
+          packets from the card, which has an IO granularity of 16
+          bits */  
+       skb = dev_alloc_skb(length+ETH_HLEN+2+1);
+       if (!skb) {
+               printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
+                      dev->name);
+               goto update_stats;
+       }
+
+       /* We'll prepend the header, so reserve space for it.  The worst
+          case is no decapsulation, when 802.3 header is prepended and
+          nothing is removed.  2 is for aligning the IP header.  */
+       skb_reserve(skb, ETH_HLEN + 2);
+
+       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                              ALIGN(length, 2), rxfid,
+                              HERMES_802_2_OFFSET);
+       if (err) {
+               printk(KERN_ERR "%s: error %d reading frame. "
+                      "Frame dropped.\n", dev->name, err);
+               goto drop;
+       }
+
+       /* Add desc and skb to rx queue */
+       rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
+       if (!rx_data) {
+               printk(KERN_WARNING "%s: Can't allocate RX packet\n",
+                       dev->name);
+               goto drop;
+       }
+       rx_data->desc = desc;
+       rx_data->skb = skb;
+       list_add_tail(&rx_data->list, &priv->rx_list);
+       tasklet_schedule(&priv->rx_tasklet);
+
+       return;
+
+drop:
+       dev_kfree_skb_irq(skb);
+update_stats:
+       stats->rx_errors++;
+       stats->rx_dropped++;
+out:
+       kfree(desc);
+}
+
+static void orinoco_rx(struct net_device *dev,
+                      struct hermes_rx_descriptor *desc,
+                      struct sk_buff *skb)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       u16 status, fc;
+       int length;
+       struct ethhdr *hdr;
+
+       status = le16_to_cpu(desc->status);
+       length = le16_to_cpu(desc->data_len);
+       fc = le16_to_cpu(desc->frame_ctl);
+
+       /* Calculate and check MIC */
+       if (status & HERMES_RXSTAT_MIC) {
+               int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
+                             HERMES_MIC_KEY_ID_SHIFT);
+               u8 mic[MICHAEL_MIC_LEN];
+               u8 *rxmic;
+               u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
+                       desc->addr3 : desc->addr2;
+
+               /* Extract Michael MIC from payload */
+               rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
+
+               skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+               length -= MICHAEL_MIC_LEN;
+
+               michael_mic(priv->rx_tfm_mic,
+                           priv->tkip_key[key_id].rx_mic,
+                           desc->addr1,
+                           src,
+                           0, /* priority or QoS? */
+                           skb->data,
+                           skb->len,
+                           &mic[0]);
+
+               if (memcmp(mic, rxmic,
+                          MICHAEL_MIC_LEN)) {
+                       union iwreq_data wrqu;
+                       struct iw_michaelmicfailure wxmic;
+
+                       printk(KERN_WARNING "%s: "
+                              "Invalid Michael MIC in data frame from %pM, "
+                              "using key %i\n",
+                              dev->name, src, key_id);
+
+                       /* TODO: update stats */
+
+                       /* Notify userspace */
+                       memset(&wxmic, 0, sizeof(wxmic));
+                       wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
+                       wxmic.flags |= (desc->addr1[0] & 1) ?
+                               IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
+                       wxmic.src_addr.sa_family = ARPHRD_ETHER;
+                       memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
+
+                       (void) orinoco_hw_get_tkip_iv(priv, key_id,
+                                                     &wxmic.tsc[0]);
+
+                       memset(&wrqu, 0, sizeof(wrqu));
+                       wrqu.data.length = sizeof(wxmic);
+                       wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
+                                           (char *) &wxmic);
+
+                       goto drop;
+               }
+       }
+
+       /* Handle decapsulation
+        * In most cases, the firmware tell us about SNAP frames.
+        * For some reason, the SNAP frames sent by LinkSys APs
+        * are not properly recognised by most firmwares.
+        * So, check ourselves */
+       if (length >= ENCAPS_OVERHEAD &&
+           (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+            ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+            is_ethersnap(skb->data))) {
+               /* These indicate a SNAP within 802.2 LLC within
+                  802.11 frame which we'll need to de-encapsulate to
+                  the original EthernetII frame. */
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
+       } else {
+               /* 802.3 frame - prepend 802.3 header as is */
+               hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+               hdr->h_proto = htons(length);
+       }
+       memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
+       if (fc & IEEE80211_FCTL_FROMDS)
+               memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
+       else
+               memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
+
+       skb->protocol = eth_type_trans(skb, dev);
+       skb->ip_summed = CHECKSUM_NONE;
+       if (fc & IEEE80211_FCTL_TODS)
+               skb->pkt_type = PACKET_OTHERHOST;
+       
+       /* Process the wireless stats if needed */
+       orinoco_stat_gather(dev, skb, desc);
+
+       /* Pass the packet to the networking stack */
+       netif_rx(skb);
+       stats->rx_packets++;
+       stats->rx_bytes += length;
+
+       return;
+
+ drop:
+       dev_kfree_skb(skb);
+       stats->rx_errors++;
+       stats->rx_dropped++;
+}
+
+static void orinoco_rx_isr_tasklet(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_rx_data *rx_data, *temp;
+       struct hermes_rx_descriptor *desc;
+       struct sk_buff *skb;
+
+       /* extract desc and skb from queue */
+       list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
+               desc = rx_data->desc;
+               skb = rx_data->skb;
+               list_del(&rx_data->list);
+               kfree(rx_data);
+
+               orinoco_rx(dev, desc, skb);
+
+               kfree(desc);
+       }
+}
+
+/********************************************************************/
+/* Rx path (info frames)                                            */
+/********************************************************************/
+
+static void print_linkstatus(struct net_device *dev, u16 status)
+{
+       char * s;
+
+       if (suppress_linkstatus)
+               return;
+
+       switch (status) {
+       case HERMES_LINKSTATUS_NOT_CONNECTED:
+               s = "Not Connected";
+               break;
+       case HERMES_LINKSTATUS_CONNECTED:
+               s = "Connected";
+               break;
+       case HERMES_LINKSTATUS_DISCONNECTED:
+               s = "Disconnected";
+               break;
+       case HERMES_LINKSTATUS_AP_CHANGE:
+               s = "AP Changed";
+               break;
+       case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+               s = "AP Out of Range";
+               break;
+       case HERMES_LINKSTATUS_AP_IN_RANGE:
+               s = "AP In Range";
+               break;
+       case HERMES_LINKSTATUS_ASSOC_FAILED:
+               s = "Association Failed";
+               break;
+       default:
+               s = "UNKNOWN";
+       }
+       
+       printk(KERN_INFO "%s: New link status: %s (%04x)\n",
+              dev->name, s, status);
+}
+
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct work_struct *work)
+{
+       struct orinoco_private *priv =
+               container_of(work, struct orinoco_private, join_work);
+       struct net_device *dev = priv->ndev;
+       struct hermes *hw = &priv->hw;
+       int err;
+       unsigned long flags;
+       struct join_req {
+               u8 bssid[ETH_ALEN];
+               __le16 channel;
+       } __attribute__ ((packed)) req;
+       const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+       struct prism2_scan_apinfo *atom = NULL;
+       int offset = 4;
+       int found = 0;
+       u8 *buf;
+       u16 len;
+
+       /* Allocate buffer for scan results */
+       buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+       if (! buf)
+               return;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               goto fail_lock;
+
+       /* Sanity checks in case user changed something in the meantime */
+       if (! priv->bssid_fixed)
+               goto out;
+
+       if (strlen(priv->desired_essid) == 0)
+               goto out;
+
+       /* Read scan results from the firmware */
+       err = hermes_read_ltv(hw, USER_BAP,
+                             HERMES_RID_SCANRESULTSTABLE,
+                             MAX_SCAN_LEN, &len, buf);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read scan results\n",
+                      dev->name);
+               goto out;
+       }
+
+       len = HERMES_RECLEN_TO_BYTES(len);
+
+       /* Go through the scan results looking for the channel of the AP
+        * we were requested to join */
+       for (; offset + atom_len <= len; offset += atom_len) {
+               atom = (struct prism2_scan_apinfo *) (buf + offset);
+               if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (! found) {
+               DEBUG(1, "%s: Requested AP not found in scan results\n",
+                     dev->name);
+               goto out;
+       }
+
+       memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+       req.channel = atom->channel;    /* both are little-endian */
+       err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+                                 &req);
+       if (err)
+               printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+ fail_lock:
+       kfree(buf);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       struct hermes *hw = &priv->hw;
+       union iwreq_data wrqu;
+       int err;
+
+       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       if (err != 0)
+               return;
+
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+       /* Send event to user space */
+       wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       struct hermes *hw = &priv->hw;
+       union iwreq_data wrqu;
+       int err;
+       u8 buf[88];
+       u8 *ie;
+
+       if (!priv->has_wpa)
+               return;
+
+       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+                             sizeof(buf), NULL, &buf);
+       if (err != 0)
+               return;
+
+       ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+       if (ie) {
+               int rem = sizeof(buf) - (ie - &buf[0]);
+               wrqu.data.length = ie[1] + 2;
+               if (wrqu.data.length > rem)
+                       wrqu.data.length = rem;
+
+               if (wrqu.data.length)
+                       /* Send event to user space */
+                       wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
+       }
+}
+
+static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
+{
+       struct net_device *dev = priv->ndev;
+       struct hermes *hw = &priv->hw;
+       union iwreq_data wrqu;
+       int err;
+       u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
+       u8 *ie;
+
+       if (!priv->has_wpa)
+               return;
+
+       err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+                             sizeof(buf), NULL, &buf);
+       if (err != 0)
+               return;
+
+       ie = orinoco_get_wpa_ie(buf, sizeof(buf));
+       if (ie) {
+               int rem = sizeof(buf) - (ie - &buf[0]);
+               wrqu.data.length = ie[1] + 2;
+               if (wrqu.data.length > rem)
+                       wrqu.data.length = rem;
+
+               if (wrqu.data.length)
+                       /* Send event to user space */
+                       wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
+       }
+}
+
+static void orinoco_send_wevents(struct work_struct *work)
+{
+       struct orinoco_private *priv =
+               container_of(work, struct orinoco_private, wevent_work);
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return;
+
+       orinoco_send_assocreqie_wevent(priv);
+       orinoco_send_assocrespie_wevent(priv);
+       orinoco_send_bssid_wevent(priv);
+
+       orinoco_unlock(priv, &flags);
+}
+
+static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
+                                             unsigned long scan_age)
+{
+       if (priv->has_ext_scan) {
+               struct xbss_element *bss;
+               struct xbss_element *tmp_bss;
+
+               /* Blow away current list of scan results */
+               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+                       if (!scan_age ||
+                           time_after(jiffies, bss->last_scanned + scan_age)) {
+                               list_move_tail(&bss->list,
+                                              &priv->bss_free_list);
+                               /* Don't blow away ->list, just BSS data */
+                               memset(&bss->bss, 0, sizeof(bss->bss));
+                               bss->last_scanned = 0;
+                       }
+               }
+       } else {
+               struct bss_element *bss;
+               struct bss_element *tmp_bss;
+
+               /* Blow away current list of scan results */
+               list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+                       if (!scan_age ||
+                           time_after(jiffies, bss->last_scanned + scan_age)) {
+                               list_move_tail(&bss->list,
+                                              &priv->bss_free_list);
+                               /* Don't blow away ->list, just BSS data */
+                               memset(&bss->bss, 0, sizeof(bss->bss));
+                               bss->last_scanned = 0;
+                       }
+               }
+       }
+}
+
+static void orinoco_add_ext_scan_result(struct orinoco_private *priv,
+                                       struct agere_ext_scan_info *atom)
+{
+       struct xbss_element *bss = NULL;
+       int found = 0;
+
+       /* Try to update an existing bss first */
+       list_for_each_entry(bss, &priv->bss_list, list) {
+               if (compare_ether_addr(bss->bss.bssid, atom->bssid))
+                       continue;
+               /* ESSID lengths */
+               if (bss->bss.data[1] != atom->data[1])
+                       continue;
+               if (memcmp(&bss->bss.data[2], &atom->data[2],
+                          atom->data[1]))
+                       continue;
+               found = 1;
+               break;
+       }
+
+       /* Grab a bss off the free list */
+       if (!found && !list_empty(&priv->bss_free_list)) {
+               bss = list_entry(priv->bss_free_list.next,
+                                struct xbss_element, list);
+               list_del(priv->bss_free_list.next);
+
+               list_add_tail(&bss->list, &priv->bss_list);
+       }
+
+       if (bss) {
+               /* Always update the BSS to get latest beacon info */
+               memcpy(&bss->bss, atom, sizeof(bss->bss));
+               bss->last_scanned = jiffies;
+       }
+}
+
+static int orinoco_process_scan_results(struct net_device *dev,
+                                       unsigned char *buf,
+                                       int len)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int                     offset;         /* In the scan data */
+       union hermes_scan_info *atom;
+       int                     atom_len;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               atom_len = sizeof(struct agere_scan_apinfo);
+               offset = 0;
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               /* Lack of documentation necessitates this hack.
+                * Different firmwares have 68 or 76 byte long atoms.
+                * We try modulo first.  If the length divides by both,
+                * we check what would be the channel in the second
+                * frame for a 68-byte atom.  76-byte atoms have 0 there.
+                * Valid channel cannot be 0.  */
+               if (len % 76)
+                       atom_len = 68;
+               else if (len % 68)
+                       atom_len = 76;
+               else if (len >= 1292 && buf[68] == 0)
+                       atom_len = 76;
+               else
+                       atom_len = 68;
+               offset = 0;
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               offset = 4;
+               if (priv->has_hostscan) {
+                       atom_len = le16_to_cpup((__le16 *)buf);
+                       /* Sanity check for atom_len */
+                       if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+                               printk(KERN_ERR "%s: Invalid atom_len in scan "
+                                      "data: %d\n", dev->name, atom_len);
+                               return -EIO;
+                       }
+               } else
+                       atom_len = offsetof(struct prism2_scan_apinfo, atim);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       /* Check that we got an whole number of atoms */
+       if ((len - offset) % atom_len) {
+               printk(KERN_ERR "%s: Unexpected scan data length %d, "
+                      "atom_len %d, offset %d\n", dev->name, len,
+                      atom_len, offset);
+               return -EIO;
+       }
+
+       orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
+
+       /* Read the entries one by one */
+       for (; offset + atom_len <= len; offset += atom_len) {
+               int found = 0;
+               struct bss_element *bss = NULL;
+
+               /* Get next atom */
+               atom = (union hermes_scan_info *) (buf + offset);
+
+               /* Try to update an existing bss first */
+               list_for_each_entry(bss, &priv->bss_list, list) {
+                       if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
+                               continue;
+                       if (le16_to_cpu(bss->bss.a.essid_len) !=
+                             le16_to_cpu(atom->a.essid_len))
+                               continue;
+                       if (memcmp(bss->bss.a.essid, atom->a.essid,
+                             le16_to_cpu(atom->a.essid_len)))
+                               continue;
+                       found = 1;
+                       break;
+               }
+
+               /* Grab a bss off the free list */
+               if (!found && !list_empty(&priv->bss_free_list)) {
+                       bss = list_entry(priv->bss_free_list.next,
+                                        struct bss_element, list);
+                       list_del(priv->bss_free_list.next);
+
+                       list_add_tail(&bss->list, &priv->bss_list);
+               }
+
+               if (bss) {
+                       /* Always update the BSS to get latest beacon info */
+                       memcpy(&bss->bss, atom, sizeof(bss->bss));
+                       bss->last_scanned = jiffies;
+               }
+       }
+
+       return 0;
+}
+
+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       u16 infofid;
+       struct {
+               __le16 len;
+               __le16 type;
+       } __attribute__ ((packed)) info;
+       int len, type;
+       int err;
+
+       /* This is an answer to an INQUIRE command that we did earlier,
+        * or an information "event" generated by the card
+        * The controller return to us a pseudo frame containing
+        * the information in question - Jean II */
+       infofid = hermes_read_regn(hw, INFOFID);
+
+       /* Read the info frame header - don't try too hard */
+       err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+                              infofid, 0);
+       if (err) {
+               printk(KERN_ERR "%s: error %d reading info frame. "
+                      "Frame dropped.\n", dev->name, err);
+               return;
+       }
+       
+       len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
+       type = le16_to_cpu(info.type);
+
+       switch (type) {
+       case HERMES_INQ_TALLIES: {
+               struct hermes_tallies_frame tallies;
+               struct iw_statistics *wstats = &priv->wstats;
+               
+               if (len > sizeof(tallies)) {
+                       printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
+                              dev->name, len);
+                       len = sizeof(tallies);
+               }
+               
+               err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
+                                      infofid, sizeof(info));
+               if (err)
+                       break;
+               
+               /* Increment our various counters */
+               /* wstats->discard.nwid - no wrong BSSID stuff */
+               wstats->discard.code +=
+                       le16_to_cpu(tallies.RxWEPUndecryptable);
+               if (len == sizeof(tallies))  
+                       wstats->discard.code +=
+                               le16_to_cpu(tallies.RxDiscards_WEPICVError) +
+                               le16_to_cpu(tallies.RxDiscards_WEPExcluded);
+               wstats->discard.misc +=
+                       le16_to_cpu(tallies.TxDiscardsWrongSA);
+               wstats->discard.fragment +=
+                       le16_to_cpu(tallies.RxMsgInBadMsgFragments);
+               wstats->discard.retries +=
+                       le16_to_cpu(tallies.TxRetryLimitExceeded);
+               /* wstats->miss.beacon - no match */
+       }
+       break;
+       case HERMES_INQ_LINKSTATUS: {
+               struct hermes_linkstatus linkstatus;
+               u16 newstatus;
+               int connected;
+
+               if (priv->iw_mode == IW_MODE_MONITOR)
+                       break;
+
+               if (len != sizeof(linkstatus)) {
+                       printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
+                              dev->name, len);
+                       break;
+               }
+
+               err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
+                                      infofid, sizeof(info));
+               if (err)
+                       break;
+               newstatus = le16_to_cpu(linkstatus.linkstatus);
+
+               /* Symbol firmware uses "out of range" to signal that
+                * the hostscan frame can be requested.  */
+               if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+                   priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+                   priv->has_hostscan && priv->scan_inprogress) {
+                       hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+                       break;
+               }
+
+               connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
+                       || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+                       || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
+
+               if (connected)
+                       netif_carrier_on(dev);
+               else if (!ignore_disconnect)
+                       netif_carrier_off(dev);
+
+               if (newstatus != priv->last_linkstatus) {
+                       priv->last_linkstatus = newstatus;
+                       print_linkstatus(dev, newstatus);
+                       /* The info frame contains only one word which is the
+                        * status (see hermes.h). The status is pretty boring
+                        * in itself, that's why we export the new BSSID...
+                        * Jean II */
+                       schedule_work(&priv->wevent_work);
+               }
+       }
+       break;
+       case HERMES_INQ_SCAN:
+               if (!priv->scan_inprogress && priv->bssid_fixed &&
+                   priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+                       schedule_work(&priv->join_work);
+                       break;
+               }
+               /* fall through */
+       case HERMES_INQ_HOSTSCAN:
+       case HERMES_INQ_HOSTSCAN_SYMBOL: {
+               /* Result of a scanning. Contains information about
+                * cells in the vicinity - Jean II */
+               union iwreq_data        wrqu;
+               unsigned char *buf;
+
+               /* Scan is no longer in progress */
+               priv->scan_inprogress = 0;
+
+               /* Sanity check */
+               if (len > 4096) {
+                       printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+                              dev->name, len);
+                       break;
+               }
+
+               /* Allocate buffer for results */
+               buf = kmalloc(len, GFP_ATOMIC);
+               if (buf == NULL)
+                       /* No memory, so can't printk()... */
+                       break;
+
+               /* Read scan data */
+               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                      infofid, sizeof(info));
+               if (err) {
+                       kfree(buf);
+                       break;
+               }
+
+#ifdef ORINOCO_DEBUG
+               {
+                       int     i;
+                       printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+                       for(i = 1; i < (len * 2); i++)
+                               printk(":%02X", buf[i]);
+                       printk("]\n");
+               }
+#endif /* ORINOCO_DEBUG */
+
+               if (orinoco_process_scan_results(dev, buf, len) == 0) {
+                       /* Send an empty event to user space.
+                        * We don't send the received data on the event because
+                        * it would require us to do complex transcoding, and
+                        * we want to minimise the work done in the irq handler
+                        * Use a request to extract the data - Jean II */
+                       wrqu.data.length = 0;
+                       wrqu.data.flags = 0;
+                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+               }
+               kfree(buf);
+       }
+       break;
+       case HERMES_INQ_CHANNELINFO:
+       {
+               struct agere_ext_scan_info *bss;
+
+               if (!priv->scan_inprogress) {
+                       printk(KERN_DEBUG "%s: Got chaninfo without scan, "
+                              "len=%d\n", dev->name, len);
+                       break;
+               }
+
+               /* An empty result indicates that the scan is complete */
+               if (len == 0) {
+                       union iwreq_data        wrqu;
+
+                       /* Scan is no longer in progress */
+                       priv->scan_inprogress = 0;
+
+                       wrqu.data.length = 0;
+                       wrqu.data.flags = 0;
+                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+                       break;
+               }
+
+               /* Sanity check */
+               else if (len > sizeof(*bss)) {
+                       printk(KERN_WARNING
+                              "%s: Ext scan results too large (%d bytes). "
+                              "Truncating results to %zd bytes.\n",
+                              dev->name, len, sizeof(*bss));
+                       len = sizeof(*bss);
+               } else if (len < (offsetof(struct agere_ext_scan_info,
+                                          data) + 2)) {
+                       /* Drop this result now so we don't have to
+                        * keep checking later */
+                       printk(KERN_WARNING
+                              "%s: Ext scan results too short (%d bytes)\n",
+                              dev->name, len);
+                       break;
+               }
+
+               bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+               if (bss == NULL)
+                       break;
+
+               /* Read scan data */
+               err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
+                                      infofid, sizeof(info));
+               if (err) {
+                       kfree(bss);
+                       break;
+               }
+
+               orinoco_add_ext_scan_result(priv, bss);
+
+               kfree(bss);
+               break;
+       }
+       case HERMES_INQ_SEC_STAT_AGERE:
+               /* Security status (Agere specific) */
+               /* Ignore this frame for now */
+               if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+                       break;
+               /* fall through */
+       default:
+               printk(KERN_DEBUG "%s: Unknown information frame received: "
+                      "type 0x%04x, length %d\n", dev->name, type, len);
+               /* We don't actually do anything about it */
+               break;
+       }
+}
+
+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
+{
+       if (net_ratelimit())
+               printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
+}
+
+/********************************************************************/
+/* Internal hardware control routines                               */
+/********************************************************************/
+
+int __orinoco_up(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+
+       netif_carrier_off(dev); /* just to make sure */
+
+       err = __orinoco_program_rids(dev);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d configuring card\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Fire things up again */
+       hermes_set_irqmask(hw, ORINOCO_INTEN);
+       err = hermes_enable_port(hw, 0);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d enabling MAC port\n",
+                      dev->name, err);
+               return err;
+       }
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+int __orinoco_down(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+
+       netif_stop_queue(dev);
+
+       if (! priv->hw_unavailable) {
+               if (! priv->broken_disableport) {
+                       err = hermes_disable_port(hw, 0);
+                       if (err) {
+                               /* Some firmwares (e.g. Intersil 1.3.x) seem
+                                * to have problems disabling the port, oh
+                                * well, too bad. */
+                               printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
+                                      dev->name, err);
+                               priv->broken_disableport = 1;
+                       }
+               }
+               hermes_set_irqmask(hw, 0);
+               hermes_write_regn(hw, EVACK, 0xffff);
+       }
+       
+       /* firmware will have to reassociate */
+       netif_carrier_off(dev);
+       priv->last_linkstatus = 0xffff;
+
+       return 0;
+}
+
+static int orinoco_allocate_fid(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+
+       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+       if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+               /* Try workaround for old Symbol firmware bug */
+               printk(KERN_WARNING "%s: firmware ALLOC bug detected "
+                      "(old Symbol firmware?). Trying to work around... ",
+                      dev->name);
+               
+               priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+               if (err)
+                       printk("failed!\n");
+               else
+                       printk("ok.\n");
+       }
+
+       return err;
+}
+
+int orinoco_reinit_firmware(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       int err;
+
+       err = hermes_init(hw);
+       if (priv->do_fw_download && !err) {
+               err = orinoco_download(priv);
+               if (err)
+                       priv->do_fw_download = 0;
+       }
+       if (!err)
+               err = orinoco_allocate_fid(dev);
+
+       return err;
+}
+
+static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+
+       if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
+               printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
+                      priv->ndev->name, priv->bitratemode);
+               return -EINVAL;
+       }
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFTXRATECONTROL,
+                                          bitrate_table[priv->bitratemode].agere_txratectrl);
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+       case FIRMWARE_TYPE_SYMBOL:
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFTXRATECONTROL,
+                                          bitrate_table[priv->bitratemode].intersil_txratectrl);
+               break;
+       default:
+               BUG();
+       }
+
+       return err;
+}
+
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+       int roaming_flag;
+       int err = 0;
+       hermes_t *hw = &priv->hw;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* not supported */
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               if (priv->bssid_fixed)
+                       roaming_flag = 2;
+               else
+                       roaming_flag = 1;
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFROAMINGMODE,
+                                          roaming_flag);
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                         HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+                                         &priv->desired_bssid);
+               break;
+       }
+       return err;
+}
+
+/* Change the WEP keys and/or the current keys.  Can be called
+ * either from __orinoco_hw_setup_enc() or directly from
+ * orinoco_ioctl_setiwencode().  In the later case the association
+ * with the AP is not broken (if the firmware can handle it),
+ * which is needed for 802.1x implementations. */
+static int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                         HERMES_RID_CNFWEPKEYS_AGERE,
+                                         &priv->keys);
+               if (err)
+                       return err;
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFTXKEY_AGERE,
+                                          priv->tx_key);
+               if (err)
+                       return err;
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+       case FIRMWARE_TYPE_SYMBOL:
+               {
+                       int keylen;
+                       int i;
+
+                       /* Force uniform key length to work around firmware bugs */
+                       keylen = le16_to_cpu(priv->keys[priv->tx_key].len);
+                       
+                       if (keylen > LARGE_KEY_SIZE) {
+                               printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
+                                      priv->ndev->name, priv->tx_key, keylen);
+                               return -E2BIG;
+                       }
+
+                       /* Write all 4 keys */
+                       for(i = 0; i < ORINOCO_MAX_KEYS; i++) {
+                               err = hermes_write_ltv(hw, USER_BAP,
+                                                      HERMES_RID_CNFDEFAULTKEY0 + i,
+                                                      HERMES_BYTES_TO_RECLEN(keylen),
+                                                      priv->keys[i].data);
+                               if (err)
+                                       return err;
+                       }
+
+                       /* Write the index of the key used in transmission */
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFWEPDEFAULTKEYID,
+                                                  priv->tx_key);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int __orinoco_hw_setup_enc(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       int master_wep_flag;
+       int auth_flag;
+       int enc_flag;
+
+       /* Setup WEP keys for WEP and WPA */
+       if (priv->encode_alg)
+               __orinoco_hw_setup_wepkeys(priv);
+
+       if (priv->wep_restrict)
+               auth_flag = HERMES_AUTH_SHARED_KEY;
+       else
+               auth_flag = HERMES_AUTH_OPEN;
+
+       if (priv->wpa_enabled)
+               enc_flag = 2;
+       else if (priv->encode_alg == IW_ENCODE_ALG_WEP)
+               enc_flag = 1;
+       else
+               enc_flag = 0;
+
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
+               if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+                       /* Enable the shared-key authentication. */
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFAUTHENTICATION_AGERE,
+                                                  auth_flag);
+               }
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFWEPENABLED_AGERE,
+                                          enc_flag);
+               if (err)
+                       return err;
+
+               if (priv->has_wpa) {
+                       /* Set WPA key management */
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                 HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
+                                 priv->key_mgmt);
+                       if (err)
+                               return err;
+               }
+
+               break;
+
+       case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
+       case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+               if (priv->encode_alg == IW_ENCODE_ALG_WEP) {
+                       if (priv->wep_restrict ||
+                           (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
+                               master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
+                                                 HERMES_WEP_EXCL_UNENCRYPTED;
+                       else
+                               master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
+
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFAUTHENTICATION,
+                                                  auth_flag);
+                       if (err)
+                               return err;
+               } else
+                       master_wep_flag = 0;
+
+               if (priv->iw_mode == IW_MODE_MONITOR)
+                       master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
+
+               /* Master WEP setting : on/off */
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFWEPFLAGS_INTERSIL,
+                                          master_wep_flag);
+               if (err)
+                       return err;     
+
+               break;
+       }
+
+       return 0;
+}
+
+/* key must be 32 bytes, including the tx and rx MIC keys.
+ * rsc must be 8 bytes
+ * tsc must be 8 bytes or NULL
+ */
+static int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
+                                    u8 *key, u8 *rsc, u8 *tsc)
+{
+       struct {
+               __le16 idx;
+               u8 rsc[IW_ENCODE_SEQ_MAX_SIZE];
+               u8 key[TKIP_KEYLEN];
+               u8 tx_mic[MIC_KEYLEN];
+               u8 rx_mic[MIC_KEYLEN];
+               u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
+       } __attribute__ ((packed)) buf;
+       int ret;
+       int err;
+       int k;
+       u16 xmitting;
+
+       key_idx &= 0x3;
+
+       if (set_tx)
+               key_idx |= 0x8000;
+
+       buf.idx = cpu_to_le16(key_idx);
+       memcpy(buf.key, key,
+              sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
+
+       if (rsc == NULL)
+               memset(buf.rsc, 0, sizeof(buf.rsc));
+       else
+               memcpy(buf.rsc, rsc, sizeof(buf.rsc));
+
+       if (tsc == NULL) {
+               memset(buf.tsc, 0, sizeof(buf.tsc));
+               buf.tsc[4] = 0x10;
+       } else {
+               memcpy(buf.tsc, tsc, sizeof(buf.tsc));
+       }
+
+       /* Wait upto 100ms for tx queue to empty */
+       k = 100;
+       do {
+               k--;
+               udelay(1000);
+               ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
+                                         &xmitting);
+               if (ret)
+                       break;
+       } while ((k > 0) && xmitting);
+
+       if (k == 0)
+               ret = -ETIMEDOUT;
+
+       err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                 HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
+                                 &buf);
+
+       return ret ? ret : err;
+}
+
+static int orinoco_clear_tkip_key(struct orinoco_private *priv,
+                                 int key_idx)
+{
+       hermes_t *hw = &priv->hw;
+       int err;
+
+       memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
+       err = hermes_write_wordrec(hw, USER_BAP,
+                                  HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
+                                  key_idx);
+       if (err)
+               printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
+                      priv->ndev->name, err, key_idx);
+       return err;
+}
+
+static int __orinoco_program_rids(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err;
+       struct hermes_idstring idbuf;
+
+       /* Set the MAC address */
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting MAC address\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set up the link mode */
+       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+                                  priv->port_type);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting port type\n",
+                      dev->name, err);
+               return err;
+       }
+       /* Set the channel/frequency */
+       if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFOWNCHANNEL,
+                                          priv->channel);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting channel %d\n",
+                              dev->name, err, priv->channel);
+                       return err;
+               }
+       }
+
+       if (priv->has_ibss) {
+               u16 createibss;
+
+               if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+                       printk(KERN_WARNING "%s: This firmware requires an "
+                              "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+                       /* With wvlan_cs, in this case, we would crash.
+                        * hopefully, this driver will behave better...
+                        * Jean II */
+                       createibss = 0;
+               } else {
+                       createibss = priv->createibss;
+               }
+               
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFCREATEIBSS,
+                                          createibss);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set the desired BSSID */
+       err = __orinoco_hw_set_wap(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting AP address\n",
+                      dev->name, err);
+               return err;
+       }
+       /* Set the desired ESSID */
+       idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+       memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+       /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+                              HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+                              &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+                      dev->name, err);
+               return err;
+       }
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+                              HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+                              &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set the station name */
+       idbuf.len = cpu_to_le16(strlen(priv->nick));
+       memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+                              &idbuf);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting nickname\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set AP density */
+       if (priv->has_sensitivity) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFSYSTEMSCALE,
+                                          priv->ap_density);
+               if (err) {
+                       printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE.  "
+                              "Disabling sensitivity control\n",
+                              dev->name, err);
+
+                       priv->has_sensitivity = 0;
+               }
+       }
+
+       /* Set RTS threshold */
+       err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+                                  priv->rts_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set fragmentation threshold or MWO robustness */
+       if (priv->has_mwo)
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMWOROBUST_AGERE,
+                                          priv->mwo_robust);
+       else
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+                                          priv->frag_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set bitrate */
+       err = __orinoco_hw_set_bitrate(priv);
+       if (err) {
+               printk(KERN_ERR "%s: Error %d setting bitrate\n",
+                      dev->name, err);
+               return err;
+       }
+
+       /* Set power management */
+       if (priv->has_pm) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPMENABLED,
+                                          priv->pm_on);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMULTICASTRECEIVE,
+                                          priv->pm_mcast);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFMAXSLEEPDURATION,
+                                          priv->pm_period);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPMHOLDOVERDURATION,
+                                          priv->pm_timeout);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting up PM\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set preamble - only for Symbol so far... */
+       if (priv->has_preamble) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
+                                          priv->preamble);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting preamble\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       /* Set up encryption */
+       if (priv->has_wep || priv->has_wpa) {
+               err = __orinoco_hw_setup_enc(priv);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d activating encryption\n",
+                              dev->name, err);
+                       return err;
+               }
+       }
+
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Enable monitor mode */
+               dev->type = ARPHRD_IEEE80211;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST | 
+                                           HERMES_TEST_MONITOR, 0, NULL);
+       } else {
+               /* Disable monitor mode */
+               dev->type = ARPHRD_ETHER;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_STOP, 0, NULL);
+       }
+       if (err)
+               return err;
+
+       /* Set promiscuity / multicast*/
+       priv->promiscuous = 0;
+       priv->mc_count = 0;
+
+       /* FIXME: what about netif_tx_lock */
+       __orinoco_set_multicast_list(dev);
+
+       return 0;
+}
+
+/* FIXME: return int? */
+static void
+__orinoco_set_multicast_list(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       int promisc, mc_count;
+
+       /* The Hermes doesn't seem to have an allmulti mode, so we go
+        * into promiscuous mode and let the upper levels deal. */
+       if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+            (dev->mc_count > MAX_MULTICAST(priv)) ) {
+               promisc = 1;
+               mc_count = 0;
+       } else {
+               promisc = 0;
+               mc_count = dev->mc_count;
+       }
+
+       if (promisc != priv->promiscuous) {
+               err = hermes_write_wordrec(hw, USER_BAP,
+                                          HERMES_RID_CNFPROMISCUOUSMODE,
+                                          promisc);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
+                              dev->name, err);
+               } else 
+                       priv->promiscuous = promisc;
+       }
+
+       /* If we're not in promiscuous mode, then we need to set the
+        * group address if either we want to multicast, or if we were
+        * multicasting and want to stop */
+       if (! promisc && (mc_count || priv->mc_count) ) {
+               struct dev_mc_list *p = dev->mc_list;
+               struct hermes_multicast mclist;
+               int i;
+
+               for (i = 0; i < mc_count; i++) {
+                       /* paranoia: is list shorter than mc_count? */
+                       BUG_ON(! p);
+                       /* paranoia: bad address size in list? */
+                       BUG_ON(p->dmi_addrlen != ETH_ALEN);
+                       
+                       memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
+                       p = p->next;
+               }
+               
+               if (p)
+                       printk(KERN_WARNING "%s: Multicast list is "
+                              "longer than mc_count\n", dev->name);
+
+               err = hermes_write_ltv(hw, USER_BAP,
+                                  HERMES_RID_CNFGROUPADDRESSES,
+                                  HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
+                                  &mclist);
+               if (err)
+                       printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+                              dev->name, err);
+               else
+                       priv->mc_count = mc_count;
+       }
+}
+
+/* This must be called from user context, without locks held - use
+ * schedule_work() */
+static void orinoco_reset(struct work_struct *work)
+{
+       struct orinoco_private *priv =
+               container_of(work, struct orinoco_private, reset_work);
+       struct net_device *dev = priv->ndev;
+       struct hermes *hw = &priv->hw;
+       int err;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               /* When the hardware becomes available again, whatever
+                * detects that is responsible for re-initializing
+                * it. So no need for anything further */
+               return;
+
+       netif_stop_queue(dev);
+
+       /* Shut off interrupts.  Depending on what state the hardware
+        * is in, this might not work, but we'll try anyway */
+       hermes_set_irqmask(hw, 0);
+       hermes_write_regn(hw, EVACK, 0xffff);
+
+       priv->hw_unavailable++;
+       priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
+       netif_carrier_off(dev);
+
+       orinoco_unlock(priv, &flags);
+
+       /* Scanning support: Cleanup of driver struct */
+       orinoco_clear_scan_results(priv, 0);
+       priv->scan_inprogress = 0;
+
+       if (priv->hard_reset) {
+               err = (*priv->hard_reset)(priv);
+               if (err) {
+                       printk(KERN_ERR "%s: orinoco_reset: Error %d "
+                              "performing hard reset\n", dev->name, err);
+                       goto disable;
+               }
+       }
+
+       err = orinoco_reinit_firmware(dev);
+       if (err) {
+               printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
+                      dev->name, err);
+               goto disable;
+       }
+
+       spin_lock_irq(&priv->lock); /* This has to be called from user context */
+
+       priv->hw_unavailable--;
+
+       /* priv->open or priv->hw_unavailable might have changed while
+        * we dropped the lock */
+       if (priv->open && (! priv->hw_unavailable)) {
+               err = __orinoco_up(dev);
+               if (err) {
+                       printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+                              dev->name, err);
+               } else
+                       dev->trans_start = jiffies;
+       }
+
+       spin_unlock_irq(&priv->lock);
+
+       return;
+ disable:
+       hermes_set_irqmask(hw, 0);
+       netif_device_detach(dev);
+       printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
+}
+
+/********************************************************************/
+/* Interrupt handler                                                */
+/********************************************************************/
+
+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
+{
+       printk(KERN_DEBUG "%s: TICK\n", dev->name);
+}
+
+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
+{
+       /* This seems to happen a fair bit under load, but ignoring it
+          seems to work fine...*/
+       printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
+              dev->name);
+}
+
+irqreturn_t orinoco_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int count = MAX_IRQLOOPS_PER_IRQ;
+       u16 evstat, events;
+       /* These are used to detect a runaway interrupt situation */
+       /* If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
+        * we panic and shut down the hardware */
+       static int last_irq_jiffy = 0; /* jiffies value the last time
+                                       * we were called */
+       static int loops_this_jiffy = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0) {
+               /* If hw is unavailable - we don't know if the irq was
+                * for us or not */
+               return IRQ_HANDLED;
+       }
+
+       evstat = hermes_read_regn(hw, EVSTAT);
+       events = evstat & hw->inten;
+       if (! events) {
+               orinoco_unlock(priv, &flags);
+               return IRQ_NONE;
+       }
+       
+       if (jiffies != last_irq_jiffy)
+               loops_this_jiffy = 0;
+       last_irq_jiffy = jiffies;
+
+       while (events && count--) {
+               if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
+                       printk(KERN_WARNING "%s: IRQ handler is looping too "
+                              "much! Resetting.\n", dev->name);
+                       /* Disable interrupts for now */
+                       hermes_set_irqmask(hw, 0);
+                       schedule_work(&priv->reset_work);
+                       break;
+               }
+
+               /* Check the card hasn't been removed */
+               if (! hermes_present(hw)) {
+                       DEBUG(0, "orinoco_interrupt(): card removed\n");
+                       break;
+               }
+
+               if (events & HERMES_EV_TICK)
+                       __orinoco_ev_tick(dev, hw);
+               if (events & HERMES_EV_WTERR)
+                       __orinoco_ev_wterr(dev, hw);
+               if (events & HERMES_EV_INFDROP)
+                       __orinoco_ev_infdrop(dev, hw);
+               if (events & HERMES_EV_INFO)
+                       __orinoco_ev_info(dev, hw);
+               if (events & HERMES_EV_RX)
+                       __orinoco_ev_rx(dev, hw);
+               if (events & HERMES_EV_TXEXC)
+                       __orinoco_ev_txexc(dev, hw);
+               if (events & HERMES_EV_TX)
+                       __orinoco_ev_tx(dev, hw);
+               if (events & HERMES_EV_ALLOC)
+                       __orinoco_ev_alloc(dev, hw);
+               
+               hermes_write_regn(hw, EVACK, evstat);
+
+               evstat = hermes_read_regn(hw, EVSTAT);
+               events = evstat & hw->inten;
+       };
+
+       orinoco_unlock(priv, &flags);
+       return IRQ_HANDLED;
+}
+
+/********************************************************************/
+/* Initialization                                                   */
+/********************************************************************/
+
+struct comp_id {
+       u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+       if (nic_id->id < 0x8000)
+               return FIRMWARE_TYPE_AGERE;
+       else if (nic_id->id == 0x8000 && nic_id->major == 0)
+               return FIRMWARE_TYPE_SYMBOL;
+       else
+               return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties */
+static int determine_firmware(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err;
+       struct comp_id nic_id, sta_id;
+       unsigned int firmver;
+       char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+       /* Get the hardware version */
+       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
+                      dev->name, err);
+               return err;
+       }
+
+       le16_to_cpus(&nic_id.id);
+       le16_to_cpus(&nic_id.variant);
+       le16_to_cpus(&nic_id.major);
+       le16_to_cpus(&nic_id.minor);
+       printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
+              dev->name, nic_id.id, nic_id.variant,
+              nic_id.major, nic_id.minor);
+
+       priv->firmware_type = determine_firmware_type(&nic_id);
+
+       /* Get the firmware version */
+       err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+       if (err) {
+               printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
+                      dev->name, err);
+               return err;
+       }
+
+       le16_to_cpus(&sta_id.id);
+       le16_to_cpus(&sta_id.variant);
+       le16_to_cpus(&sta_id.major);
+       le16_to_cpus(&sta_id.minor);
+       printk(KERN_DEBUG "%s: Station identity  %04x:%04x:%04x:%04x\n",
+              dev->name, sta_id.id, sta_id.variant,
+              sta_id.major, sta_id.minor);
+
+       switch (sta_id.id) {
+       case 0x15:
+               printk(KERN_ERR "%s: Primary firmware is active\n",
+                      dev->name);
+               return -ENODEV;
+       case 0x14b:
+               printk(KERN_ERR "%s: Tertiary firmware is active\n",
+                      dev->name);
+               return -ENODEV;
+       case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
+       case 0x21:      /* Symbol Spectrum24 Trilogy */
+               break;
+       default:
+               printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
+                      dev->name);
+               break;
+       }
+
+       /* Default capabilities */
+       priv->has_sensitivity = 1;
+       priv->has_mwo = 0;
+       priv->has_preamble = 0;
+       priv->has_port3 = 1;
+       priv->has_ibss = 1;
+       priv->has_wep = 0;
+       priv->has_big_wep = 0;
+       priv->has_alt_txcntl = 0;
+       priv->has_ext_scan = 0;
+       priv->has_wpa = 0;
+       priv->do_fw_download = 0;
+
+       /* Determine capabilities from the firmware version */
+       switch (priv->firmware_type) {
+       case FIRMWARE_TYPE_AGERE:
+               /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+                  ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+               firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+               priv->has_ibss = (firmver >= 0x60006);
+               priv->has_wep = (firmver >= 0x40020);
+               priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+                                         Gold cards from the others? */
+               priv->has_mwo = (firmver >= 0x60000);
+               priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+               priv->ibss_port = 1;
+               priv->has_hostscan = (firmver >= 0x8000a);
+               priv->do_fw_download = 1;
+               priv->broken_monitor = (firmver >= 0x80000);
+               priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+               priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+               priv->has_wpa = (firmver >= 0x9002a);
+               /* Tested with Agere firmware :
+                *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+                * Tested CableTron firmware : 4.32 => Anton */
+               break;
+       case FIRMWARE_TYPE_SYMBOL:
+               /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+               /* Intel MAC : 00:02:B3:* */
+               /* 3Com MAC : 00:50:DA:* */
+               memset(tmp, 0, sizeof(tmp));
+               /* Get the Symbol firmware version */
+               err = hermes_read_ltv(hw, USER_BAP,
+                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
+                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
+               if (err) {
+                       printk(KERN_WARNING
+                              "%s: Error %d reading Symbol firmware info. Wildly guessing capabilities...\n",
+                              dev->name, err);
+                       firmver = 0;
+                       tmp[0] = '\0';
+               } else {
+                       /* The firmware revision is a string, the format is
+                        * something like : "V2.20-01".
+                        * Quick and dirty parsing... - Jean II
+                        */
+                       firmver = ((tmp[1] - '0') << 16) | ((tmp[3] - '0') << 12)
+                               | ((tmp[4] - '0') << 8) | ((tmp[6] - '0') << 4)
+                               | (tmp[7] - '0');
+
+                       tmp[SYMBOL_MAX_VER_LEN] = '\0';
+               }
+
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Symbol %s", tmp);
+
+               priv->has_ibss = (firmver >= 0x20000);
+               priv->has_wep = (firmver >= 0x15012);
+               priv->has_big_wep = (firmver >= 0x20000);
+               priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) || 
+                              (firmver >= 0x29000 && firmver < 0x30000) ||
+                              firmver >= 0x31000;
+               priv->has_preamble = (firmver >= 0x20000);
+               priv->ibss_port = 4;
+
+               /* Symbol firmware is found on various cards, but
+                * there has been no attempt to check firmware
+                * download on non-spectrum_cs based cards.
+                *
+                * Given that the Agere firmware download works
+                * differently, we should avoid doing a firmware
+                * download with the Symbol algorithm on non-spectrum
+                * cards.
+                *
+                * For now we can identify a spectrum_cs based card
+                * because it has a firmware reset function.
+                */
+               priv->do_fw_download = (priv->stop_fw != NULL);
+
+               priv->broken_disableport = (firmver == 0x25013) ||
+                                          (firmver >= 0x30000 && firmver <= 0x31000);
+               priv->has_hostscan = (firmver >= 0x31001) ||
+                                    (firmver >= 0x29057 && firmver < 0x30000);
+               /* Tested with Intel firmware : 0x20015 => Jean II */
+               /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+               break;
+       case FIRMWARE_TYPE_INTERSIL:
+               /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+                * Samsung, Compaq 100/200 and Proxim are slightly
+                * different and less well tested */
+               /* D-Link MAC : 00:40:05:* */
+               /* Addtron MAC : 00:90:D1:* */
+               snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+                        "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+                        sta_id.variant);
+
+               firmver = ((unsigned long)sta_id.major << 16) |
+                       ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+               priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+               priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+               priv->has_pm = (firmver >= 0x000700);
+               priv->has_hostscan = (firmver >= 0x010301);
+
+               if (firmver >= 0x000800)
+                       priv->ibss_port = 0;
+               else {
+                       printk(KERN_NOTICE "%s: Intersil firmware earlier "
+                              "than v0.8.x - several features not supported\n",
+                              dev->name);
+                       priv->ibss_port = 1;
+               }
+               break;
+       }
+       printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
+              priv->fw_name);
+
+       return 0;
+}
+
+static int orinoco_init(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       struct hermes_idstring nickbuf;
+       u16 reclen;
+       int len;
+
+       /* No need to lock, the hw_unavailable flag is already set in
+        * alloc_orinocodev() */
+       priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
+
+       /* Initialize the firmware */
+       err = hermes_init(hw);
+       if (err != 0) {
+               printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
+                      dev->name, err);
+               goto out;
+       }
+
+       err = determine_firmware(dev);
+       if (err != 0) {
+               printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+                      dev->name);
+               goto out;
+       }
+
+       if (priv->do_fw_download) {
+               err = orinoco_download(priv);
+               if (err)
+                       priv->do_fw_download = 0;
+
+               /* Check firmware version again */
+               err = determine_firmware(dev);
+               if (err != 0) {
+                       printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
+                              dev->name);
+                       goto out;
+               }
+       }
+
+       if (priv->has_port3)
+               printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name);
+       if (priv->has_ibss)
+               printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
+                      dev->name);
+       if (priv->has_wep) {
+               printk(KERN_DEBUG "%s: WEP supported, ", dev->name);
+               if (priv->has_big_wep)
+                       printk("104-bit key\n");
+               else
+                       printk("40-bit key\n");
+       }
+       if (priv->has_wpa) {
+               printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+               if (orinoco_mic_init(priv)) {
+                       printk(KERN_ERR "%s: Failed to setup MIC crypto "
+                              "algorithm. Disabling WPA support\n", dev->name);
+                       priv->has_wpa = 0;
+               }
+       }
+
+       /* Now we have the firmware capabilities, allocate appropiate
+        * sized scan buffers */
+       if (orinoco_bss_data_allocate(priv))
+               goto out;
+       orinoco_bss_data_init(priv);
+
+       /* Get the MAC address */
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                             ETH_ALEN, NULL, dev->dev_addr);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to read MAC address!\n",
+                      dev->name);
+               goto out;
+       }
+
+       printk(KERN_DEBUG "%s: MAC address %pM\n",
+              dev->name, dev->dev_addr);
+
+       /* Get the station name */
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                             sizeof(nickbuf), &reclen, &nickbuf);
+       if (err) {
+               printk(KERN_ERR "%s: failed to read station name\n",
+                      dev->name);
+               goto out;
+       }
+       if (nickbuf.len)
+               len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+       else
+               len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+       memcpy(priv->nick, &nickbuf.val, len);
+       priv->nick[len] = '\0';
+
+       printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
+
+       err = orinoco_allocate_fid(dev);
+       if (err) {
+               printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
+                      dev->name);
+               goto out;
+       }
+
+       /* Get allowed channels */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+                                 &priv->channel_mask);
+       if (err) {
+               printk(KERN_ERR "%s: failed to read channel list!\n",
+                      dev->name);
+               goto out;
+       }
+
+       /* Get initial AP density */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+                                 &priv->ap_density);
+       if (err || priv->ap_density < 1 || priv->ap_density > 3) {
+               priv->has_sensitivity = 0;
+       }
+
+       /* Get initial RTS threshold */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+                                 &priv->rts_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: failed to read RTS threshold!\n",
+                      dev->name);
+               goto out;
+       }
+
+       /* Get initial fragmentation settings */
+       if (priv->has_mwo)
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFMWOROBUST_AGERE,
+                                         &priv->mwo_robust);
+       else
+               err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+                                         &priv->frag_thresh);
+       if (err) {
+               printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
+                      dev->name);
+               goto out;
+       }
+
+       /* Power management setup */
+       if (priv->has_pm) {
+               priv->pm_on = 0;
+               priv->pm_mcast = 1;
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFMAXSLEEPDURATION,
+                                         &priv->pm_period);
+               if (err) {
+                       printk(KERN_ERR "%s: failed to read power management period!\n",
+                              dev->name);
+                       goto out;
+               }
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFPMHOLDOVERDURATION,
+                                         &priv->pm_timeout);
+               if (err) {
+                       printk(KERN_ERR "%s: failed to read power management timeout!\n",
+                              dev->name);
+                       goto out;
+               }
+       }
+
+       /* Preamble setup */
+       if (priv->has_preamble) {
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFPREAMBLE_SYMBOL,
+                                         &priv->preamble);
+               if (err)
+                       goto out;
+       }
+               
+       /* Set up the default configuration */
+       priv->iw_mode = IW_MODE_INFRA;
+       /* By default use IEEE/IBSS ad-hoc mode if we have it */
+       priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
+       set_port_type(priv);
+       priv->channel = 0; /* use firmware default */
+
+       priv->promiscuous = 0;
+       priv->encode_alg = IW_ENCODE_ALG_NONE;
+       priv->tx_key = 0;
+       priv->wpa_enabled = 0;
+       priv->tkip_cm_active = 0;
+       priv->key_mgmt = 0;
+       priv->wpa_ie_len = 0;
+       priv->wpa_ie = NULL;
+
+       /* Make the hardware available, as long as it hasn't been
+        * removed elsewhere (e.g. by PCMCIA hot unplug) */
+       spin_lock_irq(&priv->lock);
+       priv->hw_unavailable--;
+       spin_unlock_irq(&priv->lock);
+
+       printk(KERN_DEBUG "%s: ready\n", dev->name);
+
+ out:
+       return err;
+}
+
+struct net_device
+*alloc_orinocodev(int sizeof_card,
+                 struct device *device,
+                 int (*hard_reset)(struct orinoco_private *),
+                 int (*stop_fw)(struct orinoco_private *, int))
+{
+       struct net_device *dev;
+       struct orinoco_private *priv;
+
+       dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
+       if (! dev)
+               return NULL;
+       priv = netdev_priv(dev);
+       priv->ndev = dev;
+       if (sizeof_card)
+               priv->card = (void *)((unsigned long)priv
+                                     + sizeof(struct orinoco_private));
+       else
+               priv->card = NULL;
+       priv->dev = device;
+
+       /* Setup / override net_device fields */
+       dev->init = orinoco_init;
+       dev->hard_start_xmit = orinoco_xmit;
+       dev->tx_timeout = orinoco_tx_timeout;
+       dev->watchdog_timeo = HZ; /* 1 second timeout */
+       dev->get_stats = orinoco_get_stats;
+       dev->ethtool_ops = &orinoco_ethtool_ops;
+       dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
+#ifdef WIRELESS_SPY
+       priv->wireless_data.spy_data = &priv->spy_data;
+       dev->wireless_data = &priv->wireless_data;
+#endif
+       dev->change_mtu = orinoco_change_mtu;
+       dev->set_multicast_list = orinoco_set_multicast_list;
+       /* we use the default eth_mac_addr for setting the MAC addr */
+
+       /* Reserve space in skb for the SNAP header */
+       dev->hard_header_len += ENCAPS_OVERHEAD;
+
+       /* Set up default callbacks */
+       dev->open = orinoco_open;
+       dev->stop = orinoco_stop;
+       priv->hard_reset = hard_reset;
+       priv->stop_fw = stop_fw;
+
+       spin_lock_init(&priv->lock);
+       priv->open = 0;
+       priv->hw_unavailable = 1; /* orinoco_init() must clear this
+                                  * before anything else touches the
+                                  * hardware */
+       INIT_WORK(&priv->reset_work, orinoco_reset);
+       INIT_WORK(&priv->join_work, orinoco_join_ap);
+       INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
+
+       INIT_LIST_HEAD(&priv->rx_list);
+       tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
+                    (unsigned long) dev);
+
+       netif_carrier_off(dev);
+       priv->last_linkstatus = 0xffff;
+
+       priv->cached_fw = NULL;
+
+       return dev;
+}
+
+void free_orinocodev(struct net_device *dev)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       /* No need to empty priv->rx_list: if the tasklet is scheduled
+        * when we call tasklet_kill it will run one final time,
+        * emptying the list */
+       tasklet_kill(&priv->rx_tasklet);
+       if (priv->cached_fw)
+               release_firmware(priv->cached_fw);
+       priv->cached_fw = NULL;
+       priv->wpa_ie_len = 0;
+       kfree(priv->wpa_ie);
+       orinoco_mic_free(priv);
+       orinoco_bss_data_free(priv);
+       free_netdev(dev);
+}
+
+/********************************************************************/
+/* Wireless extensions                                              */
+/********************************************************************/
+
+/* Return : < 0 -> error code ; >= 0 -> length */
+static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
+                               char buf[IW_ESSID_MAX_SIZE+1])
+{
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       struct hermes_idstring essidbuf;
+       char *p = (char *)(&essidbuf.val);
+       int len;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (strlen(priv->desired_essid) > 0) {
+               /* We read the desired SSID from the hardware rather
+                  than from priv->desired_essid, just in case the
+                  firmware is allowed to change it on us. I'm not
+                  sure about this */
+               /* My guess is that the OWNSSID should always be whatever
+                * we set to the card, whereas CURRENT_SSID is the one that
+                * may change... - Jean II */
+               u16 rid;
+
+               *active = 1;
+
+               rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
+                       HERMES_RID_CNFDESIREDSSID;
+               
+               err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+                                     NULL, &essidbuf);
+               if (err)
+                       goto fail_unlock;
+       } else {
+               *active = 0;
+
+               err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+                                     sizeof(essidbuf), NULL, &essidbuf);
+               if (err)
+                       goto fail_unlock;
+       }
+
+       len = le16_to_cpu(essidbuf.len);
+       BUG_ON(len > IW_ESSID_MAX_SIZE);
+
+       memset(buf, 0, IW_ESSID_MAX_SIZE);
+       memcpy(buf, p, len);
+       err = len;
+
+ fail_unlock:
+       orinoco_unlock(priv, &flags);
+
+       return err;       
+}
+
+static long orinoco_hw_get_freq(struct orinoco_private *priv)
+{
+       
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       u16 channel;
+       long freq = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
+       if (err)
+               goto out;
+
+       /* Intersil firmware 1.3.5 returns 0 when the interface is down */
+       if (channel == 0) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
+               printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
+                      priv->ndev->name, channel);
+               err = -EBUSY;
+               goto out;
+
+       }
+       freq = channel_frequency[channel-1] * 100000;
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       if (err > 0)
+               err = -EBUSY;
+       return err ? err : freq;
+}
+
+static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
+                                     int *numrates, s32 *rates, int max)
+{
+       hermes_t *hw = &priv->hw;
+       struct hermes_idstring list;
+       unsigned char *p = (unsigned char *)&list.val;
+       int err = 0;
+       int num;
+       int i;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+                             sizeof(list), NULL, &list);
+       orinoco_unlock(priv, &flags);
+
+       if (err)
+               return err;
+       
+       num = le16_to_cpu(list.len);
+       *numrates = num;
+       num = min(num, max);
+
+       for (i = 0; i < num; i++) {
+               rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
+       }
+
+       return 0;
+}
+
+static int orinoco_ioctl_getname(struct net_device *dev,
+                                struct iw_request_info *info,
+                                char *name,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int numrates;
+       int err;
+
+       err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+       if (!err && (numrates > 2))
+               strcpy(name, "IEEE 802.11b");
+       else
+               strcpy(name, "IEEE 802.11-DS");
+
+       return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
+       static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Enable automatic roaming - no sanity checks are needed */
+       if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+           memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+               priv->bssid_fixed = 0;
+               memset(priv->desired_bssid, 0, ETH_ALEN);
+
+               /* "off" means keep existing connection */
+               if (ap_addr->sa_data[0] == 0) {
+                       __orinoco_hw_set_wap(priv);
+                       err = 0;
+               }
+               goto out;
+       }
+
+       if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+               printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+                      "support manual roaming\n",
+                      dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (priv->iw_mode != IW_MODE_INFRA) {
+               printk(KERN_WARNING "%s: Manual roaming supported only in "
+                      "managed mode\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Intersil firmware hangs without Desired ESSID */
+       if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+           strlen(priv->desired_essid) == 0) {
+               printk(KERN_WARNING "%s: Desired ESSID must be set for "
+                      "manual roaming\n", dev->name);
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Finally, enable manual roaming */
+       priv->bssid_fixed = 1;
+       memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct sockaddr *ap_addr,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       ap_addr->sa_family = ARPHRD_ETHER;
+       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                             ETH_ALEN, NULL, ap_addr->sa_data);
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_setmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
+
+       if (priv->iw_mode == *mode)
+               return 0;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       switch (*mode) {
+       case IW_MODE_ADHOC:
+               if (!priv->has_ibss && !priv->has_port3)
+                       err = -EOPNOTSUPP;
+               break;
+
+       case IW_MODE_INFRA:
+               break;
+
+       case IW_MODE_MONITOR:
+               if (priv->broken_monitor && !force_monitor) {
+                       printk(KERN_WARNING "%s: Monitor mode support is "
+                              "buggy in this firmware, not enabling\n",
+                              dev->name);
+                       err = -EOPNOTSUPP;
+               }
+               break;
+
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       if (err == -EINPROGRESS) {
+               priv->iw_mode = *mode;
+               set_port_type(priv);
+       }
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+                                struct iw_request_info *info,
+                                u32 *mode,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       *mode = priv->iw_mode;
+       return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+                                   struct iw_request_info *info,
+                                   struct iw_point *rrq,
+                                   char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       struct iw_range *range = (struct iw_range *) extra;
+       int numrates;
+       int i, k;
+
+       rrq->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 22;
+
+       /* Set available channels/frequencies */
+       range->num_channels = NUM_CHANNELS;
+       k = 0;
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               if (priv->channel_mask & (1 << i)) {
+                       range->freq[k].i = i + 1;
+                       range->freq[k].m = channel_frequency[i] * 100000;
+                       range->freq[k].e = 1;
+                       k++;
+               }
+               
+               if (k >= IW_MAX_FREQUENCIES)
+                       break;
+       }
+       range->num_frequency = k;
+       range->sensitivity = 3;
+
+       if (priv->has_wep) {
+               range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+               range->encoding_size[0] = SMALL_KEY_SIZE;
+               range->num_encoding_sizes = 1;
+
+               if (priv->has_big_wep) {
+                       range->encoding_size[1] = LARGE_KEY_SIZE;
+                       range->num_encoding_sizes = 2;
+               }
+       }
+
+       if (priv->has_wpa)
+               range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
+
+       if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))){
+               /* Quality stats meaningless in ad-hoc mode */
+       } else {
+               range->max_qual.qual = 0x8b - 0x2f;
+               range->max_qual.level = 0x2f - 0x95 - 1;
+               range->max_qual.noise = 0x2f - 0x95 - 1;
+               /* Need to get better values */
+               range->avg_qual.qual = 0x24;
+               range->avg_qual.level = 0xC2;
+               range->avg_qual.noise = 0x9E;
+       }
+
+       err = orinoco_hw_get_bitratelist(priv, &numrates,
+                                        range->bitrate, IW_MAX_BITRATES);
+       if (err)
+               return err;
+       range->num_bitrates = numrates;
+
+       /* Set an indication of the max TCP throughput in bit/s that we can
+        * expect using this interface. May be use for QoS stuff...
+        * Jean II */
+       if (numrates > 2)
+               range->throughput = 5 * 1000 * 1000;    /* ~5 Mb/s */
+       else
+               range->throughput = 1.5 * 1000 * 1000;  /* ~1.5 Mb/s */
+
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       range->min_pmp = 0;
+       range->max_pmp = 65535000;
+       range->min_pmt = 0;
+       range->max_pmt = 65535 * 1000;  /* ??? */
+       range->pmp_flags = IW_POWER_PERIOD;
+       range->pmt_flags = IW_POWER_TIMEOUT;
+       range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+       range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->r_time_flags = IW_RETRY_LIFETIME;
+       range->min_retry = 0;
+       range->max_retry = 65535;       /* ??? */
+       range->min_r_time = 0;
+       range->max_r_time = 65535 * 1000;       /* ??? */
+
+       if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+               range->scan_capa = IW_SCAN_CAPA_ESSID;
+       else
+               range->scan_capa = IW_SCAN_CAPA_NONE;
+
+       /* Event capability (kernel) */
+       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+       /* Event capability (driver) */
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+       IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
+
+       return 0;
+}
+
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+       int setindex = priv->tx_key;
+       int encode_alg = priv->encode_alg;
+       int restricted = priv->wep_restrict;
+       u16 xlen = 0;
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
+
+       if (! priv->has_wep)
+               return -EOPNOTSUPP;
+
+       if (erq->pointer) {
+               /* We actually have a key to set - check its length */
+               if (erq->length > LARGE_KEY_SIZE)
+                       return -E2BIG;
+
+               if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
+                       return -E2BIG;
+       }
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Clear any TKIP key we have */
+       if ((priv->has_wpa) && (priv->encode_alg == IW_ENCODE_ALG_TKIP))
+               (void) orinoco_clear_tkip_key(priv, setindex);
+
+       if (erq->length > 0) {
+               if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
+                       index = priv->tx_key;
+
+               /* Adjust key length to a supported value */
+               if (erq->length > SMALL_KEY_SIZE) {
+                       xlen = LARGE_KEY_SIZE;
+               } else if (erq->length > 0) {
+                       xlen = SMALL_KEY_SIZE;
+               } else
+                       xlen = 0;
+
+               /* Switch on WEP if off */
+               if ((encode_alg != IW_ENCODE_ALG_WEP) && (xlen > 0)) {
+                       setindex = index;
+                       encode_alg = IW_ENCODE_ALG_WEP;
+               }
+       } else {
+               /* Important note : if the user do "iwconfig eth0 enc off",
+                * we will arrive there with an index of -1. This is valid
+                * but need to be taken care off... Jean II */
+               if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
+                       if((index != -1) || (erq->flags == 0)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+               } else {
+                       /* Set the index : Check that the key is valid */
+                       if(priv->keys[index].len == 0) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       setindex = index;
+               }
+       }
+
+       if (erq->flags & IW_ENCODE_DISABLED)
+               encode_alg = IW_ENCODE_ALG_NONE;
+       if (erq->flags & IW_ENCODE_OPEN)
+               restricted = 0;
+       if (erq->flags & IW_ENCODE_RESTRICTED)
+               restricted = 1;
+
+       if (erq->pointer && erq->length > 0) {
+               priv->keys[index].len = cpu_to_le16(xlen);
+               memset(priv->keys[index].data, 0,
+                      sizeof(priv->keys[index].data));
+               memcpy(priv->keys[index].data, keybuf, erq->length);
+       }
+       priv->tx_key = setindex;
+
+       /* Try fast key change if connected and only keys are changed */
+       if ((priv->encode_alg == encode_alg) &&
+           (priv->wep_restrict == restricted) &&
+           netif_carrier_ok(dev)) {
+               err = __orinoco_hw_setup_wepkeys(priv);
+               /* No need to commit if successful */
+               goto out;
+       }
+
+       priv->encode_alg = encode_alg;
+       priv->wep_restrict = restricted;
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    struct iw_point *erq,
+                                    char *keybuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+       u16 xlen = 0;
+       unsigned long flags;
+
+       if (! priv->has_wep)
+               return -EOPNOTSUPP;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
+               index = priv->tx_key;
+
+       erq->flags = 0;
+       if (!priv->encode_alg)
+               erq->flags |= IW_ENCODE_DISABLED;
+       erq->flags |= index + 1;
+
+       if (priv->wep_restrict)
+               erq->flags |= IW_ENCODE_RESTRICTED;
+       else
+               erq->flags |= IW_ENCODE_OPEN;
+
+       xlen = le16_to_cpu(priv->keys[index].len);
+
+       erq->length = xlen;
+
+       memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
+
+       orinoco_unlock(priv, &flags);
+       return 0;
+}
+
+static int orinoco_ioctl_setessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
+        * anyway... - Jean II */
+
+       /* Hum... Should not use Wireless Extension constant (may change),
+        * should use our own... - Jean II */
+       if (erq->length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+       memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+       /* If not ANY, get the new ESSID */
+       if (erq->flags) {
+               memcpy(priv->desired_essid, essidbuf, erq->length);
+       }
+
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getessid(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_point *erq,
+                                 char *essidbuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int active;
+       int err = 0;
+       unsigned long flags;
+
+       if (netif_running(dev)) {
+               err = orinoco_hw_get_essid(priv, &active, essidbuf);
+               if (err < 0)
+                       return err;
+               erq->length = err;
+       } else {
+               if (orinoco_lock(priv, &flags) != 0)
+                       return -EBUSY;
+               memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
+               erq->length = strlen(priv->desired_essid);
+               orinoco_unlock(priv, &flags);
+       }
+
+       erq->flags = 1;
+
+       return 0;
+}
+
+static int orinoco_ioctl_setnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       if (nrq->length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       memset(priv->nick, 0, sizeof(priv->nick));
+       memcpy(priv->nick, nickbuf, nrq->length);
+
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getnick(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *nrq,
+                                char *nickbuf)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
+       orinoco_unlock(priv, &flags);
+
+       nrq->length = strlen(priv->nick);
+
+       return 0;
+}
+
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int chan = -1;
+       unsigned long flags;
+       int err = -EINPROGRESS;         /* Call commit handler */
+
+       /* In infrastructure mode the AP sets the channel */
+       if (priv->iw_mode == IW_MODE_INFRA)
+               return -EBUSY;
+
+       if ( (frq->e == 0) && (frq->m <= 1000) ) {
+               /* Setting by channel number */
+               chan = frq->m;
+       } else {
+               /* Setting by frequency - search the table */
+               int mult = 1;
+               int i;
+
+               for (i = 0; i < (6 - frq->e); i++)
+                       mult *= 10;
+
+               for (i = 0; i < NUM_CHANNELS; i++)
+                       if (frq->m == (channel_frequency[i] * mult))
+                               chan = i+1;
+       }
+
+       if ( (chan < 1) || (chan > NUM_CHANNELS) ||
+            ! (priv->channel_mask & (1 << (chan-1)) ) )
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       priv->channel = chan;
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               /* Fast channel change - no commit if successful */
+               hermes_t *hw = &priv->hw;
+               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+                                           HERMES_TEST_SET_CHANNEL,
+                                       chan, NULL);
+       }
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_freq *frq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int tmp;
+
+       /* Locking done in there */
+       tmp = orinoco_hw_get_freq(priv);
+       if (tmp < 0) {
+               return tmp;
+       }
+
+       frq->m = tmp;
+       frq->e = 1;
+
+       return 0;
+}
+
+static int orinoco_ioctl_getsens(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *srq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       u16 val;
+       int err;
+       unsigned long flags;
+
+       if (!priv->has_sensitivity)
+               return -EOPNOTSUPP;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       err = hermes_read_wordrec(hw, USER_BAP,
+                                 HERMES_RID_CNFSYSTEMSCALE, &val);
+       orinoco_unlock(priv, &flags);
+
+       if (err)
+               return err;
+
+       srq->value = val;
+       srq->fixed = 0; /* auto */
+
+       return 0;
+}
+
+static int orinoco_ioctl_setsens(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *srq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int val = srq->value;
+       unsigned long flags;
+
+       if (!priv->has_sensitivity)
+               return -EOPNOTSUPP;
+
+       if ((val < 1) || (val > 3))
+               return -EINVAL;
+       
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       priv->ap_density = val;
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_setrts(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int val = rrq->value;
+       unsigned long flags;
+
+       if (rrq->disabled)
+               val = 2347;
+
+       if ( (val < 0) || (val > 2347) )
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       priv->rts_thresh = val;
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_param *rrq,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       rrq->value = priv->rts_thresh;
+       rrq->disabled = (rrq->value == 2347);
+       rrq->fixed = 1;
+
+       return 0;
+}
+
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *frq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (priv->has_mwo) {
+               if (frq->disabled)
+                       priv->mwo_robust = 0;
+               else {
+                       if (frq->fixed)
+                               printk(KERN_WARNING "%s: Fixed fragmentation is "
+                                      "not supported on this firmware. "
+                                      "Using MWO robust instead.\n", dev->name);
+                       priv->mwo_robust = 1;
+               }
+       } else {
+               if (frq->disabled)
+                       priv->frag_thresh = 2346;
+               else {
+                       if ( (frq->value < 256) || (frq->value > 2346) )
+                               err = -EINVAL;
+                       else
+                               priv->frag_thresh = frq->value & ~0x1; /* must be even */
+               }
+       }
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *frq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err;
+       u16 val;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       
+       if (priv->has_mwo) {
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CNFMWOROBUST_AGERE,
+                                         &val);
+               if (err)
+                       val = 0;
+
+               frq->value = val ? 2347 : 0;
+               frq->disabled = ! val;
+               frq->fixed = 0;
+       } else {
+               err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+                                         &val);
+               if (err)
+                       val = 0;
+
+               frq->value = val;
+               frq->disabled = (val >= 2346);
+               frq->fixed = 1;
+       }
+
+       orinoco_unlock(priv, &flags);
+       
+       return err;
+}
+
+static int orinoco_ioctl_setrate(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int ratemode = -1;
+       int bitrate; /* 100s of kilobits */
+       int i;
+       unsigned long flags;
+       
+       /* As the user space doesn't know our highest rate, it uses -1
+        * to ask us to set the highest rate.  Test it using "iwconfig
+        * ethX rate auto" - Jean II */
+       if (rrq->value == -1)
+               bitrate = 110;
+       else {
+               if (rrq->value % 100000)
+                       return -EINVAL;
+               bitrate = rrq->value / 100000;
+       }
+
+       if ( (bitrate != 10) && (bitrate != 20) &&
+            (bitrate != 55) && (bitrate != 110) )
+               return -EINVAL;
+
+       for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+               if ( (bitrate_table[i].bitrate == bitrate) &&
+                    (bitrate_table[i].automatic == ! rrq->fixed) ) {
+                       ratemode = i;
+                       break;
+               }
+       
+       if (ratemode == -1)
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       priv->bitratemode = ratemode;
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;
+}
+
+static int orinoco_ioctl_getrate(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_param *rrq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       int ratemode;
+       int i;
+       u16 val;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       ratemode = priv->bitratemode;
+
+       BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
+
+       rrq->value = bitrate_table[ratemode].bitrate * 100000;
+       rrq->fixed = ! bitrate_table[ratemode].automatic;
+       rrq->disabled = 0;
+
+       /* If the interface is running we try to find more about the
+          current mode */
+       if (netif_running(dev)) {
+               err = hermes_read_wordrec(hw, USER_BAP,
+                                         HERMES_RID_CURRENTTXRATE, &val);
+               if (err)
+                       goto out;
+               
+               switch (priv->firmware_type) {
+               case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
+                       /* Note : in Lucent firmware, the return value of
+                        * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
+                        * and therefore is totally different from the
+                        * encoding of HERMES_RID_CNFTXRATECONTROL.
+                        * Don't forget that 6Mb/s is really 5.5Mb/s */
+                       if (val == 6)
+                               rrq->value = 5500000;
+                       else
+                               rrq->value = val * 1000000;
+                       break;
+               case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
+               case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+                       for (i = 0; i < BITRATE_TABLE_SIZE; i++)
+                               if (bitrate_table[i].intersil_txratectrl == val) {
+                                       ratemode = i;
+                                       break;
+                               }
+                       if (i >= BITRATE_TABLE_SIZE)
+                               printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
+                                      dev->name, val);
+
+                       rrq->value = bitrate_table[ratemode].bitrate * 100000;
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_setpower(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *prq,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = -EINPROGRESS;         /* Call commit handler */
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (prq->disabled) {
+               priv->pm_on = 0;
+       } else {
+               switch (prq->flags & IW_POWER_MODE) {
+               case IW_POWER_UNICAST_R:
+                       priv->pm_mcast = 0;
+                       priv->pm_on = 1;
+                       break;
+               case IW_POWER_ALL_R:
+                       priv->pm_mcast = 1;
+                       priv->pm_on = 1;
+                       break;
+               case IW_POWER_ON:
+                       /* No flags : but we may have a value - Jean II */
+                       break;
+               default:
+                       err = -EINVAL;
+                       goto out;
+               }
+               
+               if (prq->flags & IW_POWER_TIMEOUT) {
+                       priv->pm_on = 1;
+                       priv->pm_timeout = prq->value / 1000;
+               }
+               if (prq->flags & IW_POWER_PERIOD) {
+                       priv->pm_on = 1;
+                       priv->pm_period = prq->value / 1000;
+               }
+               /* It's valid to not have a value if we are just toggling
+                * the flags... Jean II */
+               if(!priv->pm_on) {
+                       err = -EINVAL;
+                       goto out;
+               }                       
+       }
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getpower(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *prq,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       u16 enable, period, timeout, mcast;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
+       if (err)
+               goto out;
+
+       err = hermes_read_wordrec(hw, USER_BAP,
+                                 HERMES_RID_CNFMAXSLEEPDURATION, &period);
+       if (err)
+               goto out;
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
+       if (err)
+               goto out;
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
+       if (err)
+               goto out;
+
+       prq->disabled = !enable;
+       /* Note : by default, display the period */
+       if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+               prq->flags = IW_POWER_TIMEOUT;
+               prq->value = timeout * 1000;
+       } else {
+               prq->flags = IW_POWER_PERIOD;
+               prq->value = period * 1000;
+       }
+       if (mcast)
+               prq->flags |= IW_POWER_ALL_R;
+       else
+               prq->flags |= IW_POWER_UNICAST_R;
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_set_encodeext(struct net_device *dev,
+                                      struct iw_request_info *info,
+                                      union iwreq_data *wrqu,
+                                      char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, alg = ext->alg, set_key = 1;
+       unsigned long flags;
+       int err = -EINVAL;
+       u16 key_len;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Determine and validate the key index */
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if ((idx < 1) || (idx > 4))
+                       goto out;
+               idx--;
+       } else
+               idx = priv->tx_key;
+
+       if (encoding->flags & IW_ENCODE_DISABLED)
+           alg = IW_ENCODE_ALG_NONE;
+
+       if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
+               /* Clear any TKIP TX key we had */
+               (void) orinoco_clear_tkip_key(priv, priv->tx_key);
+       }
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+               priv->tx_key = idx;
+               set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
+                          (ext->key_len > 0)) ? 1 : 0;
+       }
+
+       if (set_key) {
+               /* Set the requested key first */
+               switch (alg) {
+               case IW_ENCODE_ALG_NONE:
+                       priv->encode_alg = alg;
+                       priv->keys[idx].len = 0;
+                       break;
+
+               case IW_ENCODE_ALG_WEP:
+                       if (ext->key_len > SMALL_KEY_SIZE)
+                               key_len = LARGE_KEY_SIZE;
+                       else if (ext->key_len > 0)
+                               key_len = SMALL_KEY_SIZE;
+                       else
+                               goto out;
+
+                       priv->encode_alg = alg;
+                       priv->keys[idx].len = cpu_to_le16(key_len);
+
+                       key_len = min(ext->key_len, key_len);
+
+                       memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
+                       memcpy(priv->keys[idx].data, ext->key, key_len);
+                       break;
+
+               case IW_ENCODE_ALG_TKIP:
+               {
+                       hermes_t *hw = &priv->hw;
+                       u8 *tkip_iv = NULL;
+
+                       if (!priv->has_wpa ||
+                           (ext->key_len > sizeof(priv->tkip_key[0])))
+                               goto out;
+
+                       priv->encode_alg = alg;
+                       memset(&priv->tkip_key[idx], 0,
+                              sizeof(priv->tkip_key[idx]));
+                       memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
+
+                       if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+                               tkip_iv = &ext->rx_seq[0];
+
+                       err = __orinoco_hw_set_tkip_key(hw, idx,
+                                ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
+                                (u8 *) &priv->tkip_key[idx],
+                                tkip_iv, NULL);
+                       if (err)
+                               printk(KERN_ERR "%s: Error %d setting TKIP key"
+                                      "\n", dev->name, err);
+
+                       goto out;
+               }
+               default:
+                       goto out;
+               }
+       }
+       err = -EINPROGRESS;
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_get_encodeext(struct net_device *dev,
+                                      struct iw_request_info *info,
+                                      union iwreq_data *wrqu,
+                                      char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       int idx, max_key_len;
+       unsigned long flags;
+       int err;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       err = -EINVAL;
+       max_key_len = encoding->length - sizeof(*ext);
+       if (max_key_len < 0)
+               goto out;
+
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if ((idx < 1) || (idx > 4))
+                       goto out;
+               idx--;
+       } else
+               idx = priv->tx_key;
+
+       encoding->flags = idx + 1;
+       memset(ext, 0, sizeof(*ext));
+
+       ext->alg = priv->encode_alg;
+       switch (priv->encode_alg) {
+       case IW_ENCODE_ALG_NONE:
+               ext->key_len = 0;
+               encoding->flags |= IW_ENCODE_DISABLED;
+               break;
+       case IW_ENCODE_ALG_WEP:
+               ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len),
+                                    max_key_len);
+               memcpy(ext->key, priv->keys[idx].data, ext->key_len);
+               encoding->flags |= IW_ENCODE_ENABLED;
+               break;
+       case IW_ENCODE_ALG_TKIP:
+               ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key),
+                                    max_key_len);
+               memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
+               encoding->flags |= IW_ENCODE_ENABLED;
+               break;
+       }
+
+       err = 0;
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_set_auth(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *wrqu, char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       struct iw_param *param = &wrqu->param;
+       unsigned long flags;
+       int ret = -EINPROGRESS;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+       case IW_AUTH_PRIVACY_INVOKED:
+       case IW_AUTH_DROP_UNENCRYPTED:
+               /*
+                * orinoco does not use these parameters
+                */
+               break;
+
+       case IW_AUTH_KEY_MGMT:
+               /* wl_lkm implies value 2 == PSK for Hermes I
+                * which ties in with WEXT
+                * no other hints tho :(
+                */
+               priv->key_mgmt = param->value;
+               break;
+
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+               /* When countermeasures are enabled, shut down the
+                * card; when disabled, re-enable the card. This must
+                * take effect immediately.
+                *
+                * TODO: Make sure that the EAPOL message is getting
+                *       out before card disabled
+                */
+               if (param->value) {
+                       priv->tkip_cm_active = 1;
+                       ret = hermes_enable_port(hw, 0);
+               } else {
+                       priv->tkip_cm_active = 0;
+                       ret = hermes_disable_port(hw, 0);
+               }
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (param->value & IW_AUTH_ALG_SHARED_KEY)
+                       priv->wep_restrict = 1;
+               else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
+                       priv->wep_restrict = 0;
+               else
+                       ret = -EINVAL;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               if (priv->has_wpa) {
+                       priv->wpa_enabled = param->value ? 1 : 0;
+               } else {
+                       if (param->value)
+                               ret = -EOPNOTSUPP;
+                       /* else silently accept disable of WPA */
+                       priv->wpa_enabled = 0;
+               }
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       orinoco_unlock(priv, &flags);
+       return ret;
+}
+
+static int orinoco_ioctl_get_auth(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *wrqu, char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct iw_param *param = &wrqu->param;
+       unsigned long flags;
+       int ret = 0;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_KEY_MGMT:
+               param->value = priv->key_mgmt;
+               break;
+
+       case IW_AUTH_TKIP_COUNTERMEASURES:
+               param->value = priv->tkip_cm_active;
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               if (priv->wep_restrict)
+                       param->value = IW_AUTH_ALG_SHARED_KEY;
+               else
+                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               param->value = priv->wpa_enabled;
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       orinoco_unlock(priv, &flags);
+       return ret;
+}
+
+static int orinoco_ioctl_set_genie(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *wrqu, char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       u8 *buf;
+       unsigned long flags;
+       int err = 0;
+
+       /* cut off at IEEE80211_MAX_DATA_LEN */
+       if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
+           (wrqu->data.length && (extra == NULL)))
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (wrqu->data.length) {
+               buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+               if (buf == NULL) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               memcpy(buf, extra, wrqu->data.length);
+               kfree(priv->wpa_ie);
+               priv->wpa_ie = buf;
+               priv->wpa_ie_len = wrqu->data.length;
+       } else {
+               kfree(priv->wpa_ie);
+               priv->wpa_ie = NULL;
+               priv->wpa_ie_len = 0;
+       }
+
+       if (priv->wpa_ie) {
+               /* Looks like wl_lkm wants to check the auth alg, and
+                * somehow pass it to the firmware.
+                * Instead it just calls the key mgmt rid
+                *   - we do this in set auth.
+                */
+       }
+
+out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static int orinoco_ioctl_get_genie(struct net_device *dev,
+                                  struct iw_request_info *info,
+                                  union iwreq_data *wrqu, char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err = 0;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
+               wrqu->data.length = 0;
+               goto out;
+       }
+
+       if (wrqu->data.length < priv->wpa_ie_len) {
+               err = -E2BIG;
+               goto out;
+       }
+
+       wrqu->data.length = priv->wpa_ie_len;
+       memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
+
+out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static int orinoco_ioctl_set_mlme(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 union iwreq_data *wrqu, char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       struct iw_mlme *mlme = (struct iw_mlme *)extra;
+       unsigned long flags;
+       int ret = 0;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       switch (mlme->cmd) {
+       case IW_MLME_DEAUTH:
+               /* silently ignore */
+               break;
+
+       case IW_MLME_DISASSOC:
+       {
+               struct {
+                       u8 addr[ETH_ALEN];
+                       __le16 reason_code;
+               } __attribute__ ((packed)) buf;
+
+               memcpy(buf.addr, mlme->addr.sa_data, ETH_ALEN);
+               buf.reason_code = cpu_to_le16(mlme->reason_code);
+               ret = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                         HERMES_RID_CNFDISASSOCIATE,
+                                         &buf);
+               break;
+       }
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       orinoco_unlock(priv, &flags);
+       return ret;
+}
+
+static int orinoco_ioctl_getretry(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 struct iw_param *rrq,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int err = 0;
+       u16 short_limit, long_limit, lifetime;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+       
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+                                 &short_limit);
+       if (err)
+               goto out;
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+                                 &long_limit);
+       if (err)
+               goto out;
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+                                 &lifetime);
+       if (err)
+               goto out;
+
+       rrq->disabled = 0;              /* Can't be disabled */
+
+       /* Note : by default, display the retry number */
+       if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+               rrq->flags = IW_RETRY_LIFETIME;
+               rrq->value = lifetime * 1000;   /* ??? */
+       } else {
+               /* By default, display the min number */
+               if ((rrq->flags & IW_RETRY_LONG)) {
+                       rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
+                       rrq->value = long_limit;
+               } else {
+                       rrq->flags = IW_RETRY_LIMIT;
+                       rrq->value = short_limit;
+                       if(short_limit != long_limit)
+                               rrq->flags |= IW_RETRY_SHORT;
+               }
+       }
+
+ out:
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_reset(struct net_device *dev,
+                              struct iw_request_info *info,
+                              void *wrqu,
+                              char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       if (! capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+               printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+               /* Firmware reset */
+               orinoco_reset(&priv->reset_work);
+       } else {
+               printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+               schedule_work(&priv->reset_work);
+       }
+
+       return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int val = *( (int *) extra );
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       priv->ibss_port = val ;
+
+       /* Actually update the mode we are using */
+       set_port_type(priv);
+
+       orinoco_unlock(priv, &flags);
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int *val = (int *) extra;
+
+       *val = priv->ibss_port;
+       return 0;
+}
+
+static int orinoco_ioctl_setport3(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 void *wrqu,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int val = *( (int *) extra );
+       int err = 0;
+       unsigned long flags;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       switch (val) {
+       case 0: /* Try to do IEEE ad-hoc mode */
+               if (! priv->has_ibss) {
+                       err = -EINVAL;
+                       break;
+               }
+               priv->prefer_port3 = 0;
+                       
+               break;
+
+       case 1: /* Try to do Lucent proprietary ad-hoc mode */
+               if (! priv->has_port3) {
+                       err = -EINVAL;
+                       break;
+               }
+               priv->prefer_port3 = 1;
+               break;
+
+       default:
+               err = -EINVAL;
+       }
+
+       if (! err) {
+               /* Actually update the mode we are using */
+               set_port_type(priv);
+               err = -EINPROGRESS;
+       }
+
+       orinoco_unlock(priv, &flags);
+
+       return err;
+}
+
+static int orinoco_ioctl_getport3(struct net_device *dev,
+                                 struct iw_request_info *info,
+                                 void *wrqu,
+                                 char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int *val = (int *) extra;
+
+       *val = priv->prefer_port3;
+       return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int val;
+
+       if (! priv->has_preamble)
+               return -EOPNOTSUPP;
+
+       /* 802.11b has recently defined some short preamble.
+        * Basically, the Phy header has been reduced in size.
+        * This increase performance, especially at high rates
+        * (the preamble is transmitted at 1Mb/s), unfortunately
+        * this give compatibility troubles... - Jean II */
+       val = *( (int *) extra );
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (val)
+               priv->preamble = 1;
+       else
+               priv->preamble = 0;
+
+       orinoco_unlock(priv, &flags);
+
+       return -EINPROGRESS;            /* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+                                    struct iw_request_info *info,
+                                    void *wrqu,
+                                    char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int *val = (int *) extra;
+
+       if (! priv->has_preamble)
+               return -EOPNOTSUPP;
+
+       *val = priv->preamble;
+       return 0;
+}
+
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+                               struct iw_request_info *info,
+                               struct iw_point *data,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       int rid = data->flags;
+       u16 length;
+       int err;
+       unsigned long flags;
+
+       /* It's a "get" function, but we don't want users to access the
+        * WEP key and other raw firmware data */
+       if (! capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (rid < 0xfc00 || rid > 0xffff)
+               return -EINVAL;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+                             extra);
+       if (err)
+               goto out;
+
+       data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+                            MAX_RID_LEN);
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+/* Trigger a scan (look for other cells in the vicinity) */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *srq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       hermes_t *hw = &priv->hw;
+       struct iw_scan_req *si = (struct iw_scan_req *) extra;
+       int err = 0;
+       unsigned long flags;
+
+       /* Note : you may have realised that, as this is a SET operation,
+        * this is privileged and therefore a normal user can't
+        * perform scanning.
+        * This is not an error, while the device perform scanning,
+        * traffic doesn't flow, so it's a perfect DoS...
+        * Jean II */
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       /* Scanning with port 0 disabled would fail */
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
+       /* In monitor mode, the scan results are always empty.
+        * Probe responses are passed to the driver as received
+        * frames and could be processed in software. */
+       if (priv->iw_mode == IW_MODE_MONITOR) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* Note : because we don't lock out the irq handler, the way
+        * we access scan variables in priv is critical.
+        *      o scan_inprogress : not touched by irq handler
+        *      o scan_mode : not touched by irq handler
+        * Before modifying anything on those variables, please think hard !
+        * Jean II */
+
+       /* Save flags */
+       priv->scan_mode = srq->flags;
+
+       /* Always trigger scanning, even if it's in progress.
+        * This way, if the info frame get lost, we will recover somewhat
+        * gracefully  - Jean II */
+
+       if (priv->has_hostscan) {
+               switch (priv->firmware_type) {
+               case FIRMWARE_TYPE_SYMBOL:
+                       err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFHOSTSCAN_SYMBOL,
+                                                  HERMES_HOSTSCAN_SYMBOL_ONCE |
+                                                  HERMES_HOSTSCAN_SYMBOL_BCAST);
+                       break;
+               case FIRMWARE_TYPE_INTERSIL: {
+                       __le16 req[3];
+
+                       req[0] = cpu_to_le16(0x3fff);   /* All channels */
+                       req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
+                       req[2] = 0;                     /* Any ESSID */
+                       err = HERMES_WRITE_RECORD(hw, USER_BAP,
+                                                 HERMES_RID_CNFHOSTSCAN, &req);
+               }
+               break;
+               case FIRMWARE_TYPE_AGERE:
+                       if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
+                               struct hermes_idstring idbuf;
+                               size_t len = min(sizeof(idbuf.val),
+                                                (size_t) si->essid_len);
+                               idbuf.len = cpu_to_le16(len);
+                               memcpy(idbuf.val, si->essid, len);
+
+                               err = hermes_write_ltv(hw, USER_BAP,
+                                              HERMES_RID_CNFSCANSSID_AGERE,
+                                              HERMES_BYTES_TO_RECLEN(len + 2),
+                                              &idbuf);
+                       } else
+                               err = hermes_write_wordrec(hw, USER_BAP,
+                                                  HERMES_RID_CNFSCANSSID_AGERE,
+                                                  0);  /* Any ESSID */
+                       if (err)
+                               break;
+
+                       if (priv->has_ext_scan) {
+                               /* Clear scan results at the start of
+                                * an extended scan */
+                               orinoco_clear_scan_results(priv,
+                                               msecs_to_jiffies(15000));
+
+                               /* TODO: Is this available on older firmware?
+                                *   Can we use it to scan specific channels
+                                *   for IW_SCAN_THIS_FREQ? */
+                               err = hermes_write_wordrec(hw, USER_BAP,
+                                               HERMES_RID_CNFSCANCHANNELS2GHZ,
+                                               0x7FFF);
+                               if (err)
+                                       goto out;
+
+                               err = hermes_inquire(hw,
+                                                    HERMES_INQ_CHANNELINFO);
+                       } else
+                               err = hermes_inquire(hw, HERMES_INQ_SCAN);
+                       break;
+               }
+       } else
+               err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+       /* One more client */
+       if (! err)
+               priv->scan_inprogress = 1;
+
+ out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+#define MAX_CUSTOM_LEN 64
+
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline char *orinoco_translate_scan(struct net_device *dev,
+                                          struct iw_request_info *info,
+                                          char *current_ev,
+                                          char *end_buf,
+                                          union hermes_scan_info *bss,
+                                          unsigned int last_scanned)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       u16                     capabilities;
+       u16                     channel;
+       struct iw_event         iwe;            /* Temporary buffer */
+       char custom[MAX_CUSTOM_LEN];
+
+       memset(&iwe, 0, sizeof(iwe));
+
+       /* First entry *MUST* be the AP MAC address */
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_ADDR_LEN);
+
+       /* Other entries will be displayed in the order we give them */
+
+       /* Add the ESSID */
+       iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
+       if (iwe.u.data.length > 32)
+               iwe.u.data.length = 32;
+       iwe.cmd = SIOCGIWESSID;
+       iwe.u.data.flags = 1;
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, bss->a.essid);
+
+       /* Add mode */
+       iwe.cmd = SIOCGIWMODE;
+       capabilities = le16_to_cpu(bss->a.capabilities);
+       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+               if (capabilities & WLAN_CAPABILITY_ESS)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_ADHOC;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
+       }
+
+       channel = bss->s.channel;
+       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+               /* Add channel and frequency */
+               iwe.cmd = SIOCGIWFREQ;
+               iwe.u.freq.m = channel;
+               iwe.u.freq.e = 0;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_FREQ_LEN);
+
+               iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+               iwe.u.freq.e = 1;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_FREQ_LEN);
+       }
+
+       /* Add quality statistics. level and noise in dB. No link quality */
+       iwe.cmd = IWEVQUAL;
+       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
+       iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
+       iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
+       /* Wireless tools prior to 27.pre22 will show link quality
+        * anyway, so we provide a reasonable value. */
+       if (iwe.u.qual.level > iwe.u.qual.noise)
+               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+       else
+               iwe.u.qual.qual = 0;
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_QUAL_LEN);
+
+       /* Add encryption capability */
+       iwe.cmd = SIOCGIWENCODE;
+       if (capabilities & WLAN_CAPABILITY_PRIVACY)
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, NULL);
+
+       /* Bit rate is not available in Lucent/Agere firmwares */
+       if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+               char *current_val = current_ev + iwe_stream_lcp_len(info);
+               int i;
+               int step;
+
+               if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+                       step = 2;
+               else
+                       step = 1;
+
+               iwe.cmd = SIOCGIWRATE;
+               /* Those two flags are ignored... */
+               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+               /* Max 10 values */
+               for (i = 0; i < 10; i += step) {
+                       /* NULL terminated */
+                       if (bss->p.rates[i] == 0x0)
+                               break;
+                       /* Bit rate given in 500 kb/s units (+ 0x80) */
+                       iwe.u.bitrate.value =
+                               ((bss->p.rates[i] & 0x7f) * 500000);
+                       current_val = iwe_stream_add_value(info, current_ev,
+                                                          current_val,
+                                                          end_buf, &iwe,
+                                                          IW_EV_PARAM_LEN);
+               }
+               /* Check if we added any event */
+               if ((current_val - current_ev) > iwe_stream_lcp_len(info))
+                       current_ev = current_val;
+       }
+
+       /* Beacon interval */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    "bcn_int=%d",
+                                    le16_to_cpu(bss->a.beacon_interv));
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       /* Capabilites */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    "capab=0x%04x",
+                                    capabilities);
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       /* Add EXTRA: Age to display seconds since last beacon/probe response
+        * for given network. */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    " Last beacon: %dms ago",
+                                    jiffies_to_msecs(jiffies - last_scanned));
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       return current_ev;
+}
+
+static inline char *orinoco_translate_ext_scan(struct net_device *dev,
+                                              struct iw_request_info *info,
+                                              char *current_ev,
+                                              char *end_buf,
+                                              struct agere_ext_scan_info *bss,
+                                              unsigned int last_scanned)
+{
+       u16                     capabilities;
+       u16                     channel;
+       struct iw_event         iwe;            /* Temporary buffer */
+       char custom[MAX_CUSTOM_LEN];
+       u8 *ie;
+
+       memset(&iwe, 0, sizeof(iwe));
+
+       /* First entry *MUST* be the AP MAC address */
+       iwe.cmd = SIOCGIWAP;
+       iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+       memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_ADDR_LEN);
+
+       /* Other entries will be displayed in the order we give them */
+
+       /* Add the ESSID */
+       ie = bss->data;
+       iwe.u.data.length = ie[1];
+       if (iwe.u.data.length) {
+               if (iwe.u.data.length > 32)
+                       iwe.u.data.length = 32;
+               iwe.cmd = SIOCGIWESSID;
+               iwe.u.data.flags = 1;
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, &ie[2]);
+       }
+
+       /* Add mode */
+       capabilities = le16_to_cpu(bss->capabilities);
+       if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+               iwe.cmd = SIOCGIWMODE;
+               if (capabilities & WLAN_CAPABILITY_ESS)
+                       iwe.u.mode = IW_MODE_MASTER;
+               else
+                       iwe.u.mode = IW_MODE_ADHOC;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_UINT_LEN);
+       }
+
+       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
+       channel = ie ? ie[2] : 0;
+       if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+               /* Add channel and frequency */
+               iwe.cmd = SIOCGIWFREQ;
+               iwe.u.freq.m = channel;
+               iwe.u.freq.e = 0;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_FREQ_LEN);
+
+               iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+               iwe.u.freq.e = 1;
+               current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                                 &iwe, IW_EV_FREQ_LEN);
+       }
+
+       /* Add quality statistics. level and noise in dB. No link quality */
+       iwe.cmd = IWEVQUAL;
+       iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
+       iwe.u.qual.level = bss->level - 0x95;
+       iwe.u.qual.noise = bss->noise - 0x95;
+       /* Wireless tools prior to 27.pre22 will show link quality
+        * anyway, so we provide a reasonable value. */
+       if (iwe.u.qual.level > iwe.u.qual.noise)
+               iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+       else
+               iwe.u.qual.qual = 0;
+       current_ev = iwe_stream_add_event(info, current_ev, end_buf,
+                                         &iwe, IW_EV_QUAL_LEN);
+
+       /* Add encryption capability */
+       iwe.cmd = SIOCGIWENCODE;
+       if (capabilities & WLAN_CAPABILITY_PRIVACY)
+               iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+       else
+               iwe.u.data.flags = IW_ENCODE_DISABLED;
+       iwe.u.data.length = 0;
+       current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                         &iwe, NULL);
+
+       /* WPA IE */
+       ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
+       if (ie) {
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = ie[1] + 2;
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, ie);
+       }
+
+       /* RSN IE */
+       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
+       if (ie) {
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = ie[1] + 2;
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, ie);
+       }
+
+       ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
+       if (ie) {
+               char *p = current_ev + iwe_stream_lcp_len(info);
+               int i;
+
+               iwe.cmd = SIOCGIWRATE;
+               /* Those two flags are ignored... */
+               iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+               for (i = 2; i < (ie[1] + 2); i++) {
+                       iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
+                       p = iwe_stream_add_value(info, current_ev, p, end_buf,
+                                                &iwe, IW_EV_PARAM_LEN);
+               }
+               /* Check if we added any event */
+               if (p > (current_ev + iwe_stream_lcp_len(info)))
+                       current_ev = p;
+       }
+
+       /* Timestamp */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length =
+               snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
+                        (unsigned long long) le64_to_cpu(bss->timestamp));
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       /* Beacon interval */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    "bcn_int=%d",
+                                    le16_to_cpu(bss->beacon_interval));
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       /* Capabilites */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    "capab=0x%04x",
+                                    capabilities);
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       /* Add EXTRA: Age to display seconds since last beacon/probe response
+        * for given network. */
+       iwe.cmd = IWEVCUSTOM;
+       iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
+                                    " Last beacon: %dms ago",
+                                    jiffies_to_msecs(jiffies - last_scanned));
+       if (iwe.u.data.length)
+               current_ev = iwe_stream_add_point(info, current_ev, end_buf,
+                                                 &iwe, custom);
+
+       return current_ev;
+}
+
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+                                struct iw_request_info *info,
+                                struct iw_point *srq,
+                                char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       int err = 0;
+       unsigned long flags;
+       char *current_ev = extra;
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return -EBUSY;
+
+       if (priv->scan_inprogress) {
+               /* Important note : we don't want to block the caller
+                * until results are ready for various reasons.
+                * First, managing wait queues is complex and racy.
+                * Second, we grab some rtnetlink lock before comming
+                * here (in dev_ioctl()).
+                * Third, we generate an Wireless Event, so the
+                * caller can wait itself on that - Jean II */
+               err = -EAGAIN;
+               goto out;
+       }
+
+       if (priv->has_ext_scan) {
+               struct xbss_element *bss;
+
+               list_for_each_entry(bss, &priv->bss_list, list) {
+                       /* Translate this entry to WE format */
+                       current_ev =
+                               orinoco_translate_ext_scan(dev, info,
+                                                          current_ev,
+                                                          extra + srq->length,
+                                                          &bss->bss,
+                                                          bss->last_scanned);
+
+                       /* Check if there is space for one more entry */
+                       if ((extra + srq->length - current_ev)
+                           <= IW_EV_ADDR_LEN) {
+                               /* Ask user space to try again with a
+                                * bigger buffer */
+                               err = -E2BIG;
+                               goto out;
+                       }
+               }
+
+       } else {
+               struct bss_element *bss;
+
+               list_for_each_entry(bss, &priv->bss_list, list) {
+                       /* Translate this entry to WE format */
+                       current_ev = orinoco_translate_scan(dev, info,
+                                                           current_ev,
+                                                           extra + srq->length,
+                                                           &bss->bss,
+                                                           bss->last_scanned);
+
+                       /* Check if there is space for one more entry */
+                       if ((extra + srq->length - current_ev)
+                           <= IW_EV_ADDR_LEN) {
+                               /* Ask user space to try again with a
+                                * bigger buffer */
+                               err = -E2BIG;
+                               goto out;
+                       }
+               }
+       }
+
+       srq->length = (current_ev - extra);
+       srq->flags = (__u16) priv->scan_mode;
+
+out:
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+                               struct iw_request_info *info,
+                               void *wrqu,
+                               char *extra)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct hermes *hw = &priv->hw;
+       unsigned long flags;
+       int err = 0;
+
+       if (!priv->open)
+               return 0;
+
+       if (priv->broken_disableport) {
+               orinoco_reset(&priv->reset_work);
+               return 0;
+       }
+
+       if (orinoco_lock(priv, &flags) != 0)
+               return err;
+
+       err = hermes_disable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to disable port "
+                      "while reconfiguring card\n", dev->name);
+               priv->broken_disableport = 1;
+               goto out;
+       }
+
+       err = __orinoco_program_rids(dev);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+                      dev->name);
+               goto out;
+       }
+
+       err = hermes_enable_port(hw, 0);
+       if (err) {
+               printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+                      dev->name);
+               goto out;
+       }
+
+ out:
+       if (err) {
+               printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+               schedule_work(&priv->reset_work);
+               err = 0;
+       }
+
+       orinoco_unlock(priv, &flags);
+       return err;
+}
+
+static const struct iw_priv_args orinoco_privtab[] = {
+       { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+       { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+       { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_port3" },
+       { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_port3" },
+       { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_preamble" },
+       { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_preamble" },
+       { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         0, "set_ibssport" },
+       { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+         "get_ibssport" },
+       { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+         "get_rid" },
+};
+
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+#define STD_IW_HANDLER(id, func) \
+       [IW_IOCTL_IDX(id)] = (iw_handler) func
+static const iw_handler        orinoco_handler[] = {
+       STD_IW_HANDLER(SIOCSIWCOMMIT,   orinoco_ioctl_commit),
+       STD_IW_HANDLER(SIOCGIWNAME,     orinoco_ioctl_getname),
+       STD_IW_HANDLER(SIOCSIWFREQ,     orinoco_ioctl_setfreq),
+       STD_IW_HANDLER(SIOCGIWFREQ,     orinoco_ioctl_getfreq),
+       STD_IW_HANDLER(SIOCSIWMODE,     orinoco_ioctl_setmode),
+       STD_IW_HANDLER(SIOCGIWMODE,     orinoco_ioctl_getmode),
+       STD_IW_HANDLER(SIOCSIWSENS,     orinoco_ioctl_setsens),
+       STD_IW_HANDLER(SIOCGIWSENS,     orinoco_ioctl_getsens),
+       STD_IW_HANDLER(SIOCGIWRANGE,    orinoco_ioctl_getiwrange),
+       STD_IW_HANDLER(SIOCSIWSPY,      iw_handler_set_spy),
+       STD_IW_HANDLER(SIOCGIWSPY,      iw_handler_get_spy),
+       STD_IW_HANDLER(SIOCSIWTHRSPY,   iw_handler_set_thrspy),
+       STD_IW_HANDLER(SIOCGIWTHRSPY,   iw_handler_get_thrspy),
+       STD_IW_HANDLER(SIOCSIWAP,       orinoco_ioctl_setwap),
+       STD_IW_HANDLER(SIOCGIWAP,       orinoco_ioctl_getwap),
+       STD_IW_HANDLER(SIOCSIWSCAN,     orinoco_ioctl_setscan),
+       STD_IW_HANDLER(SIOCGIWSCAN,     orinoco_ioctl_getscan),
+       STD_IW_HANDLER(SIOCSIWESSID,    orinoco_ioctl_setessid),
+       STD_IW_HANDLER(SIOCGIWESSID,    orinoco_ioctl_getessid),
+       STD_IW_HANDLER(SIOCSIWNICKN,    orinoco_ioctl_setnick),
+       STD_IW_HANDLER(SIOCGIWNICKN,    orinoco_ioctl_getnick),
+       STD_IW_HANDLER(SIOCSIWRATE,     orinoco_ioctl_setrate),
+       STD_IW_HANDLER(SIOCGIWRATE,     orinoco_ioctl_getrate),
+       STD_IW_HANDLER(SIOCSIWRTS,      orinoco_ioctl_setrts),
+       STD_IW_HANDLER(SIOCGIWRTS,      orinoco_ioctl_getrts),
+       STD_IW_HANDLER(SIOCSIWFRAG,     orinoco_ioctl_setfrag),
+       STD_IW_HANDLER(SIOCGIWFRAG,     orinoco_ioctl_getfrag),
+       STD_IW_HANDLER(SIOCGIWRETRY,    orinoco_ioctl_getretry),
+       STD_IW_HANDLER(SIOCSIWENCODE,   orinoco_ioctl_setiwencode),
+       STD_IW_HANDLER(SIOCGIWENCODE,   orinoco_ioctl_getiwencode),
+       STD_IW_HANDLER(SIOCSIWPOWER,    orinoco_ioctl_setpower),
+       STD_IW_HANDLER(SIOCGIWPOWER,    orinoco_ioctl_getpower),
+       STD_IW_HANDLER(SIOCSIWGENIE,    orinoco_ioctl_set_genie),
+       STD_IW_HANDLER(SIOCGIWGENIE,    orinoco_ioctl_get_genie),
+       STD_IW_HANDLER(SIOCSIWMLME,     orinoco_ioctl_set_mlme),
+       STD_IW_HANDLER(SIOCSIWAUTH,     orinoco_ioctl_set_auth),
+       STD_IW_HANDLER(SIOCGIWAUTH,     orinoco_ioctl_get_auth),
+       STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
+       STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
+};
+
+
+/*
+  Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler        orinoco_private_handler[] = {
+       [0] = (iw_handler) orinoco_ioctl_reset,
+       [1] = (iw_handler) orinoco_ioctl_reset,
+       [2] = (iw_handler) orinoco_ioctl_setport3,
+       [3] = (iw_handler) orinoco_ioctl_getport3,
+       [4] = (iw_handler) orinoco_ioctl_setpreamble,
+       [5] = (iw_handler) orinoco_ioctl_getpreamble,
+       [6] = (iw_handler) orinoco_ioctl_setibssport,
+       [7] = (iw_handler) orinoco_ioctl_getibssport,
+       [9] = (iw_handler) orinoco_ioctl_getrid,
+};
+
+static const struct iw_handler_def orinoco_handler_def = {
+       .num_standard = ARRAY_SIZE(orinoco_handler),
+       .num_private = ARRAY_SIZE(orinoco_private_handler),
+       .num_private_args = ARRAY_SIZE(orinoco_privtab),
+       .standard = orinoco_handler,
+       .private = orinoco_private_handler,
+       .private_args = orinoco_privtab,
+       .get_wireless_stats = orinoco_get_wireless_stats,
+};
+
+static void orinoco_get_drvinfo(struct net_device *dev,
+                               struct ethtool_drvinfo *info)
+{
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+       strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+       strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+       if (dev->dev.parent)
+               strncpy(info->bus_info, dev->dev.parent->bus_id,
+                       sizeof(info->bus_info) - 1);
+       else
+               snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+                        "PCMCIA %p", priv->hw.iobase);
+}
+
+static const struct ethtool_ops orinoco_ethtool_ops = {
+       .get_drvinfo = orinoco_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+};
+
+/********************************************************************/
+/* Module initialization                                            */
+/********************************************************************/
+
+EXPORT_SYMBOL(alloc_orinocodev);
+EXPORT_SYMBOL(free_orinocodev);
+
+EXPORT_SYMBOL(__orinoco_up);
+EXPORT_SYMBOL(__orinoco_down);
+EXPORT_SYMBOL(orinoco_reinit_firmware);
+
+EXPORT_SYMBOL(orinoco_interrupt);
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (David Gibson <hermes@gibson.dropbear.id.au>, "
+       "Pavel Roskin <proski@gnu.org>, et al)";
+
+static int __init init_orinoco(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return 0;
+}
+
+static void __exit exit_orinoco(void)
+{
+}
+
+module_init(init_orinoco);
+module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
new file mode 100644 (file)
index 0000000..8c29538
--- /dev/null
@@ -0,0 +1,218 @@
+/* orinoco.h
+ * 
+ * Common definitions to all pieces of the various orinoco
+ * drivers
+ */
+
+#ifndef _ORINOCO_H
+#define _ORINOCO_H
+
+#define DRIVER_VERSION "0.15"
+
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+#include "hermes.h"
+
+/* To enable debug messages */
+//#define ORINOCO_DEBUG                3
+
+#define WIRELESS_SPY           // enable iwspy support
+
+#define MAX_SCAN_LEN           4096
+
+#define ORINOCO_MAX_KEY_SIZE   14
+#define ORINOCO_MAX_KEYS       4
+
+struct orinoco_key {
+       __le16 len;     /* always stored as little-endian */
+       char data[ORINOCO_MAX_KEY_SIZE];
+} __attribute__ ((packed));
+
+#define TKIP_KEYLEN    16
+#define MIC_KEYLEN     8
+
+struct orinoco_tkip_key {
+       u8 tkip[TKIP_KEYLEN];
+       u8 tx_mic[MIC_KEYLEN];
+       u8 rx_mic[MIC_KEYLEN];
+};
+
+typedef enum {
+       FIRMWARE_TYPE_AGERE,
+       FIRMWARE_TYPE_INTERSIL,
+       FIRMWARE_TYPE_SYMBOL
+} fwtype_t;
+
+struct bss_element {
+       union hermes_scan_info bss;
+       unsigned long last_scanned;
+       struct list_head list;
+};
+
+struct xbss_element {
+       struct agere_ext_scan_info bss;
+       unsigned long last_scanned;
+       struct list_head list;
+};
+
+struct hermes_rx_descriptor;
+
+struct orinoco_rx_data {
+       struct hermes_rx_descriptor *desc;
+       struct sk_buff *skb;
+       struct list_head list;
+};
+
+struct firmware;
+
+struct orinoco_private {
+       void *card;     /* Pointer to card dependent structure */
+       struct device *dev;
+       int (*hard_reset)(struct orinoco_private *);
+       int (*stop_fw)(struct orinoco_private *, int);
+
+       /* Synchronisation stuff */
+       spinlock_t lock;
+       int hw_unavailable;
+       struct work_struct reset_work;
+
+       /* Interrupt tasklets */
+       struct tasklet_struct rx_tasklet;
+       struct list_head rx_list;
+       struct orinoco_rx_data *rx_data;
+
+       /* driver state */
+       int open;
+       u16 last_linkstatus;
+       struct work_struct join_work;
+       struct work_struct wevent_work;
+
+       /* Net device stuff */
+       struct net_device *ndev;
+       struct net_device_stats stats;
+       struct iw_statistics wstats;
+
+       /* Hardware control variables */
+       hermes_t hw;
+       u16 txfid;
+
+       /* Capabilities of the hardware/firmware */
+       fwtype_t firmware_type;
+       char fw_name[32];
+       int ibss_port;
+       int nicbuf_size;
+       u16 channel_mask;
+
+       /* Boolean capabilities */
+       unsigned int has_ibss:1;
+       unsigned int has_port3:1;
+       unsigned int has_wep:1;
+       unsigned int has_big_wep:1;
+       unsigned int has_mwo:1;
+       unsigned int has_pm:1;
+       unsigned int has_preamble:1;
+       unsigned int has_sensitivity:1;
+       unsigned int has_hostscan:1;
+       unsigned int has_alt_txcntl:1;
+       unsigned int has_ext_scan:1;
+       unsigned int has_wpa:1;
+       unsigned int do_fw_download:1;
+       unsigned int broken_disableport:1;
+       unsigned int broken_monitor:1;
+
+       /* Configuration paramaters */
+       u32 iw_mode;
+       int prefer_port3;
+       u16 encode_alg, wep_restrict, tx_key;
+       struct orinoco_key keys[ORINOCO_MAX_KEYS];
+       int bitratemode;
+       char nick[IW_ESSID_MAX_SIZE+1];
+       char desired_essid[IW_ESSID_MAX_SIZE+1];
+       char desired_bssid[ETH_ALEN];
+       int bssid_fixed;
+       u16 frag_thresh, mwo_robust;
+       u16 channel;
+       u16 ap_density, rts_thresh;
+       u16 pm_on, pm_mcast, pm_period, pm_timeout;
+       u16 preamble;
+#ifdef WIRELESS_SPY
+       struct iw_spy_data spy_data; /* iwspy support */
+       struct iw_public_data   wireless_data;
+#endif
+
+       /* Configuration dependent variables */
+       int port_type, createibss;
+       int promiscuous, mc_count;
+
+       /* Scanning support */
+       struct list_head bss_list;
+       struct list_head bss_free_list;
+       void *bss_xbss_data;
+
+       int     scan_inprogress;        /* Scan pending... */
+       u32     scan_mode;              /* Type of scan done */
+
+       /* WPA support */
+       u8 *wpa_ie;
+       int wpa_ie_len;
+
+       struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
+       struct crypto_hash *rx_tfm_mic;
+       struct crypto_hash *tx_tfm_mic;
+
+       unsigned int wpa_enabled:1;
+       unsigned int tkip_cm_active:1;
+       unsigned int key_mgmt:3;
+
+       /* Cached in memory firmware to use in ->resume */
+       const struct firmware *cached_fw;
+};
+
+#ifdef ORINOCO_DEBUG
+extern int orinoco_debug;
+#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif /* ORINOCO_DEBUG */
+
+/********************************************************************/
+/* Exported prototypes                                              */
+/********************************************************************/
+
+extern struct net_device *alloc_orinocodev(
+       int sizeof_card, struct device *device,
+       int (*hard_reset)(struct orinoco_private *),
+       int (*stop_fw)(struct orinoco_private *, int));
+extern void free_orinocodev(struct net_device *dev);
+extern int __orinoco_up(struct net_device *dev);
+extern int __orinoco_down(struct net_device *dev);
+extern int orinoco_reinit_firmware(struct net_device *dev);
+extern irqreturn_t orinoco_interrupt(int irq, void * dev_id);
+
+/********************************************************************/
+/* Locking and synchronization functions                            */
+/********************************************************************/
+
+static inline int orinoco_lock(struct orinoco_private *priv,
+                              unsigned long *flags)
+{
+       spin_lock_irqsave(&priv->lock, *flags);
+       if (priv->hw_unavailable) {
+               DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
+                      priv->ndev);
+               spin_unlock_irqrestore(&priv->lock, *flags);
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static inline void orinoco_unlock(struct orinoco_private *priv,
+                                 unsigned long *flags)
+{
+       spin_unlock_irqrestore(&priv->lock, *flags);
+}
+
+#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
new file mode 100644 (file)
index 0000000..6fcf2bd
--- /dev/null
@@ -0,0 +1,533 @@
+/* orinoco_cs.c (formerly known as dldwd_cs.c)
+ *
+ * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+ * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
+ * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
+ * It should also be usable on various Prism II based cards such as the
+ * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
+ * cards such as the 3Com AirConnect and Ericsson WLAN.
+ * 
+ * Copyright notice & release notes in file orinoco.c
+ */
+
+#define DRIVER_NAME "orinoco_cs"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "orinoco.h"
+
+/********************************************************************/
+/* Module stuff                                                            */
+/********************************************************************/
+
+MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Module parameters */
+
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc; /* = 0 */
+module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
+
+/********************************************************************/
+/* Data structures                                                 */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
+struct orinoco_pccard {
+       struct pcmcia_device    *p_dev;
+       dev_node_t node;
+
+       /* Used to handle hard reset */
+       /* yuck, we need this hack to work around the insanity of the
+         * PCMCIA layer */
+       unsigned long hard_reset_in_progress; 
+};
+
+
+/********************************************************************/
+/* Function prototypes                                             */
+/********************************************************************/
+
+static int orinoco_cs_config(struct pcmcia_device *link);
+static void orinoco_cs_release(struct pcmcia_device *link);
+static void orinoco_cs_detach(struct pcmcia_device *p_dev);
+
+/********************************************************************/
+/* Device methods                                                  */
+/********************************************************************/
+
+static int
+orinoco_cs_hard_reset(struct orinoco_private *priv)
+{
+       struct orinoco_pccard *card = priv->card;
+       struct pcmcia_device *link = card->p_dev;
+       int err;
+
+       /* We need atomic ops here, because we're not holding the lock */
+       set_bit(0, &card->hard_reset_in_progress);
+
+       err = pcmcia_reset_card(link->socket);
+       if (err)
+               return err;
+
+       msleep(100);
+       clear_bit(0, &card->hard_reset_in_progress);
+
+       return 0;
+}
+
+/********************************************************************/
+/* PCMCIA stuff                                                    */
+/********************************************************************/
+
+/*
+ * This 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
+orinoco_cs_probe(struct pcmcia_device *link)
+{
+       struct net_device *dev;
+       struct orinoco_private *priv;
+       struct orinoco_pccard *card;
+
+       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+                              orinoco_cs_hard_reset, NULL);
+       if (! dev)
+               return -ENOMEM;
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       /* Link both structures together */
+       card->p_dev = link;
+       link->priv = dev;
+
+       /* Interrupt setup */
+       link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
+       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+       link->irq.Handler = orinoco_interrupt;
+       link->irq.Instance = dev; 
+
+       /* General socket configuration defaults can go here.  In this
+        * client, we assume very little, and rely on the CIS for
+        * almost everything.  In most clients, many details (i.e.,
+        * number, sizes, and attributes of IO windows) are fixed by
+        * the nature of the device, and can be hard-wired here. */
+       link->conf.Attributes = 0;
+       link->conf.IntType = INT_MEMORY_AND_IO;
+
+       return orinoco_cs_config(link);
+}                              /* orinoco_cs_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 orinoco_cs_detach(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+
+       if (link->dev_node)
+               unregister_netdev(dev);
+
+       orinoco_cs_release(link);
+
+       free_orinocodev(dev);
+}                              /* orinoco_cs_detach */
+
+/*
+ * orinoco_cs_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) do { \
+               last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
+       } while (0)
+
+static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
+                                  cistpl_cftable_entry_t *cfg,
+                                  cistpl_cftable_entry_t *dflt,
+                                  unsigned int vcc,
+                                  void *priv_data)
+{
+       if (cfg->index == 0)
+               goto next_entry;
+
+       /* Use power settings for Vcc and Vpp if present */
+       /* Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       /* Do we need to allocate an interrupt? */
+       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       goto next_entry;
+       }
+       return 0;
+
+next_entry:
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+};
+
+static int
+orinoco_cs_config(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pccard *card = priv->card;
+       hermes_t *hw = &priv->hw;
+       int last_fn, last_ret;
+       void __iomem *mem;
+
+       /*
+        * 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 and accurate CIS.  In practice, a driver usually
+        * "knows" most of these things without consulting the CIS,
+        * and most client drivers will only use the CIS to fill in
+        * implementation-defined details.
+        */
+       last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
+       if (last_ret) {
+               if (!ignore_cis_vcc)
+                       printk(KERN_ERR PFX "GetNextTuple(): No matching "
+                              "CIS configuration.  Maybe you need the "
+                              "ignore_cis_vcc=1 parameter.\n");
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
+       }
+
+       /*
+        * Allocate an interrupt line.  Note that this does not assign
+        * a handler to the interrupt, unless the 'Handler' member of
+        * the irq structure is initialized.
+        */
+       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+
+       /* We initialize the hermes structure before completing PCMCIA
+        * configuration just in case the interrupt handler gets
+        * called. */
+       mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+       if (!mem)
+               goto cs_failed;
+
+       hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+
+       /*
+        * 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));
+
+       /* Ok, we have the configuration, prepare to register the netdev */
+       dev->base_addr = link->io.BasePort1;
+       dev->irq = link->irq.AssignedIRQ;
+       card->node.major = card->node.minor = 0;
+
+       SET_NETDEV_DEV(dev, &handle_to_dev(link));
+       /* Tell the stack we exist */
+       if (register_netdev(dev) != 0) {
+               printk(KERN_ERR PFX "register_netdev() failed\n");
+               goto failed;
+       }
+
+       /* At this point, the dev_node_t structure(s) needs to be
+        * initialized and arranged in a linked list at link->dev_node. */
+       strcpy(card->node.dev_name, dev->name);
+       link->dev_node = &card->node; /* link->dev_node being non-NULL is also
+                                    used to indicate that the
+                                    net_device has been registered */
+
+       /* Finally, report what we've done */
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+              link->irq.AssignedIRQ, link->io.BasePort1,
+              link->io.BasePort1 + link->io.NumPorts1 - 1);
+       return 0;
+
+ cs_failed:
+       cs_error(link, last_fn, last_ret);
+
+ failed:
+       orinoco_cs_release(link);
+       return -ENODEV;
+}                              /* orinoco_cs_config */
+
+/*
+ * After a card is removed, orinoco_cs_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
+orinoco_cs_release(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       /* We're committed to taking the device away now, so mark the
+        * hardware as unavailable */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw_unavailable++;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       pcmcia_disable_device(link);
+       if (priv->hw.iobase)
+               ioport_unmap(priv->hw.iobase);
+}                              /* orinoco_cs_release */
+
+static int orinoco_cs_suspend(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pccard *card = priv->card;
+       int err = 0;
+       unsigned long flags;
+
+       /* This is probably racy, but I can't think of
+          a better way, short of rewriting the PCMCIA
+          layer to not suck :-( */
+       if (! test_bit(0, &card->hard_reset_in_progress)) {
+               spin_lock_irqsave(&priv->lock, flags);
+
+               err = __orinoco_down(dev);
+               if (err)
+                       printk(KERN_WARNING "%s: Error %d downing interface\n",
+                              dev->name, err);
+
+               netif_device_detach(dev);
+               priv->hw_unavailable++;
+
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
+       return 0;
+}
+
+static int orinoco_cs_resume(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       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);
+               if (err) {
+                       printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+                              dev->name, err);
+                       return -EIO;
+               }
+
+               spin_lock_irqsave(&priv->lock, flags);
+
+               netif_device_attach(dev);
+               priv->hw_unavailable--;
+
+               if (priv->open && ! priv->hw_unavailable) {
+                       err = __orinoco_up(dev);
+                       if (err)
+                               printk(KERN_ERR "%s: Error %d restarting card\n",
+                                      dev->name, err);
+               }
+
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
+       return err;
+}
+
+
+/********************************************************************/
+/* Module initialization                                           */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (David Gibson <hermes@gibson.dropbear.id.au>, "
+       "Pavel Roskin <proski@gnu.org>, et al)";
+
+static struct pcmcia_device_id orinoco_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
+       PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
+       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
+       PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
+       PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
+       PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
+       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
+       PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
+       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
+       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
+       PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
+       PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
+       PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
+       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
+       PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
+       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+       PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
+       PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
+       PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
+       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
+       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
+       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+       PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
+       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+       PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
+       PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
+       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+       PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
+       PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
+       PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
+       PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
+       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
+       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
+       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
+       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
+       PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
+       PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2),
+       PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
+       PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
+       PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
+       PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
+       PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
+       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39),
+       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
+       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
+       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
+       PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
+       PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39),
+       PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
+
+static struct pcmcia_driver orinoco_driver = {
+       .owner          = THIS_MODULE,
+       .drv            = {
+               .name   = DRIVER_NAME,
+       },
+       .probe          = orinoco_cs_probe,
+       .remove         = orinoco_cs_detach,
+       .id_table       = orinoco_cs_ids,
+       .suspend        = orinoco_cs_suspend,
+       .resume         = orinoco_cs_resume,
+};
+
+static int __init
+init_orinoco_cs(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+
+       return pcmcia_register_driver(&orinoco_driver);
+}
+
+static void __exit
+exit_orinoco_cs(void)
+{
+       pcmcia_unregister_driver(&orinoco_driver);
+}
+
+module_init(init_orinoco_cs);
+module_exit(exit_orinoco_cs);
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
new file mode 100644 (file)
index 0000000..2fc8659
--- /dev/null
@@ -0,0 +1,324 @@
+/* orinoco_nortel.c
+ *
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
+ * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
+ *
+ * Copyright (C) 2002 Tobias Hoffmann
+ *           (C) 2003 Christoph Jungegger <disdos@traum404.de>
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ *     Copyright (C) 2001 Daniel Barlow
+ * Some of this code is borrowed from orinoco_pci.c 
+ *  Copyright (C) 2001 Jean Tourrilhes
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ *     Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ * 
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#define DRIVER_NAME "orinoco_nortel"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <pcmcia/cisreg.h>
+
+#include "orinoco.h"
+#include "orinoco_pci.h"
+
+#define COR_OFFSET    (0xe0)   /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA)   /* Enable PC card with interrupt in level trigger */
+
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
+{
+       struct orinoco_pci_card *card = priv->card;
+
+       /* Assert the reset until the card notices */
+       iowrite16(8, card->bridge_io + 2);
+       ioread16(card->attr_io + COR_OFFSET);
+       iowrite16(0x80, card->attr_io + COR_OFFSET);
+       mdelay(1);
+
+       /* Give time for the card to recover from this hard effort */
+       iowrite16(0, card->attr_io + COR_OFFSET);
+       iowrite16(0, card->attr_io + COR_OFFSET);
+       mdelay(1);
+
+       /* Set COR as usual */
+       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
+       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
+       mdelay(1);
+
+       iowrite16(0x228, card->bridge_io + 2);
+
+       return 0;
+}
+
+static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
+{
+       int i;
+       u32 reg;
+
+       /* Setup bridge */
+       if (ioread16(card->bridge_io) & 1) {
+               printk(KERN_ERR PFX "brg1 answer1 wrong\n");
+               return -EBUSY;
+       }
+       iowrite16(0x118, card->bridge_io + 2);
+       iowrite16(0x108, card->bridge_io + 2);
+       mdelay(30);
+       iowrite16(0x8, card->bridge_io + 2);
+       for (i = 0; i < 30; i++) {
+               mdelay(30);
+               if (ioread16(card->bridge_io) & 0x10) {
+                       break;
+               }
+       }
+       if (i == 30) {
+               printk(KERN_ERR PFX "brg1 timed out\n");
+               return -EBUSY;
+       }
+       if (ioread16(card->attr_io + COR_OFFSET) & 1) {
+               printk(KERN_ERR PFX "brg2 answer1 wrong\n");
+               return -EBUSY;
+       }
+       if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
+               printk(KERN_ERR PFX "brg2 answer2 wrong\n");
+               return -EBUSY;
+       }
+       if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
+               printk(KERN_ERR PFX "brg2 answer3 wrong\n");
+               return -EBUSY;
+       }
+
+       /* Set the PCMCIA COR register */
+       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
+       mdelay(1);
+       reg = ioread16(card->attr_io + COR_OFFSET);
+       if (reg != COR_VALUE) {
+               printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
+                      reg);
+               return -EBUSY;
+       }
+
+       /* Set LEDs */
+       iowrite16(1, card->bridge_io + 10);
+       return 0;
+}
+
+static int orinoco_nortel_init_one(struct pci_dev *pdev,
+                                  const struct pci_device_id *ent)
+{
+       int err;
+       struct orinoco_private *priv;
+       struct orinoco_pci_card *card;
+       struct net_device *dev;
+       void __iomem *hermes_io, *bridge_io, *attr_io;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+               goto fail_resources;
+       }
+
+       bridge_io = pci_iomap(pdev, 0, 0);
+       if (!bridge_io) {
+               printk(KERN_ERR PFX "Cannot map bridge registers\n");
+               err = -EIO;
+               goto fail_map_bridge;
+       }
+
+       attr_io = pci_iomap(pdev, 1, 0);
+       if (!attr_io) {
+               printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
+               err = -EIO;
+               goto fail_map_attr;
+       }
+
+       hermes_io = pci_iomap(pdev, 2, 0);
+       if (!hermes_io) {
+               printk(KERN_ERR PFX "Cannot map chipset registers\n");
+               err = -EIO;
+               goto fail_map_hermes;
+       }
+
+       /* Allocate network device */
+       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                              orinoco_nortel_cor_reset, NULL);
+       if (!dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+       card->bridge_io = bridge_io;
+       card->attr_io = attr_io;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
+
+       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+               err = -EBUSY;
+               goto fail_irq;
+       }
+
+       err = orinoco_nortel_hw_init(card);
+       if (err) {
+               printk(KERN_ERR PFX "Hardware initialization failed\n");
+               goto fail;
+       }
+
+       err = orinoco_nortel_cor_reset(priv);
+       if (err) {
+               printk(KERN_ERR PFX "Initial reset failed\n");
+               goto fail;
+       }
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register network device\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, dev);
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+              pci_name(pdev));
+
+       return 0;
+
+ fail:
+       free_irq(pdev->irq, dev);
+
+ fail_irq:
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+
+ fail_alloc:
+       pci_iounmap(pdev, hermes_io);
+
+ fail_map_hermes:
+       pci_iounmap(pdev, attr_io);
+
+ fail_map_attr:
+       pci_iounmap(pdev, bridge_io);
+
+ fail_map_bridge:
+       pci_release_regions(pdev);
+
+ fail_resources:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pci_card *card = priv->card;
+
+       /* Clear LEDs */
+       iowrite16(0, card->bridge_io + 10);
+
+       unregister_netdev(dev);
+       free_irq(pdev->irq, dev);
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+       pci_iounmap(pdev, priv->hw.iobase);
+       pci_iounmap(pdev, card->attr_io);
+       pci_iounmap(pdev, card->bridge_io);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id orinoco_nortel_id_table[] = {
+       /* Nortel emobility PCI */
+       {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
+       /* Symbol LA-4123 PCI */
+       {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
+
+static struct pci_driver orinoco_nortel_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = orinoco_nortel_id_table,
+       .probe          = orinoco_nortel_init_one,
+       .remove         = __devexit_p(orinoco_nortel_remove_one),
+       .suspend        = orinoco_pci_suspend,
+       .resume         = orinoco_pci_resume,
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
+MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
+MODULE_DESCRIPTION
+    ("Driver for wireless LAN cards using the Nortel PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init orinoco_nortel_init(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return pci_register_driver(&orinoco_nortel_driver);
+}
+
+static void __exit orinoco_nortel_exit(void)
+{
+       pci_unregister_driver(&orinoco_nortel_driver);
+}
+
+module_init(orinoco_nortel_init);
+module_exit(orinoco_nortel_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
new file mode 100644 (file)
index 0000000..4ebd638
--- /dev/null
@@ -0,0 +1,264 @@
+/* orinoco_pci.c
+ * 
+ * Driver for Prism 2.5/3 devices that have a direct PCI interface
+ * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
+ * The card contains only one PCI region, which contains all the usual
+ * hermes registers, as well as the COR register.
+ *
+ * Current maintainers are:
+ *     Pavel Roskin <proski AT gnu.org>
+ * and David Gibson <hermes AT gibson.dropbear.id.au>
+ *
+ * Some of this code is borrowed from orinoco_plx.c
+ *     Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
+ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
+ * has been copied from it. linux-wlan-ng-0.1.10 is originally :
+ *     Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ * This file originally written by:
+ *     Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
+ * And is now maintained by:
+ *     (C) Copyright David Gibson, IBM Corp. 2002-2003.
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#define DRIVER_NAME "orinoco_pci"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "orinoco.h"
+#include "orinoco_pci.h"
+
+/* Offset of the COR register of the PCI card */
+#define HERMES_PCI_COR         (0x26)
+
+/* Bitmask to reset the card */
+#define HERMES_PCI_COR_MASK    (0x0080)
+
+/* Magic timeouts for doing the reset.
+ * Those times are straight from wlan-ng, and it is claimed that they
+ * are necessary. Alan will kill me. Take your time and grab a coffee. */
+#define HERMES_PCI_COR_ONT     (250)           /* ms */
+#define HERMES_PCI_COR_OFFT    (500)           /* ms */
+#define HERMES_PCI_COR_BUSYT   (500)           /* ms */
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ * We need this to get going...
+ * This is the part of the code that is strongly inspired from wlan-ng
+ *
+ * Note : This code is done with irq enabled. This mean that many
+ * interrupts will occur while we are there. This is why we use the
+ * jiffies to regulate time instead of a straight mdelay(). Usually we
+ * need only around 245 iteration of the loop to do 250 ms delay.
+ *
+ * Note bis : Don't try to access HERMES_CMD during the reset phase.
+ * It just won't work !
+ */
+static int orinoco_pci_cor_reset(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       unsigned long timeout;
+       u16 reg;
+
+       /* Assert the reset until the card notices */
+       hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
+       mdelay(HERMES_PCI_COR_ONT);
+
+       /* Give time for the card to recover from this hard effort */
+       hermes_write_regn(hw, PCI_COR, 0x0000);
+       mdelay(HERMES_PCI_COR_OFFT);
+
+       /* The card is ready when it's no longer busy */
+       timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
+       reg = hermes_read_regn(hw, CMD);
+       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+               mdelay(1);
+               reg = hermes_read_regn(hw, CMD);
+       }
+
+       /* Still busy? */
+       if (reg & HERMES_CMD_BUSY) {
+               printk(KERN_ERR PFX "Busy timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int orinoco_pci_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       int err;
+       struct orinoco_private *priv;
+       struct orinoco_pci_card *card;
+       struct net_device *dev;
+       void __iomem *hermes_io;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+               goto fail_resources;
+       }
+
+       hermes_io = pci_iomap(pdev, 0, 0);
+       if (!hermes_io) {
+               printk(KERN_ERR PFX "Cannot remap chipset registers\n");
+               err = -EIO;
+               goto fail_map_hermes;
+       }
+
+       /* Allocate network device */
+       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                              orinoco_pci_cor_reset, NULL);
+       if (!dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
+
+       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+               err = -EBUSY;
+               goto fail_irq;
+       }
+
+       err = orinoco_pci_cor_reset(priv);
+       if (err) {
+               printk(KERN_ERR PFX "Initial reset failed\n");
+               goto fail;
+       }
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register network device\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, dev);
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+              pci_name(pdev));
+
+       return 0;
+
+ fail:
+       free_irq(pdev->irq, dev);
+
+ fail_irq:
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+
+ fail_alloc:
+       pci_iounmap(pdev, hermes_io);
+
+ fail_map_hermes:
+       pci_release_regions(pdev);
+
+ fail_resources:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       free_irq(pdev->irq, dev);
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+       pci_iounmap(pdev, priv->hw.iobase);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id orinoco_pci_id_table[] = {
+       /* Intersil Prism 3 */
+       {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
+       /* Intersil Prism 2.5 */
+       {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
+       /* Samsung MagicLAN SWL-2210P */
+       {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
+
+static struct pci_driver orinoco_pci_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = orinoco_pci_id_table,
+       .probe          = orinoco_pci_init_one,
+       .remove         = __devexit_p(orinoco_pci_remove_one),
+       .suspend        = orinoco_pci_suspend,
+       .resume         = orinoco_pci_resume,
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Pavel Roskin <proski@gnu.org>,"
+       " David Gibson <hermes@gibson.dropbear.id.au> &"
+       " Jean Tourrilhes <jt@hpl.hp.com>)";
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init orinoco_pci_init(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return pci_register_driver(&orinoco_pci_driver);
+}
+
+static void __exit orinoco_pci_exit(void)
+{
+       pci_unregister_driver(&orinoco_pci_driver);
+}
+
+module_init(orinoco_pci_init);
+module_exit(orinoco_pci_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
new file mode 100644 (file)
index 0000000..f4e5e06
--- /dev/null
@@ -0,0 +1,109 @@
+/* orinoco_pci.h
+ * 
+ * Common code for all Orinoco drivers for PCI devices, including
+ * both native PCI and PCMCIA-to-PCI bridges.
+ *
+ * Copyright (C) 2005, Pavel Roskin.
+ * See orinoco.c for license.
+ */
+
+#ifndef _ORINOCO_PCI_H
+#define _ORINOCO_PCI_H
+
+#include <linux/netdevice.h>
+
+/* Driver specific data */
+struct orinoco_pci_card {
+       void __iomem *bridge_io;
+       void __iomem *attr_io;
+};
+
+#ifdef CONFIG_PM
+static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err;
+
+       err = orinoco_lock(priv, &flags);
+       if (err) {
+               printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
+                      dev->name);
+               return err;
+       }
+
+       err = __orinoco_down(dev);
+       if (err)
+               printk(KERN_WARNING "%s: error %d bringing interface down "
+                      "for suspend\n", dev->name, err);
+       
+       netif_device_detach(dev);
+
+       priv->hw_unavailable++;
+       
+       orinoco_unlock(priv, &flags);
+
+       free_irq(pdev->irq, dev);
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int orinoco_pci_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+       int err;
+
+       pci_set_power_state(pdev, 0);
+       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,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
+                      dev->name);
+               pci_disable_device(pdev);
+               return -EBUSY;
+       }
+
+       err = orinoco_reinit_firmware(dev);
+       if (err) {
+               printk(KERN_ERR "%s: error %d re-initializing firmware "
+                      "on resume\n", dev->name, err);
+               return err;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       netif_device_attach(dev);
+
+       priv->hw_unavailable--;
+
+       if (priv->open && (! priv->hw_unavailable)) {
+               err = __orinoco_up(dev);
+               if (err)
+                       printk(KERN_ERR "%s: Error %d restarting card on resume\n",
+                              dev->name, err);
+       }
+       
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       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/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
new file mode 100644 (file)
index 0000000..ef76185
--- /dev/null
@@ -0,0 +1,371 @@
+/* orinoco_plx.c
+ *
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a PLX9052.
+ *
+ * Current maintainers are:
+ *     Pavel Roskin <proski AT gnu.org>
+ * and David Gibson <hermes AT gibson.dropbear.id.au>
+ *
+ * (C) Copyright David Gibson, IBM Corp. 2001-2003.
+ * Copyright (C) 2001 Daniel Barlow
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ *
+ * Here's the general details on how the PLX9052 adapter works:
+ *
+ * - Two PCI I/O address spaces, one 0x80 long which contains the
+ * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
+ * slot I/O address space.
+ *
+ * - One PCI memory address space, mapped to the PCMCIA attribute space
+ * (containing the CIS).
+ *
+ * Using the later, you can read through the CIS data to make sure the
+ * card is compatible with the driver. Keep in mind that the PCMCIA
+ * spec specifies the CIS as the lower 8 bits of each word read from
+ * the CIS, so to read the bytes of the CIS, read every other byte
+ * (0,2,4,...). Passing that test, you need to enable the I/O address
+ * space on the PCMCIA card via the PCMCIA COR register. This is the
+ * first byte following the CIS. In my case (which may not have any
+ * relation to what's on the PRISM2 cards), COR was at offset 0x800
+ * within the PCI memory space. Write 0x41 to the COR register to
+ * enable I/O mode and to select level triggered interrupts. To
+ * confirm you actually succeeded, read the COR register back and make
+ * sure it actually got set to 0x41, in case you have an unexpected
+ * card inserted.
+ *
+ * Following that, you can treat the second PCI I/O address space (the
+ * one that's not 0x80 in length) as the PCMCIA I/O space.
+ *
+ * Note that in the Eumitcom's source for their drivers, they register
+ * the interrupt as edge triggered when registering it with the
+ * Windows kernel. I don't recall how to register edge triggered on
+ * Linux (if it can be done at all). But in some experimentation, I
+ * don't see much operational difference between using either
+ * interrupt mode. Don't mess with the interrupt mode in the COR
+ * register though, as the PLX9052 wants level triggers with the way
+ * the serial EEPROM configures it on the WL11000.
+ *
+ * There's some other little quirks related to timing that I bumped
+ * into, but I don't recall right now. Also, there's two variants of
+ * the WL11000 I've seen, revision A1 and T2. These seem to differ
+ * slightly in the timings configured in the wait-state generator in
+ * the PLX9052. There have also been some comments from Eumitcom that
+ * cards shouldn't be hot swapped, apparently due to risk of cooking
+ * the PLX9052. I'm unsure why they believe this, as I can't see
+ * anything in the design that would really cause a problem, except
+ * for crashing drivers not written to expect it. And having developed
+ * drivers for the WL11000, I'd say it's quite tricky to write code
+ * that will successfully deal with a hot unplug. Very odd things
+ * happen on the I/O side of things. But anyway, be warned. Despite
+ * that, I've hot-swapped a number of times during debugging and
+ * driver development for various reasons (stuck WAIT# line after the
+ * radio card's firmware locks up).
+ */
+
+#define DRIVER_NAME "orinoco_plx"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <pcmcia/cisreg.h>
+
+#include "orinoco.h"
+#include "orinoco_pci.h"
+
+#define COR_OFFSET     (0x3e0) /* COR attribute offset of Prism2 PC card */
+#define COR_VALUE      (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)   /* reset bit in the COR register */
+#define PLX_RESET_TIME (500)   /* milliseconds */
+
+#define PLX_INTCSR             0x4c /* Interrupt Control & Status Register */
+#define PLX_INTCSR_INTEN       (1<<6) /* Interrupt Enable bit */
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_plx_cor_reset(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       struct orinoco_pci_card *card = priv->card;
+       unsigned long timeout;
+       u16 reg;
+
+       iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
+       mdelay(1);
+
+       iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
+       mdelay(1);
+
+       /* Just in case, wait more until the card is no longer busy */
+       timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
+       reg = hermes_read_regn(hw, CMD);
+       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+               mdelay(1);
+               reg = hermes_read_regn(hw, CMD);
+       }
+
+       /* Still busy? */
+       if (reg & HERMES_CMD_BUSY) {
+               printk(KERN_ERR PFX "Busy timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
+{
+       int i;
+       u32 csr_reg;
+       static const u8 cis_magic[] = {
+               0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
+       };
+
+       printk(KERN_DEBUG PFX "CIS: ");
+       for (i = 0; i < 16; i++) {
+               printk("%02X:", ioread8(card->attr_io + (i << 1)));
+       }
+       printk("\n");
+
+       /* Verify whether a supported PC card is present */
+       /* FIXME: we probably need to be smarted about this */
+       for (i = 0; i < sizeof(cis_magic); i++) {
+               if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
+                       printk(KERN_ERR PFX "The CIS value of Prism2 PC "
+                              "card is unexpected\n");
+                       return -ENODEV;
+               }
+       }
+
+       /* bjoern: We need to tell the card to enable interrupts, in
+          case the serial eprom didn't do this already.  See the
+          PLX9052 data book, p8-1 and 8-24 for reference. */
+       csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
+       if (!(csr_reg & PLX_INTCSR_INTEN)) {
+               csr_reg |= PLX_INTCSR_INTEN;
+               iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
+               csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
+               if (!(csr_reg & PLX_INTCSR_INTEN)) {
+                       printk(KERN_ERR PFX "Cannot enable interrupts\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int orinoco_plx_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       int err;
+       struct orinoco_private *priv;
+       struct orinoco_pci_card *card;
+       struct net_device *dev;
+       void __iomem *hermes_io, *attr_io, *bridge_io;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+               goto fail_resources;
+       }
+
+       bridge_io = pci_iomap(pdev, 1, 0);
+       if (!bridge_io) {
+               printk(KERN_ERR PFX "Cannot map bridge registers\n");
+               err = -EIO;
+               goto fail_map_bridge;
+       }
+
+       attr_io = pci_iomap(pdev, 2, 0);
+       if (!attr_io) {
+               printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
+               err = -EIO;
+               goto fail_map_attr;
+       }
+
+       hermes_io = pci_iomap(pdev, 3, 0);
+       if (!hermes_io) {
+               printk(KERN_ERR PFX "Cannot map chipset registers\n");
+               err = -EIO;
+               goto fail_map_hermes;
+       }
+
+       /* Allocate network device */
+       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                              orinoco_plx_cor_reset, NULL);
+       if (!dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+       card->bridge_io = bridge_io;
+       card->attr_io = attr_io;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
+
+       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+               err = -EBUSY;
+               goto fail_irq;
+       }
+
+       err = orinoco_plx_hw_init(card);
+       if (err) {
+               printk(KERN_ERR PFX "Hardware initialization failed\n");
+               goto fail;
+       }
+
+       err = orinoco_plx_cor_reset(priv);
+       if (err) {
+               printk(KERN_ERR PFX "Initial reset failed\n");
+               goto fail;
+       }
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register network device\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, dev);
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+              pci_name(pdev));
+
+       return 0;
+
+ fail:
+       free_irq(pdev->irq, dev);
+
+ fail_irq:
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+
+ fail_alloc:
+       pci_iounmap(pdev, hermes_io);
+
+ fail_map_hermes:
+       pci_iounmap(pdev, attr_io);
+
+ fail_map_attr:
+       pci_iounmap(pdev, bridge_io);
+
+ fail_map_bridge:
+       pci_release_regions(pdev);
+
+ fail_resources:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pci_card *card = priv->card;
+
+       unregister_netdev(dev);
+       free_irq(pdev->irq, dev);
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+       pci_iounmap(pdev, priv->hw.iobase);
+       pci_iounmap(pdev, card->attr_io);
+       pci_iounmap(pdev, card->bridge_io);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id orinoco_plx_id_table[] = {
+       {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},      /* Siemens SpeedStream SS1023 */
+       {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},      /* Netgear MA301 */
+       {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},      /* Correga  - does this work? */
+       {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},      /* SMC EZConnect SMC2602W,
+                                                          Eumitcom PCI WL11000,
+                                                          Addtron AWA-100 */
+       {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},      /* Global Sun Tech GL24110P */
+       {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},      /* Reported working, but unknown */
+       {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},      /* Linksys WDT11 */
+       {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},      /* USR 2415 */
+       {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},      /* Belkin F5D6000 tested by
+                                                          Brendan W. McAdams <rit AT jacked-in.org> */
+       {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},      /* 3Com AirConnect PCI tested by
+                                                          Damien Persohn <damien AT persohn.net> */
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
+
+static struct pci_driver orinoco_plx_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = orinoco_plx_id_table,
+       .probe          = orinoco_plx_init_one,
+       .remove         = __devexit_p(orinoco_plx_remove_one),
+       .suspend        = orinoco_pci_suspend,
+       .resume         = orinoco_pci_resume,
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Pavel Roskin <proski@gnu.org>,"
+       " David Gibson <hermes@gibson.dropbear.id.au>,"
+       " Daniel Barlow <dan@telent.net>)";
+MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init orinoco_plx_init(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return pci_register_driver(&orinoco_plx_driver);
+}
+
+static void __exit orinoco_plx_exit(void)
+{
+       pci_unregister_driver(&orinoco_plx_driver);
+}
+
+module_init(orinoco_plx_init);
+module_exit(orinoco_plx_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
new file mode 100644 (file)
index 0000000..ede24ec
--- /dev/null
@@ -0,0 +1,248 @@
+/* orinoco_tmd.c
+ *
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a TMD7160. 
+ *
+ * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net>
+ * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ *
+ * The actual driving is done by orinoco.c, this is just resource
+ * allocation stuff.
+ *
+ * This driver is modeled after the orinoco_plx driver. The main
+ * difference is that the TMD chip has only IO port ranges and doesn't
+ * provide access to the PCMCIA attribute space.
+ *
+ * Pheecom sells cards with the TMD chip as "ASIC version"
+ */
+
+#define DRIVER_NAME "orinoco_tmd"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <pcmcia/cisreg.h>
+
+#include "orinoco.h"
+#include "orinoco_pci.h"
+
+#define COR_VALUE      (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
+#define COR_RESET     (0x80)   /* reset bit in the COR register */
+#define TMD_RESET_TIME (500)   /* milliseconds */
+
+/*
+ * Do a soft reset of the card using the Configuration Option Register
+ */
+static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
+{
+       hermes_t *hw = &priv->hw;
+       struct orinoco_pci_card *card = priv->card;
+       unsigned long timeout;
+       u16 reg;
+
+       iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
+       mdelay(1);
+
+       iowrite8(COR_VALUE, card->bridge_io);
+       mdelay(1);
+
+       /* Just in case, wait more until the card is no longer busy */
+       timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
+       reg = hermes_read_regn(hw, CMD);
+       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
+               mdelay(1);
+               reg = hermes_read_regn(hw, CMD);
+       }
+
+       /* Still busy? */
+       if (reg & HERMES_CMD_BUSY) {
+               printk(KERN_ERR PFX "Busy timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+
+static int orinoco_tmd_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       int err;
+       struct orinoco_private *priv;
+       struct orinoco_pci_card *card;
+       struct net_device *dev;
+       void __iomem *hermes_io, *bridge_io;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(pdev, DRIVER_NAME);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
+               goto fail_resources;
+       }
+
+       bridge_io = pci_iomap(pdev, 1, 0);
+       if (!bridge_io) {
+               printk(KERN_ERR PFX "Cannot map bridge registers\n");
+               err = -EIO;
+               goto fail_map_bridge;
+       }
+
+       hermes_io = pci_iomap(pdev, 2, 0);
+       if (!hermes_io) {
+               printk(KERN_ERR PFX "Cannot map chipset registers\n");
+               err = -EIO;
+               goto fail_map_hermes;
+       }
+
+       /* Allocate network device */
+       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
+                              orinoco_tmd_cor_reset, NULL);
+       if (!dev) {
+               printk(KERN_ERR PFX "Cannot allocate network device\n");
+               err = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+       card->bridge_io = bridge_io;
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
+
+       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
+               err = -EBUSY;
+               goto fail_irq;
+       }
+
+       err = orinoco_tmd_cor_reset(priv);
+       if (err) {
+               printk(KERN_ERR PFX "Initial reset failed\n");
+               goto fail;
+       }
+
+       err = register_netdev(dev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register network device\n");
+               goto fail;
+       }
+
+       pci_set_drvdata(pdev, dev);
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
+              pci_name(pdev));
+
+       return 0;
+
+ fail:
+       free_irq(pdev->irq, dev);
+
+ fail_irq:
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+
+ fail_alloc:
+       pci_iounmap(pdev, hermes_io);
+
+ fail_map_hermes:
+       pci_iounmap(pdev, bridge_io);
+
+ fail_map_bridge:
+       pci_release_regions(pdev);
+
+ fail_resources:
+       pci_disable_device(pdev);
+
+       return err;
+}
+
+static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pci_card *card = priv->card;
+
+       unregister_netdev(dev);
+       free_irq(pdev->irq, dev);
+       pci_set_drvdata(pdev, NULL);
+       free_orinocodev(dev);
+       pci_iounmap(pdev, priv->hw.iobase);
+       pci_iounmap(pdev, card->bridge_io);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_device_id orinoco_tmd_id_table[] = {
+       {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,},      /* NDC and OEMs, e.g. pheecom */
+       {0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
+
+static struct pci_driver orinoco_tmd_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = orinoco_tmd_id_table,
+       .probe          = orinoco_tmd_init_one,
+       .remove         = __devexit_p(orinoco_tmd_remove_one),
+       .suspend        = orinoco_pci_suspend,
+       .resume         = orinoco_pci_resume,
+};
+
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Joerg Dorchain <joerg@dorchain.net>)";
+MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
+MODULE_LICENSE("Dual MPL/GPL");
+
+static int __init orinoco_tmd_init(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+       return pci_register_driver(&orinoco_tmd_driver);
+}
+
+static void __exit orinoco_tmd_exit(void)
+{
+       pci_unregister_driver(&orinoco_tmd_driver);
+}
+
+module_init(orinoco_tmd_init);
+module_exit(orinoco_tmd_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
new file mode 100644 (file)
index 0000000..852789a
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
+ * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
+ * Communications and Intel PRO/Wireless 2011B.
+ *
+ * The driver implements Symbol firmware download.  The rest is handled
+ * in hermes.c and orinoco.c.
+ *
+ * Utilities for downloading the Symbol firmware are available at
+ * http://sourceforge.net/projects/orinoco/
+ *
+ * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
+ * Portions based on orinoco_cs.c:
+ *     Copyright (C) David Gibson, Linuxcare Australia
+ * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
+ *     Copyright (C) Symbol Technologies.
+ *
+ * See copyright notice in file orinoco.c.
+ */
+
+#define DRIVER_NAME "spectrum_cs"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "orinoco.h"
+
+/********************************************************************/
+/* Module stuff                                                            */
+/********************************************************************/
+
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
+MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
+MODULE_LICENSE("Dual MPL/GPL");
+
+/* Module parameters */
+
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc; /* = 0 */
+module_param(ignore_cis_vcc, int, 0);
+MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
+
+/********************************************************************/
+/* Data structures                                                 */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
+struct orinoco_pccard {
+       struct pcmcia_device    *p_dev;
+       dev_node_t node;
+};
+
+/********************************************************************/
+/* Function prototypes                                             */
+/********************************************************************/
+
+static int spectrum_cs_config(struct pcmcia_device *link);
+static void spectrum_cs_release(struct pcmcia_device *link);
+
+/* Constants for the CISREG_CCSR register */
+#define HCR_RUN                0x07    /* run firmware after reset */
+#define HCR_IDLE       0x0E    /* don't run firmware after reset */
+#define HCR_MEM16      0x10    /* memory width bit, should be preserved */
+
+
+#define CS_CHECK(fn, ret) \
+  do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/*
+ * Reset the card using configuration registers COR and CCSR.
+ * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
+ */
+static int
+spectrum_reset(struct pcmcia_device *link, int idle)
+{
+       int last_ret, last_fn;
+       conf_reg_t reg;
+       u_int save_cor;
+
+       /* Doing it if hardware is gone is guaranteed crash */
+       if (!pcmcia_dev_present(link))
+               return -ENODEV;
+
+       /* Save original COR value */
+       reg.Function = 0;
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_COR;
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link, &reg));
+       save_cor = reg.Value;
+
+       /* Soft-Reset card */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = (save_cor | COR_SOFT_RESET);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link, &reg));
+       udelay(1000);
+
+       /* Read CCSR */
+       reg.Action = CS_READ;
+       reg.Offset = CISREG_CCSR;
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link, &reg));
+
+       /*
+        * Start or stop the firmware.  Memory width bit should be
+        * preserved from the value we've just read.
+        */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_CCSR;
+       reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link, &reg));
+       udelay(1000);
+
+       /* Restore original COR configuration index */
+       reg.Action = CS_WRITE;
+       reg.Offset = CISREG_COR;
+       reg.Value = (save_cor & ~COR_SOFT_RESET);
+       CS_CHECK(AccessConfigurationRegister,
+                pcmcia_access_configuration_register(link, &reg));
+       udelay(1000);
+       return 0;
+
+      cs_failed:
+       cs_error(link, last_fn, last_ret);
+       return -ENODEV;
+}
+
+/********************************************************************/
+/* Device methods                                                  */
+/********************************************************************/
+
+static int
+spectrum_cs_hard_reset(struct orinoco_private *priv)
+{
+       struct orinoco_pccard *card = priv->card;
+       struct pcmcia_device *link = card->p_dev;
+
+       /* Soft reset using COR and HCR */
+       spectrum_reset(link, 0);
+
+       return 0;
+}
+
+static int
+spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
+{
+       struct orinoco_pccard *card = priv->card;
+       struct pcmcia_device *link = card->p_dev;
+
+       return spectrum_reset(link, idle);
+}
+
+/********************************************************************/
+/* PCMCIA stuff                                                    */
+/********************************************************************/
+
+/*
+ * This 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
+spectrum_cs_probe(struct pcmcia_device *link)
+{
+       struct net_device *dev;
+       struct orinoco_private *priv;
+       struct orinoco_pccard *card;
+
+       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+                              spectrum_cs_hard_reset,
+                              spectrum_cs_stop_firmware);
+       if (! dev)
+               return -ENOMEM;
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       /* Link both structures together */
+       card->p_dev = link;
+       link->priv = dev;
+
+       /* Interrupt setup */
+       link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
+       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+       link->irq.Handler = orinoco_interrupt;
+       link->irq.Instance = dev; 
+
+       /* General socket configuration defaults can go here.  In this
+        * client, we assume very little, and rely on the CIS for
+        * almost everything.  In most clients, many details (i.e.,
+        * number, sizes, and attributes of IO windows) are fixed by
+        * the nature of the device, and can be hard-wired here. */
+       link->conf.Attributes = 0;
+       link->conf.IntType = INT_MEMORY_AND_IO;
+
+       return spectrum_cs_config(link);
+}                              /* spectrum_cs_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 spectrum_cs_detach(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+
+       if (link->dev_node)
+               unregister_netdev(dev);
+
+       spectrum_cs_release(link);
+
+       free_orinocodev(dev);
+}                              /* spectrum_cs_detach */
+
+/*
+ * spectrum_cs_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.
+ */
+
+static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
+                                   cistpl_cftable_entry_t *cfg,
+                                   cistpl_cftable_entry_t *dflt,
+                                   unsigned int vcc,
+                                   void *priv_data)
+{
+       if (cfg->index == 0)
+               goto next_entry;
+
+       /* Use power settings for Vcc and Vpp if present */
+       /* Note that the CIS values need to be rescaled */
+       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
+                       if (!ignore_cis_vcc)
+                               goto next_entry;
+               }
+       }
+
+       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+               p_dev->conf.Vpp =
+                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+       /* Do we need to allocate an interrupt? */
+       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+
+       /* IO window settings */
+       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
+       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+               if (!(io->flags & CISTPL_IO_8BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+               if (!(io->flags & CISTPL_IO_16BIT))
+                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+               p_dev->io.BasePort1 = io->win[0].base;
+               p_dev->io.NumPorts1 = io->win[0].len;
+               if (io->nwin > 1) {
+                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
+                       p_dev->io.BasePort2 = io->win[1].base;
+                       p_dev->io.NumPorts2 = io->win[1].len;
+               }
+
+               /* This reserves IO space but doesn't actually enable it */
+               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
+                       goto next_entry;
+       }
+       return 0;
+
+next_entry:
+       pcmcia_disable_device(p_dev);
+       return -ENODEV;
+};
+
+static int
+spectrum_cs_config(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       struct orinoco_pccard *card = priv->card;
+       hermes_t *hw = &priv->hw;
+       int last_fn, last_ret;
+       void __iomem *mem;
+
+       /*
+        * 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 and accurate CIS.  In practice, a driver usually
+        * "knows" most of these things without consulting the CIS,
+        * and most client drivers will only use the CIS to fill in
+        * implementation-defined details.
+        */
+       last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
+       if (last_ret) {
+               if (!ignore_cis_vcc)
+                       printk(KERN_ERR PFX "GetNextTuple(): No matching "
+                              "CIS configuration.  Maybe you need the "
+                              "ignore_cis_vcc=1 parameter.\n");
+               cs_error(link, RequestIO, last_ret);
+               goto failed;
+       }
+
+       /*
+        * Allocate an interrupt line.  Note that this does not assign
+        * a handler to the interrupt, unless the 'Handler' member of
+        * the irq structure is initialized.
+        */
+       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+
+       /* We initialize the hermes structure before completing PCMCIA
+        * configuration just in case the interrupt handler gets
+        * called. */
+       mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
+       if (!mem)
+               goto cs_failed;
+
+       hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+
+       /*
+        * 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));
+
+       /* Ok, we have the configuration, prepare to register the netdev */
+       dev->base_addr = link->io.BasePort1;
+       dev->irq = link->irq.AssignedIRQ;
+       card->node.major = card->node.minor = 0;
+
+       /* Reset card */
+       if (spectrum_cs_hard_reset(priv) != 0) {
+               goto failed;
+       }
+
+       SET_NETDEV_DEV(dev, &handle_to_dev(link));
+       /* Tell the stack we exist */
+       if (register_netdev(dev) != 0) {
+               printk(KERN_ERR PFX "register_netdev() failed\n");
+               goto failed;
+       }
+
+       /* At this point, the dev_node_t structure(s) needs to be
+        * initialized and arranged in a linked list at link->dev_node. */
+       strcpy(card->node.dev_name, dev->name);
+       link->dev_node = &card->node; /* link->dev_node being non-NULL is also
+                                    used to indicate that the
+                                    net_device has been registered */
+
+       /* Finally, report what we've done */
+       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
+              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
+              link->irq.AssignedIRQ, link->io.BasePort1,
+              link->io.BasePort1 + link->io.NumPorts1 - 1);
+
+       return 0;
+
+ cs_failed:
+       cs_error(link, last_fn, last_ret);
+
+ failed:
+       spectrum_cs_release(link);
+       return -ENODEV;
+}                              /* spectrum_cs_config */
+
+/*
+ * After a card is removed, spectrum_cs_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
+spectrum_cs_release(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       /* We're committed to taking the device away now, so mark the
+        * hardware as unavailable */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw_unavailable++;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       pcmcia_disable_device(link);
+       if (priv->hw.iobase)
+               ioport_unmap(priv->hw.iobase);
+}                              /* spectrum_cs_release */
+
+
+static int
+spectrum_cs_suspend(struct pcmcia_device *link)
+{
+       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);
+
+       err = __orinoco_down(dev);
+       if (err)
+               printk(KERN_WARNING "%s: Error %d downing interface\n",
+                      dev->name, err);
+
+       netif_device_detach(dev);
+       priv->hw_unavailable++;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return err;
+}
+
+static int
+spectrum_cs_resume(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct orinoco_private *priv = netdev_priv(dev);
+
+       netif_device_attach(dev);
+       priv->hw_unavailable--;
+       schedule_work(&priv->reset_work);
+
+       return 0;
+}
+
+
+/********************************************************************/
+/* Module initialization                                           */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+       " (Pavel Roskin <proski@gnu.org>,"
+       " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
+
+static struct pcmcia_device_id spectrum_cs_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
+       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
+       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
+
+static struct pcmcia_driver orinoco_driver = {
+       .owner          = THIS_MODULE,
+       .drv            = {
+               .name   = DRIVER_NAME,
+       },
+       .probe          = spectrum_cs_probe,
+       .remove         = spectrum_cs_detach,
+       .suspend        = spectrum_cs_suspend,
+       .resume         = spectrum_cs_resume,
+       .id_table       = spectrum_cs_ids,
+};
+
+static int __init
+init_spectrum_cs(void)
+{
+       printk(KERN_DEBUG "%s\n", version);
+
+       return pcmcia_register_driver(&orinoco_driver);
+}
+
+static void __exit
+exit_spectrum_cs(void)
+{
+       pcmcia_unregister_driver(&orinoco_driver);
+}
+
+module_init(init_spectrum_cs);
+module_exit(exit_spectrum_cs);
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
deleted file mode 100644 (file)
index 6fcf2bd..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-/* orinoco_cs.c (formerly known as dldwd_cs.c)
- *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
- * It should also be usable on various Prism II based cards such as the
- * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
- * cards such as the 3Com AirConnect and Ericsson WLAN.
- * 
- * Copyright notice & release notes in file orinoco.c
- */
-
-#define DRIVER_NAME "orinoco_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff                                                            */
-/********************************************************************/
-
-MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures                                                 */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
-       struct pcmcia_device    *p_dev;
-       dev_node_t node;
-
-       /* Used to handle hard reset */
-       /* yuck, we need this hack to work around the insanity of the
-         * PCMCIA layer */
-       unsigned long hard_reset_in_progress; 
-};
-
-
-/********************************************************************/
-/* Function prototypes                                             */
-/********************************************************************/
-
-static int orinoco_cs_config(struct pcmcia_device *link);
-static void orinoco_cs_release(struct pcmcia_device *link);
-static void orinoco_cs_detach(struct pcmcia_device *p_dev);
-
-/********************************************************************/
-/* Device methods                                                  */
-/********************************************************************/
-
-static int
-orinoco_cs_hard_reset(struct orinoco_private *priv)
-{
-       struct orinoco_pccard *card = priv->card;
-       struct pcmcia_device *link = card->p_dev;
-       int err;
-
-       /* We need atomic ops here, because we're not holding the lock */
-       set_bit(0, &card->hard_reset_in_progress);
-
-       err = pcmcia_reset_card(link->socket);
-       if (err)
-               return err;
-
-       msleep(100);
-       clear_bit(0, &card->hard_reset_in_progress);
-
-       return 0;
-}
-
-/********************************************************************/
-/* PCMCIA stuff                                                    */
-/********************************************************************/
-
-/*
- * This 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
-orinoco_cs_probe(struct pcmcia_device *link)
-{
-       struct net_device *dev;
-       struct orinoco_private *priv;
-       struct orinoco_pccard *card;
-
-       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
-                              orinoco_cs_hard_reset, NULL);
-       if (! dev)
-               return -ENOMEM;
-       priv = netdev_priv(dev);
-       card = priv->card;
-
-       /* Link both structures together */
-       card->p_dev = link;
-       link->priv = dev;
-
-       /* Interrupt setup */
-       link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
-       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-       link->irq.Handler = orinoco_interrupt;
-       link->irq.Instance = dev; 
-
-       /* General socket configuration defaults can go here.  In this
-        * client, we assume very little, and rely on the CIS for
-        * almost everything.  In most clients, many details (i.e.,
-        * number, sizes, and attributes of IO windows) are fixed by
-        * the nature of the device, and can be hard-wired here. */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
-       return orinoco_cs_config(link);
-}                              /* orinoco_cs_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 orinoco_cs_detach(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-
-       if (link->dev_node)
-               unregister_netdev(dev);
-
-       orinoco_cs_release(link);
-
-       free_orinocodev(dev);
-}                              /* orinoco_cs_detach */
-
-/*
- * orinoco_cs_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) do { \
-               last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \
-       } while (0)
-
-static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
-                                  cistpl_cftable_entry_t *cfg,
-                                  cistpl_cftable_entry_t *dflt,
-                                  unsigned int vcc,
-                                  void *priv_data)
-{
-       if (cfg->index == 0)
-               goto next_entry;
-
-       /* Use power settings for Vcc and Vpp if present */
-       /* Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       }
-
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-               if (!(io->flags & CISTPL_IO_8BIT))
-                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-               if (!(io->flags & CISTPL_IO_16BIT))
-                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->io.BasePort1 = io->win[0].base;
-               p_dev->io.NumPorts1 = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
-                       p_dev->io.BasePort2 = io->win[1].base;
-                       p_dev->io.NumPorts2 = io->win[1].len;
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
-                       goto next_entry;
-       }
-       return 0;
-
-next_entry:
-       pcmcia_disable_device(p_dev);
-       return -ENODEV;
-};
-
-static int
-orinoco_cs_config(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pccard *card = priv->card;
-       hermes_t *hw = &priv->hw;
-       int last_fn, last_ret;
-       void __iomem *mem;
-
-       /*
-        * 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 and accurate CIS.  In practice, a driver usually
-        * "knows" most of these things without consulting the CIS,
-        * and most client drivers will only use the CIS to fill in
-        * implementation-defined details.
-        */
-       last_ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
-       if (last_ret) {
-               if (!ignore_cis_vcc)
-                       printk(KERN_ERR PFX "GetNextTuple(): No matching "
-                              "CIS configuration.  Maybe you need the "
-                              "ignore_cis_vcc=1 parameter.\n");
-               cs_error(link, RequestIO, last_ret);
-               goto failed;
-       }
-
-       /*
-        * Allocate an interrupt line.  Note that this does not assign
-        * a handler to the interrupt, unless the 'Handler' member of
-        * the irq structure is initialized.
-        */
-       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-
-       /* We initialize the hermes structure before completing PCMCIA
-        * configuration just in case the interrupt handler gets
-        * called. */
-       mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
-       if (!mem)
-               goto cs_failed;
-
-       hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
-
-       /*
-        * 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));
-
-       /* Ok, we have the configuration, prepare to register the netdev */
-       dev->base_addr = link->io.BasePort1;
-       dev->irq = link->irq.AssignedIRQ;
-       card->node.major = card->node.minor = 0;
-
-       SET_NETDEV_DEV(dev, &handle_to_dev(link));
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
-               goto failed;
-       }
-
-       /* At this point, the dev_node_t structure(s) needs to be
-        * initialized and arranged in a linked list at link->dev_node. */
-       strcpy(card->node.dev_name, dev->name);
-       link->dev_node = &card->node; /* link->dev_node being non-NULL is also
-                                    used to indicate that the
-                                    net_device has been registered */
-
-       /* Finally, report what we've done */
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
-              link->irq.AssignedIRQ, link->io.BasePort1,
-              link->io.BasePort1 + link->io.NumPorts1 - 1);
-       return 0;
-
- cs_failed:
-       cs_error(link, last_fn, last_ret);
-
- failed:
-       orinoco_cs_release(link);
-       return -ENODEV;
-}                              /* orinoco_cs_config */
-
-/*
- * After a card is removed, orinoco_cs_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
-orinoco_cs_release(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* We're committed to taking the device away now, so mark the
-        * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       pcmcia_disable_device(link);
-       if (priv->hw.iobase)
-               ioport_unmap(priv->hw.iobase);
-}                              /* orinoco_cs_release */
-
-static int orinoco_cs_suspend(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pccard *card = priv->card;
-       int err = 0;
-       unsigned long flags;
-
-       /* This is probably racy, but I can't think of
-          a better way, short of rewriting the PCMCIA
-          layer to not suck :-( */
-       if (! test_bit(0, &card->hard_reset_in_progress)) {
-               spin_lock_irqsave(&priv->lock, flags);
-
-               err = __orinoco_down(dev);
-               if (err)
-                       printk(KERN_WARNING "%s: Error %d downing interface\n",
-                              dev->name, err);
-
-               netif_device_detach(dev);
-               priv->hw_unavailable++;
-
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-
-       return 0;
-}
-
-static int orinoco_cs_resume(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       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);
-               if (err) {
-                       printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
-                              dev->name, err);
-                       return -EIO;
-               }
-
-               spin_lock_irqsave(&priv->lock, flags);
-
-               netif_device_attach(dev);
-               priv->hw_unavailable--;
-
-               if (priv->open && ! priv->hw_unavailable) {
-                       err = __orinoco_up(dev);
-                       if (err)
-                               printk(KERN_ERR "%s: Error %d restarting card\n",
-                                      dev->name, err);
-               }
-
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-
-       return err;
-}
-
-
-/********************************************************************/
-/* Module initialization                                           */
-/********************************************************************/
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (David Gibson <hermes@gibson.dropbear.id.au>, "
-       "Pavel Roskin <proski@gnu.org>, et al)";
-
-static struct pcmcia_device_id orinoco_cs_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
-       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
-       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
-       PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
-       PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
-       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
-       PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
-       PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
-       PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
-       PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
-       PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
-       PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
-       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
-       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
-       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
-       PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
-       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
-       PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
-       PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
-       PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
-       PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
-       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
-       PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
-       PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
-       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
-       PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
-       PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
-       PCMCIA_DEVICE_PROD_ID123("AIRVAST", "IEEE 802.11b Wireless PCMCIA Card", "HFA3863", 0xea569531, 0x4bcb9645, 0x355cb092),
-       PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
-       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
-       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
-       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
-       PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
-       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
-       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
-       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
-       PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
-       PCMCIA_DEVICE_PROD_ID123("corega", "WL PCCL-11", "ISL37300P", 0x0a21501a, 0x59868926, 0xc9049a39),
-       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
-       PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
-       PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
-       PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
-       PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
-       PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
-       PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
-       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
-       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
-       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
-       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
-       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
-       PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
-       PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
-       PCMCIA_DEVICE_PROD_ID123("Intersil", "PRISM Freedom PCMCIA Adapter", "ISL37100P", 0x4b801a17, 0xf222ec2d, 0x630d52b2),
-       PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
-       PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
-       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
-       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
-       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
-       PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
-       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
-       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
-       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
-       PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
-       PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
-       PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
-       PCMCIA_DEVICE_PROD_ID123("PCMCIA", "11M WLAN Card v2.5", "ISL37300P", 0x281f1c5d, 0x6e440487, 0xc9049a39),
-       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
-       PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
-       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
-       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
-       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
-       PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
-       PCMCIA_DEVICE_PROD_ID123("The Linksys Group, Inc.", "Instant Wireless Network PC Card", "ISL37300P", 0xa5f472c2, 0x590eb502, 0xc9049a39),
-       PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
-       .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = DRIVER_NAME,
-       },
-       .probe          = orinoco_cs_probe,
-       .remove         = orinoco_cs_detach,
-       .id_table       = orinoco_cs_ids,
-       .suspend        = orinoco_cs_suspend,
-       .resume         = orinoco_cs_resume,
-};
-
-static int __init
-init_orinoco_cs(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-
-       return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_orinoco_cs(void)
-{
-       pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_orinoco_cs);
-module_exit(exit_orinoco_cs);
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
deleted file mode 100644 (file)
index 2fc8659..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-/* orinoco_nortel.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
- * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
- *
- * Copyright (C) 2002 Tobias Hoffmann
- *           (C) 2003 Christoph Jungegger <disdos@traum404.de>
- *
- * Some of this code is borrowed from orinoco_plx.c
- *     Copyright (C) 2001 Daniel Barlow
- * Some of this code is borrowed from orinoco_pci.c 
- *  Copyright (C) 2001 Jean Tourrilhes
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- *     Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
- * 
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_nortel"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET    (0xe0)   /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA)   /* Enable PC card with interrupt in level trigger */
-
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
-{
-       struct orinoco_pci_card *card = priv->card;
-
-       /* Assert the reset until the card notices */
-       iowrite16(8, card->bridge_io + 2);
-       ioread16(card->attr_io + COR_OFFSET);
-       iowrite16(0x80, card->attr_io + COR_OFFSET);
-       mdelay(1);
-
-       /* Give time for the card to recover from this hard effort */
-       iowrite16(0, card->attr_io + COR_OFFSET);
-       iowrite16(0, card->attr_io + COR_OFFSET);
-       mdelay(1);
-
-       /* Set COR as usual */
-       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
-       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
-       mdelay(1);
-
-       iowrite16(0x228, card->bridge_io + 2);
-
-       return 0;
-}
-
-static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
-{
-       int i;
-       u32 reg;
-
-       /* Setup bridge */
-       if (ioread16(card->bridge_io) & 1) {
-               printk(KERN_ERR PFX "brg1 answer1 wrong\n");
-               return -EBUSY;
-       }
-       iowrite16(0x118, card->bridge_io + 2);
-       iowrite16(0x108, card->bridge_io + 2);
-       mdelay(30);
-       iowrite16(0x8, card->bridge_io + 2);
-       for (i = 0; i < 30; i++) {
-               mdelay(30);
-               if (ioread16(card->bridge_io) & 0x10) {
-                       break;
-               }
-       }
-       if (i == 30) {
-               printk(KERN_ERR PFX "brg1 timed out\n");
-               return -EBUSY;
-       }
-       if (ioread16(card->attr_io + COR_OFFSET) & 1) {
-               printk(KERN_ERR PFX "brg2 answer1 wrong\n");
-               return -EBUSY;
-       }
-       if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
-               printk(KERN_ERR PFX "brg2 answer2 wrong\n");
-               return -EBUSY;
-       }
-       if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
-               printk(KERN_ERR PFX "brg2 answer3 wrong\n");
-               return -EBUSY;
-       }
-
-       /* Set the PCMCIA COR register */
-       iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
-       mdelay(1);
-       reg = ioread16(card->attr_io + COR_OFFSET);
-       if (reg != COR_VALUE) {
-               printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
-                      reg);
-               return -EBUSY;
-       }
-
-       /* Set LEDs */
-       iowrite16(1, card->bridge_io + 10);
-       return 0;
-}
-
-static int orinoco_nortel_init_one(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
-{
-       int err;
-       struct orinoco_private *priv;
-       struct orinoco_pci_card *card;
-       struct net_device *dev;
-       void __iomem *hermes_io, *bridge_io, *attr_io;
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device\n");
-               return err;
-       }
-
-       err = pci_request_regions(pdev, DRIVER_NAME);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
-               goto fail_resources;
-       }
-
-       bridge_io = pci_iomap(pdev, 0, 0);
-       if (!bridge_io) {
-               printk(KERN_ERR PFX "Cannot map bridge registers\n");
-               err = -EIO;
-               goto fail_map_bridge;
-       }
-
-       attr_io = pci_iomap(pdev, 1, 0);
-       if (!attr_io) {
-               printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
-               err = -EIO;
-               goto fail_map_attr;
-       }
-
-       hermes_io = pci_iomap(pdev, 2, 0);
-       if (!hermes_io) {
-               printk(KERN_ERR PFX "Cannot map chipset registers\n");
-               err = -EIO;
-               goto fail_map_hermes;
-       }
-
-       /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_nortel_cor_reset, NULL);
-       if (!dev) {
-               printk(KERN_ERR PFX "Cannot allocate network device\n");
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-
-       priv = netdev_priv(dev);
-       card = priv->card;
-       card->bridge_io = bridge_io;
-       card->attr_io = attr_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
-       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
-               err = -EBUSY;
-               goto fail_irq;
-       }
-
-       err = orinoco_nortel_hw_init(card);
-       if (err) {
-               printk(KERN_ERR PFX "Hardware initialization failed\n");
-               goto fail;
-       }
-
-       err = orinoco_nortel_cor_reset(priv);
-       if (err) {
-               printk(KERN_ERR PFX "Initial reset failed\n");
-               goto fail;
-       }
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
-               goto fail;
-       }
-
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
-
-       return 0;
-
- fail:
-       free_irq(pdev->irq, dev);
-
- fail_irq:
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-
- fail_alloc:
-       pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
-       pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
-       pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
-       pci_release_regions(pdev);
-
- fail_resources:
-       pci_disable_device(pdev);
-
-       return err;
-}
-
-static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pci_card *card = priv->card;
-
-       /* Clear LEDs */
-       iowrite16(0, card->bridge_io + 10);
-
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-       pci_iounmap(pdev, priv->hw.iobase);
-       pci_iounmap(pdev, card->attr_io);
-       pci_iounmap(pdev, card->bridge_io);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-}
-
-static struct pci_device_id orinoco_nortel_id_table[] = {
-       /* Nortel emobility PCI */
-       {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
-       /* Symbol LA-4123 PCI */
-       {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
-       {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
-
-static struct pci_driver orinoco_nortel_driver = {
-       .name           = DRIVER_NAME,
-       .id_table       = orinoco_nortel_id_table,
-       .probe          = orinoco_nortel_init_one,
-       .remove         = __devexit_p(orinoco_nortel_remove_one),
-       .suspend        = orinoco_pci_suspend,
-       .resume         = orinoco_pci_resume,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
-MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
-MODULE_DESCRIPTION
-    ("Driver for wireless LAN cards using the Nortel PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_nortel_init(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-       return pci_register_driver(&orinoco_nortel_driver);
-}
-
-static void __exit orinoco_nortel_exit(void)
-{
-       pci_unregister_driver(&orinoco_nortel_driver);
-}
-
-module_init(orinoco_nortel_init);
-module_exit(orinoco_nortel_exit);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
deleted file mode 100644 (file)
index 4ebd638..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/* orinoco_pci.c
- * 
- * Driver for Prism 2.5/3 devices that have a direct PCI interface
- * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
- * The card contains only one PCI region, which contains all the usual
- * hermes registers, as well as the COR register.
- *
- * Current maintainers are:
- *     Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * Some of this code is borrowed from orinoco_plx.c
- *     Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- *     Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
- * This file originally written by:
- *     Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
- * And is now maintained by:
- *     (C) Copyright David Gibson, IBM Corp. 2002-2003.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_pci"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-/* Offset of the COR register of the PCI card */
-#define HERMES_PCI_COR         (0x26)
-
-/* Bitmask to reset the card */
-#define HERMES_PCI_COR_MASK    (0x0080)
-
-/* Magic timeouts for doing the reset.
- * Those times are straight from wlan-ng, and it is claimed that they
- * are necessary. Alan will kill me. Take your time and grab a coffee. */
-#define HERMES_PCI_COR_ONT     (250)           /* ms */
-#define HERMES_PCI_COR_OFFT    (500)           /* ms */
-#define HERMES_PCI_COR_BUSYT   (500)           /* ms */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note : This code is done with irq enabled. This mean that many
- * interrupts will occur while we are there. This is why we use the
- * jiffies to regulate time instead of a straight mdelay(). Usually we
- * need only around 245 iteration of the loop to do 250 ms delay.
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_pci_cor_reset(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       unsigned long timeout;
-       u16 reg;
-
-       /* Assert the reset until the card notices */
-       hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
-       mdelay(HERMES_PCI_COR_ONT);
-
-       /* Give time for the card to recover from this hard effort */
-       hermes_write_regn(hw, PCI_COR, 0x0000);
-       mdelay(HERMES_PCI_COR_OFFT);
-
-       /* The card is ready when it's no longer busy */
-       timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
-       reg = hermes_read_regn(hw, CMD);
-       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
-               mdelay(1);
-               reg = hermes_read_regn(hw, CMD);
-       }
-
-       /* Still busy? */
-       if (reg & HERMES_CMD_BUSY) {
-               printk(KERN_ERR PFX "Busy timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int orinoco_pci_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       int err;
-       struct orinoco_private *priv;
-       struct orinoco_pci_card *card;
-       struct net_device *dev;
-       void __iomem *hermes_io;
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device\n");
-               return err;
-       }
-
-       err = pci_request_regions(pdev, DRIVER_NAME);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
-               goto fail_resources;
-       }
-
-       hermes_io = pci_iomap(pdev, 0, 0);
-       if (!hermes_io) {
-               printk(KERN_ERR PFX "Cannot remap chipset registers\n");
-               err = -EIO;
-               goto fail_map_hermes;
-       }
-
-       /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_pci_cor_reset, NULL);
-       if (!dev) {
-               printk(KERN_ERR PFX "Cannot allocate network device\n");
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-
-       priv = netdev_priv(dev);
-       card = priv->card;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
-
-       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
-               err = -EBUSY;
-               goto fail_irq;
-       }
-
-       err = orinoco_pci_cor_reset(priv);
-       if (err) {
-               printk(KERN_ERR PFX "Initial reset failed\n");
-               goto fail;
-       }
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
-               goto fail;
-       }
-
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
-
-       return 0;
-
- fail:
-       free_irq(pdev->irq, dev);
-
- fail_irq:
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-
- fail_alloc:
-       pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
-       pci_release_regions(pdev);
-
- fail_resources:
-       pci_disable_device(pdev);
-
-       return err;
-}
-
-static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-       pci_iounmap(pdev, priv->hw.iobase);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-}
-
-static struct pci_device_id orinoco_pci_id_table[] = {
-       /* Intersil Prism 3 */
-       {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
-       /* Intersil Prism 2.5 */
-       {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
-       /* Samsung MagicLAN SWL-2210P */
-       {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
-       {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
-
-static struct pci_driver orinoco_pci_driver = {
-       .name           = DRIVER_NAME,
-       .id_table       = orinoco_pci_id_table,
-       .probe          = orinoco_pci_init_one,
-       .remove         = __devexit_p(orinoco_pci_remove_one),
-       .suspend        = orinoco_pci_suspend,
-       .resume         = orinoco_pci_resume,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Pavel Roskin <proski@gnu.org>,"
-       " David Gibson <hermes@gibson.dropbear.id.au> &"
-       " Jean Tourrilhes <jt@hpl.hp.com>)";
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_pci_init(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-       return pci_register_driver(&orinoco_pci_driver);
-}
-
-static void __exit orinoco_pci_exit(void)
-{
-       pci_unregister_driver(&orinoco_pci_driver);
-}
-
-module_init(orinoco_pci_init);
-module_exit(orinoco_pci_exit);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h
deleted file mode 100644 (file)
index f4e5e06..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* orinoco_pci.h
- * 
- * Common code for all Orinoco drivers for PCI devices, including
- * both native PCI and PCMCIA-to-PCI bridges.
- *
- * Copyright (C) 2005, Pavel Roskin.
- * See orinoco.c for license.
- */
-
-#ifndef _ORINOCO_PCI_H
-#define _ORINOCO_PCI_H
-
-#include <linux/netdevice.h>
-
-/* Driver specific data */
-struct orinoco_pci_card {
-       void __iomem *bridge_io;
-       void __iomem *attr_io;
-};
-
-#ifdef CONFIG_PM
-static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       err = orinoco_lock(priv, &flags);
-       if (err) {
-               printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
-                      dev->name);
-               return err;
-       }
-
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: error %d bringing interface down "
-                      "for suspend\n", dev->name, err);
-       
-       netif_device_detach(dev);
-
-       priv->hw_unavailable++;
-       
-       orinoco_unlock(priv, &flags);
-
-       free_irq(pdev->irq, dev);
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-
-       return 0;
-}
-
-static int orinoco_pci_resume(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err;
-
-       pci_set_power_state(pdev, 0);
-       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,
-                         dev->name, dev);
-       if (err) {
-               printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
-                      dev->name);
-               pci_disable_device(pdev);
-               return -EBUSY;
-       }
-
-       err = orinoco_reinit_firmware(dev);
-       if (err) {
-               printk(KERN_ERR "%s: error %d re-initializing firmware "
-                      "on resume\n", dev->name, err);
-               return err;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       netif_device_attach(dev);
-
-       priv->hw_unavailable--;
-
-       if (priv->open && (! priv->hw_unavailable)) {
-               err = __orinoco_up(dev);
-               if (err)
-                       printk(KERN_ERR "%s: Error %d restarting card on resume\n",
-                              dev->name, err);
-       }
-       
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       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
deleted file mode 100644 (file)
index ef76185..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-/* orinoco_plx.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PLX9052.
- *
- * Current maintainers are:
- *     Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- * Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * Here's the general details on how the PLX9052 adapter works:
- *
- * - Two PCI I/O address spaces, one 0x80 long which contains the
- * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
- * slot I/O address space.
- *
- * - One PCI memory address space, mapped to the PCMCIA attribute space
- * (containing the CIS).
- *
- * Using the later, you can read through the CIS data to make sure the
- * card is compatible with the driver. Keep in mind that the PCMCIA
- * spec specifies the CIS as the lower 8 bits of each word read from
- * the CIS, so to read the bytes of the CIS, read every other byte
- * (0,2,4,...). Passing that test, you need to enable the I/O address
- * space on the PCMCIA card via the PCMCIA COR register. This is the
- * first byte following the CIS. In my case (which may not have any
- * relation to what's on the PRISM2 cards), COR was at offset 0x800
- * within the PCI memory space. Write 0x41 to the COR register to
- * enable I/O mode and to select level triggered interrupts. To
- * confirm you actually succeeded, read the COR register back and make
- * sure it actually got set to 0x41, in case you have an unexpected
- * card inserted.
- *
- * Following that, you can treat the second PCI I/O address space (the
- * one that's not 0x80 in length) as the PCMCIA I/O space.
- *
- * Note that in the Eumitcom's source for their drivers, they register
- * the interrupt as edge triggered when registering it with the
- * Windows kernel. I don't recall how to register edge triggered on
- * Linux (if it can be done at all). But in some experimentation, I
- * don't see much operational difference between using either
- * interrupt mode. Don't mess with the interrupt mode in the COR
- * register though, as the PLX9052 wants level triggers with the way
- * the serial EEPROM configures it on the WL11000.
- *
- * There's some other little quirks related to timing that I bumped
- * into, but I don't recall right now. Also, there's two variants of
- * the WL11000 I've seen, revision A1 and T2. These seem to differ
- * slightly in the timings configured in the wait-state generator in
- * the PLX9052. There have also been some comments from Eumitcom that
- * cards shouldn't be hot swapped, apparently due to risk of cooking
- * the PLX9052. I'm unsure why they believe this, as I can't see
- * anything in the design that would really cause a problem, except
- * for crashing drivers not written to expect it. And having developed
- * drivers for the WL11000, I'd say it's quite tricky to write code
- * that will successfully deal with a hot unplug. Very odd things
- * happen on the I/O side of things. But anyway, be warned. Despite
- * that, I've hot-swapped a number of times during debugging and
- * driver development for various reasons (stuck WAIT# line after the
- * radio card's firmware locks up).
- */
-
-#define DRIVER_NAME "orinoco_plx"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET     (0x3e0) /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE      (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET     (0x80)   /* reset bit in the COR register */
-#define PLX_RESET_TIME (500)   /* milliseconds */
-
-#define PLX_INTCSR             0x4c /* Interrupt Control & Status Register */
-#define PLX_INTCSR_INTEN       (1<<6) /* Interrupt Enable bit */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_plx_cor_reset(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       struct orinoco_pci_card *card = priv->card;
-       unsigned long timeout;
-       u16 reg;
-
-       iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
-       mdelay(1);
-
-       iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
-       mdelay(1);
-
-       /* Just in case, wait more until the card is no longer busy */
-       timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
-       reg = hermes_read_regn(hw, CMD);
-       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
-               mdelay(1);
-               reg = hermes_read_regn(hw, CMD);
-       }
-
-       /* Still busy? */
-       if (reg & HERMES_CMD_BUSY) {
-               printk(KERN_ERR PFX "Busy timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
-{
-       int i;
-       u32 csr_reg;
-       static const u8 cis_magic[] = {
-               0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
-       };
-
-       printk(KERN_DEBUG PFX "CIS: ");
-       for (i = 0; i < 16; i++) {
-               printk("%02X:", ioread8(card->attr_io + (i << 1)));
-       }
-       printk("\n");
-
-       /* Verify whether a supported PC card is present */
-       /* FIXME: we probably need to be smarted about this */
-       for (i = 0; i < sizeof(cis_magic); i++) {
-               if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
-                       printk(KERN_ERR PFX "The CIS value of Prism2 PC "
-                              "card is unexpected\n");
-                       return -ENODEV;
-               }
-       }
-
-       /* bjoern: We need to tell the card to enable interrupts, in
-          case the serial eprom didn't do this already.  See the
-          PLX9052 data book, p8-1 and 8-24 for reference. */
-       csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
-       if (!(csr_reg & PLX_INTCSR_INTEN)) {
-               csr_reg |= PLX_INTCSR_INTEN;
-               iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
-               csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
-               if (!(csr_reg & PLX_INTCSR_INTEN)) {
-                       printk(KERN_ERR PFX "Cannot enable interrupts\n");
-                       return -EIO;
-               }
-       }
-
-       return 0;
-}
-
-static int orinoco_plx_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       int err;
-       struct orinoco_private *priv;
-       struct orinoco_pci_card *card;
-       struct net_device *dev;
-       void __iomem *hermes_io, *attr_io, *bridge_io;
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device\n");
-               return err;
-       }
-
-       err = pci_request_regions(pdev, DRIVER_NAME);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
-               goto fail_resources;
-       }
-
-       bridge_io = pci_iomap(pdev, 1, 0);
-       if (!bridge_io) {
-               printk(KERN_ERR PFX "Cannot map bridge registers\n");
-               err = -EIO;
-               goto fail_map_bridge;
-       }
-
-       attr_io = pci_iomap(pdev, 2, 0);
-       if (!attr_io) {
-               printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
-               err = -EIO;
-               goto fail_map_attr;
-       }
-
-       hermes_io = pci_iomap(pdev, 3, 0);
-       if (!hermes_io) {
-               printk(KERN_ERR PFX "Cannot map chipset registers\n");
-               err = -EIO;
-               goto fail_map_hermes;
-       }
-
-       /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_plx_cor_reset, NULL);
-       if (!dev) {
-               printk(KERN_ERR PFX "Cannot allocate network device\n");
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-
-       priv = netdev_priv(dev);
-       card = priv->card;
-       card->bridge_io = bridge_io;
-       card->attr_io = attr_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
-       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
-               err = -EBUSY;
-               goto fail_irq;
-       }
-
-       err = orinoco_plx_hw_init(card);
-       if (err) {
-               printk(KERN_ERR PFX "Hardware initialization failed\n");
-               goto fail;
-       }
-
-       err = orinoco_plx_cor_reset(priv);
-       if (err) {
-               printk(KERN_ERR PFX "Initial reset failed\n");
-               goto fail;
-       }
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
-               goto fail;
-       }
-
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
-
-       return 0;
-
- fail:
-       free_irq(pdev->irq, dev);
-
- fail_irq:
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-
- fail_alloc:
-       pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
-       pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
-       pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
-       pci_release_regions(pdev);
-
- fail_resources:
-       pci_disable_device(pdev);
-
-       return err;
-}
-
-static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pci_card *card = priv->card;
-
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-       pci_iounmap(pdev, priv->hw.iobase);
-       pci_iounmap(pdev, card->attr_io);
-       pci_iounmap(pdev, card->bridge_io);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-}
-
-static struct pci_device_id orinoco_plx_id_table[] = {
-       {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},      /* Siemens SpeedStream SS1023 */
-       {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},      /* Netgear MA301 */
-       {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},      /* Correga  - does this work? */
-       {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},      /* SMC EZConnect SMC2602W,
-                                                          Eumitcom PCI WL11000,
-                                                          Addtron AWA-100 */
-       {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},      /* Global Sun Tech GL24110P */
-       {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},      /* Reported working, but unknown */
-       {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},      /* Linksys WDT11 */
-       {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},      /* USR 2415 */
-       {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},      /* Belkin F5D6000 tested by
-                                                          Brendan W. McAdams <rit AT jacked-in.org> */
-       {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},      /* 3Com AirConnect PCI tested by
-                                                          Damien Persohn <damien AT persohn.net> */
-       {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
-
-static struct pci_driver orinoco_plx_driver = {
-       .name           = DRIVER_NAME,
-       .id_table       = orinoco_plx_id_table,
-       .probe          = orinoco_plx_init_one,
-       .remove         = __devexit_p(orinoco_plx_remove_one),
-       .suspend        = orinoco_pci_suspend,
-       .resume         = orinoco_pci_resume,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Pavel Roskin <proski@gnu.org>,"
-       " David Gibson <hermes@gibson.dropbear.id.au>,"
-       " Daniel Barlow <dan@telent.net>)";
-MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_plx_init(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-       return pci_register_driver(&orinoco_plx_driver);
-}
-
-static void __exit orinoco_plx_exit(void)
-{
-       pci_unregister_driver(&orinoco_plx_driver);
-}
-
-module_init(orinoco_plx_init);
-module_exit(orinoco_plx_exit);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
deleted file mode 100644 (file)
index ede24ec..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/* orinoco_tmd.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a TMD7160. 
- *
- * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net>
- * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above.  If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL.  If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * The actual driving is done by orinoco.c, this is just resource
- * allocation stuff.
- *
- * This driver is modeled after the orinoco_plx driver. The main
- * difference is that the TMD chip has only IO port ranges and doesn't
- * provide access to the PCMCIA attribute space.
- *
- * Pheecom sells cards with the TMD chip as "ASIC version"
- */
-
-#define DRIVER_NAME "orinoco_tmd"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_VALUE      (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET     (0x80)   /* reset bit in the COR register */
-#define TMD_RESET_TIME (500)   /* milliseconds */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
-{
-       hermes_t *hw = &priv->hw;
-       struct orinoco_pci_card *card = priv->card;
-       unsigned long timeout;
-       u16 reg;
-
-       iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
-       mdelay(1);
-
-       iowrite8(COR_VALUE, card->bridge_io);
-       mdelay(1);
-
-       /* Just in case, wait more until the card is no longer busy */
-       timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
-       reg = hermes_read_regn(hw, CMD);
-       while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
-               mdelay(1);
-               reg = hermes_read_regn(hw, CMD);
-       }
-
-       /* Still busy? */
-       if (reg & HERMES_CMD_BUSY) {
-               printk(KERN_ERR PFX "Busy timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-
-static int orinoco_tmd_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
-{
-       int err;
-       struct orinoco_private *priv;
-       struct orinoco_pci_card *card;
-       struct net_device *dev;
-       void __iomem *hermes_io, *bridge_io;
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device\n");
-               return err;
-       }
-
-       err = pci_request_regions(pdev, DRIVER_NAME);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
-               goto fail_resources;
-       }
-
-       bridge_io = pci_iomap(pdev, 1, 0);
-       if (!bridge_io) {
-               printk(KERN_ERR PFX "Cannot map bridge registers\n");
-               err = -EIO;
-               goto fail_map_bridge;
-       }
-
-       hermes_io = pci_iomap(pdev, 2, 0);
-       if (!hermes_io) {
-               printk(KERN_ERR PFX "Cannot map chipset registers\n");
-               err = -EIO;
-               goto fail_map_hermes;
-       }
-
-       /* Allocate network device */
-       dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
-                              orinoco_tmd_cor_reset, NULL);
-       if (!dev) {
-               printk(KERN_ERR PFX "Cannot allocate network device\n");
-               err = -ENOMEM;
-               goto fail_alloc;
-       }
-
-       priv = netdev_priv(dev);
-       card = priv->card;
-       card->bridge_io = bridge_io;
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
-       err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
-               err = -EBUSY;
-               goto fail_irq;
-       }
-
-       err = orinoco_tmd_cor_reset(priv);
-       if (err) {
-               printk(KERN_ERR PFX "Initial reset failed\n");
-               goto fail;
-       }
-
-       err = register_netdev(dev);
-       if (err) {
-               printk(KERN_ERR PFX "Cannot register network device\n");
-               goto fail;
-       }
-
-       pci_set_drvdata(pdev, dev);
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
-              pci_name(pdev));
-
-       return 0;
-
- fail:
-       free_irq(pdev->irq, dev);
-
- fail_irq:
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-
- fail_alloc:
-       pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
-       pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
-       pci_release_regions(pdev);
-
- fail_resources:
-       pci_disable_device(pdev);
-
-       return err;
-}
-
-static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pci_card *card = priv->card;
-
-       unregister_netdev(dev);
-       free_irq(pdev->irq, dev);
-       pci_set_drvdata(pdev, NULL);
-       free_orinocodev(dev);
-       pci_iounmap(pdev, priv->hw.iobase);
-       pci_iounmap(pdev, card->bridge_io);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-}
-
-static struct pci_device_id orinoco_tmd_id_table[] = {
-       {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,},      /* NDC and OEMs, e.g. pheecom */
-       {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
-
-static struct pci_driver orinoco_tmd_driver = {
-       .name           = DRIVER_NAME,
-       .id_table       = orinoco_tmd_id_table,
-       .probe          = orinoco_tmd_init_one,
-       .remove         = __devexit_p(orinoco_tmd_remove_one),
-       .suspend        = orinoco_pci_suspend,
-       .resume         = orinoco_pci_resume,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Joerg Dorchain <joerg@dorchain.net>)";
-MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_tmd_init(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-       return pci_register_driver(&orinoco_tmd_driver);
-}
-
-static void __exit orinoco_tmd_exit(void)
-{
-       pci_unregister_driver(&orinoco_tmd_driver);
-}
-
-module_init(orinoco_tmd_init);
-module_exit(orinoco_tmd_exit);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- *  tab-width: 8
- * End:
- */
index eb69b904f651dd987c21b02b7fef68edbd30707d..b585ff65e0e42ec4957746cedd61ed1e6e95202e 100644 (file)
@@ -108,6 +108,7 @@ struct p54_common {
        struct timer_list stats_timer;
        struct completion stats_comp;
        struct sk_buff *cached_stats;
+       struct sk_buff *cached_beacon;
        int noise;
        void *eeprom;
        struct completion eeprom_comp;
index cf04c721a0123ce23cae6fec61851658edd43a56..1796b8c6c5b83111d8e2e526e080846ed0db05ee 100644 (file)
@@ -9,7 +9,7 @@
  * - the islsm (softmac prism54) driver, which is:
  *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
  * - stlc45xx driver
- * C\ 2  Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
  *
  * 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
@@ -214,12 +214,17 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
                printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
                        fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
 
+       if (priv->fw_var < 0x500)
+               printk(KERN_INFO "p54: you are using an obsolete firmware. "
+                      "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+                      "and grab one for \"kernel >= 2.6.28\"!\n");
+
        if (priv->fw_var >= 0x300) {
                /* Firmware supports QoS, use it! */
-               priv->tx_stats[4].limit = 3;
-               priv->tx_stats[5].limit = 4;
-               priv->tx_stats[6].limit = 3;
-               priv->tx_stats[7].limit = 1;
+               priv->tx_stats[4].limit = 3;            /* AC_VO */
+               priv->tx_stats[5].limit = 4;            /* AC_VI */
+               priv->tx_stats[6].limit = 3;            /* AC_BE */
+               priv->tx_stats[7].limit = 2;            /* AC_BK */
                dev->queues = 4;
        }
 
@@ -415,6 +420,30 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                        /* make it overrun */
                        entry_len = len;
                        break;
+               case PDR_MANUFACTURING_PART_NUMBER:
+               case PDR_PDA_VERSION:
+               case PDR_NIC_SERIAL_NUMBER:
+               case PDR_REGULATORY_DOMAIN_LIST:
+               case PDR_TEMPERATURE_TYPE:
+               case PDR_PRISM_PCI_IDENTIFIER:
+               case PDR_COUNTRY_INFORMATION:
+               case PDR_OEM_NAME:
+               case PDR_PRODUCT_NAME:
+               case PDR_UTF8_OEM_NAME:
+               case PDR_UTF8_PRODUCT_NAME:
+               case PDR_COUNTRY_LIST:
+               case PDR_DEFAULT_COUNTRY:
+               case PDR_ANTENNA_GAIN:
+               case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
+               case PDR_RSSI_LINEAR_APPROXIMATION:
+               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+               case PDR_REGULATORY_POWER_LIMITS:
+               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+               case PDR_RADIATED_TRANSMISSION_CORRECTION:
+               case PDR_PRISM_TX_IQ_CALIBRATION:
+               case PDR_BASEBAND_REGISTERS:
+               case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
+                       break;
                default:
                        printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n",
                                le16_to_cpu(entry->code));
@@ -431,12 +460,12 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
                goto err;
        }
 
-       priv->rxhw = synth & 0x07;
+       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
        if (priv->rxhw == 4)
                p54_init_xbow_synth(dev);
-       if (!(synth & 0x40))
+       if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
                dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
-       if (!(synth & 0x80))
+       if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
                dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
 
        if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
@@ -621,6 +650,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                __skb_unlink(entry, &priv->tx_queue);
                spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
+               if (unlikely(entry == priv->cached_beacon)) {
+                       kfree_skb(entry);
+                       priv->cached_beacon = NULL;
+                       goto out;
+               }
+
                /*
                 * Clear manually, ieee80211_tx_info_clear_status would
                 * clear the counts too and we need them.
@@ -654,7 +689,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
                     (!payload->status))
                        info->flags |= IEEE80211_TX_STAT_ACK;
-               if (payload->status & 0x02)
+               if (payload->status & P54_TX_PSM_CANCELLED)
                        info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                info->status.ack_signal = p54_rssi_to_dbm(dev,
                                (int)payload->ack_rssi);
@@ -706,6 +741,35 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
        mod_timer(&priv->stats_timer, jiffies + 5 * HZ);
 }
 
+static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_trap *trap = (struct p54_trap *) hdr->data;
+       u16 event = le16_to_cpu(trap->event);
+       u16 freq = le16_to_cpu(trap->frequency);
+
+       switch (event) {
+       case P54_TRAP_BEACON_TX:
+               break;
+       case P54_TRAP_RADAR:
+               printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+                       wiphy_name(dev->wiphy), freq);
+               break;
+       case P54_TRAP_NO_BEACON:
+               break;
+       case P54_TRAP_SCAN:
+               break;
+       case P54_TRAP_TBTT:
+               break;
+       case P54_TRAP_TIMER:
+               break;
+       default:
+               printk(KERN_INFO "%s: received event:%x freq:%d\n",
+                      wiphy_name(dev->wiphy), event, freq);
+               break;
+       }
+}
+
 static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
@@ -714,6 +778,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
        case P54_CONTROL_TYPE_TXDONE:
                p54_rx_frame_sent(dev, skb);
                break;
+       case P54_CONTROL_TYPE_TRAP:
+               p54_rx_trap(dev, skb);
+               break;
        case P54_CONTROL_TYPE_BBP:
                break;
        case P54_CONTROL_TYPE_STAT_READBACK:
@@ -734,9 +801,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
 /* returns zero if skb can be reused */
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
-       u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+       u16 type = le16_to_cpu(*((__le16 *)skb->data));
 
-       if (type == 0x80)
+       if (type & P54_HDR_FLAG_CONTROL)
                return p54_rx_control(dev, skb);
        else
                return p54_rx_data(dev, skb);
@@ -897,41 +964,162 @@ free:
 }
 EXPORT_SYMBOL_GPL(p54_read_eeprom);
 
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+               bool set)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *skb;
+       struct p54_tim *tim;
+
+       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+                     sizeof(struct p54_hdr) + sizeof(*tim),
+                     P54_CONTROL_TYPE_TIM, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+       tim->count = 1;
+       tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
+       priv->tx(dev, skb, 1);
+       return 0;
+}
+
+static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *skb;
+       struct p54_sta_unlock *sta;
+
+       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+               sizeof(struct p54_hdr) + sizeof(*sta),
+               P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+       memcpy(sta->addr, addr, ETH_ALEN);
+       priv->tx(dev, skb, 1);
+       return 0;
+}
+
+static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *skb;
+       struct p54_hdr *hdr;
+       struct p54_txcancel *cancel;
+
+       skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET,
+               sizeof(struct p54_hdr) + sizeof(*cancel),
+               P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       hdr = (void *)entry->data;
+       cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+       cancel->req_id = hdr->req_id;
+       priv->tx(dev, skb, 1);
+       return 0;
+}
+
+static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
+               struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
+               u16 *flags, u16 *aid)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct p54_common *priv = dev->priv;
+       int ret = 0;
+
+       if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+               if (ieee80211_is_beacon(hdr->frame_control)) {
+                       *aid = 0;
+                       *queue = 0;
+                       *extra_len = IEEE80211_MAX_TIM_LEN;
+                       *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+                       return 0;
+               } else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+                       *aid = 0;
+                       *queue = 2;
+                       *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+                                P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+                       return 0;
+               } else {
+                       *queue = 2;
+                       ret = 0;
+               }
+       } else {
+               *queue += 4;
+               ret = 1;
+       }
+
+       switch (priv->mode) {
+       case NL80211_IFTYPE_STATION:
+               *aid = 1;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+               if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+                       *aid = 0;
+                       *queue = 3;
+                       return 0;
+               }
+               if (info->control.sta)
+                       *aid = info->control.sta->aid;
+               else
+                       *flags = P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+       }
+       return ret;
+}
+
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_tx_queue_stats *current_queue;
+       struct ieee80211_tx_queue_stats *current_queue = NULL;
        struct p54_common *priv = dev->priv;
        struct p54_hdr *hdr;
        struct p54_tx_data *txhdr;
-       size_t padding, len;
+       size_t padding, len, tim_len = 0;
        int i, j, ridx;
-       u8 rate;
+       u16 hdr_flags = 0, aid = 0;
+       u8 rate, queue;
        u8 cts_rate = 0x20;
        u8 rc_flags;
        u8 calculated_tries[4];
        u8 nrates = 0, nremaining = 8;
 
-       current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
-       if (unlikely(current_queue->len > current_queue->limit))
-               return NETDEV_TX_BUSY;
-       current_queue->len++;
-       current_queue->count++;
-       if (current_queue->len == current_queue->limit)
-               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+       queue = skb_get_queue_mapping(skb);
+
+       if (p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid)) {
+               current_queue = &priv->tx_stats[queue];
+               if (unlikely(current_queue->len > current_queue->limit))
+                       return NETDEV_TX_BUSY;
+               current_queue->len++;
+               current_queue->count++;
+               if (current_queue->len == current_queue->limit)
+                       ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+       }
 
        padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
        len = skb->len;
 
+       if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) {
+               if (info->control.sta)
+                       if (p54_sta_unlock(dev, info->control.sta->addr)) {
+                               if (current_queue) {
+                                       current_queue->len--;
+                                       current_queue->count--;
+                               }
+                               return NETDEV_TX_BUSY;
+                       }
+       }
+
        txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
        hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
 
        if (padding)
-               hdr->flags = cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN);
-       else
-               hdr->flags = cpu_to_le16(0);
+               hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
        hdr->len = cpu_to_le16(len);
-       hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+       hdr->type = cpu_to_le16(aid);
        hdr->rts_tries = info->control.rates[0].count;
 
        /*
@@ -998,12 +1186,18 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                        ridx++;
                }
        }
+
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+               hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+       /* TODO: enable bursting */
+       hdr->flags = cpu_to_le16(hdr_flags);
        hdr->tries = ridx;
        txhdr->crypt_offset = 0;
        txhdr->rts_rate_idx = 0;
        txhdr->key_type = 0;
        txhdr->key_len = 0;
-       txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+       txhdr->hw_queue = queue;
        txhdr->backlog = 32;
        memset(txhdr->durations, 0, sizeof(txhdr->durations));
        txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
@@ -1014,8 +1208,12 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
                txhdr->align[0] = padding;
 
        /* modifies skb->cb and with it info, so must be last! */
-       if (unlikely(p54_assign_address(dev, skb, hdr, skb->len))) {
+       if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) {
                skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
+               if (current_queue) {
+                       current_queue->len--;
+                       current_queue->count--;
+               }
                return NETDEV_TX_BUSY;
        }
        priv->tx(dev, skb, 0);
@@ -1043,8 +1241,10 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
        else
                memcpy(setup->bssid, bssid, ETH_ALEN);
        setup->rx_antenna = priv->rx_antenna;
+       setup->rx_align = 0;
        if (priv->fw_var < 0x500) {
                setup->v1.basic_rate_mask = cpu_to_le32(0x15f);
+               memset(setup->v1.rts_rates, 0, 8);
                setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
                setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
                setup->v1.rxhw = cpu_to_le16(priv->rxhw);
@@ -1069,13 +1269,14 @@ static int p54_setup_mac(struct ieee80211_hw *dev, u16 mode, const u8 *bssid)
        return 0;
 }
 
-static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+static int p54_set_freq(struct ieee80211_hw *dev, u16 frequency)
 {
        struct p54_common *priv = dev->priv;
        struct sk_buff *skb;
        struct p54_scan *chan;
        unsigned int i;
        void *entry;
+       __le16 freq = cpu_to_le16(frequency);
 
        skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) +
                            sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN,
@@ -1127,11 +1328,11 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
                }
 
                entry += sizeof(__le16);
-               chan->pa_points_per_curve =
-                       min(priv->curve_data->points_per_channel, (u8) 8);
-
-               memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
-                      chan->pa_points_per_curve);
+               chan->pa_points_per_curve = 8;
+               memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+               memcpy(chan->curve_data, entry,
+                      sizeof(struct p54_pa_curve_data_sample) *
+                      min((u8)8, priv->curve_data->points_per_channel));
                break;
        }
 
@@ -1207,6 +1408,7 @@ static int p54_set_edcf(struct ieee80211_hw *dev)
        /* (see prism54/isl_oid.h for further details) */
        edcf->frameburst = cpu_to_le16(0);
        edcf->round_trip_delay = cpu_to_le16(0);
+       edcf->flags = 0;
        memset(edcf->mapping, 0, sizeof(edcf->mapping));
        memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
        priv->tx(dev, skb, 1);
@@ -1227,11 +1429,94 @@ static int p54_init_stats(struct ieee80211_hw *dev)
        return 0;
 }
 
+static int p54_beacon_tim(struct sk_buff *skb)
+{
+       /*
+        * the good excuse for this mess is ... the firmware.
+        * The dummy TIM MUST be at the end of the beacon frame,
+        * because it'll be overwritten!
+        */
+
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       u8 *pos, *end;
+
+       if (skb->len <= sizeof(mgmt)) {
+               printk(KERN_ERR "p54: beacon is too short!\n");
+               return -EINVAL;
+       }
+
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = skb->data + skb->len;
+       while (pos < end) {
+               if (pos + 2 + pos[1] > end) {
+                       printk(KERN_ERR "p54: parsing beacon failed\n");
+                       return -EINVAL;
+               }
+
+               if (pos[0] == WLAN_EID_TIM) {
+                       u8 dtim_len = pos[1];
+                       u8 dtim_period = pos[3];
+                       u8 *next = pos + 2 + dtim_len;
+
+                       if (dtim_len < 3) {
+                               printk(KERN_ERR "p54: invalid dtim len!\n");
+                               return -EINVAL;
+                       }
+                       memmove(pos, next, end - next);
+
+                       if (dtim_len > 3)
+                               skb_trim(skb, skb->len - (dtim_len - 3));
+
+                       pos = end - (dtim_len + 2);
+
+                       /* add the dummy at the end */
+                       pos[0] = WLAN_EID_TIM;
+                       pos[1] = 3;
+                       pos[2] = 0;
+                       pos[3] = dtim_period;
+                       pos[4] = 0;
+                       return 0;
+               }
+               pos += 2 + pos[1];
+       }
+       return 0;
+}
+
+static int p54_beacon_update(struct ieee80211_hw *dev,
+                       struct ieee80211_vif *vif)
+{
+       struct p54_common *priv = dev->priv;
+       struct sk_buff *beacon;
+       int ret;
+
+       if (priv->cached_beacon) {
+               p54_tx_cancel(dev, priv->cached_beacon);
+               /* wait for the last beacon the be freed */
+               msleep(10);
+       }
+
+       beacon = ieee80211_beacon_get(dev, vif);
+       if (!beacon)
+               return -ENOMEM;
+       ret = p54_beacon_tim(beacon);
+       if (ret)
+               return ret;
+       ret = p54_tx(dev, beacon);
+       if (ret)
+               return ret;
+       priv->cached_beacon = beacon;
+       priv->tsf_high32 = 0;
+       priv->tsf_low32 = 0;
+
+       return 0;
+}
+
 static int p54_start(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
        int err;
 
+       mutex_lock(&priv->conf_mutex);
        err = priv->open(dev);
        if (!err)
                priv->mode = NL80211_IFTYPE_MONITOR;
@@ -1243,6 +1528,7 @@ static int p54_start(struct ieee80211_hw *dev)
        if (!err)
                err = p54_init_stats(dev);
 
+       mutex_unlock(&priv->conf_mutex);
        return err;
 }
 
@@ -1251,15 +1537,22 @@ static void p54_stop(struct ieee80211_hw *dev)
        struct p54_common *priv = dev->priv;
        struct sk_buff *skb;
 
+       mutex_lock(&priv->conf_mutex);
        del_timer(&priv->stats_timer);
        p54_free_skb(dev, priv->cached_stats);
        priv->cached_stats = NULL;
+       if (priv->cached_beacon)
+               p54_tx_cancel(dev, priv->cached_beacon);
+
        while ((skb = skb_dequeue(&priv->tx_queue)))
                kfree_skb(skb);
 
+       kfree(priv->cached_beacon);
+       priv->cached_beacon = NULL;
        priv->stop(dev);
        priv->tsf_high32 = priv->tsf_low32 = 0;
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_add_interface(struct ieee80211_hw *dev,
@@ -1267,14 +1560,20 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 {
        struct p54_common *priv = dev->priv;
 
-       if (priv->mode != NL80211_IFTYPE_MONITOR)
+       mutex_lock(&priv->conf_mutex);
+       if (priv->mode != NL80211_IFTYPE_MONITOR) {
+               mutex_unlock(&priv->conf_mutex);
                return -EOPNOTSUPP;
+       }
 
        switch (conf->type) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP:
                priv->mode = conf->type;
                break;
        default:
+               mutex_unlock(&priv->conf_mutex);
                return -EOPNOTSUPP;
        }
 
@@ -1286,6 +1585,12 @@ static int p54_add_interface(struct ieee80211_hw *dev,
        case NL80211_IFTYPE_STATION:
                p54_setup_mac(dev, P54_FILTER_TYPE_STATION, NULL);
                break;
+       case NL80211_IFTYPE_AP:
+               p54_setup_mac(dev, P54_FILTER_TYPE_AP, priv->mac_addr);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               p54_setup_mac(dev, P54_FILTER_TYPE_IBSS, NULL);
+               break;
        default:
                BUG();  /* impossible */
                break;
@@ -1293,6 +1598,7 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 
        p54_set_leds(dev, 1, 0, 0);
 
+       mutex_unlock(&priv->conf_mutex);
        return 0;
 }
 
@@ -1300,9 +1606,14 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_if_init_conf *conf)
 {
        struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       if (priv->cached_beacon)
+               p54_tx_cancel(dev, priv->cached_beacon);
+       p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
        priv->mode = NL80211_IFTYPE_MONITOR;
        memset(priv->mac_addr, 0, ETH_ALEN);
-       p54_setup_mac(dev, P54_FILTER_TYPE_NONE, NULL);
+       mutex_unlock(&priv->conf_mutex);
 }
 
 static int p54_config(struct ieee80211_hw *dev, u32 changed)
@@ -1314,7 +1625,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
        mutex_lock(&priv->conf_mutex);
        priv->rx_antenna = 2; /* automatic */
        priv->output_power = conf->power_level << 2;
-       ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
+       ret = p54_set_freq(dev, conf->channel->center_freq);
        if (!ret)
                ret = p54_set_edcf(dev);
        mutex_unlock(&priv->conf_mutex);
@@ -1326,13 +1637,41 @@ static int p54_config_interface(struct ieee80211_hw *dev,
                                struct ieee80211_if_conf *conf)
 {
        struct p54_common *priv = dev->priv;
+       int ret = 0;
 
        mutex_lock(&priv->conf_mutex);
-       p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid);
-       p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
-       memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+       switch (priv->mode) {
+       case NL80211_IFTYPE_STATION:
+               ret = p54_setup_mac(dev, P54_FILTER_TYPE_STATION, conf->bssid);
+               if (ret)
+                       goto out;
+               ret = p54_set_leds(dev, 1,
+                                  !is_multicast_ether_addr(conf->bssid), 0);
+               if (ret)
+                       goto out;
+               memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+               memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+               ret = p54_set_freq(dev, dev->conf.channel->center_freq);
+               if (ret)
+                       goto out;
+               ret = p54_setup_mac(dev, priv->mac_mode, priv->bssid);
+               if (ret)
+                       goto out;
+               if (conf->changed & IEEE80211_IFCC_BEACON) {
+                       ret = p54_beacon_update(dev, vif);
+                       if (ret)
+                               goto out;
+                       ret = p54_set_edcf(dev);
+                       if (ret)
+                               goto out;
+               }
+       }
+out:
        mutex_unlock(&priv->conf_mutex);
-       return 0;
+       return ret;
 }
 
 static void p54_configure_filter(struct ieee80211_hw *dev,
@@ -1367,14 +1706,18 @@ static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
                       const struct ieee80211_tx_queue_params *params)
 {
        struct p54_common *priv = dev->priv;
+       int ret;
 
+       mutex_lock(&priv->conf_mutex);
        if ((params) && !(queue > 4)) {
                P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
                        params->cw_min, params->cw_max, params->txop);
        } else
-               return -EINVAL;
-
-       return p54_set_edcf(dev);
+               ret = -EINVAL;
+       if (!ret)
+               ret = p54_set_edcf(dev);
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
 }
 
 static int p54_init_xbow_synth(struct ieee80211_hw *dev)
@@ -1457,6 +1800,7 @@ static const struct ieee80211_ops p54_ops = {
        .stop                   = p54_stop,
        .add_interface          = p54_add_interface,
        .remove_interface       = p54_remove_interface,
+       .set_tim                = p54_set_tim,
        .config                 = p54_config,
        .config_interface       = p54_config_interface,
        .bss_info_changed       = p54_bss_info_changed,
@@ -1478,24 +1822,20 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
        priv = dev->priv;
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
        skb_queue_head_init(&priv->tx_queue);
-       dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
-                    IEEE80211_HW_RX_INCLUDES_FCS |
+       dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_NOISE_DBM;
 
-       /*
-        * XXX: when this driver gets support for any mode that
-        *      requires beacons (AP, MESH, IBSS) then it must
-        *      implement IEEE80211_TX_CTL_ASSIGN_SEQ.
-        */
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION |
+                                         NL80211_IFTYPE_ADHOC |
+                                         NL80211_IFTYPE_AP);
 
        dev->channel_change_time = 1000;        /* TODO: find actual value */
-       priv->tx_stats[0].limit = 1;
-       priv->tx_stats[1].limit = 1;
-       priv->tx_stats[2].limit = 1;
-       priv->tx_stats[3].limit = 1;
-       priv->tx_stats[4].limit = 5;
+       priv->tx_stats[0].limit = 1;            /* Beacon queue */
+       priv->tx_stats[1].limit = 1;            /* Probe queue for HW scan */
+       priv->tx_stats[2].limit = 3;            /* queue for MLMEs */
+       priv->tx_stats[3].limit = 3;            /* Broadcast / MC queue */
+       priv->tx_stats[4].limit = 5;            /* Data */
        dev->queues = 1;
        priv->noise = -94;
        /*
index b1101feace6962bc03b1375ee3aea975c47d5482..8c8793cb2d79744ab065ab9c957feb928615ac48 100644 (file)
@@ -25,6 +25,22 @@ struct bootrec {
        u32 data[10];
 } __attribute__((packed));
 
+#define PDR_SYNTH_FRONTEND_MASK                0x0007
+#define PDR_SYNTH_IQ_CAL_MASK          0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR   0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED      0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF           0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK      0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED   0x0001
+#define PDR_SYNTH_24_GHZ_MASK          0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED      0x0040
+#define PDR_SYNTH_5_GHZ_MASK           0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED       0x0080
+#define PDR_SYNTH_RX_DIV_MASK          0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED     0x0100
+#define PDR_SYNTH_TX_DIV_MASK          0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED     0x0200
+
 struct bootrec_exp_if {
        __le16 role;
        __le16 if_id;
@@ -210,6 +226,19 @@ struct pda_pa_curve_data {
 #define PDR_BASEBAND_REGISTERS                 0x8000
 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS     0x8001
 
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE          0x80
+#define PDR_COUNTRY_CERT_CODE_REAL     0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO   0x80
+#define PDR_COUNTRY_CERT_BAND          0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ     0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ     0x40
+#define PDR_COUNTRY_CERT_IODOOR                0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH   0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR        0x30
+#define PDR_COUNTRY_CERT_INDEX         0x0F
+
 /* stored in skb->cb */
 struct memrecord {
        u32 start_addr;
@@ -507,7 +536,7 @@ struct p54_sta_unlock {
 } __attribute__ ((packed));
 
 #define P54_TIM_CLEAR BIT(15)
-struct p54_tx_control_tim {
+struct p54_tim {
        u8 count;
        u8 padding[3];
        __le16 entry[8];
index 3c9d030ccb8d1e3171bbeef2ec39212e0bf491ab..c4a868ae6d6b0efef665bdfa42184b35fd21e807 100644 (file)
@@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_DESCRIPTION("Prism54 PCI wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54pci");
+MODULE_FIRMWARE("isl3886pci");
 
 static struct pci_device_id p54p_table[] __devinitdata = {
        /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
@@ -72,11 +73,13 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
        P54P_WRITE(ctrl_stat, reg);
        wmb();
 
-       err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+       err = request_firmware(&fw_entry, "isl3886pci", &priv->pdev->dev);
        if (err) {
                printk(KERN_ERR "%s (p54pci): cannot find firmware "
-                      "(isl3886)\n", pci_name(priv->pdev));
-               return err;
+                      "(isl3886pci)\n", pci_name(priv->pdev));
+               err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+               if (err)
+                       return err;
        }
 
        err = p54_parse_firmware(dev, fw_entry);
index 49739c36a449f53018a6fb115995e163e77f9087..21ba526a45bf9435a96e92baf6276bc5137cae41 100644 (file)
@@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
 MODULE_DESCRIPTION("Prism54 USB wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("prism54usb");
+MODULE_FIRMWARE("isl3886usb");
+MODULE_FIRMWARE("isl3887usb");
 
 static struct usb_device_id p54u_table[] __devinitdata = {
        /* Version 1 devices (pci chip + net2280) */
@@ -415,10 +417,13 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
                goto err_reset;
        }
 
-       err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+       err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev);
        if (err) {
-               printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
-               goto err_req_fw_failed;
+               printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb)\n");
+               err = request_firmware(&fw_entry, "isl3887usb_bare",
+                       &priv->udev->dev);
+               if (err)
+                       goto err_req_fw_failed;
        }
 
        err = p54_parse_firmware(dev, fw_entry);
@@ -553,11 +558,15 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
                return -ENOMEM;
        }
 
-       err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+       err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev);
        if (err) {
-               printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
-               kfree(buf);
-               return err;
+               printk(KERN_ERR "p54usb: cannot find firmware (isl3886usb)\n");
+               err = request_firmware(&fw_entry, "isl3890usb",
+                       &priv->udev->dev);
+               if (err) {
+                       kfree(buf);
+                       return err;
+                       }
        }
 
        err = p54_parse_firmware(dev, fw_entry);
index bd059e3c7e2badacaac1433174d70bb235921866..a1eeb48f9466b7711acfce173519e1d5962799f9 100644 (file)
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <linux/if_arp.h>
 #include <linux/ctype.h>
 #include <linux/spinlock.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 #include <linux/usb/usbnet.h>
 #include <linux/usb/rndis_host.h>
 
@@ -1652,7 +1652,7 @@ static char *rndis_translate_scan(struct net_device *dev,
 #ifdef DEBUG
        struct usbnet *usbdev = dev->priv;
 #endif
-       struct ieee80211_info_element *ie;
+       u8 *ie;
        char *current_val;
        int bssid_len, ie_len, i;
        u32 beacon, atim;
@@ -1750,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev,
        ie_len = min(bssid_len - (int)sizeof(*bssid),
                                        (int)le32_to_cpu(bssid->ie_length));
        ie_len -= sizeof(struct ndis_80211_fixed_ies);
-       while (ie_len >= sizeof(*ie) && sizeof(*ie) + ie->len <= ie_len) {
-               if ((ie->id == MFIE_TYPE_GENERIC && ie->len >= 4 &&
-                               memcmp(ie->data, "\x00\x50\xf2\x01", 4) == 0) ||
-                               ie->id == MFIE_TYPE_RSN) {
+       while (ie_len >= 2 && 2 + ie[1] <= ie_len) {
+               if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 &&
+                    memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) ||
+                   ie[0] == WLAN_EID_RSN) {
                        devdbg(usbdev, "IE: WPA%d",
-                                       (ie->id == MFIE_TYPE_RSN) ? 2 : 1);
+                                       (ie[0] == WLAN_EID_RSN) ? 2 : 1);
                        iwe.cmd = IWEVGENIE;
-                       iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN);
-                       cev = iwe_stream_add_point(info, cev, end_buf, &iwe,
-                                                               (u8 *)ie);
+                       /* arbitrary cut-off at 64 */
+                       iwe.u.data.length = min(ie[1] + 2, 64);
+                       cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie);
                }
 
-               ie_len -= sizeof(*ie) + ie->len;
-               ie = (struct ieee80211_info_element *)&ie->data[ie->len];
+               ie_len -= 2 + ie[1];
+               ie += 2 + ie[1];
        }
 
        return cev;
index 1adca7a1b9dc14ab3f620bcf3060451556601609..42bd38ac7a1db249b3a309d3ec6d89550e3f9c6b 100644 (file)
@@ -188,43 +188,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)     ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
-                              const unsigned int word, u32 *data)
-{
-       rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
-                               const unsigned int word, u32 data)
-{
-       rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2400pci_rt2x00debug = {
        .owner  = THIS_MODULE,
        .csr    = {
-               .read           = rt2400pci_read_csr,
-               .write          = rt2400pci_write_csr,
+               .read           = rt2x00pci_register_read,
+               .write          = rt2x00pci_register_write,
+               .flags          = RT2X00DEBUGFS_OFFSET,
+               .word_base      = CSR_REG_BASE,
                .word_size      = sizeof(u32),
                .word_count     = CSR_REG_SIZE / sizeof(u32),
        },
        .eeprom = {
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
+               .word_base      = EEPROM_BASE,
                .word_size      = sizeof(u16),
                .word_count     = EEPROM_SIZE / sizeof(u16),
        },
        .bbp    = {
                .read           = rt2400pci_bbp_read,
                .write          = rt2400pci_bbp_write,
+               .word_base      = BBP_BASE,
                .word_size      = sizeof(u8),
                .word_count     = BBP_SIZE / sizeof(u8),
        },
        .rf     = {
                .read           = rt2x00_rf_read,
                .write          = rt2400pci_rf_write,
+               .word_base      = RF_BASE,
                .word_size      = sizeof(u32),
                .word_count     = RF_SIZE / sizeof(u32),
        },
@@ -396,12 +387,74 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
        rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
        rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+       rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+       rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+       rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+       rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+       rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+       rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+       rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+       rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+       rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+       rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-                                    const int basic_rate_mask)
+static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev,
+                                struct antenna_setup *ant)
 {
-       rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+       u8 r1;
+       u8 r4;
+
+       /*
+        * We should never come here because rt2x00lib is supposed
+        * to catch this and send us the correct antenna explicitely.
+        */
+       BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+              ant->tx == ANTENNA_SW_DIVERSITY);
+
+       rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+       rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+       /*
+        * Configure the TX antenna.
+        */
+       switch (ant->tx) {
+       case ANTENNA_HW_DIVERSITY:
+               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+               break;
+       case ANTENNA_A:
+               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+               break;
+       case ANTENNA_B:
+       default:
+               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+               break;
+       }
+
+       /*
+        * Configure the RX antenna.
+        */
+       switch (ant->rx) {
+       case ANTENNA_HW_DIVERSITY:
+               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+               break;
+       case ANTENNA_A:
+               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+               break;
+       case ANTENNA_B:
+       default:
+               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+               break;
+       }
+
+       rt2400pci_bbp_write(rt2x00dev, 4, r4);
+       rt2400pci_bbp_write(rt2x00dev, 1, r1);
 }
 
 static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -460,56 +513,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
        rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
 }
 
-static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-                                    struct antenna_setup *ant)
+static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+                                        struct rt2x00lib_conf *libconf)
 {
-       u8 r1;
-       u8 r4;
-
-       /*
-        * We should never come here because rt2x00lib is supposed
-        * to catch this and send us the correct antenna explicitely.
-        */
-       BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-              ant->tx == ANTENNA_SW_DIVERSITY);
-
-       rt2400pci_bbp_read(rt2x00dev, 4, &r4);
-       rt2400pci_bbp_read(rt2x00dev, 1, &r1);
-
-       /*
-        * Configure the TX antenna.
-        */
-       switch (ant->tx) {
-       case ANTENNA_HW_DIVERSITY:
-               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
-               break;
-       case ANTENNA_A:
-               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
-               break;
-       case ANTENNA_B:
-       default:
-               rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
-               break;
-       }
-
-       /*
-        * Configure the RX antenna.
-        */
-       switch (ant->rx) {
-       case ANTENNA_HW_DIVERSITY:
-               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-               break;
-       case ANTENNA_A:
-               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
-               break;
-       case ANTENNA_B:
-       default:
-               rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-               break;
-       }
+       u32 reg;
 
-       rt2400pci_bbp_write(rt2x00dev, 4, r4);
-       rt2400pci_bbp_write(rt2x00dev, 1, r1);
+       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+       rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+                          libconf->conf->long_frame_max_tx_count);
+       rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+                          libconf->conf->short_frame_max_tx_count);
+       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -517,20 +531,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-       rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-       rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-       rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-       rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-       rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-       rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-       rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-       rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-       rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
        rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
        rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
        rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -548,16 +548,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
                             struct rt2x00lib_conf *libconf,
                             const unsigned int flags)
 {
-       if (flags & CONFIG_UPDATE_PHYMODE)
-               rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
-       if (flags & CONFIG_UPDATE_CHANNEL)
+       if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2400pci_config_channel(rt2x00dev, &libconf->rf);
-       if (flags & CONFIG_UPDATE_TXPOWER)
+       if (flags & IEEE80211_CONF_CHANGE_POWER)
                rt2400pci_config_txpower(rt2x00dev,
                                         libconf->conf->power_level);
-       if (flags & CONFIG_UPDATE_ANTENNA)
-               rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
-       if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+       if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+               rt2400pci_config_retry_limit(rt2x00dev, libconf);
+       if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
                rt2400pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -1502,20 +1500,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
-                                    u32 short_retry, u32 long_retry)
-{
-       struct rt2x00_dev *rt2x00dev = hw->priv;
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-       rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-       rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-       return 0;
-}
-
 static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
                             const struct ieee80211_tx_queue_params *params)
 {
@@ -1601,8 +1585,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
        .config_filter          = rt2400pci_config_filter,
        .config_intf            = rt2400pci_config_intf,
        .config_erp             = rt2400pci_config_erp,
+       .config_ant             = rt2400pci_config_ant,
        .config                 = rt2400pci_config,
-       .set_retry_limit        = rt2400pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt2400pci_queue_rx = {
index bbff381ce3963d11e28b9b261c5c44ab88d3da5b..9aefda4ab3c263c4163543fff32a7853b8139ec8 100644 (file)
@@ -46,7 +46,9 @@
 #define CSR_REG_SIZE                   0x014c
 #define EEPROM_BASE                    0x0000
 #define EEPROM_SIZE                    0x0100
+#define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0020
+#define RF_BASE                                0x0000
 #define RF_SIZE                                0x0010
 
 /*
index 85b0387f46ebdde385dae192c3cd3420cbee7f24..928452f30c25d53fdff254a6a2f5a740822ed22b 100644 (file)
@@ -188,43 +188,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)     ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev,
-                              const unsigned int word, u32 *data)
-{
-       rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev,
-                               const unsigned int word, u32 data)
-{
-       rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt2500pci_rt2x00debug = {
        .owner  = THIS_MODULE,
        .csr    = {
-               .read           = rt2500pci_read_csr,
-               .write          = rt2500pci_write_csr,
+               .read           = rt2x00pci_register_read,
+               .write          = rt2x00pci_register_write,
+               .flags          = RT2X00DEBUGFS_OFFSET,
+               .word_base      = CSR_REG_BASE,
                .word_size      = sizeof(u32),
                .word_count     = CSR_REG_SIZE / sizeof(u32),
        },
        .eeprom = {
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
+               .word_base      = EEPROM_BASE,
                .word_size      = sizeof(u16),
                .word_count     = EEPROM_SIZE / sizeof(u16),
        },
        .bbp    = {
                .read           = rt2500pci_bbp_read,
                .write          = rt2500pci_bbp_write,
+               .word_base      = BBP_BASE,
                .word_size      = sizeof(u8),
                .word_count     = BBP_SIZE / sizeof(u8),
        },
        .rf     = {
                .read           = rt2x00_rf_read,
                .write          = rt2500pci_rf_write,
+               .word_base      = RF_BASE,
                .word_size      = sizeof(u32),
                .word_count     = RF_SIZE / sizeof(u32),
        },
@@ -402,12 +393,94 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
        rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
        rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+
+       rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+
+       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+       rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
+       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+       rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+       rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
+       rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
+       rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+       rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+       rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
+       rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
+       rt2x00pci_register_write(rt2x00dev, CSR19, reg);
 }
 
-static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-                                    const int basic_rate_mask)
+static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
+                                struct antenna_setup *ant)
 {
-       rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+       u32 reg;
+       u8 r14;
+       u8 r2;
+
+       /*
+        * We should never come here because rt2x00lib is supposed
+        * to catch this and send us the correct antenna explicitely.
+        */
+       BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
+              ant->tx == ANTENNA_SW_DIVERSITY);
+
+       rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+       rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+       rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+       /*
+        * Configure the TX antenna.
+        */
+       switch (ant->tx) {
+       case ANTENNA_A:
+               rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+               rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+               rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+               break;
+       case ANTENNA_B:
+       default:
+               rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+               rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+               rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+               break;
+       }
+
+       /*
+        * Configure the RX antenna.
+        */
+       switch (ant->rx) {
+       case ANTENNA_A:
+               rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+               break;
+       case ANTENNA_B:
+       default:
+               rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+               break;
+       }
+
+       /*
+        * RT2525E and RT5222 need to flip TX I/Q
+        */
+       if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+           rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+               rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+               rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+               rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+               /*
+                * RT2525E does not need RX I/Q Flip.
+                */
+               if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+                       rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+       } else {
+               rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+               rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+       }
+
+       rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+       rt2500pci_bbp_write(rt2x00dev, 14, r14);
+       rt2500pci_bbp_write(rt2x00dev, 2, r2);
 }
 
 static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
@@ -489,76 +562,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
        rt2500pci_rf_write(rt2x00dev, 3, rf3);
 }
 
-static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-                                    struct antenna_setup *ant)
+static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+                                        struct rt2x00lib_conf *libconf)
 {
        u32 reg;
-       u8 r14;
-       u8 r2;
-
-       /*
-        * We should never come here because rt2x00lib is supposed
-        * to catch this and send us the correct antenna explicitely.
-        */
-       BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
-              ant->tx == ANTENNA_SW_DIVERSITY);
-
-       rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
-       rt2500pci_bbp_read(rt2x00dev, 14, &r14);
-       rt2500pci_bbp_read(rt2x00dev, 2, &r2);
 
-       /*
-        * Configure the TX antenna.
-        */
-       switch (ant->tx) {
-       case ANTENNA_A:
-               rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
-               rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
-               rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
-               break;
-       case ANTENNA_B:
-       default:
-               rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
-               rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
-               rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
-               break;
-       }
-
-       /*
-        * Configure the RX antenna.
-        */
-       switch (ant->rx) {
-       case ANTENNA_A:
-               rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
-               break;
-       case ANTENNA_B:
-       default:
-               rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
-               break;
-       }
-
-       /*
-        * RT2525E and RT5222 need to flip TX I/Q
-        */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
-           rt2x00_rf(&rt2x00dev->chip, RF5222)) {
-               rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
-               rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
-               rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
-
-               /*
-                * RT2525E does not need RX I/Q Flip.
-                */
-               if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
-                       rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
-       } else {
-               rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
-               rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
-       }
-
-       rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
-       rt2500pci_bbp_write(rt2x00dev, 14, r14);
-       rt2500pci_bbp_write(rt2x00dev, 2, r2);
+       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+       rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
+                          libconf->conf->long_frame_max_tx_count);
+       rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
+                          libconf->conf->short_frame_max_tx_count);
+       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 }
 
 static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -566,20 +580,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-       rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
-       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-       rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
-       rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
-       rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
-       rt2x00pci_register_write(rt2x00dev, CSR18, reg);
-
-       rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
-       rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
-       rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
-       rt2x00pci_register_write(rt2x00dev, CSR19, reg);
-
        rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
        rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
        rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
@@ -597,17 +597,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
                             struct rt2x00lib_conf *libconf,
                             const unsigned int flags)
 {
-       if (flags & CONFIG_UPDATE_PHYMODE)
-               rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
-       if (flags & CONFIG_UPDATE_CHANNEL)
+       if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2500pci_config_channel(rt2x00dev, &libconf->rf,
                                         libconf->conf->power_level);
-       if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+       if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+           !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
                rt2500pci_config_txpower(rt2x00dev,
                                         libconf->conf->power_level);
-       if (flags & CONFIG_UPDATE_ANTENNA)
-               rt2500pci_config_antenna(rt2x00dev, &libconf->ant);
-       if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+       if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+               rt2500pci_config_retry_limit(rt2x00dev, libconf);
+       if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
                rt2500pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -1827,20 +1826,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
-                                    u32 short_retry, u32 long_retry)
-{
-       struct rt2x00_dev *rt2x00dev = hw->priv;
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
-       rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
-       rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
-       rt2x00pci_register_write(rt2x00dev, CSR11, reg);
-
-       return 0;
-}
-
 static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1901,8 +1886,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
        .config_filter          = rt2500pci_config_filter,
        .config_intf            = rt2500pci_config_intf,
        .config_erp             = rt2500pci_config_erp,
+       .config_ant             = rt2500pci_config_ant,
        .config                 = rt2500pci_config,
-       .set_retry_limit        = rt2500pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt2500pci_queue_rx = {
index 8c26bef6cf49cc23d0eecafe635e20f93b89f052..e135247f7f89d6aae25fefc4bdb7673e54bfc706 100644 (file)
@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE                   0x0174
 #define EEPROM_BASE                    0x0000
 #define EEPROM_SIZE                    0x0200
+#define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0040
+#define RF_BASE                                0x0000
 #define RF_SIZE                                0x0014
 
 /*
index d19bee43861d51a30bb2074d7a51b4c9fdd38c28..639d5a2f84e241de460aba6babe686d71355b899 100644 (file)
@@ -245,43 +245,48 @@ rf_write:
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)     ( CSR_REG_BASE + ((__word) * sizeof(u16)) )
-
-static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
-                              const unsigned int word, u32 *data)
+static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
+                                    const unsigned int offset,
+                                    u32 *value)
 {
-       rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+       rt2500usb_register_read(rt2x00dev, offset, (u16 *)value);
 }
 
-static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
-                               const unsigned int word, u32 data)
+static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
+                                     const unsigned int offset,
+                                     u32 value)
 {
-       rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+       rt2500usb_register_write(rt2x00dev, offset, value);
 }
 
 static const struct rt2x00debug rt2500usb_rt2x00debug = {
        .owner  = THIS_MODULE,
        .csr    = {
-               .read           = rt2500usb_read_csr,
-               .write          = rt2500usb_write_csr,
+               .read           = _rt2500usb_register_read,
+               .write          = _rt2500usb_register_write,
+               .flags          = RT2X00DEBUGFS_OFFSET,
+               .word_base      = CSR_REG_BASE,
                .word_size      = sizeof(u16),
                .word_count     = CSR_REG_SIZE / sizeof(u16),
        },
        .eeprom = {
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
+               .word_base      = EEPROM_BASE,
                .word_size      = sizeof(u16),
                .word_count     = EEPROM_SIZE / sizeof(u16),
        },
        .bbp    = {
                .read           = rt2500usb_bbp_read,
                .write          = rt2500usb_bbp_write,
+               .word_base      = BBP_BASE,
                .word_size      = sizeof(u8),
                .word_count     = BBP_SIZE / sizeof(u8),
        },
        .rf     = {
                .read           = rt2x00_rf_read,
                .write          = rt2500usb_rf_write,
+               .word_base      = RF_BASE,
                .word_size      = sizeof(u32),
                .word_count     = RF_SIZE / sizeof(u32),
        },
@@ -423,57 +428,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
                           !!erp->short_preamble);
        rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
-}
-
-static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-                                    const int basic_rate_mask)
-{
-       rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
-}
 
-static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
-                                    struct rf_channel *rf, const int txpower)
-{
-       /*
-        * Set TXpower.
-        */
-       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates);
 
-       /*
-        * For RT2525E we should first set the channel to half band higher.
-        */
-       if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
-               static const u32 vals[] = {
-                       0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
-                       0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
-                       0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
-                       0x00000902, 0x00000906
-               };
-
-               rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
-               if (rf->rf4)
-                       rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-       }
-
-       rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
-       rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
-       rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
-       if (rf->rf4)
-               rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
-}
-
-static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-                                    const int txpower)
-{
-       u32 rf3;
-
-       rt2x00_rf_read(rt2x00dev, 3, &rf3);
-       rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-       rt2500usb_rf_write(rt2x00dev, 3, rf3);
+       rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time);
+       rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs);
+       rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs);
 }
 
-static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-                                    struct antenna_setup *ant)
+static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev,
+                                struct antenna_setup *ant)
 {
        u8 r2;
        u8 r14;
@@ -555,15 +519,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
        rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
 }
 
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+                                    struct rf_channel *rf, const int txpower)
+{
+       /*
+        * Set TXpower.
+        */
+       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+       /*
+        * For RT2525E we should first set the channel to half band higher.
+        */
+       if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+               static const u32 vals[] = {
+                       0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+                       0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+                       0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+                       0x00000902, 0x00000906
+               };
+
+               rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+               if (rf->rf4)
+                       rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+       }
+
+       rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+       rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+       rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+       if (rf->rf4)
+               rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+                                    const int txpower)
+{
+       u32 rf3;
+
+       rt2x00_rf_read(rt2x00dev, 3, &rf3);
+       rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+       rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
 static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
                                      struct rt2x00lib_conf *libconf)
 {
        u16 reg;
 
-       rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
-       rt2500usb_register_write(rt2x00dev, MAC_CSR11, libconf->sifs);
-       rt2500usb_register_write(rt2x00dev, MAC_CSR12, libconf->eifs);
-
        rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
        rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
                           libconf->conf->beacon_int * 4);
@@ -574,17 +575,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
                             struct rt2x00lib_conf *libconf,
                             const unsigned int flags)
 {
-       if (flags & CONFIG_UPDATE_PHYMODE)
-               rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates);
-       if (flags & CONFIG_UPDATE_CHANNEL)
+       if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2500usb_config_channel(rt2x00dev, &libconf->rf,
                                         libconf->conf->power_level);
-       if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+       if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+           !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
                rt2500usb_config_txpower(rt2x00dev,
                                         libconf->conf->power_level);
-       if (flags & CONFIG_UPDATE_ANTENNA)
-               rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
-       if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+       if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
                rt2500usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -1794,6 +1792,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .config_filter          = rt2500usb_config_filter,
        .config_intf            = rt2500usb_config_intf,
        .config_erp             = rt2500usb_config_erp,
+       .config_ant             = rt2500usb_config_ant,
        .config                 = rt2500usb_config,
 };
 
index 89e5ed24e4f7906a95ae0feaacc992e022840e34..dbb5d689e23dd6dc9f13382149e32ab5b2cace87 100644 (file)
@@ -57,7 +57,9 @@
 #define CSR_REG_SIZE                   0x0100
 #define EEPROM_BASE                    0x0000
 #define EEPROM_SIZE                    0x006a
+#define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0060
+#define RF_BASE                                0x0000
 #define RF_SIZE                                0x0014
 
 /*
index 0887e895d5c17cc7f1190a883acb042903612bd0..f85eedbbad683692eb0ae675d2e612c72ff38c7a 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION    "2.2.1"
+#define DRV_VERSION    "2.2.2"
 #define DRV_PROJECT    "http://rt2x00.serialmonkey.com"
 
 /*
@@ -347,13 +347,6 @@ struct rt2x00_intf {
         */
        spinlock_t lock;
 
-       /*
-        * BSS configuration. Copied from the structure
-        * passed to us through the bss_info_changed()
-        * callback funtion.
-        */
-       struct ieee80211_bss_conf conf;
-
        /*
         * MAC of the device.
         */
@@ -433,18 +426,6 @@ struct rt2x00lib_conf {
 
        struct rf_channel rf;
        struct channel_info channel;
-
-       struct antenna_setup ant;
-
-       enum ieee80211_band band;
-
-       u32 basic_rates;
-       u32 slot_time;
-
-       short sifs;
-       short pifs;
-       short difs;
-       short eifs;
 };
 
 /*
@@ -456,6 +437,15 @@ struct rt2x00lib_erp {
 
        int ack_timeout;
        int ack_consume_time;
+
+       u64 basic_rates;
+
+       int slot_time;
+
+       short sifs;
+       short pifs;
+       short difs;
+       short eifs;
 };
 
 /*
@@ -589,19 +579,11 @@ struct rt2x00lib_ops {
 
        void (*config_erp) (struct rt2x00_dev *rt2x00dev,
                            struct rt2x00lib_erp *erp);
+       void (*config_ant) (struct rt2x00_dev *rt2x00dev,
+                           struct antenna_setup *ant);
        void (*config) (struct rt2x00_dev *rt2x00dev,
                        struct rt2x00lib_conf *libconf,
-                       const unsigned int flags);
-#define CONFIG_UPDATE_PHYMODE          ( 1 << 1 )
-#define CONFIG_UPDATE_CHANNEL          ( 1 << 2 )
-#define CONFIG_UPDATE_TXPOWER          ( 1 << 3 )
-#define CONFIG_UPDATE_ANTENNA          ( 1 << 4 )
-#define CONFIG_UPDATE_SLOT_TIME        ( 1 << 5 )
-#define CONFIG_UPDATE_BEACON_INT       ( 1 << 6 )
-#define CONFIG_UPDATE_ALL              0xffff
-
-       int (*set_retry_limit) (struct ieee80211_hw *hw,
-                               u32 short_limit, u32 long_limit);
+                       const unsigned int changed_flags);
 };
 
 /*
index 7910147157b58c6e902179f291d794ffa8960775..3e4eee3ab7d2be27c55ceced5d5eaab0d8c19cf2 100644 (file)
@@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
        erp.short_preamble = bss_conf->use_short_preamble;
        erp.cts_protection = bss_conf->use_cts_prot;
 
-       erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
-       erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
+       erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
+       erp.sifs = SIFS;
+       erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
+       erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
+       erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
 
-       if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME)
-               erp.ack_timeout += SHORT_DIFS;
-       else
-               erp.ack_timeout += DIFS;
+       erp.ack_timeout = PLCP + erp.difs + get_duration(ACK_SIZE, 10);
+       erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
 
        if (bss_conf->use_short_preamble) {
                erp.ack_timeout += SHORT_PREAMBLE;
@@ -102,16 +103,18 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
                erp.ack_consume_time += PREAMBLE;
        }
 
+       erp.basic_rates = bss_conf->basic_rates;
+
        rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
 }
 
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
                              enum antenna rx, enum antenna tx)
 {
-       struct rt2x00lib_conf libconf;
+       struct antenna_setup ant;
 
-       libconf.ant.rx = rx;
-       libconf.ant.tx = tx;
+       ant.rx = rx;
+       ant.tx = tx;
 
        if (rx == rt2x00dev->link.ant.active.rx &&
            tx == rt2x00dev->link.ant.active.tx)
@@ -129,111 +132,28 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
         * The latter is required since we need to recalibrate the
         * noise-sensitivity ratio for the new setup.
         */
-       rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
+       rt2x00dev->ops->lib->config_ant(rt2x00dev, &ant);
+
        rt2x00lib_reset_link_tuner(rt2x00dev);
        rt2x00_reset_link_ant_rssi(&rt2x00dev->link);
 
-       rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-       rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+       memcpy(&rt2x00dev->link.ant.active, &ant, sizeof(ant));
 
        if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
                rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK);
 }
 
-static u32 rt2x00lib_get_basic_rates(struct ieee80211_supported_band *band)
-{
-       const struct rt2x00_rate *rate;
-       unsigned int i;
-       u32 mask = 0;
-
-       for (i = 0; i < band->n_bitrates; i++) {
-               rate = rt2x00_get_rate(band->bitrates[i].hw_value);
-               if (rate->flags & DEV_RATE_BASIC)
-                       mask |= rate->ratemask;
-       }
-
-       return mask;
-}
-
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-                     struct ieee80211_conf *conf, const int force_config)
+                     struct ieee80211_conf *conf,
+                     unsigned int ieee80211_flags)
 {
        struct rt2x00lib_conf libconf;
-       struct ieee80211_supported_band *band;
-       struct antenna_setup *default_ant = &rt2x00dev->default_ant;
-       struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
-       int flags = 0;
-       int short_slot_time;
-
-       /*
-        * In some situations we want to force all configurations
-        * to be reloaded (When resuming for instance).
-        */
-       if (force_config) {
-               flags = CONFIG_UPDATE_ALL;
-               goto config;
-       }
-
-       /*
-        * Check which configuration options have been
-        * updated and should be send to the device.
-        */
-       if (rt2x00dev->rx_status.band != conf->channel->band)
-               flags |= CONFIG_UPDATE_PHYMODE;
-       if (rt2x00dev->rx_status.freq != conf->channel->center_freq)
-               flags |= CONFIG_UPDATE_CHANNEL;
-       if (rt2x00dev->tx_power != conf->power_level)
-               flags |= CONFIG_UPDATE_TXPOWER;
-
-       /*
-        * Determining changes in the antenna setups request several checks:
-        * antenna_sel_{r,t}x = 0
-        *    -> Does active_{r,t}x match default_{r,t}x
-        *    -> Is default_{r,t}x SW_DIVERSITY
-        * antenna_sel_{r,t}x = 1/2
-        *    -> Does active_{r,t}x match antenna_sel_{r,t}x
-        * The reason for not updating the antenna while SW diversity
-        * should be used is simple: Software diversity means that
-        * we should switch between the antenna's based on the
-        * quality. This means that the current antenna is good enough
-        * to work with untill the link tuner decides that an antenna
-        * switch should be performed.
-        */
-       if (default_ant->rx != ANTENNA_SW_DIVERSITY &&
-           default_ant->rx != active_ant->rx)
-               flags |= CONFIG_UPDATE_ANTENNA;
-       else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-               flags |= CONFIG_UPDATE_ANTENNA;
-
-       if (default_ant->tx != ANTENNA_SW_DIVERSITY &&
-           default_ant->tx != active_ant->tx)
-               flags |= CONFIG_UPDATE_ANTENNA;
-       else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-               flags |= CONFIG_UPDATE_ANTENNA;
 
-       /*
-        * The following configuration options are never
-        * stored anywhere and will always be updated.
-        */
-       flags |= CONFIG_UPDATE_SLOT_TIME;
-       flags |= CONFIG_UPDATE_BEACON_INT;
-
-       /*
-        * We have determined what options should be updated,
-        * now precalculate device configuration values depending
-        * on what configuration options need to be updated.
-        */
-config:
        memset(&libconf, 0, sizeof(libconf));
 
-       if (flags & CONFIG_UPDATE_PHYMODE) {
-               band = &rt2x00dev->bands[conf->channel->band];
-
-               libconf.band = conf->channel->band;
-               libconf.basic_rates = rt2x00lib_get_basic_rates(band);
-       }
+       libconf.conf = conf;
 
-       if (flags & CONFIG_UPDATE_CHANNEL) {
+       if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
                memcpy(&libconf.rf,
                       &rt2x00dev->spec.channels[conf->channel->hw_value],
                       sizeof(libconf.rf));
@@ -243,57 +163,21 @@ config:
                       sizeof(libconf.channel));
        }
 
-       if (flags & CONFIG_UPDATE_ANTENNA) {
-               if (default_ant->rx != ANTENNA_SW_DIVERSITY)
-                       libconf.ant.rx = default_ant->rx;
-               else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
-                       libconf.ant.rx = ANTENNA_B;
-               else
-                       libconf.ant.rx = active_ant->rx;
-
-               if (default_ant->tx != ANTENNA_SW_DIVERSITY)
-                       libconf.ant.tx = default_ant->tx;
-               else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
-                       libconf.ant.tx = ANTENNA_B;
-               else
-                       libconf.ant.tx = active_ant->tx;
-       }
-
-       if (flags & CONFIG_UPDATE_SLOT_TIME) {
-               short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
-
-               libconf.slot_time =
-                   short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
-               libconf.sifs = SIFS;
-               libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
-               libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
-               libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
-       }
-
-       libconf.conf = conf;
-
        /*
         * Start configuration.
         */
-       rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags);
+       rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
 
        /*
         * Some configuration changes affect the link quality
         * which means we need to reset the link tuner.
         */
-       if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+       if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2x00lib_reset_link_tuner(rt2x00dev);
 
-       if (flags & CONFIG_UPDATE_PHYMODE) {
-               rt2x00dev->curr_band = conf->channel->band;
-               rt2x00dev->rx_status.band = conf->channel->band;
-       }
-
-       rt2x00dev->rx_status.freq = conf->channel->center_freq;
+       rt2x00dev->curr_band = conf->channel->band;
        rt2x00dev->tx_power = conf->power_level;
 
-       if (flags & CONFIG_UPDATE_ANTENNA) {
-               rt2x00dev->link.ant.active.rx = libconf.ant.rx;
-               rt2x00dev->link.ant.active.tx = libconf.ant.tx;
-       }
+       rt2x00dev->rx_status.band = conf->channel->band;
+       rt2x00dev->rx_status.freq = conf->channel->center_freq;
 }
index a31418a700c1f6de6e6fe958ed4c48f0cdc43c53..54dd10060bf1a56a8b318ee5e135463b796cc358 100644 (file)
@@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file,       \
        const struct rt2x00debug *debug = intf->debug;          \
        char line[16];                                          \
        size_t size;                                            \
+       unsigned int index = intf->offset_##__name;             \
        __type value;                                           \
                                                                \
        if (*offset)                                            \
                return 0;                                       \
                                                                \
-       if (intf->offset_##__name >= debug->__name.word_count)  \
+       if (index >= debug->__name.word_count)                  \
                return -EINVAL;                                 \
                                                                \
-       debug->__name.read(intf->rt2x00dev,                     \
-                          intf->offset_##__name, &value);      \
+       if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)         \
+               index *= debug->__name.word_size;               \
+                                                               \
+       index += debug->__name.word_base;                       \
+                                                               \
+       debug->__name.read(intf->rt2x00dev, index, &value);     \
                                                                \
        size = sprintf(line, __format, value);                  \
                                                                \
@@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,      \
        const struct rt2x00debug *debug = intf->debug;          \
        char line[16];                                          \
        size_t size;                                            \
+       unsigned int index = intf->offset_##__name;             \
        __type value;                                           \
                                                                \
        if (*offset)                                            \
                return 0;                                       \
                                                                \
-       if (intf->offset_##__name >= debug->__name.word_count)  \
+       if (index >= debug->__name.word_count)                  \
                return -EINVAL;                                 \
                                                                \
        if (copy_from_user(line, buf, length))                  \
@@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,       \
        size = strlen(line);                                    \
        value = simple_strtoul(line, NULL, 0);                  \
                                                                \
-       debug->__name.write(intf->rt2x00dev,                    \
-                           intf->offset_##__name, value);      \
+       if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)         \
+               index *= debug->__name.word_size;               \
+                                                               \
+       index += debug->__name.word_base;                       \
+                                                               \
+       debug->__name.write(intf->rt2x00dev, index, value);     \
                                                                \
        *offset += size;                                        \
        return size;                                            \
index c4ce895aa1c70776100b66536fe54064d2368125..a92104dfee9a6836d90b7ee2270b3c407fc873e8 100644 (file)
 
 struct rt2x00_dev;
 
+/**
+ * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry
+ *
+ * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset
+ *     as argument when using the callback function read()/write()
+ */
+enum rt2x00debugfs_entry_flags {
+       RT2X00DEBUGFS_OFFSET    = (1 << 0),
+};
+
 #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type)           \
 struct reg##__name {                                           \
        void (*read)(struct rt2x00_dev *rt2x00dev,              \
@@ -35,6 +45,9 @@ struct reg##__name {                                          \
        void (*write)(struct rt2x00_dev *rt2x00dev,             \
                      const unsigned int word, __type data);    \
                                                                \
+       unsigned int flags;                                     \
+                                                               \
+       unsigned int word_base;                                 \
        unsigned int word_size;                                 \
        unsigned int word_count;                                \
 } __name
index e1feab8b6b0296582c9b360295f8e56121d19803..477a944167c47f1d9370d4843bf7c01f12ccc5ae 100644 (file)
@@ -417,7 +417,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
         */
        spin_lock(&intf->lock);
 
-       memcpy(&conf, &intf->conf, sizeof(conf));
+       memcpy(&conf, &vif->bss_conf, sizeof(conf));
        delayed_flags = intf->delayed_flags;
        intf->delayed_flags = 0;
 
@@ -1056,10 +1056,16 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf);
 
-       rt2x00dev->hw->wiphy->interface_modes =
-           BIT(NL80211_IFTYPE_AP) |
-           BIT(NL80211_IFTYPE_STATION) |
-           BIT(NL80211_IFTYPE_ADHOC);
+       /*
+        * Determine which operating modes are supported, all modes
+        * which require beaconing, depend on the availability of
+        * beacon entries.
+        */
+       rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       if (rt2x00dev->ops->bcn->entry_num > 0)
+               rt2x00dev->hw->wiphy->interface_modes |=
+                   BIT(NL80211_IFTYPE_ADHOC) |
+                   BIT(NL80211_IFTYPE_AP);
 
        /*
         * Let the driver probe the device to detect the capabilities.
index 797eb619aa0af918d9591fc56a9b4281448720b0..9f214f89ba6d7afcc04047ddcdec54131d9c887f 100644 (file)
@@ -96,7 +96,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
 void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
                              enum antenna rx, enum antenna tx);
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
-                     struct ieee80211_conf *conf, const int force_config);
+                     struct ieee80211_conf *conf,
+                     const unsigned int changed_flags);
 
 /**
  * DOC: Queue handlers
index b32d59eafaa3df0ab2f086f488b25bad23d232a0..8fc2315c59637d427cd8397c83dbeb4e5d71937c 100644 (file)
@@ -349,15 +349,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
                return 0;
 
-       if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
-               rt2x00dev->ops->lib->set_retry_limit(hw,
-                       conf->short_frame_max_tx_count,
-                       conf->long_frame_max_tx_count);
-       }
-       changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS;
-       if (!changed)
-               return 0;
-
        /*
         * Only change device state when the radio is enabled. It does not
         * matter what parameters we have configured when the radio is disabled
@@ -379,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
                 * When we've just turned on the radio, we want to reprogram
                 * everything to ensure a consistent state
                 */
-               rt2x00lib_config(rt2x00dev, conf, !radio_on);
+               rt2x00lib_config(rt2x00dev, conf, changed);
 
                /* Turn RX back on */
                rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
@@ -643,7 +634,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        spin_lock(&intf->lock);
-       memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
        if (delayed) {
                intf->delayed_flags |= delayed;
                schedule_work(&rt2x00dev->intf_work);
index 80bf97c03e2d159395f46d9933db3be0275948c8..a83f45f784f28274fa7664e8bcb1d303a27357a0 100644 (file)
@@ -58,7 +58,7 @@
  * Register access.
  */
 static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
-                                          const unsigned long offset,
+                                          const unsigned int offset,
                                           u32 *value)
 {
        *value = readl(rt2x00dev->csr.base + offset);
@@ -66,14 +66,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
 
 static inline void
 rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
-                            const unsigned long offset,
+                            const unsigned int offset,
                             void *value, const u16 length)
 {
        memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
 }
 
 static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
-                                           const unsigned long offset,
+                                           const unsigned int offset,
                                            u32 value)
 {
        writel(value, rt2x00dev->csr.base + offset);
@@ -81,7 +81,7 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
 
 static inline void
 rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
-                             const unsigned long offset,
+                             const unsigned int offset,
                              const void *value, const u16 length)
 {
        memcpy_toio(rt2x00dev->csr.base + offset, value, length);
index 921dcd5064deeb9be4ada4638be9ebe1ec45f6c0..3f272793412a6d8bc47f093af8ca5d5c40d01bfe 100644 (file)
@@ -228,43 +228,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)     ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev,
-                            const unsigned int word, u32 *data)
-{
-       rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev,
-                             const unsigned int word, u32 data)
-{
-       rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt61pci_rt2x00debug = {
        .owner  = THIS_MODULE,
        .csr    = {
-               .read           = rt61pci_read_csr,
-               .write          = rt61pci_write_csr,
+               .read           = rt2x00pci_register_read,
+               .write          = rt2x00pci_register_write,
+               .flags          = RT2X00DEBUGFS_OFFSET,
+               .word_base      = CSR_REG_BASE,
                .word_size      = sizeof(u32),
                .word_count     = CSR_REG_SIZE / sizeof(u32),
        },
        .eeprom = {
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
+               .word_base      = EEPROM_BASE,
                .word_size      = sizeof(u16),
                .word_count     = EEPROM_SIZE / sizeof(u16),
        },
        .bbp    = {
                .read           = rt61pci_bbp_read,
                .write          = rt61pci_bbp_write,
+               .word_base      = BBP_BASE,
                .word_size      = sizeof(u8),
                .word_count     = BBP_SIZE / sizeof(u8),
        },
        .rf     = {
                .read           = rt2x00_rf_read,
                .write          = rt61pci_rf_write,
+               .word_base      = RF_BASE,
                .word_size      = sizeof(u32),
                .word_count     = RF_SIZE / sizeof(u32),
        },
@@ -643,95 +634,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
                           !!erp->short_preamble);
        rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-
-static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-                                   struct rt2x00lib_conf *libconf)
-{
-       u16 eeprom;
-       short lna_gain = 0;
-
-       if (libconf->band == IEEE80211_BAND_2GHZ) {
-               if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-                       lna_gain += 14;
-
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-       } else {
-               if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
-                       lna_gain += 14;
-
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-       }
 
-       rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
-                                  const int basic_rate_mask)
-{
-       rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
-
-static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
-                                  struct rf_channel *rf, const int txpower)
-{
-       u8 r3;
-       u8 r94;
-       u8 smart;
-
-       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-       rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-                 rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-       rt61pci_bbp_read(rt2x00dev, 3, &r3);
-       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-       rt61pci_bbp_write(rt2x00dev, 3, r3);
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-       r94 = 6;
-       if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-               r94 += txpower - MAX_TXPOWER;
-       else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-               r94 += txpower;
-       rt61pci_bbp_write(rt2x00dev, 94, r94);
-
-       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-       udelay(200);
-
-       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-       udelay(200);
-
-       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
-       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
-       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
-
-       msleep(1);
-}
-
-static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
-                                  const int txpower)
-{
-       struct rf_channel rf;
-
-       rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-       rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-       rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-       rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+       rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+       rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+       rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
 
-       rt61pci_config_channel(rt2x00dev, &rf, txpower);
+       rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+       rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+       rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+       rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+       rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -906,8 +820,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
        { 98,  { 0x48, 0x48 } },
 };
 
-static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-                                  struct antenna_setup *ant)
+static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
+                              struct antenna_setup *ant)
 {
        const struct antenna_sel *sel;
        unsigned int lna;
@@ -954,20 +868,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
        }
 }
 
-static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
+                                   struct rt2x00lib_conf *libconf)
+{
+       u16 eeprom;
+       short lna_gain = 0;
+
+       if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+               if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+                       lna_gain += 14;
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+       } else {
+               if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+                       lna_gain += 14;
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+       }
+
+       rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+                                  struct rf_channel *rf, const int txpower)
+{
+       u8 r3;
+       u8 r94;
+       u8 smart;
+
+       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+       rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+                 rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+       rt61pci_bbp_read(rt2x00dev, 3, &r3);
+       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+       rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+       r94 = 6;
+       if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+               r94 += txpower - MAX_TXPOWER;
+       else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+               r94 += txpower;
+       rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+       udelay(200);
+
+       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+       udelay(200);
+
+       rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+       rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+       rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+       rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+       msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+                                  const int txpower)
+{
+       struct rf_channel rf;
+
+       rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+       rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+       rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+       rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+       rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
                                    struct rt2x00lib_conf *libconf)
 {
        u32 reg;
 
-       rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
-       rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-       rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+       rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+       rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+                          libconf->conf->long_frame_max_tx_count);
+       rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+                          libconf->conf->short_frame_max_tx_count);
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
 
-       rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
-       rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-       rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-       rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-       rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+                                   struct rt2x00lib_conf *libconf)
+{
+       u32 reg;
 
        rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
        rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -990,16 +989,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
        /* Always recalculate LNA gain before changing configuration */
        rt61pci_config_lna_gain(rt2x00dev, libconf);
 
-       if (flags & CONFIG_UPDATE_PHYMODE)
-               rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
-       if (flags & CONFIG_UPDATE_CHANNEL)
+       if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt61pci_config_channel(rt2x00dev, &libconf->rf,
                                       libconf->conf->power_level);
-       if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+       if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+           !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
                rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
-       if (flags & CONFIG_UPDATE_ANTENNA)
-               rt61pci_config_antenna(rt2x00dev, &libconf->ant);
-       if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+       if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+               rt61pci_config_retry_limit(rt2x00dev, libconf);
+       if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
                rt61pci_config_duration(rt2x00dev, libconf);
 }
 
@@ -2628,20 +2626,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
-                                  u32 short_retry, u32 long_retry)
-{
-       struct rt2x00_dev *rt2x00dev = hw->priv;
-       u32 reg;
-
-       rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
-       rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-       rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-       rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-       return 0;
-}
-
 static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
                           const struct ieee80211_tx_queue_params *params)
 {
@@ -2755,8 +2739,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .config_filter          = rt61pci_config_filter,
        .config_intf            = rt61pci_config_intf,
        .config_erp             = rt61pci_config_erp,
+       .config_ant             = rt61pci_config_ant,
        .config                 = rt61pci_config,
-       .set_retry_limit        = rt61pci_set_retry_limit,
 };
 
 static const struct data_queue_desc rt61pci_queue_rx = {
index 8ec1451308ccea2700ce05e03f0be2229a3c2779..65fe3332364aa8cb414793ec0f0a057e40038252 100644 (file)
@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE                   0x04b0
 #define EEPROM_BASE                    0x0000
 #define EEPROM_SIZE                    0x0100
+#define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0080
+#define RF_BASE                                0x0000
 #define RF_SIZE                                0x0014
 
 /*
index 69a4931a2fd3f4ab19bcdd8236f026d6f74b4fe1..767e3c98184c2a8e62f8047471af21be5a31d78a 100644 (file)
@@ -249,43 +249,34 @@ rf_write:
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-#define CSR_OFFSET(__word)     ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
-
-static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev,
-                            const unsigned int word, u32 *data)
-{
-       rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
-}
-
-static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev,
-                             const unsigned int word, u32 data)
-{
-       rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
-}
-
 static const struct rt2x00debug rt73usb_rt2x00debug = {
        .owner  = THIS_MODULE,
        .csr    = {
-               .read           = rt73usb_read_csr,
-               .write          = rt73usb_write_csr,
+               .read           = rt73usb_register_read,
+               .write          = rt73usb_register_write,
+               .flags          = RT2X00DEBUGFS_OFFSET,
+               .word_base      = CSR_REG_BASE,
                .word_size      = sizeof(u32),
                .word_count     = CSR_REG_SIZE / sizeof(u32),
        },
        .eeprom = {
                .read           = rt2x00_eeprom_read,
                .write          = rt2x00_eeprom_write,
+               .word_base      = EEPROM_BASE,
                .word_size      = sizeof(u16),
                .word_count     = EEPROM_SIZE / sizeof(u16),
        },
        .bbp    = {
                .read           = rt73usb_bbp_read,
                .write          = rt73usb_bbp_write,
+               .word_base      = BBP_BASE,
                .word_size      = sizeof(u8),
                .word_count     = BBP_SIZE / sizeof(u8),
        },
        .rf     = {
                .read           = rt2x00_rf_read,
                .write          = rt73usb_rf_write,
+               .word_base      = RF_BASE,
                .word_size      = sizeof(u32),
                .word_count     = RF_SIZE / sizeof(u32),
        },
@@ -669,87 +660,18 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
                           !!erp->short_preamble);
        rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-}
-
-static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
-                                   struct rt2x00lib_conf *libconf)
-{
-       u16 eeprom;
-       short lna_gain = 0;
-
-       if (libconf->band == IEEE80211_BAND_2GHZ) {
-               if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
-                       lna_gain += 14;
-
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
-               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
-       } else {
-               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
-               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
-       }
-
-       rt2x00dev->lna_gain = lna_gain;
-}
-
-static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
-                                  const int basic_rate_mask)
-{
-       rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
-}
 
-static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
-                                  struct rf_channel *rf, const int txpower)
-{
-       u8 r3;
-       u8 r94;
-       u8 smart;
-
-       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
-       rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
-
-       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-                 rt2x00_rf(&rt2x00dev->chip, RF2527));
-
-       rt73usb_bbp_read(rt2x00dev, 3, &r3);
-       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
-       rt73usb_bbp_write(rt2x00dev, 3, r3);
+       rt73usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates);
 
-       r94 = 6;
-       if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
-               r94 += txpower - MAX_TXPOWER;
-       else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
-               r94 += txpower;
-       rt73usb_bbp_write(rt2x00dev, 94, r94);
-
-       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
-       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
-       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
-       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
-       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
-
-       udelay(10);
-}
-
-static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
-                                  const int txpower)
-{
-       struct rf_channel rf;
-
-       rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
-       rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
-       rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
-       rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+       rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+       rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
+       rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
 
-       rt73usb_config_channel(rt2x00dev, &rf, txpower);
+       rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+       rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
+       rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+       rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
+       rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
 }
 
 static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
@@ -869,8 +791,8 @@ static const struct antenna_sel antenna_sel_bg[] = {
        { 98,  { 0x48, 0x48 } },
 };
 
-static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-                                  struct antenna_setup *ant)
+static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
+                              struct antenna_setup *ant)
 {
        const struct antenna_sel *sel;
        unsigned int lna;
@@ -912,20 +834,98 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
                rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 
-static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
                                    struct rt2x00lib_conf *libconf)
+{
+       u16 eeprom;
+       short lna_gain = 0;
+
+       if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+               if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+                       lna_gain += 14;
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+       } else {
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+               lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+       }
+
+       rt2x00dev->lna_gain = lna_gain;
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+                                  struct rf_channel *rf, const int txpower)
+{
+       u8 r3;
+       u8 r94;
+       u8 smart;
+
+       rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+       rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+       smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+                 rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+       rt73usb_bbp_read(rt2x00dev, 3, &r3);
+       rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+       rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+       r94 = 6;
+       if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+               r94 += txpower - MAX_TXPOWER;
+       else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+               r94 += txpower;
+       rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+       rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+       rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+       rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+       rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+       udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+                                  const int txpower)
+{
+       struct rf_channel rf;
+
+       rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+       rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+       rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+       rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+       rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev,
+                                      struct rt2x00lib_conf *libconf)
 {
        u32 reg;
 
-       rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
-       rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
-       rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+       rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+       rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT,
+                          libconf->conf->long_frame_max_tx_count);
+       rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
+                          libconf->conf->short_frame_max_tx_count);
+       rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
 
-       rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
-       rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
-       rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
-       rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
-       rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+                                   struct rt2x00lib_conf *libconf)
+{
+       u32 reg;
 
        rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
        rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
@@ -948,16 +948,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
        /* Always recalculate LNA gain before changing configuration */
        rt73usb_config_lna_gain(rt2x00dev, libconf);
 
-       if (flags & CONFIG_UPDATE_PHYMODE)
-               rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
-       if (flags & CONFIG_UPDATE_CHANNEL)
+       if (flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt73usb_config_channel(rt2x00dev, &libconf->rf,
                                       libconf->conf->power_level);
-       if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+       if ((flags & IEEE80211_CONF_CHANGE_POWER) &&
+           !(flags & IEEE80211_CONF_CHANGE_CHANNEL))
                rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
-       if (flags & CONFIG_UPDATE_ANTENNA)
-               rt73usb_config_antenna(rt2x00dev, &libconf->ant);
-       if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+       if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+               rt73usb_config_retry_limit(rt2x00dev, libconf);
+       if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
                rt73usb_config_duration(rt2x00dev, libconf);
 }
 
@@ -2209,20 +2208,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
-                                  u32 short_retry, u32 long_retry)
-{
-       struct rt2x00_dev *rt2x00dev = hw->priv;
-       u32 reg;
-
-       rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
-       rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
-       rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
-       rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
-
-       return 0;
-}
-
 static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
                           const struct ieee80211_tx_queue_params *params)
 {
@@ -2345,8 +2330,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .config_filter          = rt73usb_config_filter,
        .config_intf            = rt73usb_config_intf,
        .config_erp             = rt73usb_config_erp,
+       .config_ant             = rt73usb_config_ant,
        .config                 = rt73usb_config,
-       .set_retry_limit        = rt73usb_set_retry_limit,
 };
 
 static const struct data_queue_desc rt73usb_queue_rx = {
index 868386c457f65c39c4e15d11ef92cefbebb534a4..46e1405eb0e21ae7d643e5b6d17a011101199d30 100644 (file)
@@ -48,7 +48,9 @@
 #define CSR_REG_SIZE                   0x04b0
 #define EEPROM_BASE                    0x0000
 #define EEPROM_SIZE                    0x0100
+#define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0080
+#define RF_BASE                                0x0000
 #define RF_SIZE                                0x0014
 
 /*
index 6260ed8ce12be08f2e4fbaf03cd391349bb6c144..66add5e77e00763ff8ca9721cc259c18b94c6270 100644 (file)
@@ -152,8 +152,6 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
        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);
-
-       msleep(1);
 }
 
 static void rtl8187_tx_cb(struct urb *urb)
@@ -669,7 +667,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
        rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488);
        rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
-       msleep(1100);
+       msleep(100);
 
        priv->rf->init(dev);
 
@@ -872,7 +870,6 @@ static int rtl8187_config(struct ieee80211_hw *dev, u32 changed)
         */
        rtl818x_iowrite32(priv, &priv->map->TX_CONF,
                          reg | RTL818X_TX_CONF_LOOPBACK_MAC);
-       msleep(10);
        priv->rf->set_chan(dev, conf);
        msleep(10);
        rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
index b999f87ed150d40ce468ab2f82ee16990491f410..69030be62b366fc99f85b980485a08f1e59fca57 100644 (file)
@@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
 
        rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-       msleep(2);
 }
 
 static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
@@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
 
        rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
        rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
-       msleep(2);
 }
 
 static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
@@ -333,21 +331,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
        struct rtl8187_priv *priv = dev->priv;
        int i;
 
-       rtl8225_write(dev, 0x0, 0x067); msleep(1);
-       rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
-       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-       rtl8225_write(dev, 0x3, 0x441); msleep(1);
-       rtl8225_write(dev, 0x4, 0x486); msleep(1);
-       rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
-       rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
-       rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-       rtl8225_write(dev, 0x8, 0x01F); msleep(1);
-       rtl8225_write(dev, 0x9, 0x334); msleep(1);
-       rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
-       rtl8225_write(dev, 0xB, 0x391); msleep(1);
-       rtl8225_write(dev, 0xC, 0x050); msleep(1);
-       rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
-       rtl8225_write(dev, 0xE, 0x029); msleep(1);
+       rtl8225_write(dev, 0x0, 0x067);
+       rtl8225_write(dev, 0x1, 0xFE0);
+       rtl8225_write(dev, 0x2, 0x44D);
+       rtl8225_write(dev, 0x3, 0x441);
+       rtl8225_write(dev, 0x4, 0x486);
+       rtl8225_write(dev, 0x5, 0xBC0);
+       rtl8225_write(dev, 0x6, 0xAE6);
+       rtl8225_write(dev, 0x7, 0x82A);
+       rtl8225_write(dev, 0x8, 0x01F);
+       rtl8225_write(dev, 0x9, 0x334);
+       rtl8225_write(dev, 0xA, 0xFD4);
+       rtl8225_write(dev, 0xB, 0x391);
+       rtl8225_write(dev, 0xC, 0x050);
+       rtl8225_write(dev, 0xD, 0x6DB);
+       rtl8225_write(dev, 0xE, 0x029);
        rtl8225_write(dev, 0xF, 0x914); msleep(100);
 
        rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
@@ -375,91 +373,89 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev)
 
        for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
                rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-               msleep(1);
                rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-               msleep(1);
        }
 
        msleep(1);
 
-       rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+       rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+       rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+       rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+       rtl8225_write_phy_ofdm(dev, 0x0a, 0x09);
+       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
+       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+       rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+       rtl8225_write_phy_ofdm(dev, 0x11, 0x06);
+       rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+       rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x1b, 0x76);
+       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+       rtl8225_write_phy_ofdm(dev, 0x21, 0x27);
+       rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+       rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+       rtl8225_write_phy_ofdm(dev, 0x25, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+       rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
        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); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x00, 0x98);
+       rtl8225_write_phy_cck(dev, 0x03, 0x20);
+       rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+       rtl8225_write_phy_cck(dev, 0x05, 0x12);
+       rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+       rtl8225_write_phy_cck(dev, 0x07, 0x78);
+       rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+       rtl8225_write_phy_cck(dev, 0x11, 0x88);
+       rtl8225_write_phy_cck(dev, 0x12, 0x47);
        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); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+       rtl8225_write_phy_cck(dev, 0x42, 0x15);
+       rtl8225_write_phy_cck(dev, 0x43, 0x18);
+       rtl8225_write_phy_cck(dev, 0x44, 0x1f);
+       rtl8225_write_phy_cck(dev, 0x45, 0x1e);
+       rtl8225_write_phy_cck(dev, 0x46, 0x1a);
+       rtl8225_write_phy_cck(dev, 0x47, 0x15);
+       rtl8225_write_phy_cck(dev, 0x48, 0x10);
+       rtl8225_write_phy_cck(dev, 0x49, 0x0a);
+       rtl8225_write_phy_cck(dev, 0x4a, 0x05);
+       rtl8225_write_phy_cck(dev, 0x4b, 0x02);
+       rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
        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); msleep(1);      /* B: 0xDB */
-       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);     /* B: 0x10 */
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b);                 /* B: 0xDB */
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90);                /* B: 0x10 */
 
        rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);   /* B: 0x00 */
        msleep(1);
@@ -629,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
                rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
 
        rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
-                        rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+                        rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1);
        msleep(1);
 
        rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
@@ -687,22 +683,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
        struct rtl8187_priv *priv = dev->priv;
        int i;
 
-       rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
-       rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-       rtl8225_write(dev, 0x3, 0x441); msleep(1);
-       rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-       rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-       rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-       rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-       rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-       rtl8225_write(dev, 0x9, 0x335); msleep(1);
-       rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-       rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-       rtl8225_write(dev, 0xc, 0x850); msleep(1);
-       rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-       rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-       rtl8225_write(dev, 0xf, 0x114); msleep(100);
+       rtl8225_write(dev, 0x0, 0x2BF);
+       rtl8225_write(dev, 0x1, 0xEE0);
+       rtl8225_write(dev, 0x2, 0x44D);
+       rtl8225_write(dev, 0x3, 0x441);
+       rtl8225_write(dev, 0x4, 0x8C3);
+       rtl8225_write(dev, 0x5, 0xC72);
+       rtl8225_write(dev, 0x6, 0x0E6);
+       rtl8225_write(dev, 0x7, 0x82A);
+       rtl8225_write(dev, 0x8, 0x03F);
+       rtl8225_write(dev, 0x9, 0x335);
+       rtl8225_write(dev, 0xa, 0x9D4);
+       rtl8225_write(dev, 0xb, 0x7BB);
+       rtl8225_write(dev, 0xc, 0x850);
+       rtl8225_write(dev, 0xd, 0xCDF);
+       rtl8225_write(dev, 0xe, 0x02B);
+       rtl8225_write(dev, 0xf, 0x114);
+       msleep(100);
 
        rtl8225_write(dev, 0x0, 0x1B7);
 
@@ -736,94 +733,92 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
 
        for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
                rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
-               msleep(1);
                rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
-               msleep(1);
        }
 
        msleep(1);
 
-       rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x00, 0x01);
+       rtl8225_write_phy_ofdm(dev, 0x01, 0x02);
+       rtl8225_write_phy_ofdm(dev, 0x02, 0x42);
+       rtl8225_write_phy_ofdm(dev, 0x03, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x04, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x05, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x06, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x07, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x08, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x09, 0xfe);
+       rtl8225_write_phy_ofdm(dev, 0x0a, 0x08);
+       rtl8225_write_phy_ofdm(dev, 0x0b, 0x80);
+       rtl8225_write_phy_ofdm(dev, 0x0c, 0x01);
        rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
-       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
-       rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3);
+       rtl8225_write_phy_ofdm(dev, 0x0f, 0x38);
+       rtl8225_write_phy_ofdm(dev, 0x10, 0x84);
+       rtl8225_write_phy_ofdm(dev, 0x11, 0x07);
+       rtl8225_write_phy_ofdm(dev, 0x12, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x13, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x14, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x15, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x16, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x17, 0x40);
+       rtl8225_write_phy_ofdm(dev, 0x18, 0xef);
+       rtl8225_write_phy_ofdm(dev, 0x19, 0x19);
+       rtl8225_write_phy_ofdm(dev, 0x1a, 0x20);
+       rtl8225_write_phy_ofdm(dev, 0x1b, 0x15);
+       rtl8225_write_phy_ofdm(dev, 0x1c, 0x04);
+       rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5);
+       rtl8225_write_phy_ofdm(dev, 0x1e, 0x95);
+       rtl8225_write_phy_ofdm(dev, 0x1f, 0x75);
+       rtl8225_write_phy_ofdm(dev, 0x20, 0x1f);
+       rtl8225_write_phy_ofdm(dev, 0x21, 0x17);
+       rtl8225_write_phy_ofdm(dev, 0x22, 0x16);
+       rtl8225_write_phy_ofdm(dev, 0x23, 0x80);
+       rtl8225_write_phy_ofdm(dev, 0x24, 0x46);
+       rtl8225_write_phy_ofdm(dev, 0x25, 0x00);
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90);
+       rtl8225_write_phy_ofdm(dev, 0x27, 0x88);
 
        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); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x00, 0x98);
+       rtl8225_write_phy_cck(dev, 0x03, 0x20);
+       rtl8225_write_phy_cck(dev, 0x04, 0x7e);
+       rtl8225_write_phy_cck(dev, 0x05, 0x12);
+       rtl8225_write_phy_cck(dev, 0x06, 0xfc);
+       rtl8225_write_phy_cck(dev, 0x07, 0x78);
+       rtl8225_write_phy_cck(dev, 0x08, 0x2e);
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b);
+       rtl8225_write_phy_cck(dev, 0x11, 0x88);
+       rtl8225_write_phy_cck(dev, 0x12, 0x47);
        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); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
-       rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+       rtl8225_write_phy_cck(dev, 0x41, 0x8d);
+       rtl8225_write_phy_cck(dev, 0x42, 0x15);
+       rtl8225_write_phy_cck(dev, 0x43, 0x18);
+       rtl8225_write_phy_cck(dev, 0x44, 0x36);
+       rtl8225_write_phy_cck(dev, 0x45, 0x35);
+       rtl8225_write_phy_cck(dev, 0x46, 0x2e);
+       rtl8225_write_phy_cck(dev, 0x47, 0x25);
+       rtl8225_write_phy_cck(dev, 0x48, 0x1c);
+       rtl8225_write_phy_cck(dev, 0x49, 0x12);
+       rtl8225_write_phy_cck(dev, 0x4a, 0x09);
+       rtl8225_write_phy_cck(dev, 0x4b, 0x04);
+       rtl8225_write_phy_cck(dev, 0x4c, 0x05);
 
        rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
 
        rtl8225z2_rf_set_tx_power(dev, 1);
 
        /* RX antenna default to A */
-       rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);      /* B: 0xDB */
-       rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);     /* B: 0x10 */
+       rtl8225_write_phy_cck(dev, 0x10, 0x9b);                 /* B: 0xDB */
+       rtl8225_write_phy_ofdm(dev, 0x26, 0x90);                /* B: 0x10 */
 
        rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);   /* B: 0x00 */
        msleep(1);
@@ -835,40 +830,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
        struct rtl8187_priv *priv = dev->priv;
        int i;
 
-       rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-       rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
-       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-       rtl8225_write(dev, 0x3, 0x441); msleep(1);
-       rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
-       rtl8225_write(dev, 0x5, 0xC72); msleep(1);
-       rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
-       rtl8225_write(dev, 0x7, 0x82A); msleep(1);
-       rtl8225_write(dev, 0x8, 0x03F); msleep(1);
-       rtl8225_write(dev, 0x9, 0x335); msleep(1);
-       rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
-       rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
-       rtl8225_write(dev, 0xc, 0x850); msleep(1);
-       rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
-       rtl8225_write(dev, 0xe, 0x02B); msleep(1);
-       rtl8225_write(dev, 0xf, 0x114); msleep(1);
-
-       rtl8225_write(dev, 0x0, 0x1B7); msleep(1);
+       rtl8225_write(dev, 0x0, 0x0B7);
+       rtl8225_write(dev, 0x1, 0xEE0);
+       rtl8225_write(dev, 0x2, 0x44D);
+       rtl8225_write(dev, 0x3, 0x441);
+       rtl8225_write(dev, 0x4, 0x8C3);
+       rtl8225_write(dev, 0x5, 0xC72);
+       rtl8225_write(dev, 0x6, 0x0E6);
+       rtl8225_write(dev, 0x7, 0x82A);
+       rtl8225_write(dev, 0x8, 0x03F);
+       rtl8225_write(dev, 0x9, 0x335);
+       rtl8225_write(dev, 0xa, 0x9D4);
+       rtl8225_write(dev, 0xb, 0x7BB);
+       rtl8225_write(dev, 0xc, 0x850);
+       rtl8225_write(dev, 0xd, 0xCDF);
+       rtl8225_write(dev, 0xe, 0x02B);
+       rtl8225_write(dev, 0xf, 0x114);
+
+       rtl8225_write(dev, 0x0, 0x1B7);
 
        for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
-               rtl8225_write(dev, 0x1, i + 1); msleep(1);
-               rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1);
+               rtl8225_write(dev, 0x1, i + 1);
+               rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
        }
 
-       rtl8225_write(dev, 0x3, 0x080); msleep(1);
-       rtl8225_write(dev, 0x5, 0x004); msleep(1);
-       rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
-       msleep(3000);
+       rtl8225_write(dev, 0x3, 0x080);
+       rtl8225_write(dev, 0x5, 0x004);
+       rtl8225_write(dev, 0x0, 0x0B7);
 
-       rtl8225_write(dev, 0x2, 0xC4D); msleep(1);
-       msleep(2000);
+       rtl8225_write(dev, 0x2, 0xC4D);
 
-       rtl8225_write(dev, 0x2, 0x44D); msleep(1);
-       rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+       rtl8225_write(dev, 0x2, 0x44D);
+       rtl8225_write(dev, 0x0, 0x2BF);
 
        rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03);
        rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07);
@@ -891,10 +884,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev)
        rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28);
        rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0);
 
-       rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1);
-       rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1);
-       rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1);
+       rtl8225_write_phy_ofdm(dev, 0x97, 0x46);
+       rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6);
+       rtl8225_write_phy_ofdm(dev, 0x85, 0xfc);
+       rtl8225_write_phy_cck(dev, 0xc1, 0x88);
 }
 
 static void rtl8225_rf_stop(struct ieee80211_hw *dev)
@@ -902,7 +895,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
        u8 reg;
        struct rtl8187_priv *priv = dev->priv;
 
-       rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+       rtl8225_write(dev, 0x4, 0x1f);
 
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
deleted file mode 100644 (file)
index 852789a..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
- * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
- * Communications and Intel PRO/Wireless 2011B.
- *
- * The driver implements Symbol firmware download.  The rest is handled
- * in hermes.c and orinoco.c.
- *
- * Utilities for downloading the Symbol firmware are available at
- * http://sourceforge.net/projects/orinoco/
- *
- * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
- * Portions based on orinoco_cs.c:
- *     Copyright (C) David Gibson, Linuxcare Australia
- * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
- *     Copyright (C) Symbol Technologies.
- *
- * See copyright notice in file orinoco.c.
- */
-
-#define DRIVER_NAME "spectrum_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff                                                            */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
-MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures                                                 */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
-       struct pcmcia_device    *p_dev;
-       dev_node_t node;
-};
-
-/********************************************************************/
-/* Function prototypes                                             */
-/********************************************************************/
-
-static int spectrum_cs_config(struct pcmcia_device *link);
-static void spectrum_cs_release(struct pcmcia_device *link);
-
-/* Constants for the CISREG_CCSR register */
-#define HCR_RUN                0x07    /* run firmware after reset */
-#define HCR_IDLE       0x0E    /* don't run firmware after reset */
-#define HCR_MEM16      0x10    /* memory width bit, should be preserved */
-
-
-#define CS_CHECK(fn, ret) \
-  do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
-/*
- * Reset the card using configuration registers COR and CCSR.
- * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
- */
-static int
-spectrum_reset(struct pcmcia_device *link, int idle)
-{
-       int last_ret, last_fn;
-       conf_reg_t reg;
-       u_int save_cor;
-
-       /* Doing it if hardware is gone is guaranteed crash */
-       if (!pcmcia_dev_present(link))
-               return -ENODEV;
-
-       /* Save original COR value */
-       reg.Function = 0;
-       reg.Action = CS_READ;
-       reg.Offset = CISREG_COR;
-       CS_CHECK(AccessConfigurationRegister,
-                pcmcia_access_configuration_register(link, &reg));
-       save_cor = reg.Value;
-
-       /* Soft-Reset card */
-       reg.Action = CS_WRITE;
-       reg.Offset = CISREG_COR;
-       reg.Value = (save_cor | COR_SOFT_RESET);
-       CS_CHECK(AccessConfigurationRegister,
-                pcmcia_access_configuration_register(link, &reg));
-       udelay(1000);
-
-       /* Read CCSR */
-       reg.Action = CS_READ;
-       reg.Offset = CISREG_CCSR;
-       CS_CHECK(AccessConfigurationRegister,
-                pcmcia_access_configuration_register(link, &reg));
-
-       /*
-        * Start or stop the firmware.  Memory width bit should be
-        * preserved from the value we've just read.
-        */
-       reg.Action = CS_WRITE;
-       reg.Offset = CISREG_CCSR;
-       reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16);
-       CS_CHECK(AccessConfigurationRegister,
-                pcmcia_access_configuration_register(link, &reg));
-       udelay(1000);
-
-       /* Restore original COR configuration index */
-       reg.Action = CS_WRITE;
-       reg.Offset = CISREG_COR;
-       reg.Value = (save_cor & ~COR_SOFT_RESET);
-       CS_CHECK(AccessConfigurationRegister,
-                pcmcia_access_configuration_register(link, &reg));
-       udelay(1000);
-       return 0;
-
-      cs_failed:
-       cs_error(link, last_fn, last_ret);
-       return -ENODEV;
-}
-
-/********************************************************************/
-/* Device methods                                                  */
-/********************************************************************/
-
-static int
-spectrum_cs_hard_reset(struct orinoco_private *priv)
-{
-       struct orinoco_pccard *card = priv->card;
-       struct pcmcia_device *link = card->p_dev;
-
-       /* Soft reset using COR and HCR */
-       spectrum_reset(link, 0);
-
-       return 0;
-}
-
-static int
-spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
-{
-       struct orinoco_pccard *card = priv->card;
-       struct pcmcia_device *link = card->p_dev;
-
-       return spectrum_reset(link, idle);
-}
-
-/********************************************************************/
-/* PCMCIA stuff                                                    */
-/********************************************************************/
-
-/*
- * This 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
-spectrum_cs_probe(struct pcmcia_device *link)
-{
-       struct net_device *dev;
-       struct orinoco_private *priv;
-       struct orinoco_pccard *card;
-
-       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
-                              spectrum_cs_hard_reset,
-                              spectrum_cs_stop_firmware);
-       if (! dev)
-               return -ENOMEM;
-       priv = netdev_priv(dev);
-       card = priv->card;
-
-       /* Link both structures together */
-       card->p_dev = link;
-       link->priv = dev;
-
-       /* Interrupt setup */
-       link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
-       link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-       link->irq.Handler = orinoco_interrupt;
-       link->irq.Instance = dev; 
-
-       /* General socket configuration defaults can go here.  In this
-        * client, we assume very little, and rely on the CIS for
-        * almost everything.  In most clients, many details (i.e.,
-        * number, sizes, and attributes of IO windows) are fixed by
-        * the nature of the device, and can be hard-wired here. */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
-       return spectrum_cs_config(link);
-}                              /* spectrum_cs_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 spectrum_cs_detach(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-
-       if (link->dev_node)
-               unregister_netdev(dev);
-
-       spectrum_cs_release(link);
-
-       free_orinocodev(dev);
-}                              /* spectrum_cs_detach */
-
-/*
- * spectrum_cs_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.
- */
-
-static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
-                                   cistpl_cftable_entry_t *cfg,
-                                   cistpl_cftable_entry_t *dflt,
-                                   unsigned int vcc,
-                                   void *priv_data)
-{
-       if (cfg->index == 0)
-               goto next_entry;
-
-       /* Use power settings for Vcc and Vpp if present */
-       /* Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n",  vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       }
-
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-               if (!(io->flags & CISTPL_IO_8BIT))
-                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-               if (!(io->flags & CISTPL_IO_16BIT))
-                       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-               p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->io.BasePort1 = io->win[0].base;
-               p_dev->io.NumPorts1 = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->io.Attributes2 = p_dev->io.Attributes1;
-                       p_dev->io.BasePort2 = io->win[1].base;
-                       p_dev->io.NumPorts2 = io->win[1].len;
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev, &p_dev->io) != 0)
-                       goto next_entry;
-       }
-       return 0;
-
-next_entry:
-       pcmcia_disable_device(p_dev);
-       return -ENODEV;
-};
-
-static int
-spectrum_cs_config(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       struct orinoco_pccard *card = priv->card;
-       hermes_t *hw = &priv->hw;
-       int last_fn, last_ret;
-       void __iomem *mem;
-
-       /*
-        * 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 and accurate CIS.  In practice, a driver usually
-        * "knows" most of these things without consulting the CIS,
-        * and most client drivers will only use the CIS to fill in
-        * implementation-defined details.
-        */
-       last_ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
-       if (last_ret) {
-               if (!ignore_cis_vcc)
-                       printk(KERN_ERR PFX "GetNextTuple(): No matching "
-                              "CIS configuration.  Maybe you need the "
-                              "ignore_cis_vcc=1 parameter.\n");
-               cs_error(link, RequestIO, last_ret);
-               goto failed;
-       }
-
-       /*
-        * Allocate an interrupt line.  Note that this does not assign
-        * a handler to the interrupt, unless the 'Handler' member of
-        * the irq structure is initialized.
-        */
-       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-
-       /* We initialize the hermes structure before completing PCMCIA
-        * configuration just in case the interrupt handler gets
-        * called. */
-       mem = ioport_map(link->io.BasePort1, link->io.NumPorts1);
-       if (!mem)
-               goto cs_failed;
-
-       hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
-
-       /*
-        * 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));
-
-       /* Ok, we have the configuration, prepare to register the netdev */
-       dev->base_addr = link->io.BasePort1;
-       dev->irq = link->irq.AssignedIRQ;
-       card->node.major = card->node.minor = 0;
-
-       /* Reset card */
-       if (spectrum_cs_hard_reset(priv) != 0) {
-               goto failed;
-       }
-
-       SET_NETDEV_DEV(dev, &handle_to_dev(link));
-       /* Tell the stack we exist */
-       if (register_netdev(dev) != 0) {
-               printk(KERN_ERR PFX "register_netdev() failed\n");
-               goto failed;
-       }
-
-       /* At this point, the dev_node_t structure(s) needs to be
-        * initialized and arranged in a linked list at link->dev_node. */
-       strcpy(card->node.dev_name, dev->name);
-       link->dev_node = &card->node; /* link->dev_node being non-NULL is also
-                                    used to indicate that the
-                                    net_device has been registered */
-
-       /* Finally, report what we've done */
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
-              link->irq.AssignedIRQ, link->io.BasePort1,
-              link->io.BasePort1 + link->io.NumPorts1 - 1);
-
-       return 0;
-
- cs_failed:
-       cs_error(link, last_fn, last_ret);
-
- failed:
-       spectrum_cs_release(link);
-       return -ENODEV;
-}                              /* spectrum_cs_config */
-
-/*
- * After a card is removed, spectrum_cs_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
-spectrum_cs_release(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* We're committed to taking the device away now, so mark the
-        * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       pcmcia_disable_device(link);
-       if (priv->hw.iobase)
-               ioport_unmap(priv->hw.iobase);
-}                              /* spectrum_cs_release */
-
-
-static int
-spectrum_cs_suspend(struct pcmcia_device *link)
-{
-       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);
-
-       err = __orinoco_down(dev);
-       if (err)
-               printk(KERN_WARNING "%s: Error %d downing interface\n",
-                      dev->name, err);
-
-       netif_device_detach(dev);
-       priv->hw_unavailable++;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return err;
-}
-
-static int
-spectrum_cs_resume(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct orinoco_private *priv = netdev_priv(dev);
-
-       netif_device_attach(dev);
-       priv->hw_unavailable--;
-       schedule_work(&priv->reset_work);
-
-       return 0;
-}
-
-
-/********************************************************************/
-/* Module initialization                                           */
-/********************************************************************/
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Pavel Roskin <proski@gnu.org>,"
-       " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
-
-static struct pcmcia_device_id spectrum_cs_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
-       PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
-       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
-       .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = DRIVER_NAME,
-       },
-       .probe          = spectrum_cs_probe,
-       .remove         = spectrum_cs_detach,
-       .suspend        = spectrum_cs_suspend,
-       .resume         = spectrum_cs_resume,
-       .id_table       = spectrum_cs_ids,
-};
-
-static int __init
-init_spectrum_cs(void)
-{
-       printk(KERN_DEBUG "%s\n", version);
-
-       return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_spectrum_cs(void)
-{
-       pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_spectrum_cs);
-module_exit(exit_spectrum_cs);
index 65ceb088f7000c9e06b371605857302d59beeeff..59bb3a55ab48c82838da43c1545d9863560bf572 100644 (file)
@@ -2,7 +2,7 @@
 #define __WL3501_H__
 
 #include <linux/spinlock.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 
 /* define for WLA 2.0 */
 #define WL3501_BLKSZ 256
@@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr {
 
 struct wl3501_80211_tx_hdr {
        struct wl3501_80211_tx_plcp_hdr pclp_hdr;
-       struct ieee80211_hdr_4addr              mac_hdr;
+       struct ieee80211_hdr            mac_hdr;
 } __attribute__ ((packed));
 
 /*
index bf744c1f5b232102a66e38150260ddbed9be404b..1134e2fb18902bd0a80444fd4ee7b3427157e496 100644 (file)
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/ieee80211.h>
 #include <net/iw_handler.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
 #include <linux/firmware.h>
-#include <net/ieee80211.h>
 #include "zd1201.h"
 
 static struct usb_device_id zd1201_table[] = {
@@ -345,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb)
                                frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
                                if (!frag)
                                        goto resubmit;
-                               skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2);
+                               skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
                                if (!skb) {
                                        kfree(frag);
                                        goto resubmit;
index aad99195a4cc6f839c7cd40e7c0fc1853937fd08..56b0eb25d9276a6600e5898682fddcad85d994d3 100644 (file)
 #define IEEE80211_MAX_FRAME_LEN                2352
 
 #define IEEE80211_MAX_SSID_LEN         32
+
 #define IEEE80211_MAX_MESH_ID_LEN      32
+#define IEEE80211_MESH_CONFIG_LEN      19
+
 #define IEEE80211_QOS_CTL_LEN          2
 #define IEEE80211_QOS_CTL_TID_MASK     0x000F
 #define IEEE80211_QOS_CTL_TAG1D_MASK   0x0007
@@ -666,6 +669,13 @@ struct ieee80211_cts {
        u8 ra[6];
 } __attribute__ ((packed));
 
+struct ieee80211_pspoll {
+       __le16 frame_control;
+       __le16 aid;
+       u8 bssid[6];
+       u8 ta[6];
+} __attribute__ ((packed));
+
 /**
  * struct ieee80211_bar - HT Block Ack Request
  *
index e4cc7869b22f0b2ebf76a023dd6ca20c20b4c398..79827345351d061439b1154a44c1da8d6354ea7d 100644 (file)
@@ -25,8 +25,9 @@
  *
  * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
  *     to get a list of all present wiphys.
- * @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and
- *     %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ *     %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
+ *     and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
  * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
  *     or rename notification. Has attributes %NL80211_ATTR_WIPHY and
  *     %NL80211_ATTR_WIPHY_NAME.
@@ -178,6 +179,7 @@ enum nl80211_commands {
  * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
  *     /sys/class/ieee80211/<phyname>/index
  * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
  *
  * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
  * @NL80211_ATTR_IFNAME: network interface name
@@ -243,6 +245,9 @@ enum nl80211_commands {
  *     (u8, 0 or 1)
  * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
  *     (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ *     rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ *     restriction (at most %NL80211_MAX_SUPP_RATES).
  *
  * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
  *     association request when used with NL80211_CMD_NEW_STATION)
@@ -307,6 +312,10 @@ enum nl80211_attrs {
 
        NL80211_ATTR_MESH_PARAMS,
 
+       NL80211_ATTR_BSS_BASIC_RATES,
+
+       NL80211_ATTR_WIPHY_TXQ_PARAMS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -318,6 +327,8 @@ enum nl80211_attrs {
  * here
  */
 #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -692,4 +703,38 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ *     disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ *     2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ *     2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+       __NL80211_TXQ_ATTR_INVALID,
+       NL80211_TXQ_ATTR_QUEUE,
+       NL80211_TXQ_ATTR_TXOP,
+       NL80211_TXQ_ATTR_CWMIN,
+       NL80211_TXQ_ATTR_CWMAX,
+       NL80211_TXQ_ATTR_AIFS,
+
+       /* keep last */
+       __NL80211_TXQ_ATTR_AFTER_LAST,
+       NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+       NL80211_TXQ_Q_VO,
+       NL80211_TXQ_Q_VI,
+       NL80211_TXQ_Q_BE,
+       NL80211_TXQ_Q_BK
+};
+
 #endif /* __LINUX_NL80211_H */
index 03e1e88c6a099972b556ed03d79fb761618ebcaf..1d57835d73f2d3d7c262c643a41e2b571f49fe4f 100644 (file)
@@ -280,11 +280,16 @@ struct mpath_info {
  *     (0 = no, 1 = yes, -1 = do not change)
  * @use_short_slot_time: Whether the use of short slot time is allowed
  *     (0 = no, 1 = yes, -1 = do not change)
+ * @basic_rates: basic rates in IEEE 802.11 format
+ *     (or NULL for no change)
+ * @basic_rates_len: number of basic rates
  */
 struct bss_parameters {
        int use_cts_prot;
        int use_short_preamble;
        int use_short_slot_time;
+       u8 *basic_rates;
+       u8 basic_rates_len;
 };
 
 /**
@@ -331,19 +336,19 @@ struct ieee80211_regdomain {
        struct ieee80211_reg_rule reg_rules[];
 };
 
-#define MHZ_TO_KHZ(freq) (freq * 1000)
-#define KHZ_TO_MHZ(freq) (freq / 1000)
-#define DBI_TO_MBI(gain) (gain * 100)
-#define MBI_TO_DBI(gain) (gain / 100)
-#define DBM_TO_MBM(gain) (gain * 100)
-#define MBM_TO_DBM(gain) (gain / 100)
+#define MHZ_TO_KHZ(freq) ((freq) * 1000)
+#define KHZ_TO_MHZ(freq) ((freq) / 1000)
+#define DBI_TO_MBI(gain) ((gain) * 100)
+#define MBI_TO_DBI(gain) ((gain) / 100)
+#define DBM_TO_MBM(gain) ((gain) * 100)
+#define MBM_TO_DBM(gain) ((gain) / 100)
 
 #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \
-       .freq_range.start_freq_khz = (start) * 1000, \
-       .freq_range.end_freq_khz = (end) * 1000, \
-       .freq_range.max_bandwidth_khz = (bw) * 1000, \
-       .power_rule.max_antenna_gain = (gain) * 100, \
-       .power_rule.max_eirp = (eirp) * 100, \
+       .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
+       .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
+       .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
+       .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \
+       .power_rule.max_eirp = DBM_TO_MBM(eirp), \
        .flags = reg_flags, \
        }
 
@@ -366,6 +371,24 @@ struct mesh_config {
        u16 dot11MeshHWMPnetDiameterTraversalTime;
 };
 
+/**
+ * struct ieee80211_txq_params - TX queue parameters
+ * @queue: TX queue identifier (NL80211_TXQ_Q_*)
+ * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled
+ * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range
+ *     1..32767]
+ * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range
+ *     1..32767]
+ * @aifs: Arbitration interframe space [0..255]
+ */
+struct ieee80211_txq_params {
+       enum nl80211_txq_q queue;
+       u16 txop;
+       u16 cwmin;
+       u16 cwmax;
+       u8 aifs;
+};
+
 /* from net/wireless.h */
 struct wiphy;
 
@@ -425,6 +448,8 @@ struct wiphy;
  * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
  *
  * @change_bss: Modify parameters for a given BSS.
+ *
+ * @set_txq_params: Set TX queue parameters
  */
 struct cfg80211_ops {
        int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -485,6 +510,9 @@ struct cfg80211_ops {
                                const struct mesh_config *nconf, u32 mask);
        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                              struct bss_parameters *params);
+
+       int     (*set_txq_params)(struct wiphy *wiphy,
+                                 struct ieee80211_txq_params *params);
 };
 
 #endif /* __NET_CFG80211_H */
index 0b983bed3829bda243c68a8e5ade585c92f806df..53856003aa183993761e8856cf344329ef11d97e 100644 (file)
@@ -616,14 +616,12 @@ struct ieee80211_if_init_conf {
  * enum ieee80211_if_conf_change - interface config change flags
  *
  * @IEEE80211_IFCC_BSSID: The BSSID changed.
- * @IEEE80211_IFCC_SSID: The SSID changed.
  * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
  *     (currently AP and MESH only), use ieee80211_beacon_get().
  */
 enum ieee80211_if_conf_change {
        IEEE80211_IFCC_BSSID    = BIT(0),
-       IEEE80211_IFCC_SSID     = BIT(1),
-       IEEE80211_IFCC_BEACON   = BIT(2),
+       IEEE80211_IFCC_BEACON   = BIT(1),
 };
 
 /**
@@ -631,11 +629,6 @@ enum ieee80211_if_conf_change {
  *
  * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
  * @bssid: BSSID of the network we are associated to/creating.
- * @ssid: used (together with @ssid_len) by drivers for hardware that
- *     generate beacons independently. The pointer is valid only during the
- *     config_interface() call, so copy the value somewhere if you need
- *     it.
- * @ssid_len: length of the @ssid field.
  *
  * This structure is passed to the config_interface() callback of
  * &struct ieee80211_hw.
@@ -643,8 +636,6 @@ enum ieee80211_if_conf_change {
 struct ieee80211_if_conf {
        u32 changed;
        u8 *bssid;
-       u8 *ssid;
-       size_t ssid_len;
 };
 
 /**
@@ -1136,12 +1127,14 @@ enum ieee80211_filter_flags {
  * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation
  * @IEEE80211_AMPDU_TX_START: start Tx aggregation
  * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation
+ * @IEEE80211_AMPDU_TX_RESUME: resume TX aggregation
  */
 enum ieee80211_ampdu_mlme_action {
        IEEE80211_AMPDU_RX_START,
        IEEE80211_AMPDU_RX_STOP,
        IEEE80211_AMPDU_TX_START,
        IEEE80211_AMPDU_TX_STOP,
+       IEEE80211_AMPDU_TX_RESUME,
 };
 
 /**
index 41294c5f6f8ffc9a7db3b046dc191c738bae4528..17d4b582cf346a9370dbbb1fb99c37173e33c69a 100644 (file)
@@ -340,6 +340,22 @@ ieee80211_get_channel(struct wiphy *wiphy, int freq)
        return __ieee80211_get_channel(wiphy, freq);
 }
 
+/**
+ * ieee80211_get_response_rate - get basic rate for a given rate
+ *
+ * @sband: the band to look for rates in
+ * @basic_rates: bitmap of basic rates
+ * @bitrate: the bitrate for which to find the basic rate
+ *
+ * This function returns the basic rate corresponding to a given
+ * bitrate, that is the next lower bitrate contained in the basic
+ * rate map, which is, for this function, given as a bitmap of
+ * indices of rates in the band's bitrate table.
+ */
+struct ieee80211_rate *
+ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
+                           u64 basic_rates, int bitrate);
+
 /**
  * regulatory_hint - driver hint to the wireless core a regulatory domain
  * @wiphy: the wireless device giving the hint (used only for reporting
index 29eb41695a82f1745898c94b4356a0bb742a4092..7cc4e5ee3660faf47c978ed014ac06a5472131d4 100644 (file)
@@ -399,6 +399,10 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
 
        /* If a new key was provided, set it up */
        if (erq->length > 0) {
+#ifdef CONFIG_IEEE80211_DEBUG
+               DECLARE_SSID_BUF(ssid);
+#endif
+
                len = erq->length <= 5 ? 5 : 13;
                memcpy(sec.keys[key], keybuf, erq->length);
                if (len > erq->length)
index 91f56a48e2b46c29fc6fe28752fe6975633cd175..16423f94801bb3a9154e294fa9e95d8602f1806a 100644 (file)
@@ -26,6 +26,8 @@ static bool nl80211_type_check(enum nl80211_iftype type)
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
 #endif
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_WDS:
                return true;
        default:
@@ -1046,11 +1048,53 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                changed |= BSS_CHANGED_ERP_SLOT;
        }
 
+       if (params->basic_rates) {
+               int i, j;
+               u32 rates = 0;
+               struct ieee80211_local *local = wiphy_priv(wiphy);
+               struct ieee80211_supported_band *sband =
+                       wiphy->bands[local->oper_channel->band];
+
+               for (i = 0; i < params->basic_rates_len; i++) {
+                       int rate = (params->basic_rates[i] & 0x7f) * 5;
+                       for (j = 0; j < sband->n_bitrates; j++) {
+                               if (sband->bitrates[j].bitrate == rate)
+                                       rates |= BIT(j);
+                       }
+               }
+               sdata->vif.bss_conf.basic_rates = rates;
+               changed |= BSS_CHANGED_BASIC_RATES;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        return 0;
 }
 
+static int ieee80211_set_txq_params(struct wiphy *wiphy,
+                                   struct ieee80211_txq_params *params)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_tx_queue_params p;
+
+       if (!local->ops->conf_tx)
+               return -EOPNOTSUPP;
+
+       memset(&p, 0, sizeof(p));
+       p.aifs = params->aifs;
+       p.cw_max = params->cwmax;
+       p.cw_min = params->cwmin;
+       p.txop = params->txop;
+       if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) {
+               printk(KERN_DEBUG "%s: failed to set TX queue "
+                      "parameters for queue %d\n", local->mdev->name,
+                      params->queue);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -1077,4 +1121,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .get_mesh_params = ieee80211_get_mesh_params,
 #endif
        .change_bss = ieee80211_change_bss,
+       .set_txq_params = ieee80211_set_txq_params,
 };
index 08009d4b7d6ef1d86adb08e05b9790f390facad4..3e231d7567768355f55f89c4cf82e48f1d92bcab 100644 (file)
@@ -987,7 +987,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 {
        struct ieee80211_hw *hw = &local->hw;
        u16 capab;
-       u16 tid;
+       u16 tid, start_seq_num;
        u8 *state;
 
        capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
@@ -1024,6 +1024,14 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
                    local->hw.ampdu_queues)
                        ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
 
+               if (local->ops->ampdu_action) {
+                       (void)local->ops->ampdu_action(hw,
+                                              IEEE80211_AMPDU_TX_RESUME,
+                                              &sta->sta, tid, &start_seq_num);
+               }
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
                spin_unlock_bh(&sta->lock);
        } else {
                sta->ampdu_mlme.addba_req_num[tid]++;
index 2c91108e3901d1c89e751e018f7894cf93b93bdd..155a20410017661e60436712019f0b114a5abf83 100644 (file)
@@ -212,9 +212,6 @@ struct ieee80211_if_ap {
 
        struct list_head vlans;
 
-       u8 ssid[IEEE80211_MAX_SSID_LEN];
-       size_t ssid_len;
-
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
         * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
index fa0cc7a1e6b4b7146356cc49fab39733dac463f8..d631dc96c3231a0de2f9ed9ad36329edc330e687 100644 (file)
@@ -171,19 +171,13 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
        conf.changed = changed;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+           sdata->vif.type == NL80211_IFTYPE_ADHOC)
                conf.bssid = sdata->u.sta.bssid;
-               conf.ssid = sdata->u.sta.ssid;
-               conf.ssid_len = sdata->u.sta.ssid_len;
-       } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+       else if (sdata->vif.type == NL80211_IFTYPE_AP)
                conf.bssid = sdata->dev->dev_addr;
-               conf.ssid = sdata->u.ap.ssid;
-               conf.ssid_len = sdata->u.ap.ssid_len;
-       } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+       else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                u8 zero[ETH_ALEN] = { 0 };
                conf.bssid = zero;
-               conf.ssid = zero;
-               conf.ssid_len = 0;
        } else {
                WARN_ON(1);
                return -EINVAL;
@@ -192,9 +186,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
        if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
                return -EINVAL;
 
-       if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
-               return -EINVAL;
-
        return local->ops->config_interface(local_to_hw(local),
                                            &sdata->vif, &conf);
 }
index d3b6e1a648bd1ba9fa50904fc6b58c7ffd6ff41d..82f568e943657c2c5114ef111f57e53292011edc 100644 (file)
@@ -238,7 +238,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
 
        pos = skb_put(skb, 21);
        *pos++ = WLAN_EID_MESH_CONFIG;
-       *pos++ = MESH_CFG_LEN;
+       *pos++ = IEEE80211_MESH_CONFIG_LEN;
        /* Version */
        *pos++ = 1;
 
index e10471c6ba42457894ebca93db6a7f8c9376323f..c197ab545e54a05e56b46f946d1d2bb8e3f5e5e9 100644 (file)
@@ -145,9 +145,6 @@ struct mesh_rmc {
 };
 
 
-/* Mesh IEs constants */
-#define MESH_CFG_LEN           19
-
 /*
  * MESH_CFG_COMP_LEN Includes:
  *     - Active path selection protocol ID.
@@ -157,7 +154,7 @@ struct mesh_rmc {
  * Does not include mesh capabilities, which may vary across nodes in the same
  * mesh
  */
-#define MESH_CFG_CMP_LEN       17
+#define MESH_CFG_CMP_LEN       (IEEE80211_MESH_CONFIG_LEN - 2)
 
 /* Default values, timeouts in ms */
 #define MESH_TTL               5
index 29fafbe440b7888c7190c3f73645258b635f7a3e..dee6448c4eb0879a1c4d2f2853d34d03e8ff248b 100644 (file)
@@ -1123,7 +1123,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
        if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
-               printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name);
+               printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
+                               sdata->dev->name, reason_code);
 
        if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
            ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
@@ -1154,7 +1155,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
        if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
-               printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name);
+               printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+                               sdata->dev->name, reason_code);
 
        if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
                ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
@@ -1289,29 +1291,35 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        for (i = 0; i < elems.supp_rates_len; i++) {
                int rate = (elems.supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
                if (rate > 110)
                        have_higher_than_11mbit = true;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate)
+                       if (sband->bitrates[j].bitrate == rate) {
                                rates |= BIT(j);
-                       if (elems.supp_rates[i] & 0x80)
-                               basic_rates |= BIT(j);
+                               if (is_basic)
+                                       basic_rates |= BIT(j);
+                               break;
+                       }
                }
        }
 
        for (i = 0; i < elems.ext_supp_rates_len; i++) {
                int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(elems.supp_rates[i] & 0x80);
 
                if (rate > 110)
                        have_higher_than_11mbit = true;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate)
+                       if (sband->bitrates[j].bitrate == rate) {
                                rates |= BIT(j);
-                       if (elems.ext_supp_rates[i] & 0x80)
-                               basic_rates |= BIT(j);
+                               if (is_basic)
+                                       basic_rates |= BIT(j);
+                               break;
+                       }
                }
        }
 
@@ -2414,7 +2422,6 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
 int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
 {
        struct ieee80211_if_sta *ifsta;
-       int res;
 
        if (len > IEEE80211_MAX_SSID_LEN)
                return -EINVAL;
@@ -2426,19 +2433,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size
                memcpy(ifsta->ssid, ssid, len);
                ifsta->ssid_len = len;
                ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-
-               res = 0;
-               /*
-                * Hack! MLME code needs to be cleaned up to have different
-                * entry points for configuration and internal selection change
-                */
-               if (netif_running(sdata->dev))
-                       res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
-               if (res) {
-                       printk(KERN_DEBUG "%s: Failed to config new SSID to "
-                              "the low-level driver\n", sdata->dev->name);
-                       return res;
-               }
        }
 
        if (len)
index c643e373fc50fde1d82b7acec7a330762e7ab7c4..2b3b490a6073467755e3b83998d1480398864148 100644 (file)
@@ -225,7 +225,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi)
        return sample_ndx;
 }
 
-void
+static void
 minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                  void *priv_sta, struct ieee80211_tx_rate_control *txrc)
 {
index 7372d7abb8c0ecc439bb5a076640d1168e65947f..f5c7c3371929a5c41651bcbefa45771149b5c2d4 100644 (file)
@@ -159,7 +159,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i
 {
        struct ieee80211_bss *bss;
 
-       if (mesh_config_len != MESH_CFG_LEN)
+       if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN)
                return NULL;
 
        bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
index d6392af9cd20f3f94cce26372c67a226acfeec54..0d81b2cfd1a6d7cbcca80a1d1b3a31dbbdc0ba26 100644 (file)
@@ -698,7 +698,6 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
        left = payload_len - per_fragm;
        for (i = 0; i < num_fragm - 1; i++) {
                struct ieee80211_hdr *fhdr;
-               struct ieee80211_tx_info *info;
                size_t copylen;
 
                if (left <= 0)
index 231cab57351f11b9b4674b6a401955902d66f973..63f36e9d1af8714f82ea8f6d9ba503ad5c9179d4 100644 (file)
@@ -407,13 +407,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
                return 0;
        }
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP) {
-               memcpy(sdata->u.ap.ssid, ssid, len);
-               memset(sdata->u.ap.ssid + len, 0,
-                      IEEE80211_MAX_SSID_LEN - len);
-               sdata->u.ap.ssid_len = len;
-               return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
-       }
        return -EOPNOTSUPP;
 }
 
@@ -437,15 +430,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
                return res;
        }
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP) {
-               len = sdata->u.ap.ssid_len;
-               if (len > IW_ESSID_MAX_SIZE)
-                       len = IW_ESSID_MAX_SIZE;
-               memcpy(ssid, sdata->u.ap.ssid, len);
-               data->length = len;
-               data->flags = 1;
-               return 0;
-       }
        return -EOPNOTSUPP;
 }
 
index 5e1d658a8b5a2d26b11b629543412b9e4ecb1743..e3e1494e769a43c97c9b414665d00af15c05262f 100644 (file)
@@ -58,6 +58,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
                                      .len = BUS_ID_SIZE-1 },
+       [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
 
        [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
        [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -95,6 +96,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
        [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
        [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
+       [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
+                                          .len = NL80211_MAX_SUPP_RATES },
 
        [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED },
 
@@ -284,20 +287,76 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
        return -ENOBUFS;
 }
 
+static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
+       [NL80211_TXQ_ATTR_QUEUE]                = { .type = NLA_U8 },
+       [NL80211_TXQ_ATTR_TXOP]                 = { .type = NLA_U16 },
+       [NL80211_TXQ_ATTR_CWMIN]                = { .type = NLA_U16 },
+       [NL80211_TXQ_ATTR_CWMAX]                = { .type = NLA_U16 },
+       [NL80211_TXQ_ATTR_AIFS]                 = { .type = NLA_U8 },
+};
+
+static int parse_txq_params(struct nlattr *tb[],
+                           struct ieee80211_txq_params *txq_params)
+{
+       if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] ||
+           !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] ||
+           !tb[NL80211_TXQ_ATTR_AIFS])
+               return -EINVAL;
+
+       txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]);
+       txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]);
+       txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]);
+       txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]);
+       txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]);
+
+       return 0;
+}
+
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
-       int result;
-
-       if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
-               return -EINVAL;
+       int result = 0, rem_txq_params = 0;
+       struct nlattr *nl_txq_params;
 
        rdev = cfg80211_get_dev_from_info(info);
        if (IS_ERR(rdev))
                return PTR_ERR(rdev);
 
-       result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
+       if (info->attrs[NL80211_ATTR_WIPHY_NAME]) {
+               result = cfg80211_dev_rename(
+                       rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
+               if (result)
+                       goto bad_res;
+       }
+
+       if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
+               struct ieee80211_txq_params txq_params;
+               struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
+
+               if (!rdev->ops->set_txq_params) {
+                       result = -EOPNOTSUPP;
+                       goto bad_res;
+               }
 
+               nla_for_each_nested(nl_txq_params,
+                                   info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
+                                   rem_txq_params) {
+                       nla_parse(tb, NL80211_TXQ_ATTR_MAX,
+                                 nla_data(nl_txq_params),
+                                 nla_len(nl_txq_params),
+                                 txq_params_policy);
+                       result = parse_txq_params(tb, &txq_params);
+                       if (result)
+                               goto bad_res;
+
+                       result = rdev->ops->set_txq_params(&rdev->wiphy,
+                                                          &txq_params);
+                       if (result)
+                               goto bad_res;
+               }
+       }
+
+bad_res:
        cfg80211_put_dev(rdev);
        return result;
 }
@@ -1613,6 +1672,12 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
                params.use_short_slot_time =
                    nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
+       if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+               params.basic_rates =
+                       nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+               params.basic_rates_len =
+                       nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+       }
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
index 9dff716d1b0203c175d6f8368ccf612b941ed21d..4c7e39d466c430e34d4f2ec5bad649f1f6111ca7 100644 (file)
 #include "core.h"
 #include "reg.h"
 
-/*
- * wiphy is set if this request's initiator is
- * REGDOM_SET_BY_COUNTRY_IE or _DRIVER
+/**
+ * struct regulatory_request - receipt of last regulatory request
+ *
+ * @wiphy: this is set if this request's initiator is
+ *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
+ *     can be used by the wireless core to deal with conflicts
+ *     and potentially inform users of which devices specifically
+ *     cased the conflicts.
+ * @initiator: indicates who sent this request, could be any of
+ *     of those set in reg_set_by, %REGDOM_SET_BY_*
+ * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
+ *     regulatory domain. We have a few special codes:
+ *     00 - World regulatory domain
+ *     99 - built by driver but a specific alpha2 cannot be determined
+ *     98 - result of an intersection between two regulatory domains
+ * @intersect: indicates whether the wireless core should intersect
+ *     the requested regulatory domain with the presently set regulatory
+ *     domain.
  */
 struct regulatory_request {
        struct wiphy *wiphy;
        enum reg_set_by initiator;
        char alpha2[2];
+       bool intersect;
 };
 
+/* Receipt of information from last regulatory request */
 static struct regulatory_request *last_request;
 
 /* To trigger userspace events */
@@ -321,7 +338,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
 
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
 
-       if (freq_range->max_bandwidth_khz > freq_diff)
+       if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff)
                return false;
 
        return true;
@@ -359,6 +376,143 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range,
        return 0;
 }
 
+/* Helper for regdom_intersect(), this does the real
+ * mathematical intersection fun */
+static int reg_rules_intersect(
+       const struct ieee80211_reg_rule *rule1,
+       const struct ieee80211_reg_rule *rule2,
+       struct ieee80211_reg_rule *intersected_rule)
+{
+       const struct ieee80211_freq_range *freq_range1, *freq_range2;
+       struct ieee80211_freq_range *freq_range;
+       const struct ieee80211_power_rule *power_rule1, *power_rule2;
+       struct ieee80211_power_rule *power_rule;
+       u32 freq_diff;
+
+       freq_range1 = &rule1->freq_range;
+       freq_range2 = &rule2->freq_range;
+       freq_range = &intersected_rule->freq_range;
+
+       power_rule1 = &rule1->power_rule;
+       power_rule2 = &rule2->power_rule;
+       power_rule = &intersected_rule->power_rule;
+
+       freq_range->start_freq_khz = max(freq_range1->start_freq_khz,
+               freq_range2->start_freq_khz);
+       freq_range->end_freq_khz = min(freq_range1->end_freq_khz,
+               freq_range2->end_freq_khz);
+       freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz,
+               freq_range2->max_bandwidth_khz);
+
+       freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
+       if (freq_range->max_bandwidth_khz > freq_diff)
+               freq_range->max_bandwidth_khz = freq_diff;
+
+       power_rule->max_eirp = min(power_rule1->max_eirp,
+               power_rule2->max_eirp);
+       power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
+               power_rule2->max_antenna_gain);
+
+       intersected_rule->flags = (rule1->flags | rule2->flags);
+
+       if (!is_valid_reg_rule(intersected_rule))
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * regdom_intersect - do the intersection between two regulatory domains
+ * @rd1: first regulatory domain
+ * @rd2: second regulatory domain
+ *
+ * Use this function to get the intersection between two regulatory domains.
+ * Once completed we will mark the alpha2 for the rd as intersected, "98",
+ * as no one single alpha2 can represent this regulatory domain.
+ *
+ * Returns a pointer to the regulatory domain structure which will hold the
+ * resulting intersection of rules between rd1 and rd2. We will
+ * kzalloc() this structure for you.
+ */
+static struct ieee80211_regdomain *regdom_intersect(
+       const struct ieee80211_regdomain *rd1,
+       const struct ieee80211_regdomain *rd2)
+{
+       int r, size_of_regd;
+       unsigned int x, y;
+       unsigned int num_rules = 0, rule_idx = 0;
+       const struct ieee80211_reg_rule *rule1, *rule2;
+       struct ieee80211_reg_rule *intersected_rule;
+       struct ieee80211_regdomain *rd;
+       /* This is just a dummy holder to help us count */
+       struct ieee80211_reg_rule irule;
+
+       /* Uses the stack temporarily for counter arithmetic */
+       intersected_rule = &irule;
+
+       memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule));
+
+       if (!rd1 || !rd2)
+               return NULL;
+
+       /* First we get a count of the rules we'll need, then we actually
+        * build them. This is to so we can malloc() and free() a
+        * regdomain once. The reason we use reg_rules_intersect() here
+        * is it will return -EINVAL if the rule computed makes no sense.
+        * All rules that do check out OK are valid. */
+
+       for (x = 0; x < rd1->n_reg_rules; x++) {
+               rule1 = &rd1->reg_rules[x];
+               for (y = 0; y < rd2->n_reg_rules; y++) {
+                       rule2 = &rd2->reg_rules[y];
+                       if (!reg_rules_intersect(rule1, rule2,
+                                       intersected_rule))
+                               num_rules++;
+                       memset(intersected_rule, 0,
+                                       sizeof(struct ieee80211_reg_rule));
+               }
+       }
+
+       if (!num_rules)
+               return NULL;
+
+       size_of_regd = sizeof(struct ieee80211_regdomain) +
+               ((num_rules + 1) * sizeof(struct ieee80211_reg_rule));
+
+       rd = kzalloc(size_of_regd, GFP_KERNEL);
+       if (!rd)
+               return NULL;
+
+       for (x = 0; x < rd1->n_reg_rules; x++) {
+               rule1 = &rd1->reg_rules[x];
+               for (y = 0; y < rd2->n_reg_rules; y++) {
+                       rule2 = &rd2->reg_rules[y];
+                       /* This time around instead of using the stack lets
+                        * write to the target rule directly saving ourselves
+                        * a memcpy() */
+                       intersected_rule = &rd->reg_rules[rule_idx];
+                       r = reg_rules_intersect(rule1, rule2,
+                               intersected_rule);
+                       /* No need to memset here the intersected rule here as
+                        * we're not using the stack anymore */
+                       if (r)
+                               continue;
+                       rule_idx++;
+               }
+       }
+
+       if (rule_idx != num_rules) {
+               kfree(rd);
+               return NULL;
+       }
+
+       rd->n_reg_rules = num_rules;
+       rd->alpha2[0] = '9';
+       rd->alpha2[1] = '8';
+
+       return rd;
+}
+
 /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
  * want to just have the channel structure use these */
 static u32 map_regdom_flags(u32 rd_flags)
@@ -468,6 +622,10 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
        }
 }
 
+/* Return value which can be used by ignore_request() to indicate
+ * it has been determined we should intersect two regulatory domains */
+#define REG_INTERSECT  1
+
 /* This has the logic which determines when a new request
  * should be ignored. */
 static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
@@ -517,14 +675,8 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
                        return -EALREADY;
                return 0;
        case REGDOM_SET_BY_USER:
-               /*
-                * If the user wants to override the AP's hint, we may
-                * need to follow both and use the intersection. For now,
-                * reject any such attempt (but we don't support country
-                * IEs right now anyway.)
-                */
                if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
-                       return -EOPNOTSUPP;
+                       return REG_INTERSECT;
                return 0;
        }
 
@@ -536,10 +688,14 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
                      const char *alpha2)
 {
        struct regulatory_request *request;
+       bool intersect = false;
        int r = 0;
 
        r = ignore_request(wiphy, set_by, alpha2);
-       if (r)
+
+       if (r == REG_INTERSECT)
+               intersect = true;
+       else if (r)
                return r;
 
        switch (set_by) {
@@ -556,6 +712,7 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
                request->alpha2[1] = alpha2[1];
                request->initiator = set_by;
                request->wiphy = wiphy;
+               request->intersect = intersect;
 
                kfree(last_request);
                last_request = request;
@@ -638,7 +795,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
        print_rd_rules(rd);
 }
 
-void print_regdomain_info(const struct ieee80211_regdomain *rd)
+static void print_regdomain_info(const struct ieee80211_regdomain *rd)
 {
        printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n",
                rd->alpha2[0], rd->alpha2[1]);
@@ -648,6 +805,7 @@ void print_regdomain_info(const struct ieee80211_regdomain *rd)
 /* Takes ownership of rd only if it doesn't fail */
 static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
+       const struct ieee80211_regdomain *intersected_rd = NULL;
        /* Some basic sanity checks first */
 
        if (is_world_regdom(rd->alpha2)) {
@@ -697,6 +855,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return -EOPNOTSUPP;
        }
 
+       if (unlikely(last_request->intersect)) {
+               intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
+               if (!intersected_rd)
+                       return -EINVAL;
+               kfree(rd);
+               rd = intersected_rd;
+       }
+
        /* Tada! */
        cfg80211_regdomain = rd;
 
index f54424693a38a378bd5e7cdc25326907b5fbb983..e76cc28b034557fc1dfcadbae21a09307f6fee5c 100644 (file)
@@ -7,6 +7,25 @@
 #include <asm/bitops.h>
 #include "core.h"
 
+struct ieee80211_rate *
+ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
+                           u64 basic_rates, int bitrate)
+{
+       struct ieee80211_rate *result = &sband->bitrates[0];
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (!(basic_rates & BIT(i)))
+                       continue;
+               if (sband->bitrates[i].bitrate > bitrate)
+                       continue;
+               result = &sband->bitrates[i];
+       }
+
+       return result;
+}
+EXPORT_SYMBOL(ieee80211_get_response_rate);
+
 int ieee80211_channel_to_frequency(int chan)
 {
        if (chan < 14)
This page took 0.625608 seconds and 5 git commands to generate.