|
Subject: [PATCH wireless-dev] add adm8211 driver Newsgroups: gmane.linux.network Date: 2006-06-23 16:51:24 GMT (3 years, 1 week, 4 days, 13 hours and 21 minutes ago)
(resend, please merge)
This patch adds support for the ADMtek ADM8211 card. It is not completed yet,
but I feel the code is clean enough to merge into wireless-dev. It currently
supports STA mode.
Signed-off-by: Michael Wu <flamingice <at> sourmilk.net>
diff --git a/drivers/net/wireless/d80211/Kconfig
b/drivers/net/wireless/d80211/Kconfig
index 972c473..3656ee5 100644
--- a/drivers/net/wireless/d80211/Kconfig
+++ b/drivers/net/wireless/d80211/Kconfig
<at> <at> -1,2 +1,3 <at> <at>
source "drivers/net/wireless/d80211/bcm43xx/Kconfig"
source "drivers/net/wireless/d80211/rt2x00/Kconfig"
+source "drivers/net/wireless/d80211/adm8211/Kconfig"
diff --git a/drivers/net/wireless/d80211/Makefile
b/drivers/net/wireless/d80211/Makefile
index 32c5c8d..e491a41 100644
--- a/drivers/net/wireless/d80211/Makefile
+++ b/drivers/net/wireless/d80211/Makefile
<at> <at> -1,2 +1,3 <at> <at>
obj-$(CONFIG_BCM43XX_D80211) += bcm43xx/
obj-$(CONFIG_RT2X00) += rt2x00/
+obj-$(CONFIG_ADM8211) += adm8211/
diff --git a/drivers/net/wireless/d80211/adm8211/Kconfig
b/drivers/net/wireless/d80211/adm8211/Kconfig
new file mode 100644
index 0000000..9846cdf
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/Kconfig
<at> <at> -0,0 +1,24 <at> <at>
+config ADM8211
+ tristate "ADMtek ADM8211 support"
+ depends on NET_RADIO && PCI && D80211 && EXPERIMENTAL
+ ---help---
+ This driver is for ADM8211A, ADM8211B, and ADM8211C based cards.
+ These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as:
+
+ Xterasys Cardbus XN-2411b
+ Blitz NetWave Point PC
+ TrendNet 221pc
+ Belkin F5D6001
+ SMC 2635W
+ Linksys WPC11 v1
+ Fiberline FL-WL-200X
+ 3com Office Connect (3CRSHPW796)
+ Corega WLPCIB-11
+ SMC 2602W V2 EU
+ D-Link DWL-520 Revision C
+
+ However, some of these cards have been replaced with other chips
+ like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or
+ the Ralink RT2400 (SMC2635W) without a model number change.
+
+ Thanks to Infineon-ADMtek for their support of this driver.
diff --git a/drivers/net/wireless/d80211/adm8211/Makefile
b/drivers/net/wireless/d80211/adm8211/Makefile
new file mode 100644
index 0000000..9cca7e5
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/Makefile
<at> <at> -0,0 +1 <at> <at>
+obj-$(CONFIG_ADM8211) += adm8211.o
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.c
b/drivers/net/wireless/d80211/adm8211/adm8211.c
new file mode 100644
index 0000000..c766c4e
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.c
<at> <at> -0,0 +1,2202 <at> <at>
+
+/*
+ * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
+ *
+ * Copyright (c) 2003, Jouni Malinen <jkmaline <at> cc.hut.fi>
+ * Copyright (c) 2004-2006, Michael Wu <flamingice <at> sourmilk.net>
+ * Some parts copyright (c) 2003 by David Young <dyoung <at> pobox.com>
+ * and used with permission.
+ *
+ * Much thanks to Infineon-ADMtek for their support of this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/wireless.h>
+#include <net/d80211.h>
+#include <asm/delay.h>
+#include <asm/unaligned.h>
+#include <asm/types.h>
+#include <asm/div64.h>
+
+#include "adm8211.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice <at> sourmilk.net>, Jouni Malinen
<jkmaline <at> cc.hut.fi>");
+MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless LAN cards based on
ADMtek ADM8211");
+MODULE_SUPPORTED_DEVICE("ADM8211");
+MODULE_LICENSE("GPL");
+
+static unsigned int tx_ring_size = 16;
+static unsigned int rx_ring_size = 16;
+static int debug = 1;
+
+module_param(tx_ring_size, uint, 0);
+module_param(rx_ring_size, uint, 0);
+module_param(debug, int, 0);
+
+static const char *version = KERN_INFO "adm8211: "
+"Copyright 2003, Jouni Malinen <jkmaline <at> cc.hut.fi>; "
+"Copyright 2004-2006, Michael Wu <flamingice <at> sourmilk.net>\n";
+
+
+static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+ /* ADMtek ADM8211 */
+ { 0x10B7, 0x6000, PCI_ANY_ID, PCI_ANY_ID }, /* 3Com 3CRSHPW796 */
+ { 0x1200, 0x8201, PCI_ANY_ID, PCI_ANY_ID }, /* ? */
+ { 0x1317, 0x8201, PCI_ANY_ID, PCI_ANY_ID }, /* ADM8211A */
+ { 0x1317, 0x8211, PCI_ANY_ID, PCI_ANY_ID }, /* ADM8211B/C */
+ { 0 }
+};
+
+#define ADM8211_INTMASK \
+(ADM8211_IER_NIE | ADM8211_IER_AIE | ADM8211_IER_RCIE | ADM8211_IER_TCIE | \
+ADM8211_IER_TDUIE | ADM8211_IER_GPTIE)
+
+#define PLCP_SIGNAL_1M 0x0a
+#define PLCP_SIGNAL_2M 0x14
+#define PLCP_SIGNAL_5M5 0x37
+#define PLCP_SIGNAL_11M 0x6e
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],
((u8*)(x))[4],((u8*)(x))[5]
+
+struct adm8211_tx_hdr {
+ u8 da[6];
+ u8 signal; /* PLCP signal / TX rate in 100 Kbps */
+ u8 service;
+ __le16 frame_body_size;
+ __le16 frame_control;
+ __le16 plcp_frag_tail_len;
+ __le16 plcp_frag_head_len;
+ __le16 dur_frag_tail;
+ __le16 dur_frag_head;
+ u8 addr4[6];
+
+#define ADM8211_TXHDRCTL_SHORT_PREAMBLE (1 << 0)
+#define ADM8211_TXHDRCTL_MORE_FRAG (1 << 1)
+#define ADM8211_TXHDRCTL_MORE_DATA (1 << 2)
+#define ADM8211_TXHDRCTL_FRAG_NO (1 << 3) /* ? */
+#define ADM8211_TXHDRCTL_ENABLE_RTS (1 << 4)
+#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE (1 << 5)
+#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER (1 << 15) /* ? */
+ __le16 header_control;
+ __le16 frag;
+ u8 reserved_0;
+ u8 retry_limit;
+
+ u32 wep2key0;
+ u32 wep2key1;
+ u32 wep2key2;
+ u32 wep2key3;
+
+ u8 keyid;
+ u8 entry_control; // huh??
+ u16 reserved_1;
+ u32 reserved_2;
+} __attribute__ ((packed));
+
+
+#define RX_COPY_BREAK 128
+#define RX_PKT_SIZE 2500
+
+/* Serial EEPROM reading for 93C66/93C46 */
+#define EE_ENB (0x4000 | ADM8211_SPR_SRS | ADM8211_SPR_SCS)
+#define EE_READ_CMD (6)
+#define eeprom_delay() ADM8211_CSR_READ(SPR);
+
+
+static u16 adm8211_eeprom_read_word(struct net_device *dev, unsigned int
addr,
+ unsigned int addr_len)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int read_cmd = addr | (EE_READ_CMD << addr_len);
+ int i;
+ u16 retval = 0;
+
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB & ~ADM8211_SPR_SCS));
+ eeprom_delay();
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+ eeprom_delay();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ u32 dataval = EE_ENB | ((read_cmd & (1 << i)) ? ADM8211_SPR_SDI : 0);
+ ADM8211_CSR_WRITE(SPR, cpu_to_le32(dataval));
+ eeprom_delay();
+ ADM8211_CSR_WRITE(SPR, cpu_to_le32(dataval | ADM8211_SPR_SCLK));
+ eeprom_delay();
+ }
+
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+ eeprom_delay();
+
+ for (i = 16; i > 0; i--) {
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB | ADM8211_SPR_SCLK));
+ eeprom_delay();
+ retval <<= 1;
+ if (ADM8211_CSR_READ(SPR) & __constant_cpu_to_le32(ADM8211_SPR_SDO))
+ retval |= 1;
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB));
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ ADM8211_CSR_WRITE(SPR, __constant_cpu_to_le32(EE_ENB & ~ADM8211_SPR_SCS));
+
+ return retval;
+}
+
+
+static int adm8211_read_eeprom(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int addr_len, words, i;
+ struct ieee80211_chan_range chan_range;
+ u16 cr49;
+
+ if (ADM8211_CSR_READ(CSR_TEST0) & __constant_cpu_to_le32
(ADM8211_CSR_TEST0_EPTYP)) {
+ printk(KERN_DEBUG "%s (adm8211): EEPROM type: 93C66\n",
pci_name(priv->pdev));
+ /* 256 * 16-bit = 512 bytes */
+ addr_len = 8;
+ words = 256;
+ } else {
+ printk(KERN_DEBUG "%s (adm8211): EEPROM type 93C46\n",
pci_name(priv->pdev));
+ /* 64 * 16-bit = 128 bytes */
+ addr_len = 6;
+ words = 64;
+ }
+
+ priv->eeprom_len = words * 2;
+ priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL);
+ if (priv->eeprom == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < words; i++)
+ *((u16 *) &((u8 *)priv->eeprom)[i * 2]) =
+ adm8211_eeprom_read_word(dev, i, addr_len);
+
+ cr49 = le16_to_cpu(priv->eeprom->cr49);
+ priv->rf_type = (cr49 >> 3) & 0x7;
+ switch (priv->rf_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+
+ default:
+ if (priv->revid < ADM8211_REV_CA)
+ priv->rf_type = ADM8211_TYPE_RFMD;
+ else
+ priv->rf_type = ADM8211_TYPE_AIROHA;
+
+ printk(KERN_WARNING "%s (adm8211): Invalid or unsupported RFtype: %d,
assuming %d\n",
+ pci_name(priv->pdev), (cr49 >> 3) & 0x7, priv->rf_type);
+ }
+
+ priv->bbp_type = cr49 & 0x7;
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+
+ default:
+ if (priv->revid < ADM8211_REV_CA)
+ priv->bbp_type = ADM8211_TYPE_RFMD;
+ else
+ priv->bbp_type = ADM8211_TYPE_ADMTEK;
+
+ printk(KERN_WARNING "%s (adm8211): Invalid or unsupported BBPtype: %d,
assuming %d\n",
+ pci_name(priv->pdev), cr49 >> 3, priv->bbp_type);
+ }
+
+ if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid country code (%d) in EEPROM,
assuming ETSI\n",
+ pci_name(priv->pdev), priv->eeprom->country_code);
+
+ chan_range = cranges[2];
+ } else
+ chan_range = cranges[priv->eeprom->country_code];
+
+ printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+ pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+ priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+ priv->modes[0].channels = kmalloc(priv->modes[0].num_channels *
sizeof(struct ieee80211_channel), GFP_KERNEL);
+ if (priv->modes[0].channels == NULL) {
+ kfree(priv->eeprom);
+ return -ENOMEM;
+ }
+
+ memcpy(priv->modes[0].channels, &adm8211_channels[chan_range.min-1],
+ priv->modes[0].num_channels * sizeof(struct ieee80211_channel));
+
+ switch (priv->eeprom->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ case ADM8211_BBP_ADM8011:
+ priv->specific_bbptype = priv->eeprom->specific_bbptype;
+ break;
+
+ default:
+ if (priv->revid < ADM8211_REV_CA)
+ priv->specific_bbptype = ADM8211_BBP_RFMD3000;
+ else
+ priv->specific_bbptype = ADM8211_BBP_ADM8011;
+
+ printk(KERN_WARNING "%s (adm8211): Invalid or unsupported specific BBP: %d,
assuming %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_bbptype,
priv->specific_bbptype);
+ }
+
+ switch (priv->eeprom->specific_rftype) {
+ case ADM8211_RFMD2948:
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ case ADM8211_MAX2820:
+ case ADM8211_AL2210L:
+ priv->transceiver_type = priv->eeprom->specific_rftype;
+ break;
+
+ default:
+ if (priv->revid == ADM8211_REV_BA)
+ priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER;
+ else if (priv->revid == ADM8211_REV_CA)
+ priv->transceiver_type = ADM8211_AL2210L;
+ else if (priv->revid == ADM8211_REV_AB)
+ priv->transceiver_type = ADM8211_RFMD2948;
+
+ printk(KERN_WARNING "%s (adm8211): Invalid or unsupported transceiver: %d,
assuming %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_rftype,
priv->transceiver_type);
+
+ break;
+ }
+
+ printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d
Transceiver=%d\n",
+ pci_name(priv->pdev), priv->rf_type, priv->bbp_type,
+ priv->specific_bbptype, priv->transceiver_type);
+
+ return 0;
+}
+
+static inline void adm8211_write_sram(struct net_device *dev, u32 addr,
__le32 data)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ ADM8211_CSR_WRITE(WEPCTL, cpu_to_le32(addr | ADM8211_WEPCTL_TABLE_WR |
+ (priv->revid < ADM8211_REV_BA ?
+ 0 : ADM8211_WEPCTL_SEL_WEPTABLE )) );
+ ADM8211_CSR_READ(WEPCTL);
+ mdelay(1);
+
+ ADM8211_CSR_WRITE(WESK, data);
+ ADM8211_CSR_READ(WESK);
+ mdelay(1);
+}
+
+static void adm8211_write_sram_bytes(struct net_device *dev,
+ unsigned int addr, u8 *buf, unsigned int len)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ __le32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int i;
+
+ if (priv->revid < ADM8211_REV_BA) {
+ for (i = 0; i < len; i += 2) {
+ u16 val = buf[i] | buf[i + 1] << 8;
+ adm8211_write_sram(dev, addr + i / 2, cpu_to_le32(val));
+ }
+ } else {
+ for (i = 0; i < len; i += 4) {
+ u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) |
+ (buf[i + 2] << 16) | (buf[i + 3] << 24);
+ adm8211_write_sram(dev, addr + i / 4, cpu_to_le32(val));
+ }
+ }
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static void adm8211_clear_sram(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ __le32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int addr;
+
+ for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++)
+ adm8211_write_sram(dev, addr, 0);
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static int adm8211_get_stats(struct net_device *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+
+ return 0;
+}
+
+static void adm8211_set_rx_mode(struct net_device *dev,
+ unsigned short flags, int mc_count)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int bit_nr;
+ __le32 mc_filter[2];
+ struct dev_mc_list *mclist;
+ void *tmp;
+
+ mc_filter[1] = mc_filter[0] = 0;
+ if (flags & IFF_PROMISC) {
+ priv->nar |= ADM8211_NAR_PR;
+ priv->nar &= ~ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = __constant_cpu_to_le32(~0);
+ } else if ((flags & IFF_ALLMULTI) || (mc_count > -1)) {
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = __constant_cpu_to_le32(~0);
+ } else {
+ priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+ mc_filter[1] = mc_filter[0] = 0;
+ mclist = NULL;
+ while ((mclist = ieee80211_get_mc_list_item(dev, mclist, &tmp))) {
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
+ }
+ }
+
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ ADM8211_RESTORE();
+}
+
+static int adm8211_get_tx_stats(struct net_device *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
+
+ data->len = priv->cur_tx - priv->dirty_tx;
+ data->limit = priv->tx_ring_size - 2;
+ data->count = priv->dirty_tx;
+
+ return 0;
+}
+
+static void adm8211_interrupt_tci(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ struct net_device_stats *stats = ieee80211_dev_stats(dev);
+ unsigned dirty_tx;
+
+ spin_lock(&priv->lock);
+
+ for (dirty_tx = priv->dirty_tx;
+ priv->cur_tx - dirty_tx > 0; dirty_tx++) {
+ unsigned entry = dirty_tx % priv->tx_ring_size;
+ u32 status = le32_to_cpu(priv->tx_ring[entry].status);
+ struct sk_buff *skb;
+
+ if (status & TDES0_CONTROL_OWN ||
+ !(status & TDES0_CONTROL_DONE))
+ break;
+
+ if (status & TDES0_STATUS_ES) {
+ stats->tx_errors++;
+ priv->tx_buffers[entry].tx_status.ack = 0;
+
+ if (status & (TDES0_STATUS_TUF | TDES0_STATUS_TRO))
+ stats->tx_fifo_errors++;
+ } else
+ priv->tx_buffers[entry].tx_status.ack = 1;
+
+ skb = priv->tx_buffers[entry].skb;
+ pci_unmap_single(priv->pdev, priv->tx_buffers[entry].mapping,
+ skb->len, PCI_DMA_TODEVICE);
+
+ if (priv->tx_buffers[entry].tx_status.control.req_tx_status ||
+ priv->tx_buffers[entry].unicast)
+ ieee80211_tx_status_irqsafe(dev, priv->tx_buffers[entry].skb,
+ &priv->tx_buffers[entry].tx_status);
+ else
+ dev_kfree_skb_irq(priv->tx_buffers[entry].skb);
+ priv->tx_buffers[entry].skb = NULL;
+ }
+
+ if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
+ netif_wake_queue(dev);
+
+ priv->dirty_tx = dirty_tx;
+ spin_unlock(&priv->lock);
+}
+
+
+static void adm8211_interrupt_rci(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ struct net_device_stats *stats = ieee80211_dev_stats(dev);
+ unsigned int entry = priv->cur_rx % priv->rx_ring_size;
+ u32 status;
+ unsigned pktlen;
+ struct sk_buff *skb, *newskb;
+ unsigned int limit = priv->rx_ring_size;
+ static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+ u8 rssi, rate;
+
+ while (!(priv->rx_ring[entry].status &
+ __constant_cpu_to_le32(RDES0_STATUS_OWN))) {
+ if (limit-- == 0)
+ break;
+
+ status = le32_to_cpu(priv->rx_ring[entry].status);
+ rate = (status & RDES0_STATUS_RXDR) >> 12;
+ rssi = le32_to_cpu(priv->rx_ring[entry].length) &
+ RDES1_STATUS_RSSI;
+
+ pktlen = status & RDES0_STATUS_FL;
+ if (pktlen > RX_PKT_SIZE) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: too long frame (pktlen=%d)\n",
+ dev->name, pktlen);
+ pktlen = RX_PKT_SIZE;
+ }
+
+ if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) {
+ skb = NULL; /* old buffer will be reused */
+ stats->rx_errors++;
+ if (status & (RDES0_STATUS_CRC16E | RDES0_STATUS_CRC32E))
+ stats->rx_crc_errors++;
+
+ } else if (pktlen < RX_COPY_BREAK) {
+ skb = dev_alloc_skb(pktlen);
+ if (skb) {
+ skb->dev = dev;
+ pci_dma_sync_single_for_cpu(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ pktlen, PCI_DMA_FROMDEVICE);
+ memcpy(skb_put(skb, pktlen),
+ priv->rx_buffers[entry].skb->tail,
+ pktlen);
+ pci_dma_sync_single_for_device(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ }
+ } else {
+ newskb = dev_alloc_skb(RX_PKT_SIZE);
+ if (newskb) {
+ newskb->dev = dev;
+ skb = priv->rx_buffers[entry].skb;
+ skb_put(skb, pktlen);
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ priv->rx_buffers[entry].skb = newskb;
+ priv->rx_buffers[entry].mapping =
+ pci_map_single(priv->pdev,
+ newskb->tail,
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ } else {
+ skb = NULL;
+ stats->rx_dropped++;
+ }
+
+ priv->rx_ring[entry].buffer1 =
+ cpu_to_le32(priv->rx_buffers[entry].mapping);
+ }
+
+ priv->rx_ring[entry].status = cpu_to_le32( RDES0_STATUS_OWN |
RDES0_STATUS_SQL );
+ priv->rx_ring[entry].length =
+ cpu_to_le32(RX_PKT_SIZE |
+ (entry == priv->rx_ring_size - 1 ?
+ RDES1_CONTROL_RER : 0));
+
+ if (skb) {
+ struct ieee80211_rx_status rx_status = {0};
+
+ if (priv->revid < ADM8211_REV_CA)
+ rx_status.ssi = rssi;
+ else
+ rx_status.ssi = 100 - rssi;
+
+ if (rate <= 4)
+ rx_status.rate = rate_tbl[rate];
+
+ /* remove FCS */
+ /* TODO: remove this and set flag in ieee80211_hw instead? */
+ if (dev->flags & IFF_PROMISC)
+ skb_trim(skb, skb->len - FCS_LEN);
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ }
+
+ entry = (++priv->cur_rx) % priv->rx_ring_size;
+ }
+
+ stats->rx_missed_errors += le32_to_cpu(ADM8211_CSR_READ(LPC)) & 0xFFFF;
+}
+
+
+static irqreturn_t adm8211_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+#define ADM8211_INT(x) if (unlikely(stsr & ADM8211_STSR_ ## x))
printk(KERN_DEBUG "%s: " #x "\n", dev->name)
+
+ struct net_device *dev = dev_id;
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int count = 0;
+ u32 stsr;
+
+ do {
+ stsr = le32_to_cpu(ADM8211_CSR_READ(STSR));
+ ADM8211_CSR_WRITE(STSR, cpu_to_le32(stsr));
+ if (stsr == 0xffffffff)
+ return IRQ_HANDLED;
+
+ if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS)))
+ break;
+
+ if (stsr & ADM8211_STSR_RCI)
+ adm8211_interrupt_rci(dev);
+ if (stsr & ADM8211_STSR_TCI)
+ adm8211_interrupt_tci(dev);
+
+ if ((stsr & (ADM8211_STSR_LinkOn | ADM8211_STSR_LinkOff))
+ != (ADM8211_STSR_LinkOn | ADM8211_STSR_LinkOff)) {
+ if (stsr & ADM8211_STSR_LinkOn)
+ printk(KERN_DEBUG "%s: LinkOn\n", dev->name);
+
+ if (stsr & ADM8211_STSR_LinkOff)
+ printk(KERN_DEBUG "%s: LinkOff\n", dev->name);
+ }
+
+ ADM8211_INT(PCF);
+ ADM8211_INT(BCNTC);
+ ADM8211_INT(GPINT);
+ ADM8211_INT(ATIMTC);
+ ADM8211_INT(TSFTF);
+ ADM8211_INT(TSCZ);
+ ADM8211_INT(SQL);
+ ADM8211_INT(WEPTD);
+ ADM8211_INT(ATIME);
+ /*ADM8211_INT(TBTT);*/
+ ADM8211_INT(TEIS);
+ ADM8211_INT(FBE);
+ ADM8211_INT(REIS);
+ ADM8211_INT(GPTT);
+ ADM8211_INT(RPS);
+ ADM8211_INT(RDU);
+ ADM8211_INT(TUF);
+ /*ADM8211_INT(TRT);*/
+ /*ADM8211_INT(TLT);*/
+ /*ADM8211_INT(TDU);*/
+ ADM8211_INT(TPS);
+
+ } while (count++ < 20);
+
+ return IRQ_RETVAL(count);
+
+#undef ADM8211_INT
+}
+
+#define
WRITE_SYN(valmask,valshift,addrmask,addrshift,bits,prewrite,postwrite) do {\
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);\
+ unsigned int i;\
+ u32 reg, bitbuf;\
+ \
+ value &= valmask;\
+ addr &= addrmask;\
+ bitbuf = (value << valshift) | (addr << addrshift);\
+ \
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_IF_SELECT_1));
\
+ ADM8211_CSR_READ(SYNRF);\
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_IF_SELECT_0));
\
+ ADM8211_CSR_READ(SYNRF);\
+ \
+ if (prewrite) {\
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32
(ADM8211_SYNRF_WRITE_SYNDATA_0));\
+ ADM8211_CSR_READ(SYNRF);\
+ }\
+ \
+ for (i = 0; i <= bits; i++) {\
+ if ( bitbuf & (1 << (bits - i)) )\
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_1;\
+ else\
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_0;\
+ \
+ ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg));\
+ ADM8211_CSR_READ(SYNRF);\
+ \
+ ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_WRITE_CLOCK_1));\
+ ADM8211_CSR_READ(SYNRF);\
+ ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_WRITE_CLOCK_0));\
+ ADM8211_CSR_READ(SYNRF);\
+ }\
+ \
+ if (postwrite == 1) {\
+ ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_IF_SELECT_0));\
+ ADM8211_CSR_READ(SYNRF);\
+ }\
+ if (postwrite == 2) {\
+ ADM8211_CSR_WRITE(SYNRF, cpu_to_le32(reg | ADM8211_SYNRF_IF_SELECT_1));\
+ ADM8211_CSR_READ(SYNRF);\
+ }\
+ \
+ ADM8211_CSR_WRITE(SYNRF, 0);\
+ ADM8211_CSR_READ(SYNRF);\
+} while (0)
+
+static void adm8211_rf_write_syn_max2820 (struct net_device *dev, u16 addr,
u32 value)
+{
+ WRITE_SYN(0x00FFF, 0, 0x0F, 12, 15, 1, 1);
+}
+
+static void adm8211_rf_write_syn_al2210l (struct net_device *dev, u16 addr,
u32 value)
+{
+ WRITE_SYN(0xFFFFF, 4, 0x0F, 0, 23, 1, 1);
+}
+
+static void adm8211_rf_write_syn_rfmd2958 (struct net_device *dev, u16 addr,
u32 value)
+{
+ WRITE_SYN(0x3FFFF, 0, 0x1F, 18, 23, 0, 1);
+}
+
+static void adm8211_rf_write_syn_rfmd2948 (struct net_device *dev, u16 addr,
u32 value)
+{
+ WRITE_SYN(0x0FFFF, 4, 0x0F, 0, 21, 0, 2);
+}
+
+static int adm8211_write_bbp(struct net_device *dev, u8 addr, u8 data)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int timeout;
+ u32 reg;
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+ if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD)))
+ break;
+ timeout--;
+ mdelay(2);
+ }
+
+ if (timeout == 0) {
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed prewrite "
+ "(reg=0x%08x)\n",
+ dev->name, addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */
+ break;
+ case ADM8211_TYPE_RFMD:
+ reg = (0x20<<24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x01<<18);
+ break;
+ case ADM8211_TYPE_ADMTEK:
+ reg = (0x20<<24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x05<<18);
+ break;
+ }
+ reg |= ADM8211_BBPCTL_WR | (addr << 8) | data;
+
+ ADM8211_CSR_WRITE(BBPCTL, cpu_to_le32(reg));
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+ if (!(reg & ADM8211_BBPCTL_WR))
+ break;
+ timeout--;
+ mdelay(2);
+ }
+
+ if (timeout == 0) {
+ ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
+ __constant_cpu_to_le32(~ADM8211_BBPCTL_WR));
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed postwrite "
+ "(reg=0x%08x)\n",
+ dev->name, addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int adm8211_rf_set_channel(struct net_device *dev, unsigned int
channel)
+{
+ static const u32 adm8211_rfmd2958_reg5[] =
+ {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340,
+ 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7};
+ static const u32 adm8211_rfmd2958_reg6[] =
+ {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000,
+ 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745};
+
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u8 ant_power = priv->ant_power > 0x3F ?
+ priv->eeprom->antenna_power[channel-1] : priv->ant_power;
+ u8 tx_power = priv->tx_power > 0x3F ?
+ priv->eeprom->tx_power[channel-1] : priv->tx_power;
+ u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ?
+ priv->eeprom->lpf_cutoff[channel-1] : priv->lpf_cutoff;
+ u8 lnags_thresh = priv->lnags_threshold == 0xFF ?
+ priv->eeprom->lnags_threshold[channel-1] : priv->lnags_threshold;
+ u32 reg;
+
+ if (channel < 1 || channel > 14)
+ return -EINVAL;
+
+ ADM8211_IDLE();
+
+ /* Program synthesizer to new channel */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033);
+
+ adm8211_rf_write_syn_rfmd2958(dev, 0x05,
+ adm8211_rfmd2958_reg5[channel-1]);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x06,
+ adm8211_rfmd2958_reg6[channel-1]);
+ break;
+
+ case ADM8211_RFMD2948:
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF, SI4126_MAIN_XINDIV2);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN,
+ SI4126_POWERDOWN_PDIB | SI4126_POWERDOWN_PDRB);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV,
+ (channel == 14 ? 2110 : (2033 + (channel * 5))));
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x3,
+ (channel == 14 ? 0x054 : (0x7 + (channel * 5))));
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0,
+ (channel == 14 ? 0x229B4 : (0x22967 + (channel * 5))));
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+ dev->name, priv->transceiver_type);
+ break;
+ }
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+
+ /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */
+ /* TODO: remove if SMC 2635W doesn't need this */
+ if (priv->transceiver_type == ADM8211_RFMD2948) {
+ reg = le32_to_cpu(ADM8211_CSR_READ(GPIO));
+ reg &= 0xfffc0000;
+ reg |= ADM8211_CSR_GPIO_EN0;
+ if (channel != 14)
+ reg |= ADM8211_CSR_GPIO_O0;
+ ADM8211_CSR_WRITE(GPIO, cpu_to_le32(reg));
+ }
+
+ if (priv->transceiver_type == ADM8211_RFMD2958) {
+ /* set PCNT2 */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100);
+ /* set PCNT1 P_DESIRED/MID_BIAS */
+ reg = le16_to_cpu(priv->eeprom->cr49);
+ reg >>= 13;
+ reg <<= 15;
+ reg |= ant_power<<9;
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg);
+ /* set TXRX TX_GAIN */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 |
+ (priv->revid < ADM8211_REV_CA ? tx_power : 0));
+ } else {
+ reg = le32_to_cpu(ADM8211_CSR_READ(PLCPHD));
+ reg &= 0xff00ffff;
+ reg |= tx_power<<18;
+ ADM8211_CSR_WRITE(PLCPHD, cpu_to_le32(reg));
+ }
+
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST));
+ ADM8211_CSR_READ(SYNRF);
+ mdelay(30);
+
+ /* RF3000 BBP */
+ if (priv->transceiver_type != ADM8211_RFMD2958)
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT,
+ tx_power<<2);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh);
+ adm8211_write_bbp(dev, 0x1c, priv->revid == ADM8211_REV_BA
+ ? priv->eeprom->cr28 : 0);
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) { /* Nothing to do for
ADMtek BBP */
+ printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+ dev->name, priv->bbp_type);
+ }
+
+ ADM8211_RESTORE();
+
+ /* update current channel for adhoc (and maybe AP mode) */
+ reg = le32_to_cpu(ADM8211_CSR_READ(CAP0));
+ reg &= ~0xF;
+ reg |= channel;
+ ADM8211_CSR_WRITE(CAP0, cpu_to_le32(reg));
+
+ return 0;
+}
+
+static void adm8211_update_mode(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ ADM8211_IDLE();
+
+ priv->soft_rx_crc = 0;
+ switch (priv->mode) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
+ priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
+
+ /* don't trust the error bits on rev 0x20 and up in adhoc */
+ if (priv->revid >= ADM8211_REV_BA)
+ priv->soft_rx_crc = 1;
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
+ priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
+ break;
+ }
+
+ ADM8211_RESTORE();
+}
+
+static void adm8211_hw_init_syn(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ /* comments taken from ADMtek driver */
+
+ /* Reset RF2958 after power on */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000);
+ /* Initialize RF VCO Core Bias to maximum */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F);
+ /* Initialize IF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03);
+ /* Initialize IF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F);
+ /* Initialize RF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403);
+ /* Initialize RF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F);
+ /* Initialize TX gain and filter BW (R9) */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09,
+ (priv->transceiver_type == ADM8211_RFMD2958
+ ? 0x10050 : 0x00050) );
+ /* Initialize CAL register */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E);
+ adm8211_rf_write_syn_max2820(dev, 0x2, 0x001);
+ adm8211_rf_write_syn_max2820(dev, 0x3, 0x054);
+ adm8211_rf_write_syn_max2820(dev, 0x4, 0x310);
+ adm8211_rf_write_syn_max2820(dev, 0x5, 0x000);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C);
+ adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB);
+ adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F);
+ adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9);
+ adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280);
+ adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641);
+ adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130);
+ adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000);
+ adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F);
+ adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C);
+ adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000);
+ adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000);
+ break;
+
+ case ADM8211_RFMD2948:
+ default:
+ break;
+ }
+}
+
+static int adm8211_hw_init_bbp(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+
+ /* write addresses */
+ if (priv->bbp_type == ADM8211_TYPE_INTERSIL) {
+ ADM8211_CSR_WRITE(MMIWA, __constant_cpu_to_le32(0x100E0C0A));
+ ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00007c7e));
+ ADM8211_CSR_WRITE(MMIRD1, __constant_cpu_to_le32(0x00100000));
+ } else if (priv->bbp_type == ADM8211_TYPE_RFMD ||
+ priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+
+ /* check specific BBP type */
+ switch (priv->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ ADM8211_CSR_WRITE(MMIWA, __constant_cpu_to_le32(0x00009101));
+ ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00000301));
+ break;
+
+ case ADM8211_BBP_ADM8011:
+ ADM8211_CSR_WRITE(MMIWA, __constant_cpu_to_le32(0x00008903));
+ ADM8211_CSR_WRITE(MMIRD0, __constant_cpu_to_le32(0x00001716));
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(BBPCTL));
+ reg &= ~ADM8211_BBPCTL_TYPE;
+ reg |= 0x5 << 18;
+ ADM8211_CSR_WRITE(BBPCTL, cpu_to_le32(reg));
+ break;
+ }
+
+ switch (priv->revid) {
+ case ADM8211_REV_CA:
+ if (priv->transceiver_type == ADM8211_RFMD2958 ||
+ priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+ priv->transceiver_type == ADM8211_RFMD2948)
+ ADM8211_CSR_WRITE(SYNCTL, __constant_cpu_to_le32(0x1 << 22));
+ else if (priv->transceiver_type == ADM8211_MAX2820 ||
+ priv->transceiver_type == ADM8211_AL2210L)
+ ADM8211_CSR_WRITE(SYNCTL, __constant_cpu_to_le32(0x3 << 22));
+ break;
+
+ case ADM8211_REV_BA:
+ reg = le32_to_cpu(ADM8211_CSR_READ(MMIRD1));
+ reg &= 0x0000FFFF;
+ reg |= 0x7e100000;
+ ADM8211_CSR_WRITE(MMIRD1, cpu_to_le32(reg));
+ break;
+
+ case ADM8211_REV_AB:
+ case ADM8211_REV_AF:
+ default:
+ ADM8211_CSR_WRITE(MMIRD1, __constant_cpu_to_le32(0x7e100000));
+ break;
+ }
+
+ /* For RFMD */
+ ADM8211_CSR_WRITE(MACTEST, __constant_cpu_to_le32(0x800));
+ }
+
+ adm8211_hw_init_syn(dev);
+
+ /* Set RF Power control IF pin to PE1+PHYRST# */
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST));
+ ADM8211_CSR_READ(SYNRF);
+ mdelay(20);
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+ /* RF3000 BBP */
+ /* another set:
+ * 11: c8
+ * 14: 14
+ * 15: 50 (chan 1..13; chan 14: d0)
+ * 1c: 00
+ * 1d: 84
+ */
+ adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80);
+ adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80); /* antenna selection:
diversity */
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40);
+
+ if (priv->eeprom->major_version < 2) {
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+ adm8211_write_bbp(dev, 0x1d, 0x80);
+ } else {
+ if (priv->revid == ADM8211_REV_BA)
+ adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28);
+ else
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+ }
+ } else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+ adm8211_write_bbp(dev, 0x00, 0xFF); /* reset baseband */
+ adm8211_write_bbp(dev, 0x07, 0x0A); /* antenna selection: diversity */
+
+ /* TODO: find documentation for this */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x00);
+ adm8211_write_bbp(dev, 0x0f, 0xAA);
+ adm8211_write_bbp(dev, 0x10, 0x8c);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x40);
+ adm8211_write_bbp(dev, 0x20, 0x23);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x28);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x28, 0x35);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x2d, 0x0A);
+ adm8211_write_bbp(dev, 0x29, 0x40);
+ adm8211_write_bbp(dev, 0x60, 0x08);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x05);
+ adm8211_write_bbp(dev, 0x0a, 0x02);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x0f);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0x4a);
+ adm8211_write_bbp(dev, 0x60, 0x2b);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x07, 0x05);
+ adm8211_write_bbp(dev, 0x08, 0x03);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x10);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0xaa);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0xfa);
+ adm8211_write_bbp(dev, 0x60, 0x2d);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_RFMD2948:
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+ dev->name, priv->transceiver_type);
+ break;
+ }
+ } else {
+ printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+ dev->name, priv->bbp_type);
+ }
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ /* Set RF CAL control source to MAC control */
+ reg = le32_to_cpu(ADM8211_CSR_READ(SYNCTL));
+ reg |= ADM8211_SYNCTL_SELCAL;
+ ADM8211_CSR_WRITE(SYNCTL, cpu_to_le32(reg));
+
+ return 0;
+}
+
+// configures hw beacons/probe responses
+static int adm8211_set_rate(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+ int i = 0;
+ u8 rate_buf[12] = {0};
+
+ /* write supported rates */
+ if (priv->revid != ADM8211_REV_BA) {
+ rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+ for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+ rate_buf[i+1] = (adm8211_rates[i].rate/5) | 0x80;
+ } else {
+ /* workaround for rev BA specific bug */
+ rate_buf[0]=4;
+ rate_buf[1]=0x82;
+ rate_buf[2]=0x04;
+ rate_buf[3]=0x0b;
+ rate_buf[4]=0x16;
+ }
+
+ adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf,
ARRAY_SIZE(adm8211_rates)+1);
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(PLCPHD)) & 0x00FFFFFF; /* keep bits 0-23
*/
+ reg |= (1 << 15); /* short preamble */
+ reg |= 110 << 24;
+ ADM8211_CSR_WRITE(PLCPHD, cpu_to_le32(reg));
+
+ /* MTMLT = 512 TU (max TX MSDU lifetime)
+ * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate)
+ * SRTYLIM = 224 (short retry limit, value in TX header used by default) */
+ ADM8211_CSR_WRITE(TXLMT, cpu_to_le32((512<<16) | (110<<8) | (224<<0)));
+
+ return 0;
+}
+
+static void adm8211_hw_init(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+ u8 cacheline;
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+ reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+ reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+ if (!pci_set_mwi(priv->pdev)) {
+ reg |= (0x1<<24);
+ pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cacheline);
+
+ switch (cacheline) {
+ case 0x8: reg |= (0x1<<14);
+ break;
+ case 0x16: reg |= (0x2<<14);
+ break;
+ case 0x32: reg |= (0x3<<14);
+ break;
+ default: reg |= (0x0<<14);
+ break;
+ }
+ }
+
+ ADM8211_CSR_WRITE(PAR, cpu_to_le32(reg));
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+ reg &= ~(0xF<<28);
+ reg |= ((1 << 28) | (1 << 31));
+ ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+
+ /* lose link after 4 lost beacons */
+ reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE;
+ ADM8211_CSR_WRITE(WCSR, cpu_to_le32(reg));
+
+ /* Disable APM, enable receive FIFO threshold, and set drain receive
+ * threshold to store-and-forward */
+ reg = le32_to_cpu(ADM8211_CSR_READ(CMDR));
+ reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT);
+ reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF;
+ ADM8211_CSR_WRITE(CMDR, cpu_to_le32(reg));
+
+ adm8211_set_rate(dev);
+
+ /* 4-bit values:
+ * PWR1UP = 8 * 2 ms
+ * PWR0PAPE = 8 us or 5 us
+ * PWR1PAPE = 1 us or 3 us
+ * PWR0TRSW = 5 us
+ * PWR1TRSW = 12 us
+ * PWR0PE2 = 13 us
+ * PWR1PE2 = 1 us
+ * PWR0TXPE = 8 or 6 */
+ if (priv->revid < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(TOFS2, __constant_cpu_to_le32(0x8815cd18));
+ else
+ ADM8211_CSR_WRITE(TOFS2, __constant_cpu_to_le32(0x8535cd16));
+
+ /* Enable store and forward for transmit */
+ priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB;
+ ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar));
+
+ /* Reset RF */
+ ADM8211_CSR_WRITE(SYNRF, __constant_cpu_to_le32(ADM8211_SYNRF_RADIO));
+ ADM8211_CSR_READ(SYNRF);
+ mdelay(10);
+ ADM8211_CSR_WRITE(SYNRF, 0);
+ ADM8211_CSR_READ(SYNRF);
+ mdelay(5);
+
+ /* Set CFP Max Duration to 0x10 TU */
+ reg = le32_to_cpu(ADM8211_CSR_READ(CFPP));
+ reg &= ~(0xffff<<8);
+ reg |= 0x0010<<8;
+ ADM8211_CSR_WRITE(CFPP, cpu_to_le32(reg));
+
+ /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us
+ * TUCNT = 0x3ff - Tu counter 1024 us */
+ ADM8211_CSR_WRITE(TOFS0, __constant_cpu_to_le32((0x16 << 24) | 0x3ff));
+
+ /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us),
+ * DIFS=50 us, EIFS=100 us */
+ if (priv->revid < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(IFST, __constant_cpu_to_le32(
+ (20 << 23) | (110 << 15) |
+ (50 << 9) | 100));
+ else
+ ADM8211_CSR_WRITE(IFST, __constant_cpu_to_le32(
+ (20 << 23) | (24 << 15) |
+ (50 << 9) | 100));
+
+ /* PCNT = 1 (MAC idle time awake/sleep, unit S)
+ * RMRD = 2346 * 8 + 1 us (max RX duration) */
+ ADM8211_CSR_WRITE(RMD, __constant_cpu_to_le32((1 << 16) | 18769));
+
+ /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */
+ ADM8211_CSR_WRITE(RSPT, __constant_cpu_to_le32(0xffffff00));
+
+ /* Initialize BBP (and SYN) */
+ adm8211_hw_init_bbp(dev);
+
+ /* make sure interrupts are off */
+ ADM8211_CSR_WRITE(IER, 0);
+
+ /* ACK interrupts */
+ ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR));
+
+ /* Setup WEP (turns it off for now) */
+ reg = le32_to_cpu(ADM8211_CSR_READ(MACTEST));
+ reg &= ~(7<<20);
+ ADM8211_CSR_WRITE(MACTEST, cpu_to_le32(reg));
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(WEPCTL));
+ reg &= ~ADM8211_WEPCTL_WEPENABLE;
+ reg |= ADM8211_WEPCTL_WEPRXBYP;
+ ADM8211_CSR_WRITE(WEPCTL, cpu_to_le32(reg));
+
+ /* Clear the missed-packet counter. */
+ ADM8211_CSR_READ(LPC);
+
+ /* set mac address */
+ ADM8211_CSR_WRITE(PAR0, *(u32 *)dev->dev_addr);
+ ADM8211_CSR_WRITE(PAR1, *(u16 *)(dev->dev_addr + 4));
+}
+
+static int adm8211_hw_reset(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+ __le32 tmp;
+ int timeout = 50;
+
+ /* Power-on issue */
+ /* TODO: check if this is necessary */
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ /* Reset the chip */
+ tmp = ADM8211_CSR_READ(PAR);
+ ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR);
+
+ while ((ADM8211_CSR_READ(PAR) & __constant_cpu_to_le32(ADM8211_PAR_SWR)) &&
timeout--)
+ mdelay(100);
+
+ if (timeout <= 0)
+ return -ETIMEDOUT;
+
+ ADM8211_CSR_WRITE(PAR, tmp);
+
+ if (priv->revid == ADM8211_REV_BA &&
+ ( priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER
+ || priv->transceiver_type == ADM8211_RFMD2958)) {
+ reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+ reg |= (1 << 4) | (1 << 5);
+ ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+ } else if (priv->revid == ADM8211_REV_CA) {
+ reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST1));
+ reg &= ~((1 << 4) | (1 << 5));
+ ADM8211_CSR_WRITE(CSR_TEST1, cpu_to_le32(reg));
+ }
+
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(CSR_TEST0));
+ reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */
+ ADM8211_CSR_WRITE(CSR_TEST0, cpu_to_le32(reg));
+
+ adm8211_clear_sram(dev);
+
+ return 0;
+}
+
+static u64 adm8211_get_tsft(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 tsftl;
+ u64 tsft;
+
+ tsftl = le32_to_cpu(ADM8211_CSR_READ(TSFTL));
+ tsft = le32_to_cpu(ADM8211_CSR_READ(TSFTH));
+ tsft <<= 32;
+ tsft |= tsftl;
+
+ return tsft;
+}
+
+static void adm8211_set_interval(struct net_device *dev,
+ unsigned short bi, unsigned short li)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+
+ /* BP (beacon interval) = data->beacon_interval
+ * LI (listen interval) = data->listen_interval (in beacon intervals) */
+ reg = (bi << 16) | li;
+ ADM8211_CSR_WRITE(BPLI, cpu_to_le32(reg));
+}
+
+static void adm8211_set_bssid(struct net_device *dev, u8 *bssid)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ u32 reg;
+
+ reg = bssid[0] | (bssid[1] << 8) | (bssid[2] << 16) | (bssid[3] << 24);
+ ADM8211_CSR_WRITE(BSSID0, cpu_to_le32(reg));
+ reg = le32_to_cpu(ADM8211_CSR_READ(ABDA1));
+ reg &= 0x0000ffff;
+ reg |= (bssid[4] << 16) | (bssid[5] << 24);
+ ADM8211_CSR_WRITE(ABDA1, cpu_to_le32(reg));
+}
+
+static int adm8211_set_ssid(struct net_device *dev, u8 *ssid, size_t
ssid_len)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ 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);
+ //adm8211_set_beacon(dev);
+ return 0;
+}
+
+static int adm8211_config(struct net_device *dev, struct ieee80211_conf
*conf)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ if (conf->channel != priv->channel) {
+ priv->channel = conf->channel;
+ adm8211_rf_set_channel(dev, priv->channel);
+ }
+
+ return 0;
+}
+
+static int adm8211_config_interface(struct net_device *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
+ adm8211_set_bssid(dev, conf->bssid);
+ 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;
+}
+static int adm8211_scan(struct net_device *dev, int state,
+ struct ieee80211_scan_conf *conf)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ if (state == IEEE80211_SCAN_START) {
+ priv->channel = conf->scan_channel;
+ adm8211_rf_set_channel(dev, conf->scan_channel);
+ } else if (state == IEEE80211_SCAN_END) {
+ priv->channel = conf->running_channel;
+ adm8211_rf_set_channel(dev, conf->running_channel);
+ }
+
+ return 0;
+}
+
+static int adm8211_add_interface(struct net_device *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
+ if (priv->mode != IEEE80211_IF_TYPE_MGMT)
+ return -1;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->mode = conf->type;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static void adm8211_remove_interface(struct net_device *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
+static int adm8211_init_rings(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ struct adm8211_desc *desc = NULL;
+ struct adm8211_ring_info *info;
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ desc->status = 0;
+ desc->length = cpu_to_le32(RX_PKT_SIZE);
+ priv->rx_buffers[i].skb = NULL;
+ }
+ /* Mark the end of RX ring; hw returns to base address after this
+ * descriptor */
+ desc->length |= cpu_to_le32(RDES1_CONTROL_RER);
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ info = &priv->rx_buffers[i];
+
+ info->skb = dev_alloc_skb(RX_PKT_SIZE);
+ if (info->skb == NULL)
+ break;
+ info->mapping = pci_map_single(priv->pdev, info->skb->tail,
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ info->skb->dev = dev;
+ desc->buffer1 = cpu_to_le32(info->mapping);
+ desc->status = cpu_to_le32( RDES0_STATUS_OWN | RDES0_STATUS_SQL );
+ }
+
+ /* Setup TX ring. TX buffers descriptors will be filled in as needed */
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ desc = &priv->tx_ring[i];
+ info = &priv->tx_buffers[i];
+
+ info->skb = NULL;
+ info->mapping = 0;
+ desc->status = 0;
+ }
+ desc->length = cpu_to_le32(TDES1_CONTROL_TER);
+
+ priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0;
+ ADM8211_CSR_WRITE(RDB, cpu_to_le32(priv->rx_ring_dma));
+ ADM8211_CSR_WRITE(TDBD, cpu_to_le32(priv->tx_ring_dma));
+
+ return 0;
+}
+
+static void adm8211_free_rings(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ if (!priv->rx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[i].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+
+ dev_kfree_skb(priv->rx_buffers[i].skb);
+ }
+
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ if (!priv->tx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(
+ priv->pdev,
+ priv->tx_buffers[i].mapping,
+ priv->tx_buffers[i].skb->len, PCI_DMA_TODEVICE);
+
+ dev_kfree_skb(priv->tx_buffers[i].skb);
+ }
+}
+
+static int adm8211_open(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ int retval;
+
+ /* Power up MAC and RF chips */
+ retval = adm8211_hw_reset(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: hardware reset failed\n", dev->name);
+ goto fail;
+ }
+
+ retval = adm8211_init_rings(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to initialize rings\n", dev->name);
+ goto fail;
+ }
+
+ /* Init hardware */
+ adm8211_hw_init(dev);
+ adm8211_rf_set_channel(dev, priv->channel);
+
+ retval = request_irq(dev->irq, &adm8211_interrupt,
+ SA_SHIRQ, dev->name, dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to register IRQ handler\n",
+ dev->name);
+ goto fail;
+ }
+
+ ADM8211_CSR_WRITE(IER, __constant_cpu_to_le32(ADM8211_INTMASK));
+ adm8211_update_mode(dev);
+ ADM8211_CSR_WRITE(RDR, 0);
+
+ adm8211_set_interval(dev, 100, 10);
+ return 0;
+
+fail:
+ return retval;
+}
+
+static int adm8211_stop(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+
+ priv->nar = 0;
+ ADM8211_CSR_WRITE(NAR, 0);
+ ADM8211_CSR_WRITE(IER, 0);
+ ADM8211_CSR_READ(NAR);
+
+ free_irq(dev->irq, dev);
+
+ adm8211_free_rings(dev);
+
+ adm8211_hw_reset(dev);
+ return 0;
+}
+
+static int adm8211_reset(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ int retval = 0;
+
+ priv->nar = 0;
+ ADM8211_CSR_WRITE(NAR, 0);
+ ADM8211_CSR_WRITE(IER, 0);
+ ADM8211_CSR_READ(NAR);
+
+ adm8211_free_rings(dev);
+
+ retval = adm8211_hw_reset(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: hardware reset failed\n", dev->name);
+ goto fail;
+ }
+
+ retval = adm8211_init_rings(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to initialize rings\n", dev->name);
+ goto fail;
+ }
+
+ adm8211_hw_init(dev);
+ adm8211_rf_set_channel(dev, priv->channel);
+
+ ADM8211_CSR_WRITE(IER, __constant_cpu_to_le32(ADM8211_INTMASK));
+ adm8211_update_mode(dev);
+ ADM8211_CSR_WRITE(RDR, 0);
+
+fail:
+ return retval;
+}
+
+static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len,
int len,
+ int plcp_signal, int short_preamble)
+{
+ /* Alternative calculation from NetBSD: */
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE 144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR 24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48
+#define IEEE80211_DUR_DS_SLOW_ACK 112
+#define IEEE80211_DUR_DS_FAST_ACK 56
+#define IEEE80211_DUR_DS_SLOW_CTS 112
+#define IEEE80211_DUR_DS_FAST_CTS 56
+#define IEEE80211_DUR_DS_SLOT 20
+#define IEEE80211_DUR_DS_SIFS 10
+
+ int remainder;
+
+ *dur = (80 * (24 + payload_len) + plcp_signal - 1)
+ / plcp_signal;
+
+ if (plcp_signal <= PLCP_SIGNAL_2M)
+ /* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;
+ else
+ /* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;
+
+ /* lengthen duration if long preamble */
+ if (!short_preamble)
+ *dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+ IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+ 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+ IEEE80211_DUR_DS_FAST_PLCPHDR);
+
+
+ *plcp = (80 * len) / plcp_signal;
+ remainder = (80 * len) % plcp_signal;
+ if (plcp_signal == PLCP_SIGNAL_11M &&
+ remainder <= 30 && remainder > 0)
+ *plcp = (*plcp | 0x8000) + 1;
+ else if (remainder)
+ (*plcp)++;
+}
+
+/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
+static void adm8211_tx_raw(struct net_device *dev, struct sk_buff *skb,
+ u16 plcp_signal, struct ieee80211_tx_control *control, int unicast)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned long flags;
+ dma_addr_t mapping;
+ unsigned entry;
+ u32 flag;
+
+ mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size / 2)
+ flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ else if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
+ flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ else if (priv->cur_tx - priv->dirty_tx < priv->tx_ring_size - 2)
+ flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ else {
+ flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ printk(KERN_DEBUG "%s: Yikes, this shouldn't happen!\n", dev->name);
+ netif_stop_queue(dev);
+ }
+
+ entry = priv->cur_tx % priv->tx_ring_size;
+
+ priv->tx_buffers[entry].skb = skb;
+ priv->tx_buffers[entry].mapping = mapping;
+ memcpy(&priv->tx_buffers[entry].tx_status.control, control,
sizeof(*control));
+ priv->tx_buffers[entry].unicast = unicast;
+ priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
+
+ if (entry == priv->tx_ring_size - 1)
+ flag |= TDES1_CONTROL_TER;
+ priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);
+
+ /* Set TX rate (SIGNAL field in PLCP PPDU format) */
+ flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;
+ priv->tx_ring[entry].status = cpu_to_le32(flag);
+
+ priv->cur_tx++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Trigger transmit poll */
+ ADM8211_CSR_WRITE(TDR, 0);
+
+ dev->trans_start = jiffies;
+}
+
+/* Put adm8211_tx_hdr on skb and transmit */
+static int adm8211_tx(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct adm8211_tx_hdr *txhdr;
+ struct ieee80211_hdr *hdr;
+ u16 fc_;
+ __le16 fc;
+ u8 dst[ETH_ALEN];
+ size_t payload_len, hdrlen;
+ int plcp, dur, len;
+ int plcp_signal;
+ int short_preamble;
+
+ if (control->tx_rate < 0) {
+ short_preamble = 1;
+ plcp_signal = -control->tx_rate;
+ } else {
+ short_preamble = 0;
+ plcp_signal = control->tx_rate;
+ }
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ fc_ = le16_to_cpu(fc);
+ memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
+
+ hdrlen = ieee80211_get_hdrlen(fc_);
+ skb_pull(skb, hdrlen);
+ fc_ &= ~WLAN_FC_ISWEP;
+ payload_len = skb->len;
+
+ if (skb_headroom(skb) < sizeof(struct adm8211_tx_hdr)) {
+ if (pskb_expand_head(skb, sizeof(struct adm8211_tx_hdr), 0, GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: failed to allocate room for TX "
+ "header\n", dev->name);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
+ memset(txhdr, 0, sizeof(*txhdr));
+ memcpy(txhdr->da, dst, ETH_ALEN);
+ txhdr->signal = plcp_signal;
+ txhdr->frame_body_size = cpu_to_le16(payload_len);
+ txhdr->frame_control = fc;
+
+ len = hdrlen + payload_len + FCS_LEN;
+ if (fc_ & WLAN_FC_ISWEP)
+ len += 8;
+
+ txhdr->frag = cpu_to_le16(0x0FFF);
+ adm8211_calc_durations(&dur, &plcp, payload_len,
+ len, plcp_signal, short_preamble);
+ txhdr->plcp_frag_head_len = cpu_to_le16(plcp);
+ txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);
+ txhdr->dur_frag_head = cpu_to_le16(dur);
+ txhdr->dur_frag_tail = cpu_to_le16(dur);
+
+ txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);
+
+ if (short_preamble)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+
+ if (control->use_rts_cts)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+
+ if (fc_ & WLAN_FC_ISWEP)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
+
+ txhdr->retry_limit = control->retry_limit;
+
+ adm8211_tx_raw(dev, skb, plcp_signal,
control, !is_multicast_ether_addr(dst));
+
+ return NETDEV_TX_OK;
+}
+
+static int adm8211_alloc_rings(struct net_device *dev)
+{
+ struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
+ unsigned int ring_size;
+
+ priv->rx_buffers = kmalloc(sizeof(struct adm8211_ring_info) *
+ (priv->rx_ring_size + priv->tx_ring_size), GFP_KERNEL);
+ if (!priv->rx_buffers)
+ return -ENOMEM;
+
+ priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct
adm8211_ring_info) * priv->tx_ring_size;
+
+ /* Allocate TX/RX descriptors */
+ ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size;
+ priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,
+ &priv->rx_ring_dma);
+
+ if (!priv->rx_ring) {
+ kfree(priv->rx_buffers);
+ priv->rx_buffers = priv->tx_buffers = NULL;
+ return -ENOMEM;
+ }
+
+ priv->tx_ring = (struct adm8211_desc *) (priv->rx_ring +
priv->rx_ring_size);
+ priv->tx_ring_dma = priv->rx_ring_dma +
+ sizeof(struct adm8211_desc) * priv->rx_ring_size;
+
+ return 0;
+}
+
+static int __devinit adm8211_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *dev;
+ struct ieee80211_hw *hw;
+ struct adm8211_priv *priv;
+ unsigned long mem_addr, mem_len;
+ unsigned int io_addr, io_len;
+ int err;
+ u32 reg;
+
+#ifndef MODULE
+ static unsigned int cardidx;
+ if (!cardidx++)
+ printk(version);
+#endif
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n",
pci_name(pdev));
+ return err;
+ }
+
+ io_addr = pci_resource_start(pdev, 0);
+ io_len = pci_resource_len(pdev, 0);
+ mem_addr = pci_resource_start(pdev, 1);
+ mem_len = pci_resource_len(pdev, 1);
+ if (io_len < 256 || mem_len < 1024) {
+ printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", pci_name(pdev));
+ goto err_disable_pdev;
+ }
+
+
+ /* check signature */
+ pci_read_config_dword(pdev, 0x80 /* CR32 */, ®);
+ if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {
+ printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n", pci_name(pdev),
reg);
+ goto err_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, "adm8211");
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n",
pci_name(pdev));
+ return err; /* someone else grabbed it? don't disable it */
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "%s (adm8211): No suitable DMA available\n",
pci_name(pdev));
+ goto err_free_reg;
+ }
+
+ pci_set_master(pdev);
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), NULL);
+ if (!dev) {
+ printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n", pci_name(pdev));
+ err = -ENOMEM;
+ goto err_free_reg;
+ }
+ priv = ieee80211_dev_hw_data(dev);
+ hw = &priv->hw;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->lock);
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ pci_set_drvdata(pdev, dev);
+ priv->msg_enable = netif_msg_init(debug, NETIF_MSG_DRV | NETIF_MSG_PROBE);
+
+ priv->map = pci_iomap(pdev, 1, mem_len);
+ if (!priv->map)
+ priv->map = pci_iomap(pdev, 0, io_len);
+
+ if (!priv->map) {
+ printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
pci_name(pdev));
+ goto err_free_dev;
+ }
+
+ dev->mem_start = mem_addr;
+ dev->mem_end = mem_addr + mem_len;
+ dev->base_addr = io_addr;
+ dev->irq = pdev->irq;
+
+ priv->rx_ring_size = rx_ring_size;
+ priv->tx_ring_size = tx_ring_size;
+
+ if (adm8211_alloc_rings(dev)) {
+ printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n",
pci_name(pdev));
+ goto err_iounmap;
+ }
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &priv->revid);
+
+ put_unaligned(ADM8211_CSR_READ(PAR0), (u32 *) dev->dev_addr);
+ put_unaligned(ADM8211_CSR_READ(PAR1) & (__force u32) __constant_cpu_to_le32
(0xffff),
+ (u16 *) &dev->dev_addr[4]);
+
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid hwaddr! Using randomly generated
hwaddr\n", pci_name(pdev));
+ random_ether_addr(dev->dev_addr);
+ }
+
+ hw->version = 2;
+ hw->name = "adm8211";
+ hw->host_gen_beacon = 0;
+ hw->device_hides_wep = 0;
+ hw->rx_includes_fcs = 0; // however, FCS is kept in promisc mode
+ hw->host_broadcast_ps_buffering = 0;
+ hw->wep_include_iv = 1;
+ hw->data_nullfunc_ack = 0;
+ hw->no_tkip_wmm_hwaccel = 1;
+ hw->extra_hdr_room = 0;
+ hw->device_strips_mic = 0;
+ hw->monitor_during_oper = 0;
+ hw->fraglist = 0;
+ hw->channel_change_time = 1000;
+
+ hw->num_modes = 1;
+ hw->modes = priv->modes;
+ priv->modes[0].mode = MODE_IEEE80211B;
+ /* channel info filled in by adm8211_read_eeprom */
+ memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+ priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+ priv->modes[0].rates = priv->rates;
+
+ hw->tx = adm8211_tx;
+ hw->reset = adm8211_reset;
+ hw->open = adm8211_open;
+ hw->stop = adm8211_stop;
+ hw->add_interface = adm8211_add_interface;
+ hw->remove_interface = adm8211_remove_interface;
+
+ hw->config = adm8211_config;
+ hw->config_interface = adm8211_config_interface;
+ hw->set_multicast_list = adm8211_set_rx_mode;
+ hw->passive_scan = adm8211_scan;
+ hw->get_stats = adm8211_get_stats;
+ hw->get_tsf = adm8211_get_tsft;
+ hw->get_tx_stats = adm8211_get_tx_stats;
+ hw->queues = 1; // ADM8211C supports more, maybe ADM8211B
+
+ priv->retry_limit = 3;
+ priv->ant_power = 0x40;
+ priv->tx_power = 0x40;
+ priv->lpf_cutoff = 0xFF;
+ priv->lnags_threshold = 0xFF;
+
+ /* Power-on issue. EEPROM won't read correctly without */
+ if (priv->revid >= ADM8211_REV_BA) {
+ ADM8211_CSR_WRITE(FRCTL, 0);
+ ADM8211_CSR_READ(FRCTL);
+ ADM8211_CSR_WRITE(FRCTL, 1);
+ ADM8211_CSR_READ(FRCTL);
+ mdelay(100);
+ }
+
+ err = adm8211_read_eeprom(dev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot allocate eeprom buffer\n",
pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ priv->channel = priv->modes[0].channels[0].chan;
+
+ err = ieee80211_register_hw(dev, &priv->hw);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot register netdevice\n",
pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ printk("%s: hwaddr " MAC_FMT ", Rev 0x%02x\n",
+ dev->name, MAC_ARG(dev->dev_addr), priv->revid);
+
+ return 0;
+
+ err_free_desc:
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+ kfree(priv->rx_buffers);
+
+ err_iounmap:
+ pci_iounmap(pdev, priv->map);
+
+ err_free_dev:
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(dev);
+
+ err_free_reg:
+ pci_release_regions(pdev);
+
+ err_disable_pdev:
+ pci_disable_device(pdev);
+ return err;
+}
+
+
+static void __devexit adm8211_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = ieee80211_dev_hw_data(dev);
+
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+
+ kfree(priv->rx_buffers);
+ kfree(priv->eeprom);
+ pci_iounmap(pdev, priv->map);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(dev);
+}
+
+
+#ifdef CONFIG_PM
+static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ netif_device_detach(dev);
+
+ if (dev->flags & IFF_UP)
+ dev->stop(dev);
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+
+static int adm8211_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (dev->flags & IFF_UP)
+ dev->open(dev);
+
+ netif_device_attach(dev);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);
+
+/* TODO: enable_wake */
+static struct pci_driver adm8211_driver = {
+ .name = "adm8211",
+ .id_table = adm8211_pci_id_table,
+ .probe = adm8211_probe,
+ .remove = __devexit_p(adm8211_remove),
+#ifdef CONFIG_PM
+ .suspend = adm8211_suspend,
+ .resume = adm8211_resume,
+#endif /* CONFIG_PM */
+};
+
+
+
+static int __init adm8211_init(void)
+{
+#ifdef MODULE
+ printk(version);
+#endif
+
+ return pci_register_driver(&adm8211_driver);
+}
+
+
+static void __exit adm8211_exit(void)
+{
+ pci_unregister_driver(&adm8211_driver);
+}
+
+
+module_init(adm8211_init);
+module_exit(adm8211_exit);
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.h
b/drivers/net/wireless/d80211/adm8211/adm8211.h
new file mode 100644
index 0000000..c215013
--- /dev/null
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.h
<at> <at> -0,0 +1,631 <at> <at>
+#ifndef ADM8211_H
+#define ADM8211_H
+
+/* ADM8211 Registers */
+
+/* CR32 (SIG) signature */
+#define ADM8211_SIG1 0x82011317 /* ADM8211A */
+#define ADM8211_SIG2 0x82111317 /* ADM8211B/ADM8211C */
+
+#define ADM8211_CSR_READ(r) ioread32(&priv->map->r)
+#define ADM8211_CSR_WRITE(r, val) iowrite32((__force u32)(val),
&priv->map->r)
+
+/* CSR (Host Control and Status Registers) */
+struct adm8211_csr {
+ __le32 PAR; /* 0x00 CSR0 */
+ __le32 FRCTL; /* 0x04 CSR0A */
+ __le32 TDR; /* 0x08 CSR1 */
+ __le32 WTDP; /* 0x0C CSR1A */
+ __le32 RDR; /* 0x10 CSR2 */
+ __le32 WRDP; /* 0x14 CSR2A */
+ __le32 RDB; /* 0x18 CSR3 */
+ __le32 TDBH; /* 0x1C CSR3A */
+ __le32 TDBD; /* 0x20 CSR4 */
+ __le32 TDBP; /* 0x24 CSR4A */
+ __le32 STSR; /* 0x28 CSR5 */
+ __le32 TDBB; /* 0x2C CSR5A */
+ __le32 NAR; /* 0x30 CSR6 */
+ __le32 CSR6A; /* reserved */
+ __le32 IER; /* 0x38 CSR7 */
+ __le32 TKIPSCEP; /* 0x3C CSR7A */
+ __le32 LPC; /* 0x40 CSR8 */
+ __le32 CSR_TEST1; /* 0x44 CSR8A */
+ __le32 SPR; /* 0x48 CSR9 */
+ __le32 CSR_TEST0; /* 0x4C CSR9A */
+ __le32 WCSR; /* 0x50 CSR10 */
+ __le32 WPDR; /* 0x54 CSR10A */
+ __le32 GPTMR; /* 0x58 CSR11 */
+ __le32 GPIO; /* 0x5C CSR11A */
+ __le32 BBPCTL; /* 0x60 CSR12 */
+ __le32 SYNCTL; /* 0x64 CSR12A */
+ __le32 PLCPHD; /* 0x68 CSR13 */
+ __le32 MMIWA; /* 0x6C CSR13A */
+ __le32 MMIRD0; /* 0x70 CSR14 */
+ __le32 MMIRD1; /* 0x74 CSR14A */
+ __le32 TXBR; /* 0x78 CSR15 */
+ __le32 SYNDATA; /* 0x7C CSR15A */
+ __le32 ALCS; /* 0x80 CSR16 */
+ __le32 TOFS2; /* 0x84 CSR17 */
+ __le32 CMDR; /* 0x88 CSR18 */
+ __le32 PCIC; /* 0x8C CSR19 */
+ __le32 PMCSR; /* 0x90 CSR20 */
+ __le32 PAR0; /* 0x94 CSR21 */
+ __le32 PAR1; /* 0x98 CSR22 */
+ __le32 MAR0; /* 0x9C CSR23 */
+ __le32 MAR1; /* 0xA0 CSR24 */
+ __le32 ATIMDA0; /* 0xA4 CSR25 */
+ __le32 ABDA1; /* 0xA8 CSR26 */
+ __le32 BSSID0; /* 0xAC CSR27 */
+ __le32 TXLMT; /* 0xB0 CSR28 */
+ __le32 MIBCNT; /* 0xB4 CSR29 */
+ __le32 BCNT; /* 0xB8 CSR30 */
+ __le32 TSFTH; /* 0xBC CSR31 */
+ __le32 TSC; /* 0xC0 CSR32 */
+ __le32 SYNRF; /* 0xC4 CSR33 */
+ __le32 BPLI; /* 0xC8 CSR34 */
+ __le32 CAP0; /* 0xCC CSR35 */
+ __le32 CAP1; /* 0xD0 CSR36 */
+ __le32 RMD; /* 0xD4 CSR37 */
+ __le32 CFPP; /* 0xD8 CSR38 */
+ __le32 TOFS0; /* 0xDC CSR39 */
+ __le32 TOFS1; /* 0xE0 CSR40 */
+ __le32 IFST; /* 0xE4 CSR41 */
+ __le32 RSPT; /* 0xE8 CSR42 */
+ __le32 TSFTL; /* 0xEC CSR43 */
+ __le32 WEPCTL; /* 0xF0 CSR44 */
+ __le32 WESK; /* 0xF4 CSR45 */
+ __le32 WEPCNT; /* 0xF8 CSR46 */
+ __le32 MACTEST; /* 0xFC CSR47 */
+ __le32 FER; /* 0x100 */
+ __le32 FEMR; /* 0x104 */
+ __le32 FPSR; /* 0x108 */
+ __le32 FFER; /* 0x10C */
+} __attribute__ ((packed));
+
+/* CSR0 - PAR (PCI Address Register) */
+#define ADM8211_PAR_MWIE (1 << 24)
+#define ADM8211_PAR_MRLE (1 << 23)
+#define ADM8211_PAR_MRME (1 << 21)
+#define ADM8211_PAR_RAP ((1 << 18) | (1 << 17))
+#define ADM8211_PAR_CAL ((1 << 15) | (1 << 14))
+#define ADM8211_PAR_PBL 0x00003f00
+#define ADM8211_PAR_BLE (1 << 7)
+#define ADM8211_PAR_DSL 0x0000007c
+#define ADM8211_PAR_BAR (1 << 1)
+#define ADM8211_PAR_SWR (1 << 0)
+
+/* CSR1 - FRCTL (Frame Control Register) */
+#define ADM8211_FRCTL_PWRMGT (1 << 31)
+#define ADM8211_FRCTL_MAXPSP (1 << 27)
+#define ADM8211_FRCTL_DRVPRSP (1 << 26)
+#define ADM8211_FRCTL_DRVBCON (1 << 25)
+#define ADM8211_FRCTL_AID 0x0000ffff
+#define ADM8211_FRCTL_AID_ON 0x0000c000
+
+/* CSR5 - STSR (Status Register) */
+#define ADM8211_STSR_PCF (1 << 31)
+#define ADM8211_STSR_BCNTC (1 << 30)
+#define ADM8211_STSR_GPINT (1 << 29)
+#define ADM8211_STSR_LinkOff (1 << 28)
+#define ADM8211_STSR_ATIMTC (1 << 27)
+#define ADM8211_STSR_TSFTF (1 << 26)
+#define ADM8211_STSR_TSCZ (1 << 25)
+#define ADM8211_STSR_LinkOn (1 << 24)
+#define ADM8211_STSR_SQL (1 << 23)
+#define ADM8211_STSR_WEPTD (1 << 22)
+#define ADM8211_STSR_ATIME (1 << 21)
+#define ADM8211_STSR_TBTT (1 << 20)
+#define ADM8211_STSR_NISS (1 << 16)
+#define ADM8211_STSR_AISS (1 << 15)
+#define ADM8211_STSR_TEIS (1 << 14)
+#define ADM8211_STSR_FBE (1 << 13)
+#define ADM8211_STSR_REIS (1 << 12)
+#define ADM8211_STSR_GPTT (1 << 11)
+#define ADM8211_STSR_RPS (1 << 8)
+#define ADM8211_STSR_RDU (1 << 7)
+#define ADM8211_STSR_RCI (1 << 6)
+#define ADM8211_STSR_TUF (1 << 5)
+#define ADM8211_STSR_TRT (1 << 4)
+#define ADM8211_STSR_TLT (1 << 3)
+#define ADM8211_STSR_TDU (1 << 2)
+#define ADM8211_STSR_TPS (1 << 1)
+#define ADM8211_STSR_TCI (1 << 0)
+
+/* CSR6 - NAR (Network Access Register) */
+#define ADM8211_NAR_TXCF (1 << 31)
+#define ADM8211_NAR_HF (1 << 30)
+#define ADM8211_NAR_UTR (1 << 29)
+#define ADM8211_NAR_SQ (1 << 28)
+#define ADM8211_NAR_CFP (1 << 27)
+#define ADM8211_NAR_SF (1 << 21)
+#define ADM8211_NAR_TR ((1 << 15) | (1 << 14))
+#define ADM8211_NAR_ST (1 << 13)
+#define ADM8211_NAR_OM ((1 << 11) | (1 << 10))
+#define ADM8211_NAR_MM (1 << 7)
+#define ADM8211_NAR_PR (1 << 6)
+#define ADM8211_NAR_EA (1 << 5)
+#define ADM8211_NAR_PB (1 << 3)
+#define ADM8211_NAR_STPDMA (1 << 2)
+#define ADM8211_NAR_SR (1 << 1)
+#define ADM8211_NAR_CTX (1 << 0)
+
+#define ADM8211_IDLE() do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) {\
+ ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~(ADM8211_NAR_SR |
ADM8211_NAR_ST)));\
+ ADM8211_CSR_READ(NAR);\
+ mdelay(20);\
+ }\
+} while (0)
+
+#define ADM8211_IDLE_RX() do { \
+ if (priv->nar & ADM8211_NAR_SR) {\
+ ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~ADM8211_NAR_SR));\
+ ADM8211_CSR_READ(NAR);\
+ mdelay(20);\
+ }\
+} while (0)
+
+#define ADM8211_IDLE_TX() do { \
+ if (priv->nar & ADM8211_NAR_ST) {\
+ ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar & ~ADM8211_NAR_ST));\
+ ADM8211_CSR_READ(NAR);\
+ mdelay(20);\
+ }\
+} while (0)
+
+#define ADM8211_RESTORE() do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \
+ ADM8211_CSR_WRITE(NAR, cpu_to_le32(priv->nar));\
+} while (0)
+
+/* CSR7 - IER (Interrupt Enable Register) */
+#define ADM8211_IER_PCFIE (1 << 31)
+#define ADM8211_IER_BCNTCIE (1 << 30)
+#define ADM8211_IER_GPIE (1 << 29)
+#define ADM8211_IER_LinkOffIE (1 << 28)
+#define ADM8211_IER_ATIMTCIE (1 << 27)
+#define ADM8211_IER_TSFTFIE (1 << 26)
+#define ADM8211_IER_TSCZE (1 << 25)
+#define ADM8211_IER_LinkOnIE (1 << 24)
+#define ADM8211_IER_SQLIE (1 << 23)
+#define ADM8211_IER_WEPIE (1 << 22)
+#define ADM8211_IER_ATIMEIE (1 << 21)
+#define ADM8211_IER_TBTTIE (1 << 20)
+#define ADM8211_IER_NIE (1 << 16)
+#define ADM8211_IER_AIE (1 << 15)
+#define ADM8211_IER_TEIE (1 << 14)
+#define ADM8211_IER_FBEIE (1 << 13)
+#define ADM8211_IER_REIE (1 << 12)
+#define ADM8211_IER_GPTIE (1 << 11)
+#define ADM8211_IER_RSIE (1 << 8)
+#define ADM8211_IER_RUIE (1 << 7)
+#define ADM8211_IER_RCIE (1 << 6)
+#define ADM8211_IER_TUIE (1 << 5)
+#define ADM8211_IER_TRTIE (1 << 4)
+#define ADM8211_IER_TLTTIE (1 << 3)
+#define ADM8211_IER_TDUIE (1 << 2)
+#define ADM8211_IER_TPSIE (1 << 1)
+#define ADM8211_IER_TCIE (1 << 0)
+
+/* CSR9 - SPR (Serial Port Register) */
+#define ADM8211_SPR_SRS (1 << 11)
+#define ADM8211_SPR_SDO (1 << 3)
+#define ADM8211_SPR_SDI (1 << 2)
+#define ADM8211_SPR_SCLK (1 << 1)
+#define ADM8211_SPR_SCS (1 << 0)
+
+/* CSR9A - CSR_TEST0 */
+#define ADM8211_CSR_TEST0_EPNE (1 << 18)
+#define ADM8211_CSR_TEST0_EPSNM (1 << 17)
+#define ADM8211_CSR_TEST0_EPTYP (1 << 16)
+#define ADM8211_CSR_TEST0_EPRLD (1 << 15)
+
+/* CSR10 - WCSR (Wake-up Control/Status Register) */
+#define ADM8211_WCSR_CRCT (1 << 30)
+#define ADM8211_WCSR_TSFTWE (1 << 20)
+#define ADM8211_WCSR_TIMWE (1 << 19)
+#define ADM8211_WCSR_ATIMWE (1 << 18)
+#define ADM8211_WCSR_KEYWE (1 << 17)
+#define ADM8211_WCSR_MPRE (1 << 9)
+#define ADM8211_WCSR_LSOE (1 << 8)
+#define ADM8211_WCSR_KEYUP (1 << 6)
+#define ADM8211_WCSR_TSFTW (1 << 5)
+#define ADM8211_WCSR_TIMW (1 << 4)
+#define ADM8211_WCSR_ATIMW (1 << 3)
+#define ADM8211_WCSR_MPR (1 << 1)
+#define ADM8211_WCSR_LSO (1 << 0)
+
+/* CSR11A - GPIO */
+#define ADM8211_CSR_GPIO_EN5 (1 << 17)
+#define ADM8211_CSR_GPIO_EN4 (1 << 16)
+#define ADM8211_CSR_GPIO_EN3 (1 << 15)
+#define ADM8211_CSR_GPIO_EN2 (1 << 14)
+#define ADM8211_CSR_GPIO_EN1 (1 << 13)
+#define ADM8211_CSR_GPIO_EN0 (1 << 12)
+#define ADM8211_CSR_GPIO_O5 (1 << 11)
+#define ADM8211_CSR_GPIO_O4 (1 << 10)
+#define ADM8211_CSR_GPIO_O3 (1 << 9)
+#define ADM8211_CSR_GPIO_O2 (1 << 8)
+#define ADM8211_CSR_GPIO_O1 (1 << 7)
+#define ADM8211_CSR_GPIO_O0 (1 << 6)
+#define ADM8211_CSR_GPIO_IN 0x0000003f
+
+/* CSR12 - BBPCTL (BBP Control port) */
+#define ADM8211_BBPCTL_MMISEL (1 << 31)
+#define ADM8211_BBPCTL_SPICADD (0x7F << 24)
+#define ADM8211_BBPCTL_RF3000 (0x20 << 24)
+#define ADM8211_BBPCTL_TXCE (1 << 23)
+#define ADM8211_BBPCTL_RXCE (1 << 22)
+#define ADM8211_BBPCTL_CCAP (1 << 21)
+#define ADM8211_BBPCTL_TYPE 0x001c0000
+#define ADM8211_BBPCTL_WR (1 << 17)
+#define ADM8211_BBPCTL_RD (1 << 16)
+#define ADM8211_BBPCTL_ADDR 0x0000ff00
+#define ADM8211_BBPCTL_DATA 0x000000ff
+
+/* CSR12A - SYNCTL (Synthesizer Control port) */
+#define ADM8211_SYNCTL_WR (1 << 31)
+#define ADM8211_SYNCTL_RD (1 << 30)
+#define ADM8211_SYNCTL_CS0 (1 << 29)
+#define ADM8211_SYNCTL_CS1 (1 << 28)
+#define ADM8211_SYNCTL_CAL (1 << 27)
+#define ADM8211_SYNCTL_SELCAL (1 << 26)
+#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFMD (1 << 22)
+#define ADM8211_SYNCTL_GENERAL (0x7 << 22)
+/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
+
+/* CSR18 - CMDR (Command Register) */
+#define ADM8211_CMDR_PM (1 << 19)
+#define ADM8211_CMDR_APM (1 << 18)
+#define ADM8211_CMDR_RTE (1 << 4)
+#define ADM8211_CMDR_DRT ((1 << 3) | (1 << 2))
+#define ADM8211_CMDR_DRT_8DW (0x0 << 2)
+#define ADM8211_CMDR_DRT_16DW (0x1 << 2)
+#define ADM8211_CMDR_DRT_SF (0x2 << 2)
+
+/* CSR33 - SYNRF (SYNRF direct control) */
+#define ADM8211_SYNRF_SELSYN (1 << 31)
+#define ADM8211_SYNRF_SELRF (1 << 30)
+#define ADM8211_SYNRF_LERF (1 << 29)
+#define ADM8211_SYNRF_LEIF (1 << 28)
+#define ADM8211_SYNRF_SYNCLK (1 << 27)
+#define ADM8211_SYNRF_SYNDATA (1 << 26)
+#define ADM8211_SYNRF_PE1 (1 << 25)
+#define ADM8211_SYNRF_PE2 (1 << 24)
+#define ADM8211_SYNRF_PA_PE (1 << 23)
+#define ADM8211_SYNRF_TR_SW (1 << 22)
+#define ADM8211_SYNRF_TR_SWN (1 << 21)
+#define ADM8211_SYNRF_RADIO (1 << 20)
+#define ADM8211_SYNRF_CAL_EN (1 << 19)
+#define ADM8211_SYNRF_PHYRST (1 << 18)
+
+#define ADM8211_SYNRF_IF_SELECT_0 (1 << 31)
+#define ADM8211_SYNRF_IF_SELECT_1 ((1 << 31) | (1 << 28))
+#define ADM8211_SYNRF_WRITE_SYNDATA_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_SYNDATA_1 ((1 << 31) | (1 << 26))
+#define ADM8211_SYNRF_WRITE_CLOCK_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_CLOCK_1 ((1 << 31) | (1 << 27))
+
+/* CSR44 - WEPCTL (WEP Control) */
+#define ADM8211_WEPCTL_WEPENABLE (1 << 31)
+#define ADM8211_WEPCTL_WPAENABLE (1 << 30)
+#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29)
+#define ADM8211_WEPCTL_TABLE_WR (1 << 28)
+#define ADM8211_WEPCTL_TABLE_RD (1 << 27)
+#define ADM8211_WEPCTL_WEPRXBYP (1 << 25)
+#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23)
+#define ADM8211_WEPCTL_ADDR (0x000001ff)
+
+/* CSR45 - WESK (Data Entry for Share/Individual Key) */
+#define ADM8211_WESK_DATA (0x0000ffff)
+
+/* FER (Function Event Register) */
+#define ADM8211_FER_INTR_EV_ENT (1 << 15)
+
+
+/* Si4126 RF Synthesizer - Control Registers */
+#define SI4126_MAIN_CONF 0
+#define SI4126_PHASE_DET_GAIN 1
+#define SI4126_POWERDOWN 2
+#define SI4126_RF1_N_DIV 3 /* only Si4136 */
+#define SI4126_RF2_N_DIV 4
+#define SI4126_IF_N_DIV 5
+#define SI4126_RF1_R_DIV 6 /* only Si4136 */
+#define SI4126_RF2_R_DIV 7
+#define SI4126_IF_R_DIV 8
+
+/* Main Configuration */
+#define SI4126_MAIN_XINDIV2 (1 << 6)
+#define SI4126_MAIN_IFDIV ((1 << 11) | (1 << 10))
+/* Powerdown */
+#define SI4126_POWERDOWN_PDIB (1 << 1)
+#define SI4126_POWERDOWN_PDRB (1 << 0)
+
+
+/* RF3000 BBP - Control Port Registers */
+/* 0x00 - reserved */
+#define RF3000_MODEM_CTRL__RX_STATUS 0x01
+#define RF3000_CCA_CTRL 0x02
+#define RF3000_DIVERSITY__RSSI 0x03
+#define RF3000_RX_SIGNAL_FIELD 0x04
+#define RF3000_RX_LEN_MSB 0x05
+#define RF3000_RX_LEN_LSB 0x06
+#define RF3000_RX_SERVICE_FIELD 0x07
+#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11
+#define RF3000_TX_LEN_MSB 0x12
+#define RF3000_TX_LEN_LSB 0x13
+#define RF3000_LOW_GAIN_CALIB 0x14
+#define RF3000_HIGH_GAIN_CALIB 0x15
+
+/* ADM8211 revisions */
+#define ADM8211_REV_AB 0x11
+#define ADM8211_REV_AF 0x15
+#define ADM8211_REV_BA 0x20
+#define ADM8211_REV_CA 0x30
+
+struct adm8211_desc {
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2;
+};
+
+#define RDES0_STATUS_OWN (1 << 31)
+#define RDES0_STATUS_ES (1 << 30)
+#define RDES0_STATUS_SQL (1 << 29)
+#define RDES0_STATUS_DE (1 << 28)
+#define RDES0_STATUS_FS (1 << 27)
+#define RDES0_STATUS_LS (1 << 26)
+#define RDES0_STATUS_PCF (1 << 25)
+#define RDES0_STATUS_SFDE (1 << 24)
+#define RDES0_STATUS_SIGE (1 << 23)
+#define RDES0_STATUS_CRC16E (1 << 22)
+#define RDES0_STATUS_RXTOE (1 << 21)
+#define RDES0_STATUS_CRC32E (1 << 20)
+#define RDES0_STATUS_ICVE (1 << 19)
+#define RDES0_STATUS_DA1 (1 << 17)
+#define RDES0_STATUS_DA0 (1 << 16)
+#define RDES0_STATUS_RXDR ((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12))
+#define RDES0_STATUS_FL (0x00000fff)
+
+#define RDES1_CONTROL_RER (1 << 25)
+#define RDES1_CONTROL_RCH (1 << 24)
+#define RDES1_CONTROL_RBS2 (0x00fff000)
+#define RDES1_CONTROL_RBS1 (0x00000fff)
+
+#define RDES1_STATUS_RSSI (0x0000007f)
+
+
+#define TDES0_CONTROL_OWN (1 << 31)
+#define TDES0_CONTROL_DONE (1 << 30)
+#define TDES0_CONTROL_TXDR (0x0ff00000)
+
+#define TDES0_STATUS_OWN (1 << 31)
+#define TDES0_STATUS_DONE (1 << 30)
+#define TDES0_STATUS_ES (1 << 29)
+#define TDES0_STATUS_TLT (1 << 28)
+#define TDES0_STATUS_TRT (1 << 27)
+#define TDES0_STATUS_TUF (1 << 26)
+#define TDES0_STATUS_TRO (1 << 25)
+#define TDES0_STATUS_SOFBR (1 << 24)
+#define TDES0_STATUS_ACR (0x00000fff)
+
+#define TDES1_CONTROL_IC (1 << 31)
+#define TDES1_CONTROL_LS (1 << 30)
+#define TDES1_CONTROL_FS (1 << 29)
+#define TDES1_CONTROL_TER (1 << 25)
+#define TDES1_CONTROL_TCH (1 << 24)
+#define TDES1_CONTROL_RBS2 (0x00fff000)
+#define TDES1_CONTROL_RBS1 (0x00000fff)
+
+/* SRAM offsets */
+#define ADM8211_SRAM(x) (priv->revid < ADM8211_REV_BA ? \
+ ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x)
+
+#define ADM8211_SRAM_INDIV_KEY 0x0000
+#define ADM8211_SRAM_A_SHARE_KEY 0x0160
+#define ADM8211_SRAM_B_SHARE_KEY 0x00c0
+
+#define ADM8211_SRAM_A_SSID 0x0180
+#define ADM8211_SRAM_B_SSID 0x00d4
+#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID)
+
+#define ADM8211_SRAM_A_SUPP_RATE 0x0191
+#define ADM8211_SRAM_B_SUPP_RATE 0x00dd
+#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE)
+
+#define ADM8211_SRAM_A_SIZE 0x0200
+#define ADM8211_SRAM_B_SIZE 0x01c0
+#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
+
+struct adm8211_ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ struct ieee80211_tx_status tx_status;
+ int unicast;
+};
+
+struct adm8211_eeprom {
+ __le16 signature; /* 0x00 */
+ u8 major_version; /* 0x02 */
+ u8 minor_version; /* 0x03 */
+ u8 reserved_1[4]; /* 0x04 */
+ u8 hwaddr[6]; /* 0x08 */
+ u8 reserved_2[8]; /* 0x1E */
+ __le16 cr49; /* 0x16 */
+ u8 cr03; /* 0x18 */
+ u8 cr28; /* 0x19 */
+ u8 cr29; /* 0x1A */
+ u8 country_code; /* 0x1B */
+
+/* specific bbp types */
+#define ADM8211_BBP_RFMD3000 0x00
+#define ADM8211_BBP_RFMD3002 0x01
+#define ADM8211_BBP_ADM8011 0x04
+ u8 specific_bbptype; /* 0x1C */
+ u8 specific_rftype; /* 0x1D */
+ u8 reserved_3[2]; /* 0x1E */
+ __le16 device_id; /* 0x20 */
+ __le16 vendor_id; /* 0x22 */
+ __le16 subsystem_id; /* 0x24 */
+ __le16 subsystem_vendor_id; /* 0x26 */
+ u8 maxlat; /* 0x28 */
+ u8 mingnt; /* 0x29 */
+ __le16 cis_pointer_low; /* 0x2A */
+ __le16 cis_pointer_high; /* 0x2C */
+ __le16 csr18; /* 0x2E */
+ u8 reserved_4[16]; /* 0x30 */
+ u8 d1_pwrdara; /* 0x40 */
+ u8 d0_pwrdara; /* 0x41 */
+ u8 d3_pwrdara; /* 0x42 */
+ u8 d2_pwrdara; /* 0x43 */
+ u8 antenna_power[14]; /* 0x44 */
+ __le16 cis_wordcnt; /* 0x52 */
+ u8 tx_power[14]; /* 0x54 */
+ u8 lpf_cutoff[14]; /* 0x62 */
+ u8 lnags_threshold[14]; /* 0x70 */
+ __le16 checksum; /* 0x7E */
+ u8 cis_data[0]; /* 0x80, 384 bytes */
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate adm8211_rates[] = {
+ { .rate = 10,
+ .val = 10,
+ .val2 = -10,
+ .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK },
+ { .rate = 20,
+ .val = 20,
+ .val2 = -20,
+ .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = 55,
+ .val2 = -55,
+ .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = 110,
+ .val2 = -110,
+ .flags = IEEE80211_RATE_PREAMBLE2 | IEEE80211_RATE_CCK_2 }
+};
+
+struct ieee80211_chan_range {
+ u8 min;
+ u8 max;
+};
+
+struct adm8211_priv {
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ struct adm8211_csr __iomem *map;
+ struct adm8211_desc *rx_ring;
+ struct adm8211_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+ struct adm8211_ring_info *rx_buffers;
+ struct adm8211_ring_info *tx_buffers;
+ unsigned rx_ring_size, tx_ring_size;
+ unsigned cur_tx, dirty_tx, cur_rx;
+
+ struct ieee80211_hw hw;
+ struct ieee80211_low_level_stats stats;
+ struct ieee80211_hw_modes modes[1];
+ struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+ int mode;
+
+ int channel;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+
+ u32 msg_enable;
+
+ int (*eth_header_parse)(struct sk_buff *skb, unsigned char *haddr);
+
+ u8 soft_rx_crc;
+ u8 retry_limit;
+
+ u8 ant_power;
+ u8 tx_power;
+ u8 lpf_cutoff;
+ u8 lnags_threshold;
+ struct adm8211_eeprom *eeprom;
+ size_t eeprom_len;
+
+ u8 revid;
+
+ u32 nar;
+
+#define ADM8211_TYPE_INTERSIL 0x00
+#define ADM8211_TYPE_RFMD 0x01
+#define ADM8211_TYPE_MARVEL 0x02
+#define ADM8211_TYPE_AIROHA 0x03
+#define ADM8211_TYPE_ADMTEK 0x05
+ unsigned int rf_type:3;
+ unsigned int bbp_type:3;
+
+ u8 specific_bbptype;
+ enum {
+ ADM8211_RFMD2948 = 0x0,
+ ADM8211_RFMD2958 = 0x1,
+ ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2,
+ ADM8211_MAX2820 = 0x8,
+ ADM8211_AL2210L = 0xC, /* Airoha */
+ } transceiver_type;
+};
+
+static const struct ieee80211_chan_range cranges[] = {
+ {1, 11}, /* FCC */
+ {1, 11}, /* IC */
+ {1, 13}, /* ETSI */
+ {10, 11}, /* SPAIN */
+ {10, 13}, /* FRANCE */
+ {14, 14}, /* MMK */
+ {1, 14}, /* MMK2 */
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+ { .chan = 1,
+ .freq = 2412,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 2,
+ .freq = 2417,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 3,
+ .freq = 2422,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 4,
+ .freq = 2427,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 5,
+ .freq = 2432,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 6,
+ .freq = 2437,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 7,
+ .freq = 2442,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 8,
+ .freq = 2447,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 9,
+ .freq = 2452,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 10,
+ .freq = 2457,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 11,
+ .freq = 2462,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 12,
+ .freq = 2467,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 13,
+ .freq = 2472,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS},
+ { .chan = 14,
+ .freq = 2484,
+ .flag = IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
IEEE80211_CHAN_W_IBSS}
+};
+
+#endif /* ADM8211_H */
|
|
|