From 1c740ed2210a0d124674a477ea538468aba47810 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 31 Oct 2008 17:19:31 -0700 Subject: Move all rtl818x files to a common directory. This change improves the maintainability of these drivers. No functionality is changed. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/Makefile | 8 +- drivers/net/wireless/rtl8180.h | 120 --- drivers/net/wireless/rtl8180_dev.c | 1081 -------------------- drivers/net/wireless/rtl8180_grf5101.c | 180 ---- drivers/net/wireless/rtl8180_grf5101.h | 28 - drivers/net/wireless/rtl8180_max2820.c | 152 --- drivers/net/wireless/rtl8180_max2820.h | 28 - drivers/net/wireless/rtl8180_rtl8225.c | 780 -------------- drivers/net/wireless/rtl8180_rtl8225.h | 23 - drivers/net/wireless/rtl8180_sa2400.c | 202 ---- drivers/net/wireless/rtl8180_sa2400.h | 36 - drivers/net/wireless/rtl8187.h | 220 ---- drivers/net/wireless/rtl8187_dev.c | 1298 ------------------------ drivers/net/wireless/rtl8187_rtl8225.c | 977 ------------------ drivers/net/wireless/rtl8187_rtl8225.h | 44 - drivers/net/wireless/rtl818x.h | 231 ----- drivers/net/wireless/rtl818x/Makefile | 7 + drivers/net/wireless/rtl818x/rtl8180.h | 120 +++ drivers/net/wireless/rtl818x/rtl8180_dev.c | 1081 ++++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8180_grf5101.c | 180 ++++ drivers/net/wireless/rtl818x/rtl8180_grf5101.h | 28 + drivers/net/wireless/rtl818x/rtl8180_max2820.c | 152 +++ drivers/net/wireless/rtl818x/rtl8180_max2820.h | 28 + drivers/net/wireless/rtl818x/rtl8180_rtl8225.c | 780 ++++++++++++++ drivers/net/wireless/rtl818x/rtl8180_rtl8225.h | 23 + drivers/net/wireless/rtl818x/rtl8180_sa2400.c | 202 ++++ drivers/net/wireless/rtl818x/rtl8180_sa2400.h | 36 + drivers/net/wireless/rtl818x/rtl8187.h | 220 ++++ drivers/net/wireless/rtl818x/rtl8187_dev.c | 1298 ++++++++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8187_rtl8225.c | 977 ++++++++++++++++++ drivers/net/wireless/rtl818x/rtl8187_rtl8225.h | 44 + drivers/net/wireless/rtl818x/rtl818x.h | 231 +++++ 32 files changed, 5409 insertions(+), 5406 deletions(-) delete mode 100644 drivers/net/wireless/rtl8180.h delete mode 100644 drivers/net/wireless/rtl8180_dev.c delete mode 100644 drivers/net/wireless/rtl8180_grf5101.c delete mode 100644 drivers/net/wireless/rtl8180_grf5101.h delete mode 100644 drivers/net/wireless/rtl8180_max2820.c delete mode 100644 drivers/net/wireless/rtl8180_max2820.h delete mode 100644 drivers/net/wireless/rtl8180_rtl8225.c delete mode 100644 drivers/net/wireless/rtl8180_rtl8225.h delete mode 100644 drivers/net/wireless/rtl8180_sa2400.c delete mode 100644 drivers/net/wireless/rtl8180_sa2400.h delete mode 100644 drivers/net/wireless/rtl8187.h delete mode 100644 drivers/net/wireless/rtl8187_dev.c delete mode 100644 drivers/net/wireless/rtl8187_rtl8225.c delete mode 100644 drivers/net/wireless/rtl8187_rtl8225.h delete mode 100644 drivers/net/wireless/rtl818x.h create mode 100644 drivers/net/wireless/rtl818x/Makefile create mode 100644 drivers/net/wireless/rtl818x/rtl8180.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_dev.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_grf5101.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_grf5101.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_max2820.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_max2820.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_rtl8225.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_rtl8225.h create mode 100644 drivers/net/wireless/rtl818x/rtl8180_sa2400.c create mode 100644 drivers/net/wireless/rtl818x/rtl8180_sa2400.h create mode 100644 drivers/net/wireless/rtl818x/rtl8187.h create mode 100644 drivers/net/wireless/rtl818x/rtl8187_dev.c create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.c create mode 100644 drivers/net/wireless/rtl818x/rtl8187_rtl8225.h create mode 100644 drivers/net/wireless/rtl818x/rtl818x.h (limited to 'drivers') diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 78820840fe2..ed0023d0095 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -31,6 +31,8 @@ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ +obj-$(CONFIG_RTL8180) += rtl818x/ +obj-$(CONFIG_RTL8187) += rtl818x/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o @@ -43,12 +45,6 @@ obj-$(CONFIG_LIBERTAS) += libertas/ obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ -rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o - -obj-$(CONFIG_RTL8180) += rtl8180.o -obj-$(CONFIG_RTL8187) += rtl8187.o - obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h deleted file mode 100644 index 8721282a818..00000000000 --- a/drivers/net/wireless/rtl8180.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef RTL8180_H -#define RTL8180_H - -#include "rtl818x.h" - -#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD - -#define RF_PARAM_ANALOGPHY (1 << 0) -#define RF_PARAM_ANTBDEFAULT (1 << 1) -#define RF_PARAM_CARRIERSENSE1 (1 << 2) -#define RF_PARAM_CARRIERSENSE2 (1 << 3) - -#define BB_ANTATTEN_CHAN14 0x0C -#define BB_ANTENNA_B 0x40 - -#define BB_HOST_BANG (1 << 30) -#define BB_HOST_BANG_EN (1 << 2) -#define BB_HOST_BANG_CLK (1 << 1) -#define BB_HOST_BANG_DATA 1 - -#define ANAPARAM_TXDACOFF_SHIFT 27 -#define ANAPARAM_PWR0_SHIFT 28 -#define ANAPARAM_PWR0_MASK (0x07 << ANAPARAM_PWR0_SHIFT) -#define ANAPARAM_PWR1_SHIFT 20 -#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) - -struct rtl8180_tx_desc { - __le32 flags; - __le16 rts_duration; - __le16 plcp_len; - __le32 tx_buf; - __le32 frame_len; - __le32 next_tx_desc; - u8 cw; - u8 retry_limit; - u8 agc; - u8 flags2; - u32 reserved[2]; -} __attribute__ ((packed)); - -struct rtl8180_rx_desc { - __le32 flags; - __le32 flags2; - union { - __le32 rx_buf; - __le64 tsft; - }; -} __attribute__ ((packed)); - -struct rtl8180_tx_ring { - struct rtl8180_tx_desc *desc; - dma_addr_t dma; - unsigned int idx; - unsigned int entries; - struct sk_buff_head queue; -}; - -struct rtl8180_priv { - /* common between rtl818x drivers */ - struct rtl818x_csr __iomem *map; - const struct rtl818x_rf_ops *rf; - struct ieee80211_vif *vif; - int mode; - - /* rtl8180 driver specific */ - spinlock_t lock; - struct rtl8180_rx_desc *rx_ring; - dma_addr_t rx_ring_dma; - unsigned int rx_idx; - struct sk_buff *rx_buf[32]; - struct rtl8180_tx_ring tx_ring[4]; - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_supported_band band; - struct pci_dev *pdev; - u32 rx_conf; - - int r8185; - u32 anaparam; - u16 rfparam; - u8 csthreshold; -}; - -void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); -void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam); - -static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr) -{ - return ioread8(addr); -} - -static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr) -{ - return ioread16(addr); -} - -static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr) -{ - return ioread32(addr); -} - -static inline void rtl818x_iowrite8(struct rtl8180_priv *priv, - u8 __iomem *addr, u8 val) -{ - iowrite8(val, addr); -} - -static inline void rtl818x_iowrite16(struct rtl8180_priv *priv, - __le16 __iomem *addr, u16 val) -{ - iowrite16(val, addr); -} - -static inline void rtl818x_iowrite32(struct rtl8180_priv *priv, - __le32 __iomem *addr, u32 val) -{ - iowrite32(val, addr); -} - -#endif /* RTL8180_H */ diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c deleted file mode 100644 index 6c226c024dd..00000000000 --- a/drivers/net/wireless/rtl8180_dev.c +++ /dev/null @@ -1,1081 +0,0 @@ - -/* - * Linux device driver for RTL8180 / RTL8185 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_rtl8225.h" -#include "rtl8180_sa2400.h" -#include "rtl8180_max2820.h" -#include "rtl8180_grf5101.h" - -MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); -MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); -MODULE_LICENSE("GPL"); - -static struct pci_device_id rtl8180_table[] __devinitdata = { - /* rtl8185 */ - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, - { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, - { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, - - /* rtl8180 */ - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, - { PCI_DEVICE(0x1799, 0x6001) }, - { PCI_DEVICE(0x1799, 0x6020) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, - { } -}; - -MODULE_DEVICE_TABLE(pci, rtl8180_table); - -static const struct ieee80211_rate rtl818x_rates[] = { - { .bitrate = 10, .hw_value = 0, }, - { .bitrate = 20, .hw_value = 1, }, - { .bitrate = 55, .hw_value = 2, }, - { .bitrate = 110, .hw_value = 3, }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - - - - -void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - int i = 10; - u32 buf; - - buf = (data << 8) | addr; - - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); - while (i--) { - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); - if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) - return; - } -} - -static void rtl8180_handle_rx(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - unsigned int count = 32; - - while (count--) { - struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; - struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; - u32 flags = le32_to_cpu(entry->flags); - - if (flags & RTL818X_RX_DESC_FLAG_OWN) - return; - - if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | - RTL818X_RX_DESC_FLAG_FOF | - RTL818X_RX_DESC_FLAG_RX_ERR))) - goto done; - else { - u32 flags2 = le32_to_cpu(entry->flags2); - struct ieee80211_rx_status rx_status = {0}; - struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); - - if (unlikely(!new_skb)) - goto done; - - pci_unmap_single(priv->pdev, - *((dma_addr_t *)skb->cb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - skb_put(skb, flags & 0xFFF); - - rx_status.antenna = (flags2 >> 15) & 1; - /* TODO: improve signal/rssi reporting */ - rx_status.qual = flags2 & 0xFF; - rx_status.signal = (flags2 >> 8) & 0x7F; - /* XXX: is this correct? */ - rx_status.rate_idx = (flags >> 20) & 0xF; - rx_status.freq = dev->conf.channel->center_freq; - rx_status.band = dev->conf.channel->band; - rx_status.mactime = le64_to_cpu(entry->tsft); - rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - - ieee80211_rx_irqsafe(dev, skb, &rx_status); - - skb = new_skb; - priv->rx_buf[priv->rx_idx] = skb; - *((dma_addr_t *) skb->cb) = - pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - } - - done: - entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); - entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | - MAX_RX_SIZE); - if (priv->rx_idx == 31) - entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); - priv->rx_idx = (priv->rx_idx + 1) % 32; - } -} - -static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb; - struct ieee80211_tx_info *info; - u32 flags = le32_to_cpu(entry->flags); - - if (flags & RTL818X_TX_DESC_FLAG_OWN) - return; - - ring->idx = (ring->idx + 1) % ring->entries; - skb = __skb_dequeue(&ring->queue); - pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), - skb->len, PCI_DMA_TODEVICE); - - info = IEEE80211_SKB_CB(skb); - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (flags & RTL818X_TX_DESC_FLAG_TX_OK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.rates[0].count = (flags & 0xFF) + 1; - - ieee80211_tx_status_irqsafe(dev, skb); - if (ring->entries - skb_queue_len(&ring->queue) == 2) - ieee80211_wake_queue(dev, prio); - } -} - -static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) -{ - struct ieee80211_hw *dev = dev_id; - struct rtl8180_priv *priv = dev->priv; - u16 reg; - - spin_lock(&priv->lock); - reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); - if (unlikely(reg == 0xFFFF)) { - spin_unlock(&priv->lock); - return IRQ_HANDLED; - } - - rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); - - if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) - rtl8180_handle_tx(dev, 3); - - if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) - rtl8180_handle_tx(dev, 2); - - if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) - rtl8180_handle_tx(dev, 1); - - if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) - rtl8180_handle_tx(dev, 0); - - if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) - rtl8180_handle_rx(dev); - - spin_unlock(&priv->lock); - - return IRQ_HANDLED; -} - -static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring; - struct rtl8180_tx_desc *entry; - unsigned long flags; - unsigned int idx, prio; - dma_addr_t mapping; - u32 tx_flags; - u8 rc_flags; - u16 plcp_len = 0; - __le16 rts_duration = 0; - - prio = skb_get_queue_mapping(skb); - ring = &priv->tx_ring[prio]; - - mapping = pci_map_single(priv->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); - - tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | - RTL818X_TX_DESC_FLAG_LS | - (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | - skb->len; - - if (priv->r8185) - tx_flags |= RTL818X_TX_DESC_FLAG_DMA | - RTL818X_TX_DESC_FLAG_NO_ENC; - - rc_flags = info->control.rates[0].flags; - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - tx_flags |= RTL818X_TX_DESC_FLAG_RTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - tx_flags |= RTL818X_TX_DESC_FLAG_CTS; - tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } - - if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) - rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, - info); - - if (!priv->r8185) { - unsigned int remainder; - - plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - remainder = (16 * (skb->len + 4)) % - ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); - if (remainder > 0 && remainder <= 6) - plcp_len |= 1 << 15; - } - - spin_lock_irqsave(&priv->lock, flags); - idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; - entry = &ring->desc[idx]; - - entry->rts_duration = rts_duration; - entry->plcp_len = cpu_to_le16(plcp_len); - entry->tx_buf = cpu_to_le32(mapping); - entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = info->control.rates[1].idx >= 0 ? - ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.rates[0].count; - entry->flags = cpu_to_le32(tx_flags); - __skb_queue_tail(&ring->queue, skb); - if (ring->entries - skb_queue_len(&ring->queue) < 2) - ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); - spin_unlock_irqrestore(&priv->lock, flags); - - rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); - - return 0; -} - -void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) -{ - u8 reg; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static int rtl8180_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg; - - rtl818x_iowrite8(priv, &priv->map->CMD, 0); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(10); - - /* reset */ - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - rtl818x_ioread8(priv, &priv->map->CMD); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= (1 << 1); - reg |= RTL818X_CMD_RESET; - rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(200); - - /* check success of reset */ - if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { - printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); - rtl818x_ioread8(priv, &priv->map->CMD); - msleep(200); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { - /* For cardbus */ - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= 1 << 1; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - reg = rtl818x_ioread16(priv, &priv->map->FEMR); - reg |= (1 << 15) | (1 << 14) | (1 << 4); - rtl818x_iowrite16(priv, &priv->map->FEMR, reg); - } - - rtl818x_iowrite8(priv, &priv->map->MSR, 0); - - if (!priv->r8185) - rtl8180_set_anaparam(priv, priv->anaparam); - - rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); - rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); - rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); - rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); - rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); - - /* TODO: necessary? specs indicate not */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); - rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); - if (priv->r8185) { - reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); - rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); - } - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ - - /* TODO: turn off hw wep on rtl8180 */ - - rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); - - if (priv->r8185) { - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); - - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - - /* TODO: set ClkRun enable? necessary? */ - reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - } else { - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); - rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); - - rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); - rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); - } - - priv->rf->init(dev); - if (priv->r8185) - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - return 0; -} - -static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_rx_desc *entry; - int i; - - priv->rx_ring = pci_alloc_consistent(priv->pdev, - sizeof(*priv->rx_ring) * 32, - &priv->rx_ring_dma); - - if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { - printk(KERN_ERR "%s: Cannot allocate RX ring\n", - wiphy_name(dev->wiphy)); - return -ENOMEM; - } - - memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32); - priv->rx_idx = 0; - - for (i = 0; i < 32; i++) { - struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); - dma_addr_t *mapping; - entry = &priv->rx_ring[i]; - if (!skb) - return 0; - - priv->rx_buf[i] = skb; - mapping = (dma_addr_t *)skb->cb; - *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - entry->rx_buf = cpu_to_le32(*mapping); - entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | - MAX_RX_SIZE); - } - entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); - return 0; -} - -static void rtl8180_free_rx_ring(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < 32; i++) { - struct sk_buff *skb = priv->rx_buf[i]; - if (!skb) - continue; - - pci_unmap_single(priv->pdev, - *((dma_addr_t *)skb->cb), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - kfree_skb(skb); - } - - pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32, - priv->rx_ring, priv->rx_ring_dma); - priv->rx_ring = NULL; -} - -static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, - unsigned int prio, unsigned int entries) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_desc *ring; - dma_addr_t dma; - int i; - - ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); - if (!ring || (unsigned long)ring & 0xFF) { - printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n", - wiphy_name(dev->wiphy), prio); - return -ENOMEM; - } - - memset(ring, 0, sizeof(*ring)*entries); - priv->tx_ring[prio].desc = ring; - priv->tx_ring[prio].dma = dma; - priv->tx_ring[prio].idx = 0; - priv->tx_ring[prio].entries = entries; - skb_queue_head_init(&priv->tx_ring[prio].queue); - - for (i = 0; i < entries; i++) - ring[i].next_tx_desc = - cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); - - return 0; -} - -static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) -{ - struct rtl8180_priv *priv = dev->priv; - struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb = __skb_dequeue(&ring->queue); - - pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), - skb->len, PCI_DMA_TODEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - - pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, - ring->desc, ring->dma); - ring->desc = NULL; -} - -static int rtl8180_start(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int ret, i; - u32 reg; - - ret = rtl8180_init_rx_ring(dev); - if (ret) - return ret; - - for (i = 0; i < 4; i++) - if ((ret = rtl8180_init_tx_ring(dev, i, 16))) - goto err_free_rings; - - ret = rtl8180_init_hw(dev); - if (ret) - goto err_free_rings; - - rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); - rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); - rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); - rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); - rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); - - ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, - IRQF_SHARED, KBUILD_MODNAME, dev); - if (ret) { - printk(KERN_ERR "%s: failed to register IRQ handler\n", - wiphy_name(dev->wiphy)); - goto err_free_rings; - } - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); - rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); - - reg = RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - (7 << 8 /* MAX RX DMA */) | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC; - - if (priv->r8185) - reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; - else { - reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) - ? RTL818X_RX_CONF_CSDM1 : 0; - reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) - ? RTL818X_RX_CONF_CSDM2 : 0; - } - - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - if (priv->r8185) { - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - /* disable early TX */ - rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); - } - - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg |= (6 << 21 /* MAX TX DMA */) | - RTL818X_TX_CONF_NO_ICV; - - if (priv->r8185) - reg &= ~RTL818X_TX_CONF_PROBE_DTS; - else - reg &= ~RTL818X_TX_CONF_HW_SEQNUM; - - /* different meaning, same value on both rtl8185 and rtl8180 */ - reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg |= RTL818X_CMD_RX_ENABLE; - reg |= RTL818X_CMD_TX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->mode = NL80211_IFTYPE_MONITOR; - return 0; - - err_free_rings: - rtl8180_free_rx_ring(dev); - for (i = 0; i < 4; i++) - if (priv->tx_ring[i].desc) - rtl8180_free_tx_ring(dev, i); - - return ret; -} - -static void rtl8180_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u8 reg; - int i; - - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= ~RTL818X_CMD_TX_ENABLE; - reg &= ~RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->rf->stop(dev); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); - rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - free_irq(priv->pdev->irq, dev); - - rtl8180_free_rx_ring(dev); - for (i = 0; i < 4; i++) - rtl8180_free_tx_ring(dev, i); -} - -static int rtl8180_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - - if (priv->mode != NL80211_IFTYPE_MONITOR) - return -EOPNOTSUPP; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - priv->mode = conf->type; - break; - default: - return -EOPNOTSUPP; - } - - priv->vif = conf->vif; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], - le32_to_cpu(*(__le32 *)conf->mac_addr)); - rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], - le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - return 0; -} - -static void rtl8180_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - priv->mode = NL80211_IFTYPE_MONITOR; - priv->vif = NULL; -} - -static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) -{ - struct rtl8180_priv *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - - priv->rf->set_chan(dev, conf); - - return 0; -} - -static int rtl8180_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); - else - rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); - - return 0; -} - -static void rtl8180_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) -{ - struct rtl8180_priv *priv = dev->priv; - - if (changed_flags & FIF_FCSFAIL) - priv->rx_conf ^= RTL818X_RX_CONF_FCS; - if (changed_flags & FIF_CONTROL) - priv->rx_conf ^= RTL818X_RX_CONF_CTRL; - if (changed_flags & FIF_OTHER_BSS) - priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) - priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; - else - priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; - - *total_flags = 0; - - if (priv->rx_conf & RTL818X_RX_CONF_FCS) - *total_flags |= FIF_FCSFAIL; - if (priv->rx_conf & RTL818X_RX_CONF_CTRL) - *total_flags |= FIF_CONTROL; - if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) - *total_flags |= FIF_OTHER_BSS; - if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) - *total_flags |= FIF_ALLMULTI; - - rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); -} - -static const struct ieee80211_ops rtl8180_ops = { - .tx = rtl8180_tx, - .start = rtl8180_start, - .stop = rtl8180_stop, - .add_interface = rtl8180_add_interface, - .remove_interface = rtl8180_remove_interface, - .config = rtl8180_config, - .config_interface = rtl8180_config_interface, - .configure_filter = rtl8180_configure_filter, -}; - -static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; - u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - - eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; - eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; - eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; - eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; -} - -static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8180_priv *priv = dev->priv; - u8 reg = 2 << 6; - - if (eeprom->reg_data_in) - reg |= RTL818X_EEPROM_CMD_WRITE; - if (eeprom->reg_data_out) - reg |= RTL818X_EEPROM_CMD_READ; - if (eeprom->reg_data_clock) - reg |= RTL818X_EEPROM_CMD_CK; - if (eeprom->reg_chip_select) - reg |= RTL818X_EEPROM_CMD_CS; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); -} - -static int __devinit rtl8180_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct ieee80211_hw *dev; - struct rtl8180_priv *priv; - unsigned long mem_addr, mem_len; - unsigned int io_addr, io_len; - int err, i; - struct eeprom_93cx6 eeprom; - const char *chip_name, *rf_name = NULL; - u32 reg; - u16 eeprom_val; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", - pci_name(pdev)); - return err; - } - - err = pci_request_regions(pdev, KBUILD_MODNAME); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\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 (mem_len < sizeof(struct rtl818x_csr) || - io_len < sizeof(struct rtl818x_csr)) { - printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", - pci_name(pdev)); - err = -ENOMEM; - goto err_free_reg; - } - - if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) || - (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) { - printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", - pci_name(pdev)); - goto err_free_reg; - } - - pci_set_master(pdev); - - dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); - if (!dev) { - printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", - pci_name(pdev)); - err = -ENOMEM; - goto err_free_reg; - } - - priv = dev->priv; - priv->pdev = pdev; - - dev->max_rates = 2; - SET_IEEE80211_DEV(dev, &pdev->dev); - pci_set_drvdata(pdev, dev); - - 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 (rtl8180): Cannot map device memory\n", - pci_name(pdev)); - goto err_free_dev; - } - - BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); - BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); - - memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); - memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - - priv->band.band = IEEE80211_BAND_2GHZ; - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = 4; - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_SIGNAL_UNSPEC; - dev->queues = 1; - dev->max_signal = 65; - - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg &= RTL818X_TX_CONF_HWVER_MASK; - switch (reg) { - case RTL818X_TX_CONF_R8180_ABCD: - chip_name = "RTL8180"; - break; - case RTL818X_TX_CONF_R8180_F: - chip_name = "RTL8180vF"; - break; - case RTL818X_TX_CONF_R8185_ABC: - chip_name = "RTL8185"; - break; - case RTL818X_TX_CONF_R8185_D: - chip_name = "RTL8185vD"; - break; - default: - printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", - pci_name(pdev), reg >> 25); - goto err_iounmap; - } - - priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; - if (priv->r8185) { - priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); - pci_try_set_mwi(pdev); - } - - eeprom.data = dev; - eeprom.register_read = rtl8180_eeprom_register_read; - eeprom.register_write = rtl8180_eeprom_register_write; - if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) - eeprom.width = PCI_EEPROM_WIDTH_93C66; - else - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); - eeprom_val &= 0xFF; - switch (eeprom_val) { - case 1: rf_name = "Intersil"; - break; - case 2: rf_name = "RFMD"; - break; - case 3: priv->rf = &sa2400_rf_ops; - break; - case 4: priv->rf = &max2820_rf_ops; - break; - case 5: priv->rf = &grf5101_rf_ops; - break; - case 9: priv->rf = rtl8180_detect_rf(dev); - break; - case 10: - rf_name = "RTL8255"; - break; - default: - printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", - pci_name(pdev), eeprom_val); - goto err_iounmap; - } - - if (!priv->rf) { - printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", - pci_name(pdev), rf_name); - goto err_iounmap; - } - - eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); - priv->csthreshold = eeprom_val >> 8; - if (!priv->r8185) { - __le32 anaparam; - eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); - priv->anaparam = le32_to_cpu(anaparam); - eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); - } - - eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3); - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" - " randomly generated MAC addr\n", pci_name(pdev)); - random_ether_addr(dev->wiphy->perm_addr); - } - - /* CCK TX power */ - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); - priv->channels[i].hw_value = txpwr & 0xFF; - priv->channels[i + 1].hw_value = txpwr >> 8; - } - - /* OFDM TX power */ - if (priv->r8185) { - for (i = 0; i < 14; i += 2) { - u16 txpwr; - eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); - priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; - priv->channels[i + 1].hw_value |= txpwr & 0xFF00; - } - } - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - spin_lock_init(&priv->lock); - - err = ieee80211_register_hw(dev); - if (err) { - printk(KERN_ERR "%s (rtl8180): Cannot register device\n", - pci_name(pdev)); - goto err_iounmap; - } - - printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", - wiphy_name(dev->wiphy), dev->wiphy->perm_addr, - chip_name, priv->rf->name); - - return 0; - - err_iounmap: - iounmap(priv->map); - - err_free_dev: - pci_set_drvdata(pdev, NULL); - ieee80211_free_hw(dev); - - err_free_reg: - pci_release_regions(pdev); - pci_disable_device(pdev); - return err; -} - -static void __devexit rtl8180_remove(struct pci_dev *pdev) -{ - struct ieee80211_hw *dev = pci_get_drvdata(pdev); - struct rtl8180_priv *priv; - - if (!dev) - return; - - ieee80211_unregister_hw(dev); - - priv = dev->priv; - - pci_iounmap(pdev, priv->map); - pci_release_regions(pdev); - pci_disable_device(pdev); - ieee80211_free_hw(dev); -} - -#ifdef CONFIG_PM -static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int rtl8180_resume(struct pci_dev *pdev) -{ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - return 0; -} - -#endif /* CONFIG_PM */ - -static struct pci_driver rtl8180_driver = { - .name = KBUILD_MODNAME, - .id_table = rtl8180_table, - .probe = rtl8180_probe, - .remove = __devexit_p(rtl8180_remove), -#ifdef CONFIG_PM - .suspend = rtl8180_suspend, - .resume = rtl8180_resume, -#endif /* CONFIG_PM */ -}; - -static int __init rtl8180_init(void) -{ - return pci_register_driver(&rtl8180_driver); -} - -static void __exit rtl8180_exit(void) -{ - pci_unregister_driver(&rtl8180_driver); -} - -module_init(rtl8180_init); -module_exit(rtl8180_exit); diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c deleted file mode 100644 index 947ee55f18b..00000000000 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ /dev/null @@ -1,180 +0,0 @@ - -/* - * Radio tuning for GCT GRF5101 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_grf5101.h" - -static const int grf5101_encode[] = { - 0x0, 0x8, 0x4, 0xC, - 0x2, 0xA, 0x6, 0xE, - 0x1, 0x9, 0x5, 0xD, - 0x3, 0xB, 0x7, 0xF -}; - -static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - phy_config = grf5101_encode[(data >> 8) & 0xF]; - phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4; - phy_config |= grf5101_encode[data & 0xF] << 8; - phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12; - phy_config |= (addr & 1) << 16; - phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24; - - /* MAC will bang bits to the chip */ - phy_config |= 0x90000000; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(3); -} - -static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant = GRF5101_ANTENNA; - - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); -} - -static void grf5101_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; - u32 chan = channel - 1; - - /* set TX power */ - write_grf5101(dev, 0x15, 0x0); - write_grf5101(dev, 0x06, txpw); - write_grf5101(dev, 0x15, 0x10); - write_grf5101(dev, 0x15, 0x0); - - /* set frequency */ - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x0B, chan); - write_grf5101(dev, 0x07, 0x1000); - - grf5101_write_phy_antenna(dev, channel); -} - -static void grf5101_rf_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u32 anaparam; - - anaparam = priv->anaparam; - anaparam &= 0x000fffff; - anaparam |= 0x3f900000; - rtl8180_set_anaparam(priv, anaparam); - - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x1f, 0x45); - write_grf5101(dev, 0x1f, 0x5); - write_grf5101(dev, 0x00, 0x8e4); -} - -static void grf5101_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - - rtl8180_set_anaparam(priv, priv->anaparam); - - write_grf5101(dev, 0x1f, 0x0); - write_grf5101(dev, 0x1f, 0x0); - write_grf5101(dev, 0x1f, 0x40); - write_grf5101(dev, 0x1f, 0x60); - write_grf5101(dev, 0x1f, 0x61); - write_grf5101(dev, 0x1f, 0x61); - write_grf5101(dev, 0x00, 0xae4); - write_grf5101(dev, 0x1f, 0x1); - write_grf5101(dev, 0x1f, 0x41); - write_grf5101(dev, 0x1f, 0x61); - - write_grf5101(dev, 0x01, 0x1a23); - write_grf5101(dev, 0x02, 0x4971); - write_grf5101(dev, 0x03, 0x41de); - write_grf5101(dev, 0x04, 0x2d80); - write_grf5101(dev, 0x05, 0x68ff); /* 0x61ff original value */ - write_grf5101(dev, 0x06, 0x0); - write_grf5101(dev, 0x07, 0x0); - write_grf5101(dev, 0x08, 0x7533); - write_grf5101(dev, 0x09, 0xc401); - write_grf5101(dev, 0x0a, 0x0); - write_grf5101(dev, 0x0c, 0x1c7); - write_grf5101(dev, 0x0d, 0x29d3); - write_grf5101(dev, 0x0e, 0x2e8); - write_grf5101(dev, 0x10, 0x192); - write_grf5101(dev, 0x11, 0x248); - write_grf5101(dev, 0x12, 0x0); - write_grf5101(dev, 0x13, 0x20c4); - write_grf5101(dev, 0x14, 0xf4fc); - write_grf5101(dev, 0x15, 0x0); - write_grf5101(dev, 0x16, 0x1500); - - write_grf5101(dev, 0x07, 0x1000); - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0xa8); - rtl8180_write_phy(dev, 3, 0x0); - rtl8180_write_phy(dev, 4, 0xc0); - rtl8180_write_phy(dev, 5, 0x90); - rtl8180_write_phy(dev, 6, 0x1e); - rtl8180_write_phy(dev, 7, 0x64); - - grf5101_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x88); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */ - else - rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */ - - rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); - - rtl8180_write_phy(dev, 0x19, 0x0); - rtl8180_write_phy(dev, 0x1a, 0xa0); - rtl8180_write_phy(dev, 0x1b, 0x44); -} - -const struct rtl818x_rf_ops grf5101_rf_ops = { - .name = "GCT", - .init = grf5101_rf_init, - .stop = grf5101_rf_stop, - .set_chan = grf5101_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl8180_grf5101.h deleted file mode 100644 index 76647111bcf..00000000000 --- a/drivers/net/wireless/rtl8180_grf5101.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef RTL8180_GRF5101_H -#define RTL8180_GRF5101_H - -/* - * Radio tuning for GCT GRF5101 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * 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. - */ - -#define GRF5101_ANTENNA 0xA3 - -extern const struct rtl818x_rf_ops grf5101_rf_ops; - -#endif /* RTL8180_GRF5101_H */ diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c deleted file mode 100644 index 6c825fd7f3b..00000000000 --- a/drivers/net/wireless/rtl8180_max2820.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Radio tuning for Maxim max2820 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_max2820.h" - -static const u32 max2820_chan[] = { - 12, /* CH 1 */ - 17, - 22, - 27, - 32, - 37, - 42, - 47, - 52, - 57, - 62, - 67, - 72, - 84, /* CH 14 */ -}; - -static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - phy_config = 0x90 + (data & 0xf); - phy_config <<= 16; - phy_config += addr; - phy_config <<= 8; - phy_config += (data >> 4) & 0xff; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(1); -} - -static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant; - - ant = MAXIM_ANTENNA; - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); -} - -static void max2820_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = conf ? - ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; - unsigned int chan_idx = channel - 1; - u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; - u32 chan = max2820_chan[chan_idx]; - - /* While philips SA2400 drive the PA bias from - * sa2400, for MAXIM we do this directly from BB */ - rtl8180_write_phy(dev, 3, txpw); - - max2820_write_phy_antenna(dev, channel); - write_max2820(dev, 3, chan); -} - -static void max2820_rf_stop(struct ieee80211_hw *dev) -{ - rtl8180_write_phy(dev, 3, 0x8); - write_max2820(dev, 1, 0); -} - - -static void max2820_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - - /* MAXIM from netbsd driver */ - write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ - write_max2820(dev, 1, 0x01e); /* enable register */ - write_max2820(dev, 2, 0x001); /* synt register */ - - max2820_rf_set_channel(dev, NULL); - - write_max2820(dev, 4, 0x313); /* rx register */ - - /* PA is driven directly by the BB, we keep the MAXIM bias - * at the highest value in case that setting it to lower - * values may introduce some further attenuation somewhere.. - */ - write_max2820(dev, 5, 0x00f); - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ - rtl8180_write_phy(dev, 3, 0x08); /* txagc */ - rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ - rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ - rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ - rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ - - max2820_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc7); - else - rtl8180_write_phy(dev, 0x12, 0x47); - - rtl8180_write_phy(dev, 0x13, 0x9b); - - rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ - rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ - - max2820_rf_set_channel(dev, NULL); -} - -const struct rtl818x_rf_ops max2820_rf_ops = { - .name = "Maxim", - .init = max2820_rf_init, - .stop = max2820_rf_stop, - .set_chan = max2820_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl8180_max2820.h deleted file mode 100644 index 61cf6d1e7d5..00000000000 --- a/drivers/net/wireless/rtl8180_max2820.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef RTL8180_MAX2820_H -#define RTL8180_MAX2820_H - -/* - * Radio tuning for Maxim max2820 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * 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. - */ - -#define MAXIM_ANTENNA 0xb3 - -extern const struct rtl818x_rf_ops max2820_rf_ops; - -#endif /* RTL8180_MAX2820_H */ diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c deleted file mode 100644 index cd22781728a..00000000000 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ /dev/null @@ -1,780 +0,0 @@ - -/* - * Radio tuning for RTL8225 on RTL8180 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8180 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_rtl8225.h" - -static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg80, reg84, reg82; - u32 bangdata; - int i; - - bangdata = (data << 4) | (addr & 0xf); - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); - - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - for (i = 15; i >= 0; i--) { - u16 reg = reg80 | !!(bangdata & (1 << i)); - - if (i & 1) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - - if (!(i & 1)) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); -} - -static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg80, reg82, reg84, out; - int i; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400; - - reg80 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(4); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(5); - - for (i = 4; i >= 0; i--) { - u16 reg = reg80 | ((addr >> i) & 1); - - if (!(i & 1)) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - if (i & 1) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - } - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - out = 0; - for (i = 11; i >= 0; i--) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(1); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) - out |= 1 << i; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 2)); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); - - return out; -} - -static const u16 rtl8225bcd_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, - 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb -}; - -static const u8 rtl8225_agc[] = { - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, - 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, - 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, - 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, - 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, - 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, - 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 -}; - -static const u8 rtl8225_gain[] = { - 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ - 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ - 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ - 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ - 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ - 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ - 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ -}; - -static const u8 rtl8225_threshold[] = { - 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd -}; - -static const u8 rtl8225_tx_gain_cck_ofdm[] = { - 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e -}; - -static const u8 rtl8225_tx_power_cck[] = { - 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, - 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, - 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, - 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 -}; - -static const u8 rtl8225_tx_power_cck_ch14[] = { - 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225_tx_power_ofdm[] = { - 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 -}; - -static const u32 rtl8225_chan[] = { - 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, - 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 -}; - -static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8180_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xFF; - ofdm_power = priv->channels[channel - 1].hw_value >> 8; - - cck_power = min(cck_power, (u8)35); - ofdm_power = min(ofdm_power, (u8)35); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); - - if (channel == 14) - tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; - else - tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - msleep(1); /* FIXME: optional? */ - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1); - - tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; - - rtl8225_write_phy_ofdm(dev, 5, *tmp); - rtl8225_write_phy_ofdm(dev, 7, *tmp); - - msleep(1); -} - -static void rtl8225_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); - - /* host_pci_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(200); /* FIXME: ehh?? */ - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); - - /* TODO: check if we need really to change BRSR to do RF config */ - rtl818x_ioread16(priv, &priv->map->BRSR); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write(dev, 0x0, 0x067); - rtl8225_write(dev, 0x1, 0xFE0); - rtl8225_write(dev, 0x2, 0x44D); - rtl8225_write(dev, 0x3, 0x441); - rtl8225_write(dev, 0x4, 0x8BE); - rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */ - rtl8225_write(dev, 0x6, 0xAE6); - rtl8225_write(dev, 0x7, rtl8225_chan[0]); - 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(1); - - rtl8225_write(dev, 0x2, 0xC4D); msleep(100); - - rtl8225_write(dev, 0x0, 0x127); - - for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x027); - rtl8225_write(dev, 0x0, 0x22F); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - 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, 0x62); 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, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x00); 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, 0x03); 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_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, 0x93); 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, 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); - - rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1); - - 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 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - rtl8225_write(dev, 0x0c, 0x50); - /* set OFDM initial gain */ - rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]); - rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]); - /* set CCK threshold */ - rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]); -} - -static const u8 rtl8225z2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225z2_tx_power_cck_B[] = { - 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 -}; - -static const u8 rtl8225z2_tx_power_cck_A[] = { - 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 -}; - -static const u8 rtl8225z2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 -}; - -static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8180_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xFF; - ofdm_power = priv->channels[channel - 1].hw_value >> 8; - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else if (cck_power == 12) - tmp = rtl8225z2_tx_power_cck_B; - else if (cck_power == 13) - tmp = rtl8225z2_tx_power_cck_A; - else - tmp = rtl8225z2_tx_power_cck; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - cck_power = min(cck_power, (u8)35); - if (cck_power == 13 || cck_power == 14) - cck_power = 12; - if (cck_power >= 15) - cck_power -= 2; - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power); - rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK); - msleep(1); - - ofdm_power = min(ofdm_power, (u8)35); - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power); - - rtl8225_write_phy_ofdm(dev, 2, 0x62); - rtl8225_write_phy_ofdm(dev, 5, 0x00); - rtl8225_write_phy_ofdm(dev, 6, 0x40); - rtl8225_write_phy_ofdm(dev, 7, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x40); - - msleep(1); -} - -static const u16 rtl8225z2_rxgain[] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, - 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, - 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, - 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, - 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, - 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, - 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, - 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, - 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, - 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, - 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb -}; - -static void rtl8225z2_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - int i; - - rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); - - /* host_pci_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(200); /* FIXME: ehh?? */ - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008); - - /* TODO: check if we need really to change BRSR to do RF config */ - rtl818x_ioread16(priv, &priv->map->BRSR); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - 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(100); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0C4D); - msleep(200); - rtl8225_write(dev, 0x02, 0x044D); - msleep(100); - /* TODO: readd calibration failure message when the calibration - check works */ - } - - rtl8225_write(dev, 0x0, 0x1B7); - rtl8225_write(dev, 0x3, 0x002); - rtl8225_write(dev, 0x5, 0x004); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x0B7); msleep(100); - rtl8225_write(dev, 0x2, 0xC4D); - - msleep(200); - rtl8225_write(dev, 0x2, 0x44D); - msleep(100); - - rtl8225_write(dev, 0x00, 0x2BF); - rtl8225_write(dev, 0xFF, 0xFFFF); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - - 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, 0x62); 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, 0x18, 0xef); 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, 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, 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, 0x11); 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, 0xb3); 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, 0x23, 0x80); msleep(1); /* FIXME: not needed? */ - 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_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, 0x93); 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, 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, 0x8a); 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); - - rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 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 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); -} - -static void rtl8225_rf_stop(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u8 reg; - - rtl8225_write(dev, 0x4, 0x1f); msleep(1); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); - - if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, chan); - else - rtl8225z2_rf_set_tx_power(dev, chan); - - rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); - msleep(10); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 81); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } -} - -static const struct rtl818x_rf_ops rtl8225_ops = { - .name = "rtl8225", - .init = rtl8225_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u16 reg8, reg9; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - msleep(100); - - rtl8225_write(dev, 0, 0x1B7); - - reg8 = rtl8225_read(dev, 8); - reg9 = rtl8225_read(dev, 9); - - rtl8225_write(dev, 0, 0x0B7); - - if (reg8 != 0x588 || reg9 != 0x700) - return &rtl8225_ops; - - return &rtl8225z2_ops; -} diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl8180_rtl8225.h deleted file mode 100644 index 310013a2d72..00000000000 --- a/drivers/net/wireless/rtl8180_rtl8225.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef RTL8180_RTL8225_H -#define RTL8180_RTL8225_H - -#define RTL8225_ANAPARAM_ON 0xa0000b59 -#define RTL8225_ANAPARAM2_ON 0x860dec11 -#define RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8225_ANAPARAM2_OFF 0x840dec11 - -const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *); - -static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, - u8 addr, u8 data) -{ - rtl8180_write_phy(dev, addr, data); -} - -static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, - u8 addr, u8 data) -{ - rtl8180_write_phy(dev, addr, data | 0x10000); -} - -#endif /* RTL8180_RTL8225_H */ diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c deleted file mode 100644 index cea4e0ccb92..00000000000 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ /dev/null @@ -1,202 +0,0 @@ - -/* - * Radio tuning for Philips SA2400 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include "rtl8180.h" -#include "rtl8180_sa2400.h" - -static const u32 sa2400_chan[] = { - 0x00096c, /* ch1 */ - 0x080970, - 0x100974, - 0x180978, - 0x000980, - 0x080984, - 0x100988, - 0x18098c, - 0x000994, - 0x080998, - 0x10099c, - 0x1809a0, - 0x0009a8, - 0x0009b4, /* ch 14 */ -}; - -static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8180_priv *priv = dev->priv; - u32 phy_config; - - /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ - phy_config = 0xb0000000; - - phy_config |= ((u32)(addr & 0xf)) << 24; - phy_config |= data & 0xffffff; - - rtl818x_iowrite32(priv, - (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); - - msleep(3); -} - -static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) -{ - struct rtl8180_priv *priv = dev->priv; - u8 ant = SA2400_ANTENNA; - - if (priv->rfparam & RF_PARAM_ANTBDEFAULT) - ant |= BB_ANTENNA_B; - - if (chan == 14) - ant |= BB_ANTATTEN_CHAN14; - - rtl8180_write_phy(dev, 0x10, ant); - -} - -static void sa2400_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8180_priv *priv = dev->priv; - int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; - u32 chan = sa2400_chan[channel - 1]; - - write_sa2400(dev, 7, txpw); - - sa2400_write_phy_antenna(dev, channel); - - write_sa2400(dev, 0, chan); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); -} - -static void sa2400_rf_stop(struct ieee80211_hw *dev) -{ - write_sa2400(dev, 4, 0); -} - -static void sa2400_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8180_priv *priv = dev->priv; - u32 anaparam, txconf; - u8 firdac; - int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; - - anaparam = priv->anaparam; - anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); - anaparam &= ~ANAPARAM_PWR1_MASK; - anaparam &= ~ANAPARAM_PWR0_MASK; - - if (analogphy) { - anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; - firdac = 0; - } else { - anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); - anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); - firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; - } - - rtl8180_set_anaparam(priv, anaparam); - - write_sa2400(dev, 0, sa2400_chan[0]); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); - write_sa2400(dev, 4, 0x19340 | firdac); - write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); - write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ - - if (!analogphy) - write_sa2400(dev, 4, 0x1938c); /*???*/ - - write_sa2400(dev, 4, 0x19340 | firdac); - - write_sa2400(dev, 0, sa2400_chan[0]); - write_sa2400(dev, 1, 0xbb50); - write_sa2400(dev, 2, 0x80); - write_sa2400(dev, 3, 0); - write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ - - /* new from rtl8180 embedded driver (rtl8181 project) */ - write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ - write_sa2400(dev, 8, 0); /* VCO */ - - if (analogphy) { - rtl8180_set_anaparam(priv, anaparam | - (1 << ANAPARAM_TXDACOFF_SHIFT)); - - txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - txconf | RTL818X_TX_CONF_LOOPBACK_CONT); - - write_sa2400(dev, 4, 0x19341); /* calibrates DC */ - - /* a 5us sleep is required here, - * we rely on the 3ms delay introduced in write_sa2400 */ - write_sa2400(dev, 4, 0x19345); - - /* a 20us sleep is required here, - * we rely on the 3ms delay introduced in write_sa2400 */ - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); - - rtl8180_set_anaparam(priv, anaparam); - } - /* end new code */ - - write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ - - /* baseband configuration */ - rtl8180_write_phy(dev, 0, 0x98); - rtl8180_write_phy(dev, 3, 0x38); - rtl8180_write_phy(dev, 4, 0xe0); - rtl8180_write_phy(dev, 5, 0x90); - rtl8180_write_phy(dev, 6, 0x1a); - rtl8180_write_phy(dev, 7, 0x64); - - sa2400_write_phy_antenna(dev, 1); - - rtl8180_write_phy(dev, 0x11, 0x80); - - if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & - RTL818X_CONFIG2_ANTENNA_DIV) - rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ - else - rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ - - rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); - - rtl8180_write_phy(dev, 0x19, 0x0); - rtl8180_write_phy(dev, 0x1a, 0xa0); -} - -const struct rtl818x_rf_ops sa2400_rf_ops = { - .name = "Philips", - .init = sa2400_rf_init, - .stop = sa2400_rf_stop, - .set_chan = sa2400_rf_set_channel -}; diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl8180_sa2400.h deleted file mode 100644 index a4aaa0d413f..00000000000 --- a/drivers/net/wireless/rtl8180_sa2400.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef RTL8180_SA2400_H -#define RTL8180_SA2400_H - -/* - * Radio tuning for Philips SA2400 on RTL8180 - * - * Copyright 2007 Andrea Merello - * - * Code from the BSD driver and the rtl8181 project have been - * very useful to understand certain things - * - * I want to thanks the Authors of such projects and the Ndiswrapper - * project Authors. - * - * A special Big Thanks also is for all people who donated me cards, - * making possible the creation of the original rtl8180 driver - * from which this code is derived! - * - * 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. - */ - -#define SA2400_ANTENNA 0x91 -#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 -#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 -#define SA2400_ANAPARAM_PWR0_ON 0x3 - -/* RX sensitivity in dbm */ -#define SA2400_MAX_SENS 85 - -#define SA2400_REG4_FIRDAC_SHIFT 7 - -extern const struct rtl818x_rf_ops sa2400_rf_ops; - -#endif /* RTL8180_SA2400_H */ diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h deleted file mode 100644 index 33725d0978b..00000000000 --- a/drivers/net/wireless/rtl8187.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Definitions for RTL8187 hardware - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * 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. - */ - -#ifndef RTL8187_H -#define RTL8187_H - -#include "rtl818x.h" - -#define RTL8187_EEPROM_TXPWR_BASE 0x05 -#define RTL8187_EEPROM_MAC_ADDR 0x07 -#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ -#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ -#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ - -#define RTL8187_REQT_READ 0xC0 -#define RTL8187_REQT_WRITE 0x40 -#define RTL8187_REQ_GET_REG 0x05 -#define RTL8187_REQ_SET_REG 0x05 - -#define RTL8187_MAX_RX 0x9C4 - -struct rtl8187_rx_info { - struct urb *urb; - struct ieee80211_hw *dev; -}; - -struct rtl8187_rx_hdr { - __le32 flags; - u8 noise; - u8 signal; - u8 agc; - u8 reserved; - __le64 mac_time; -} __attribute__((packed)); - -struct rtl8187b_rx_hdr { - __le32 flags; - __le64 mac_time; - u8 sq; - u8 rssi; - u8 agc; - u8 flags2; - __le16 snr_long2end; - s8 pwdb_g12; - u8 fot; -} __attribute__((packed)); - -/* {rtl8187,rtl8187b}_tx_info is in skb */ - -struct rtl8187_tx_hdr { - __le32 flags; - __le16 rts_duration; - __le16 len; - __le32 retry; -} __attribute__((packed)); - -struct rtl8187b_tx_hdr { - __le32 flags; - __le16 rts_duration; - __le16 len; - __le32 unused_1; - __le16 unused_2; - __le16 tx_duration; - __le32 unused_3; - __le32 retry; - __le32 unused_4[2]; -} __attribute__((packed)); - -enum { - DEVICE_RTL8187, - DEVICE_RTL8187B -}; - -struct rtl8187_priv { - /* common between rtl818x drivers */ - struct rtl818x_csr *map; - const struct rtl818x_rf_ops *rf; - struct ieee80211_vif *vif; - int mode; - /* The mutex protects the TX loopback state. - * Any attempt to set channels concurrently locks the device. - */ - struct mutex conf_mutex; - - /* rtl8187 specific */ - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_supported_band band; - struct usb_device *udev; - u32 rx_conf; - u16 txpwr_base; - u8 asic_rev; - u8 is_rtl8187b; - enum { - RTL8187BvB, - RTL8187BvD, - RTL8187BvE - } hw_rev; - struct sk_buff_head rx_queue; - u8 signal; - u8 quality; - u8 noise; -}; - -void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); - -static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv, - u8 *addr, u8 idx) -{ - u8 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return val; -} - -static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) -{ - return rtl818x_ioread8_idx(priv, addr, 0); -} - -static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv, - __le16 *addr, u8 idx) -{ - __le16 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return le16_to_cpu(val); -} - -static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) -{ - return rtl818x_ioread16_idx(priv, addr, 0); -} - -static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv, - __le32 *addr, u8 idx) -{ - __le32 val; - - usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), - RTL8187_REQ_GET_REG, RTL8187_REQT_READ, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); - - return le32_to_cpu(val); -} - -static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) -{ - return rtl818x_ioread32_idx(priv, addr, 0); -} - -static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv, - u8 *addr, u8 val, u8 idx) -{ - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &val, - sizeof(val), HZ / 2); -} - -static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val) -{ - rtl818x_iowrite8_idx(priv, addr, val, 0); -} - -static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv, - __le16 *addr, u16 val, u8 idx) -{ - __le16 buf = cpu_to_le16(val); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), - HZ / 2); -} - -static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr, - u16 val) -{ - rtl818x_iowrite16_idx(priv, addr, val, 0); -} - -static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv, - __le32 *addr, u32 val, u8 idx) -{ - __le32 buf = cpu_to_le32(val); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), - HZ / 2); -} - -static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr, - u32 val) -{ - rtl818x_iowrite32_idx(priv, addr, val, 0); -} - -#endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c deleted file mode 100644 index e1399d0b55d..00000000000 --- a/drivers/net/wireless/rtl8187_dev.c +++ /dev/null @@ -1,1298 +0,0 @@ -/* - * Linux device driver for RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Magic delays and register offsets below are taken from the original - * r8187 driver sources. Thanks to Realtek for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "rtl8187.h" -#include "rtl8187_rtl8225.h" - -MODULE_AUTHOR("Michael Wu "); -MODULE_AUTHOR("Andrea Merello "); -MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); -MODULE_LICENSE("GPL"); - -static struct usb_device_id rtl8187_table[] __devinitdata = { - /* Asus */ - {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, - /* Belkin */ - {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, - /* Realtek */ - {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, - {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, - {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, - /* Netgear */ - {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B}, - /* HP */ - {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187}, - /* Sitecom */ - {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187}, - {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B}, - /* Abocom */ - {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187}, - {} -}; - -MODULE_DEVICE_TABLE(usb, rtl8187_table); - -static const struct ieee80211_rate rtl818x_rates[] = { - { .bitrate = 10, .hw_value = 0, }, - { .bitrate = 20, .hw_value = 1, }, - { .bitrate = 55, .hw_value = 2, }, - { .bitrate = 110, .hw_value = 3, }, - { .bitrate = 60, .hw_value = 4, }, - { .bitrate = 90, .hw_value = 5, }, - { .bitrate = 120, .hw_value = 6, }, - { .bitrate = 180, .hw_value = 7, }, - { .bitrate = 240, .hw_value = 8, }, - { .bitrate = 360, .hw_value = 9, }, - { .bitrate = 480, .hw_value = 10, }, - { .bitrate = 540, .hw_value = 11, }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .center_freq = 2412 }, - { .center_freq = 2417 }, - { .center_freq = 2422 }, - { .center_freq = 2427 }, - { .center_freq = 2432 }, - { .center_freq = 2437 }, - { .center_freq = 2442 }, - { .center_freq = 2447 }, - { .center_freq = 2452 }, - { .center_freq = 2457 }, - { .center_freq = 2462 }, - { .center_freq = 2467 }, - { .center_freq = 2472 }, - { .center_freq = 2484 }, -}; - -static void rtl8187_iowrite_async_cb(struct urb *urb) -{ - kfree(urb->context); - usb_free_urb(urb); -} - -static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, - void *data, u16 len) -{ - struct usb_ctrlrequest *dr; - struct urb *urb; - struct rtl8187_async_write_data { - u8 data[4]; - struct usb_ctrlrequest dr; - } *buf; - int rc; - - buf = kmalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) - return; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(buf); - return; - } - - dr = &buf->dr; - - dr->bRequestType = RTL8187_REQT_WRITE; - dr->bRequest = RTL8187_REQ_SET_REG; - dr->wValue = addr; - dr->wIndex = 0; - dr->wLength = cpu_to_le16(len); - - memcpy(buf, data, len); - - usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), - (unsigned char *)dr, buf, len, - rtl8187_iowrite_async_cb, buf); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - kfree(buf); - usb_free_urb(urb); - } -} - -static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, - __le32 *addr, u32 val) -{ - __le32 buf = cpu_to_le32(val); - - rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), - &buf, sizeof(buf)); -} - -void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) -{ - struct rtl8187_priv *priv = dev->priv; - - data <<= 8; - data |= addr | 0x80; - - rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); - rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); -} - -static void rtl8187_tx_cb(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *)urb->context; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->rate_driver_data[0]; - struct rtl8187_priv *priv = hw->priv; - - usb_free_urb(info->rate_driver_data[1]); - skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : - sizeof(struct rtl8187_tx_hdr)); - ieee80211_tx_info_clear_status(info); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); -} - -static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) -{ - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - unsigned int ep; - void *buf; - struct urb *urb; - __le16 rts_dur = 0; - u32 flags; - int rc; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree_skb(skb); - return 0; - } - - flags = skb->len; - flags |= RTL818X_TX_DESC_FLAG_NO_ENC; - - flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; - if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) - flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - flags |= RTL818X_TX_DESC_FLAG_RTS; - flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - rts_dur = ieee80211_rts_duration(dev, priv->vif, - skb->len, info); - } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - flags |= RTL818X_TX_DESC_FLAG_CTS; - flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } - - if (!priv->is_rtl8187b) { - struct rtl8187_tx_hdr *hdr = - (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); - hdr->flags = cpu_to_le32(flags); - hdr->len = 0; - hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); - buf = hdr; - - ep = 2; - } else { - /* fc needs to be calculated before skb_push() */ - unsigned int epmap[4] = { 6, 7, 5, 4 }; - struct ieee80211_hdr *tx_hdr = - (struct ieee80211_hdr *)(skb->data); - u16 fc = le16_to_cpu(tx_hdr->frame_control); - - struct rtl8187b_tx_hdr *hdr = - (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); - struct ieee80211_rate *txrate = - ieee80211_get_tx_rate(dev, info); - memset(hdr, 0, sizeof(*hdr)); - hdr->flags = cpu_to_le32(flags); - hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); - hdr->tx_duration = - ieee80211_generic_frame_duration(dev, priv->vif, - skb->len, txrate); - buf = hdr; - - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) - ep = 12; - else - ep = epmap[skb_get_queue_mapping(skb)]; - } - - info->rate_driver_data[0] = dev; - info->rate_driver_data[1] = urb; - - usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), - buf, skb->len, rtl8187_tx_cb, skb); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - usb_free_urb(urb); - kfree_skb(skb); - } - - return 0; -} - -static void rtl8187_rx_cb(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *)urb->context; - struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; - struct ieee80211_hw *dev = info->dev; - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_rx_status rx_status = { 0 }; - int rate, signal; - u32 flags; - u32 quality; - - spin_lock(&priv->rx_queue.lock); - if (skb->next) - __skb_unlink(skb, &priv->rx_queue); - else { - spin_unlock(&priv->rx_queue.lock); - return; - } - spin_unlock(&priv->rx_queue.lock); - - if (unlikely(urb->status)) { - usb_free_urb(urb); - dev_kfree_skb_irq(skb); - return; - } - - skb_put(skb, urb->actual_length); - if (!priv->is_rtl8187b) { - struct rtl8187_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); - flags = le32_to_cpu(hdr->flags); - signal = hdr->signal & 0x7f; - rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.noise = hdr->noise; - rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->quality = signal; - rx_status.qual = priv->quality; - priv->noise = hdr->noise; - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - rx_status.signal = signal; - priv->signal = signal; - } else { - struct rtl8187b_rx_hdr *hdr = - (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); - /* The Realtek datasheet for the RTL8187B shows that the RX - * header contains the following quantities: signal quality, - * RSSI, AGC, the received power in dB, and the measured SNR. - * In testing, none of these quantities show qualitative - * agreement with AP signal strength, except for the AGC, - * which is inversely proportional to the strength of the - * signal. In the following, the quality and signal strength - * are derived from the AGC. The arbitrary scaling constants - * are chosen to make the results close to the values obtained - * for a BCM4312 using b43 as the driver. The noise is ignored - * for now. - */ - flags = le32_to_cpu(hdr->flags); - quality = 170 - hdr->agc; - if (quality > 100) - quality = 100; - signal = 14 - hdr->agc / 2; - rx_status.qual = quality; - priv->quality = quality; - rx_status.signal = signal; - priv->signal = signal; - rx_status.antenna = (hdr->rssi >> 7) & 1; - rx_status.mactime = le64_to_cpu(hdr->mac_time); - rate = (flags >> 20) & 0xF; - } - - skb_trim(skb, flags & 0x0FFF); - rx_status.rate_idx = rate; - rx_status.freq = dev->conf.channel->center_freq; - rx_status.band = dev->conf.channel->band; - rx_status.flag |= RX_FLAG_TSFT; - if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - ieee80211_rx_irqsafe(dev, skb, &rx_status); - - skb = dev_alloc_skb(RTL8187_MAX_RX); - if (unlikely(!skb)) { - usb_free_urb(urb); - /* TODO check rx queue length and refill *somewhere* */ - return; - } - - info = (struct rtl8187_rx_info *)skb->cb; - info->urb = urb; - info->dev = dev; - urb->transfer_buffer = skb_tail_pointer(skb); - urb->context = skb; - skb_queue_tail(&priv->rx_queue, skb); - - usb_submit_urb(urb, GFP_ATOMIC); -} - -static int rtl8187_init_urbs(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - struct urb *entry; - struct sk_buff *skb; - struct rtl8187_rx_info *info; - - while (skb_queue_len(&priv->rx_queue) < 8) { - skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); - if (!skb) - break; - entry = usb_alloc_urb(0, GFP_KERNEL); - if (!entry) { - kfree_skb(skb); - break; - } - usb_fill_bulk_urb(entry, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->is_rtl8187b ? 3 : 1), - skb_tail_pointer(skb), - RTL8187_MAX_RX, rtl8187_rx_cb, skb); - info = (struct rtl8187_rx_info *)skb->cb; - info->urb = entry; - info->dev = dev; - skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); - } - - return 0; -} - -static int rtl8187_cmd_reset(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u8 reg; - int i; - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= (1 << 1); - reg |= RTL818X_CMD_RESET; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - i = 10; - do { - msleep(2); - if (!(rtl818x_ioread8(priv, &priv->map->CMD) & - RTL818X_CMD_RESET)) - break; - } while (--i); - - if (!i) { - printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - /* reload registers from eeprom */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); - - i = 10; - do { - msleep(4); - if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & - RTL818X_EEPROM_CMD_CONFIG)) - break; - } while (--i); - - if (!i) { - printk(KERN_ERR "%s: eeprom reset timeout!\n", - wiphy_name(dev->wiphy)); - return -ETIMEDOUT; - } - - return 0; -} - -static int rtl8187_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u8 reg; - int res; - - /* reset */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | - RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & - ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - msleep(200); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); - rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); - msleep(200); - - res = rtl8187_cmd_reset(dev); - if (res) - return res; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - /* setup card */ - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); - - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 1); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - - rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); - reg &= 0x3F; - reg |= 0x80; - rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); - - // TODO: set RESP_RATE and BRSR properly - rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - - /* host_usb_init */ - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0); - reg = rtl818x_ioread8(priv, (u8 *)0xFE53); - rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); - rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); - rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); - msleep(100); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); - rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); - rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); - msleep(100); - - priv->rf->init(dev); - - rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); - rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); - rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); - rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); - - return 0; -} - -static const u8 rtl8187b_reg_table[][3] = { - {0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0}, - {0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0}, - {0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0}, - {0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0}, - - {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, - {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, - {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, - {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, - {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, - {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, - - {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, - {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, - {0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2}, - {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, - {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, - {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, - {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, - {0x73, 0x9A, 2}, - - {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, - {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, - {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, - {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, - {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, - - {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, - {0x8E, 0x08, 0}, {0x8F, 0x00, 0} -}; - -static int rtl8187b_init_hw(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int res, i; - u8 reg; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_ON); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_ON); - - rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); - reg = rtl818x_ioread8(priv, (u8 *)0xFF62); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); - - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - res = rtl8187_cmd_reset(dev); - if (res) - return res; - - rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | - RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); - reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK); - reg |= RTL818X_RATE_FALLBACK_ENABLE; - rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg); - - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); - rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); - for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) { - rtl818x_iowrite8_idx(priv, - (u8 *)(uintptr_t) - (rtl8187b_reg_table[i][0] | 0xFF00), - rtl8187b_reg_table[i][1], - rtl8187b_reg_table[i][2]); - } - - rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); - rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); - - rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1); - rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1); - rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1); - - rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - msleep(100); - - priv->rf->init(dev); - - reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4); - rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); - rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); - rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); - - reg = rtl818x_ioread8(priv, (u8 *)0xFFDB); - rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2)); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3); - rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3); - rtl818x_iowrite8(priv, (u8 *)0xFF61, 0); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1); - rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10); - rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2); - - rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B); - - rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); - - return 0; -} - -static int rtl8187_start(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - u32 reg; - int ret; - - ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : - rtl8187b_init_hw(dev); - if (ret) - return ret; - - mutex_lock(&priv->conf_mutex); - if (priv->is_rtl8187b) { - reg = RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC | - RTL818X_RX_CONF_BSSID | - (7 << 13 /* RX FIFO threshold NONE */) | - (7 << 10 /* MAX RX DMA */) | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_MULTICAST; - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - RTL818X_TX_CONF_HW_SEQNUM | - RTL818X_TX_CONF_DISREQQSIZE | - (7 << 8 /* short retry limit */) | - (7 << 0 /* long retry limit */) | - (7 << 21 /* MAX TX DMA */)); - rtl8187_init_urbs(dev); - mutex_unlock(&priv->conf_mutex); - return 0; - } - - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); - - rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); - rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); - - rtl8187_init_urbs(dev); - - reg = RTL818X_RX_CONF_ONLYERLPKT | - RTL818X_RX_CONF_RX_AUTORESETPHY | - RTL818X_RX_CONF_BSSID | - RTL818X_RX_CONF_MGMT | - RTL818X_RX_CONF_DATA | - (7 << 13 /* RX FIFO threshold NONE */) | - (7 << 10 /* MAX RX DMA */) | - RTL818X_RX_CONF_BROADCAST | - RTL818X_RX_CONF_NICMAC; - - priv->rx_conf = reg; - rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); - reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; - reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; - rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); - - reg = RTL818X_TX_CONF_CW_MIN | - (7 << 21 /* MAX TX DMA */) | - RTL818X_TX_CONF_NO_ICV; - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg |= RTL818X_CMD_TX_ENABLE; - reg |= RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - mutex_unlock(&priv->conf_mutex); - - return 0; -} - -static void rtl8187_stop(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_info *info; - struct sk_buff *skb; - u32 reg; - - mutex_lock(&priv->conf_mutex); - rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); - - reg = rtl818x_ioread8(priv, &priv->map->CMD); - reg &= ~RTL818X_CMD_TX_ENABLE; - reg &= ~RTL818X_CMD_RX_ENABLE; - rtl818x_iowrite8(priv, &priv->map->CMD, reg); - - priv->rf->stop(dev); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); - rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct rtl8187_rx_info *)skb->cb; - usb_kill_urb(info->urb); - kfree_skb(skb); - } - mutex_unlock(&priv->conf_mutex); -} - -static int rtl8187_add_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - if (priv->mode != NL80211_IFTYPE_MONITOR) - return -EOPNOTSUPP; - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - priv->mode = conf->type; - break; - default: - return -EOPNOTSUPP; - } - - mutex_lock(&priv->conf_mutex); - priv->vif = conf->vif; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->MAC[i], - ((u8 *)conf->mac_addr)[i]); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void rtl8187_remove_interface(struct ieee80211_hw *dev, - struct ieee80211_if_init_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - mutex_lock(&priv->conf_mutex); - priv->mode = NL80211_IFTYPE_MONITOR; - priv->vif = NULL; - mutex_unlock(&priv->conf_mutex); -} - -static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) -{ - struct rtl8187_priv *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; - u32 reg; - - mutex_lock(&priv->conf_mutex); - reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); - /* Enable TX loopback on MAC level to avoid TX during channel - * changes, as this has be seen to causes problems and the - * card will stop work until next reset - */ - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - reg | RTL818X_TX_CONF_LOOPBACK_MAC); - priv->rf->set_chan(dev, conf); - msleep(10); - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); - rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static int rtl8187_config_interface(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_if_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - u8 reg; - - mutex_lock(&priv->conf_mutex); - for (i = 0; i < ETH_ALEN; i++) - rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); - - if (is_valid_ether_addr(conf->bssid)) { - reg = RTL818X_MSR_INFRA; - if (priv->is_rtl8187b) - reg |= RTL818X_MSR_ENEDCA; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } else { - reg = RTL818X_MSR_NO_LINK; - rtl818x_iowrite8(priv, &priv->map->MSR, reg); - } - - mutex_unlock(&priv->conf_mutex); - return 0; -} - -static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, - bool use_short_preamble) -{ - if (priv->is_rtl8187b) { - u8 difs, eifs, slot_time; - u16 ack_timeout; - - if (use_short_slot) { - slot_time = 0x9; - difs = 0x1c; - eifs = 0x53; - } else { - slot_time = 0x14; - difs = 0x32; - eifs = 0x5b; - } - rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); - rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); - rtl818x_iowrite8(priv, &priv->map->DIFS, difs); - - /* - * BRSR+1 on 8187B is in fact EIFS register - * Value in units of 4 us - */ - rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); - - /* - * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout - * register. In units of 4 us like eifs register - * ack_timeout = ack duration + plcp + difs + preamble - */ - ack_timeout = 112 + 48 + difs; - if (use_short_preamble) - ack_timeout += 72; - else - ack_timeout += 144; - rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, - DIV_ROUND_UP(ack_timeout, 4)); - } else { - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - if (use_short_slot) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } - } -} - -static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u32 changed) -{ - struct rtl8187_priv *priv = dev->priv; - - if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) - rtl8187_conf_erp(priv, info->use_short_slot, - info->use_short_preamble); -} - -static void rtl8187_configure_filter(struct ieee80211_hw *dev, - unsigned int changed_flags, - unsigned int *total_flags, - int mc_count, struct dev_addr_list *mclist) -{ - struct rtl8187_priv *priv = dev->priv; - - if (changed_flags & FIF_FCSFAIL) - priv->rx_conf ^= RTL818X_RX_CONF_FCS; - if (changed_flags & FIF_CONTROL) - priv->rx_conf ^= RTL818X_RX_CONF_CTRL; - if (changed_flags & FIF_OTHER_BSS) - priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; - if (*total_flags & FIF_ALLMULTI || mc_count > 0) - priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; - else - priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; - - *total_flags = 0; - - if (priv->rx_conf & RTL818X_RX_CONF_FCS) - *total_flags |= FIF_FCSFAIL; - if (priv->rx_conf & RTL818X_RX_CONF_CTRL) - *total_flags |= FIF_CONTROL; - if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) - *total_flags |= FIF_OTHER_BSS; - if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) - *total_flags |= FIF_ALLMULTI; - - rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); -} - -static const struct ieee80211_ops rtl8187_ops = { - .tx = rtl8187_tx, - .start = rtl8187_start, - .stop = rtl8187_stop, - .add_interface = rtl8187_add_interface, - .remove_interface = rtl8187_remove_interface, - .config = rtl8187_config, - .config_interface = rtl8187_config_interface, - .bss_info_changed = rtl8187_bss_info_changed, - .configure_filter = rtl8187_configure_filter, -}; - -static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8187_priv *priv = dev->priv; - u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); - - eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; - eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; - eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; - eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; -} - -static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) -{ - struct ieee80211_hw *dev = eeprom->data; - struct rtl8187_priv *priv = dev->priv; - u8 reg = RTL818X_EEPROM_CMD_PROGRAM; - - if (eeprom->reg_data_in) - reg |= RTL818X_EEPROM_CMD_WRITE; - if (eeprom->reg_data_out) - reg |= RTL818X_EEPROM_CMD_READ; - if (eeprom->reg_data_clock) - reg |= RTL818X_EEPROM_CMD_CK; - if (eeprom->reg_chip_select) - reg |= RTL818X_EEPROM_CMD_CS; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); - udelay(10); -} - -static int __devinit rtl8187_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct ieee80211_hw *dev; - struct rtl8187_priv *priv; - struct eeprom_93cx6 eeprom; - struct ieee80211_channel *channel; - const char *chip_name; - u16 txpwr, reg; - int err, i; - - dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); - if (!dev) { - printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n"); - return -ENOMEM; - } - - priv = dev->priv; - priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B); - - SET_IEEE80211_DEV(dev, &intf->dev); - usb_set_intfdata(intf, dev); - priv->udev = udev; - - usb_get_dev(udev); - - skb_queue_head_init(&priv->rx_queue); - - BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); - BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); - - memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); - memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - priv->map = (struct rtl818x_csr *)0xFF00; - - priv->band.band = IEEE80211_BAND_2GHZ; - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); - priv->band.bitrates = priv->rates; - priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); - dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; - - - priv->mode = NL80211_IFTYPE_MONITOR; - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_RX_INCLUDES_FCS; - - eeprom.data = dev; - eeprom.register_read = rtl8187_eeprom_register_read; - eeprom.register_write = rtl8187_eeprom_register_write; - if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) - eeprom.width = PCI_EEPROM_WIDTH_93C66; - else - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - udelay(10); - - eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR, - (__le16 __force *)dev->wiphy->perm_addr, 3); - if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { - printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly " - "generated MAC address\n"); - random_ether_addr(dev->wiphy->perm_addr); - } - - channel = priv->channels; - for (i = 0; i < 3; i++) { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - for (i = 0; i < 2; i++) { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, - &priv->txpwr_base); - - reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); - /* 0 means asic B-cut, we should use SW 3 wire - * bit-by-bit banging for radio. 1 means we can use - * USB specific request to write radio registers */ - priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; - rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - if (!priv->is_rtl8187b) { - u32 reg32; - reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF); - reg32 &= RTL818X_TX_CONF_HWVER_MASK; - switch (reg32) { - case RTL818X_TX_CONF_R8187vD_B: - /* Some RTL8187B devices have a USB ID of 0x8187 - * detect them here */ - chip_name = "RTL8187BvB(early)"; - priv->is_rtl8187b = 1; - priv->hw_rev = RTL8187BvB; - break; - case RTL818X_TX_CONF_R8187vD: - chip_name = "RTL8187vD"; - break; - default: - chip_name = "RTL8187vB (default)"; - } - } else { - /* - * Force USB request to write radio registers for 8187B, Realtek - * only uses it in their sources - */ - /*if (priv->asic_rev == 0) { - printk(KERN_WARNING "rtl8187: Forcing use of USB " - "requests to write to radio registers\n"); - priv->asic_rev = 1; - }*/ - switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) { - case RTL818X_R8187B_B: - chip_name = "RTL8187BvB"; - priv->hw_rev = RTL8187BvB; - break; - case RTL818X_R8187B_D: - chip_name = "RTL8187BvD"; - priv->hw_rev = RTL8187BvD; - break; - case RTL818X_R8187B_E: - chip_name = "RTL8187BvE"; - priv->hw_rev = RTL8187BvE; - break; - default: - chip_name = "RTL8187BvB (default)"; - priv->hw_rev = RTL8187BvB; - } - } - - if (!priv->is_rtl8187b) { - for (i = 0; i < 2; i++) { - eeprom_93cx6_read(&eeprom, - RTL8187_EEPROM_TXPWR_CHAN_6 + i, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - } else { - eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6, - &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - - eeprom_93cx6_read(&eeprom, 0x0A, &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - - eeprom_93cx6_read(&eeprom, 0x1C, &txpwr); - (*channel++).hw_value = txpwr & 0xFF; - (*channel++).hw_value = txpwr >> 8; - } - - if (priv->is_rtl8187b) { - printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " - "is EXPERIMENTAL, and could damage your\n" - " hardware, use at your own risk\n"); - dev->flags |= IEEE80211_HW_SIGNAL_DBM; - } else { - dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; - } - - /* - * XXX: Once this driver supports anything that requires - * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. - */ - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - - if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) - printk(KERN_INFO "rtl8187: inconsistency between id with OEM" - " info!\n"); - - priv->rf = rtl8187_detect_rf(dev); - dev->extra_tx_headroom = (!priv->is_rtl8187b) ? - sizeof(struct rtl8187_tx_hdr) : - sizeof(struct rtl8187b_tx_hdr); - if (!priv->is_rtl8187b) - dev->queues = 1; - else - dev->queues = 4; - - err = ieee80211_register_hw(dev); - if (err) { - printk(KERN_ERR "rtl8187: Cannot register device\n"); - goto err_free_dev; - } - mutex_init(&priv->conf_mutex); - - printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", - wiphy_name(dev->wiphy), dev->wiphy->perm_addr, - chip_name, priv->asic_rev, priv->rf->name); - - return 0; - - err_free_dev: - ieee80211_free_hw(dev); - usb_set_intfdata(intf, NULL); - usb_put_dev(udev); - return err; -} - -static void __devexit rtl8187_disconnect(struct usb_interface *intf) -{ - struct ieee80211_hw *dev = usb_get_intfdata(intf); - struct rtl8187_priv *priv; - - if (!dev) - return; - - ieee80211_unregister_hw(dev); - - priv = dev->priv; - usb_put_dev(interface_to_usbdev(intf)); - ieee80211_free_hw(dev); -} - -static struct usb_driver rtl8187_driver = { - .name = KBUILD_MODNAME, - .id_table = rtl8187_table, - .probe = rtl8187_probe, - .disconnect = __devexit_p(rtl8187_disconnect), -}; - -static int __init rtl8187_init(void) -{ - return usb_register(&rtl8187_driver); -} - -static void __exit rtl8187_exit(void) -{ - usb_deregister(&rtl8187_driver); -} - -module_init(rtl8187_init); -module_exit(rtl8187_exit); diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c deleted file mode 100644 index 69030be62b3..00000000000 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * Radio tuning for RTL8225 on RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * Magic delays, register offsets, and phy value tables below are - * taken from the original r8187 driver sources. Thanks to Realtek - * for their support! - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#include "rtl8187.h" -#include "rtl8187_rtl8225.h" - -static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg84, reg82; - u32 bangdata; - int i; - - bangdata = (data << 4) | (addr & 0xf); - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); - - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(10); - - for (i = 15; i >= 0; i--) { - u16 reg = reg80 | (bangdata & (1 << i)) >> i; - - if (i & 1) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); - - if (!(i & 1)) - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); -} - -static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg82, reg84; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - - reg80 &= ~(0x3 << 2); - reg84 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(10); - - usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), - RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, - addr, 0x8225, &data, sizeof(data), HZ / 2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(10); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); -} - -static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) -{ - struct rtl8187_priv *priv = dev->priv; - - if (priv->asic_rev) - rtl8225_write_8051(dev, addr, cpu_to_le16(data)); - else - rtl8225_write_bitbang(dev, addr, data); -} - -static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) -{ - struct rtl8187_priv *priv = dev->priv; - u16 reg80, reg82, reg84, out; - int i; - - reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); - reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); - reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); - - reg80 &= ~0xF; - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); - udelay(4); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); - udelay(5); - - for (i = 4; i >= 0; i--) { - u16 reg = reg80 | ((addr >> i) & 1); - - if (!(i & 1)) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - udelay(1); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg | (1 << 1)); - udelay(2); - - if (i & 1) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); - udelay(1); - } - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - - out = 0; - for (i = 11; i >= 0; i--) { - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(1); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 1)); - udelay(2); - - if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) - out |= 1 << i; - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3)); - udelay(2); - } - - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, - reg80 | (1 << 3) | (1 << 2)); - udelay(2); - - rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); - rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); - - return out; -} - -static const u16 rtl8225bcd_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, - 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb -}; - -static const u8 rtl8225_agc[] = { - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, - 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, - 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, - 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, - 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, - 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, - 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 -}; - -static const u8 rtl8225_gain[] = { - 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */ - 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */ - 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */ - 0x33, 0x80, 0x79, 0xc5, /* -78dBm */ - 0x43, 0x78, 0x76, 0xc5, /* -74dBm */ - 0x53, 0x60, 0x73, 0xc5, /* -70dBm */ - 0x63, 0x58, 0x70, 0xc5, /* -66dBm */ -}; - -static const u8 rtl8225_threshold[] = { - 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd -}; - -static const u8 rtl8225_tx_gain_cck_ofdm[] = { - 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e -}; - -static const u8 rtl8225_tx_power_cck[] = { - 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, - 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, - 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, - 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 -}; - -static const u8 rtl8225_tx_power_cck_ch14[] = { - 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225_tx_power_ofdm[] = { - 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 -}; - -static const u32 rtl8225_chan[] = { - 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, - 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 -}; - -static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - cck_power = min(cck_power, (u8)11); - ofdm_power = min(ofdm_power, (u8)35); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); - - if (channel == 14) - tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; - else - tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - msleep(1); // FIXME: optional? - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write_phy_ofdm(dev, 2, 0x42); - rtl8225_write_phy_ofdm(dev, 6, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x00); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1); - - tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; - - rtl8225_write_phy_ofdm(dev, 5, *tmp); - rtl8225_write_phy_ofdm(dev, 7, *tmp); - - msleep(1); -} - -static void rtl8225_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - 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); - rtl8225_write(dev, 0x2, 0x44D); msleep(200); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0c4d); - msleep(200); - rtl8225_write(dev, 0x02, 0x044d); - msleep(100); - if (!(rtl8225_read(dev, 6) & (1 << 7))) - printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", - wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); - } - - rtl8225_write(dev, 0x0, 0x127); - - for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); - } - - rtl8225_write(dev, 0x0, 0x027); - rtl8225_write(dev, 0x0, 0x22F); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - } - - 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); - 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); - 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); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); - - /* set sensitivity */ - rtl8225_write(dev, 0x0c, 0x50); - rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); - rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); - rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); - rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); -} - -static const u8 rtl8225z2_agc[] = { - 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f, - 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, - 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f, - 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, - 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, - 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 -}; -static const u8 rtl8225z2_ofdm[] = { - 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, - 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, - 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, - 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, - 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, - 0x6d, 0x3c, 0xfb, 0x07 -}; - -static const u8 rtl8225z2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225z2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, - 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 -}; - -static const u8 rtl8225z2_tx_power_ofdm[] = { - 0x42, 0x00, 0x40, 0x00, 0x40 -}; - -static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 -}; - -static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - u32 reg; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - cck_power = min(cck_power, (u8)15); - cck_power += priv->txpwr_base & 0xF; - cck_power = min(cck_power, (u8)35); - - ofdm_power = min(ofdm_power, (u8)15); - ofdm_power += priv->txpwr_base >> 4; - ofdm_power = min(ofdm_power, (u8)35); - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else - tmp = rtl8225z2_tx_power_cck; - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power]); - msleep(1); - - /* anaparam2 on */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - - rtl8225_write_phy_ofdm(dev, 2, 0x42); - rtl8225_write_phy_ofdm(dev, 5, 0x00); - rtl8225_write_phy_ofdm(dev, 6, 0x40); - rtl8225_write_phy_ofdm(dev, 7, 0x00); - rtl8225_write_phy_ofdm(dev, 8, 0x40); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225z2_tx_gain_cck_ofdm[ofdm_power]); - msleep(1); -} - -static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) -{ - struct rtl8187_priv *priv = dev->priv; - u8 cck_power, ofdm_power; - const u8 *tmp; - int i; - - cck_power = priv->channels[channel - 1].hw_value & 0xF; - ofdm_power = priv->channels[channel - 1].hw_value >> 4; - - if (cck_power > 15) - cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22; - else - cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7; - cck_power += priv->txpwr_base & 0xF; - cck_power = min(cck_power, (u8)35); - - if (ofdm_power > 15) - ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25; - else - ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10; - ofdm_power += (priv->txpwr_base >> 4) & 0xF; - ofdm_power = min(ofdm_power, (u8)35); - - if (channel == 14) - tmp = rtl8225z2_tx_power_cck_ch14; - else - tmp = rtl8225z2_tx_power_cck; - - if (priv->hw_rev == RTL8187BvB) { - if (cck_power <= 6) - ; /* do nothing */ - else if (cck_power <= 11) - tmp += 8; - else - tmp += 16; - } else { - if (cck_power <= 5) - ; /* do nothing */ - else if (cck_power <= 11) - tmp += 8; - else if (cck_power <= 17) - tmp += 16; - else - tmp += 24; - } - - for (i = 0; i < 8; i++) - rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); - msleep(1); - - rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, - rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1); - if (priv->hw_rev == RTL8187BvB) { - if (ofdm_power <= 11) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x60); - rtl8225_write_phy_ofdm(dev, 0x89, 0x60); - } else { - rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); - rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); - } - } else { - if (ofdm_power <= 11) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); - rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); - } else if (ofdm_power <= 17) { - rtl8225_write_phy_ofdm(dev, 0x87, 0x54); - rtl8225_write_phy_ofdm(dev, 0x89, 0x54); - } else { - rtl8225_write_phy_ofdm(dev, 0x87, 0x50); - rtl8225_write_phy_ofdm(dev, 0x89, 0x50); - } - } - msleep(1); -} - -static const u16 rtl8225z2_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb -}; - -static const u8 rtl8225z2_gain_bg[] = { - 0x23, 0x15, 0xa5, /* -82-1dBm */ - 0x23, 0x15, 0xb5, /* -82-2dBm */ - 0x23, 0x15, 0xc5, /* -82-3dBm */ - 0x33, 0x15, 0xc5, /* -78dBm */ - 0x43, 0x15, 0xc5, /* -74dBm */ - 0x53, 0x15, 0xc5, /* -70dBm */ - 0x63, 0x15, 0xc5 /* -66dBm */ -}; - -static void rtl8225z2_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - 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); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x3, 0x080); - rtl8225_write(dev, 0x5, 0x004); - rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xc4D); - - msleep(200); - rtl8225_write(dev, 0x2, 0x44D); - msleep(100); - - if (!(rtl8225_read(dev, 6) & (1 << 7))) { - rtl8225_write(dev, 0x02, 0x0C4D); - msleep(200); - rtl8225_write(dev, 0x02, 0x044D); - msleep(100); - if (!(rtl8225_read(dev, 6) & (1 << 7))) - printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", - wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); - } - - msleep(200); - - rtl8225_write(dev, 0x0, 0x2BF); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - } - - 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); - 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); - 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); - 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); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ - - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ - msleep(1); - rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); -} - -static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) -{ - struct rtl8187_priv *priv = dev->priv; - int i; - - 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); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); - } - - rtl8225_write(dev, 0x3, 0x080); - rtl8225_write(dev, 0x5, 0x004); - rtl8225_write(dev, 0x0, 0x0B7); - - rtl8225_write(dev, 0x2, 0xC4D); - - 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); - rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); - - rtl8225_write_phy_ofdm(dev, 0x80, 0x12); - for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) { - rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]); - rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i); - rtl8225_write_phy_ofdm(dev, 0xE, 0); - } - rtl8225_write_phy_ofdm(dev, 0x80, 0x10); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) - rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - - rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); - 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); - 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) -{ - u8 reg; - struct rtl8187_priv *priv = dev->priv; - - rtl8225_write(dev, 0x4, 0x1f); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - if (!priv->is_rtl8187b) { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_OFF); - } else { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_OFF); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_OFF); - } - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); -} - -static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, - struct ieee80211_conf *conf) -{ - struct rtl8187_priv *priv = dev->priv; - int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); - - if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, chan); - else if (priv->rf->init == rtl8225z2_rf_init) - rtl8225z2_rf_set_tx_power(dev, chan); - else - rtl8225z2_b_rf_set_tx_power(dev, chan); - - rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); - msleep(10); -} - -static const struct rtl818x_rf_ops rtl8225_ops = { - .name = "rtl8225", - .init = rtl8225_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -static const struct rtl818x_rf_ops rtl8225z2_b_ops = { - .name = "rtl8225z2", - .init = rtl8225z2_b_rf_init, - .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel -}; - -const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) -{ - u16 reg8, reg9; - struct rtl8187_priv *priv = dev->priv; - - if (!priv->is_rtl8187b) { - rtl8225_write(dev, 0, 0x1B7); - - reg8 = rtl8225_read(dev, 8); - reg9 = rtl8225_read(dev, 9); - - rtl8225_write(dev, 0, 0x0B7); - - if (reg8 != 0x588 || reg9 != 0x700) - return &rtl8225_ops; - - return &rtl8225z2_ops; - } else - return &rtl8225z2_b_ops; -} diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h deleted file mode 100644 index 20c5b6ead0f..00000000000 --- a/drivers/net/wireless/rtl8187_rtl8225.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Radio tuning definitions for RTL8225 on RTL8187 - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * 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. - */ - -#ifndef RTL8187_RTL8225_H -#define RTL8187_RTL8225_H - -#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59 -#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312 -#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11 - -#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658 -#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52 -#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00 -#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658 -#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50 -#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00 - -const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); - -static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, - u8 addr, u32 data) -{ - rtl8187_write_phy(dev, addr, data); -} - -static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, - u8 addr, u32 data) -{ - rtl8187_write_phy(dev, addr, data | 0x10000); -} - -#endif /* RTL8187_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h deleted file mode 100644 index 3538b15211b..00000000000 --- a/drivers/net/wireless/rtl818x.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Definitions for RTL818x hardware - * - * Copyright 2007 Michael Wu - * Copyright 2007 Andrea Merello - * - * Based on the r8187 driver, which is: - * Copyright 2005 Andrea Merello , et al. - * - * 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. - */ - -#ifndef RTL818X_H -#define RTL818X_H - -struct rtl818x_csr { - u8 MAC[6]; - u8 reserved_0[2]; - __le32 MAR[2]; - u8 RX_FIFO_COUNT; - u8 reserved_1; - u8 TX_FIFO_COUNT; - u8 BQREQ; - u8 reserved_2[4]; - __le32 TSFT[2]; - __le32 TLPDA; - __le32 TNPDA; - __le32 THPDA; - __le16 BRSR; - u8 BSSID[6]; - u8 RESP_RATE; - u8 EIFS; - u8 reserved_3[1]; - u8 CMD; -#define RTL818X_CMD_TX_ENABLE (1 << 2) -#define RTL818X_CMD_RX_ENABLE (1 << 3) -#define RTL818X_CMD_RESET (1 << 4) - u8 reserved_4[4]; - __le16 INT_MASK; - __le16 INT_STATUS; -#define RTL818X_INT_RX_OK (1 << 0) -#define RTL818X_INT_RX_ERR (1 << 1) -#define RTL818X_INT_TXL_OK (1 << 2) -#define RTL818X_INT_TXL_ERR (1 << 3) -#define RTL818X_INT_RX_DU (1 << 4) -#define RTL818X_INT_RX_FO (1 << 5) -#define RTL818X_INT_TXN_OK (1 << 6) -#define RTL818X_INT_TXN_ERR (1 << 7) -#define RTL818X_INT_TXH_OK (1 << 8) -#define RTL818X_INT_TXH_ERR (1 << 9) -#define RTL818X_INT_TXB_OK (1 << 10) -#define RTL818X_INT_TXB_ERR (1 << 11) -#define RTL818X_INT_ATIM (1 << 12) -#define RTL818X_INT_BEACON (1 << 13) -#define RTL818X_INT_TIME_OUT (1 << 14) -#define RTL818X_INT_TX_FO (1 << 15) - __le32 TX_CONF; -#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) -#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17) -#define RTL818X_TX_CONF_NO_ICV (1 << 19) -#define RTL818X_TX_CONF_DISCW (1 << 20) -#define RTL818X_TX_CONF_SAT_HWPLCP (1 << 24) -#define RTL818X_TX_CONF_R8180_ABCD (2 << 25) -#define RTL818X_TX_CONF_R8180_F (3 << 25) -#define RTL818X_TX_CONF_R8185_ABC (4 << 25) -#define RTL818X_TX_CONF_R8185_D (5 << 25) -#define RTL818X_TX_CONF_R8187vD (5 << 25) -#define RTL818X_TX_CONF_R8187vD_B (6 << 25) -#define RTL818X_TX_CONF_HWVER_MASK (7 << 25) -#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28) -#define RTL818X_TX_CONF_PROBE_DTS (1 << 29) -#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) -#define RTL818X_TX_CONF_CW_MIN (1 << 31) - __le32 RX_CONF; -#define RTL818X_RX_CONF_MONITOR (1 << 0) -#define RTL818X_RX_CONF_NICMAC (1 << 1) -#define RTL818X_RX_CONF_MULTICAST (1 << 2) -#define RTL818X_RX_CONF_BROADCAST (1 << 3) -#define RTL818X_RX_CONF_FCS (1 << 5) -#define RTL818X_RX_CONF_DATA (1 << 18) -#define RTL818X_RX_CONF_CTRL (1 << 19) -#define RTL818X_RX_CONF_MGMT (1 << 20) -#define RTL818X_RX_CONF_ADDR3 (1 << 21) -#define RTL818X_RX_CONF_PM (1 << 22) -#define RTL818X_RX_CONF_BSSID (1 << 23) -#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) -#define RTL818X_RX_CONF_CSDM1 (1 << 29) -#define RTL818X_RX_CONF_CSDM2 (1 << 30) -#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) - __le32 INT_TIMEOUT; - __le32 TBDA; - u8 EEPROM_CMD; -#define RTL818X_EEPROM_CMD_READ (1 << 0) -#define RTL818X_EEPROM_CMD_WRITE (1 << 1) -#define RTL818X_EEPROM_CMD_CK (1 << 2) -#define RTL818X_EEPROM_CMD_CS (1 << 3) -#define RTL818X_EEPROM_CMD_NORMAL (0 << 6) -#define RTL818X_EEPROM_CMD_LOAD (1 << 6) -#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6) -#define RTL818X_EEPROM_CMD_CONFIG (3 << 6) - u8 CONFIG0; - u8 CONFIG1; - u8 CONFIG2; -#define RTL818X_CONFIG2_ANTENNA_DIV (1 << 6) - __le32 ANAPARAM; - u8 MSR; -#define RTL818X_MSR_NO_LINK (0 << 2) -#define RTL818X_MSR_ADHOC (1 << 2) -#define RTL818X_MSR_INFRA (2 << 2) -#define RTL818X_MSR_MASTER (3 << 2) -#define RTL818X_MSR_ENEDCA (4 << 2) - u8 CONFIG3; -#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) -#define RTL818X_CONFIG3_GNT_SELECT (1 << 7) - u8 CONFIG4; -#define RTL818X_CONFIG4_POWEROFF (1 << 6) -#define RTL818X_CONFIG4_VCOOFF (1 << 7) - u8 TESTR; - u8 reserved_9[2]; - u8 PGSELECT; - u8 SECURITY; - __le32 ANAPARAM2; - u8 reserved_10[12]; - __le16 BEACON_INTERVAL; - __le16 ATIM_WND; - __le16 BEACON_INTERVAL_TIME; - __le16 ATIMTR_INTERVAL; - u8 PHY_DELAY; - u8 CARRIER_SENSE_COUNTER; - u8 reserved_11[2]; - u8 PHY[4]; - __le16 RFPinsOutput; - __le16 RFPinsEnable; - __le16 RFPinsSelect; - __le16 RFPinsInput; - __le32 RF_PARA; - __le32 RF_TIMING; - u8 GP_ENABLE; - u8 GPIO; - u8 reserved_12[2]; - __le32 HSSI_PARA; - u8 reserved_13[4]; - u8 TX_AGC_CTL; -#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) -#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) -#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2) - u8 TX_GAIN_CCK; - u8 TX_GAIN_OFDM; - u8 TX_ANTENNA; - u8 reserved_14[16]; - u8 WPA_CONF; - u8 reserved_15[3]; - u8 SIFS; - u8 DIFS; - u8 SLOT; - u8 reserved_16[5]; - u8 CW_CONF; -#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) -#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) - u8 CW_VAL; - u8 RATE_FALLBACK; -#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7) - u8 ACM_CONTROL; - u8 reserved_17[24]; - u8 CONFIG5; - u8 TX_DMA_POLLING; - u8 reserved_18[2]; - __le16 CWR; - u8 RETRY_CTR; - u8 reserved_19[3]; - __le16 INT_MIG; -/* RTL818X_R8187B_*: magic numbers from ioregisters */ -#define RTL818X_R8187B_B 0 -#define RTL818X_R8187B_D 1 -#define RTL818X_R8187B_E 2 - __le32 RDSAR; - __le16 TID_AC_MAP; - u8 reserved_20[4]; - u8 ANAPARAM3; - u8 reserved_21[5]; - __le16 FEMR; - u8 reserved_22[4]; - __le16 TALLY_CNT; - u8 TALLY_SEL; -} __attribute__((packed)); - -struct rtl818x_rf_ops { - char *name; - void (*init)(struct ieee80211_hw *); - void (*stop)(struct ieee80211_hw *); - void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); -}; - -/* Tx/Rx flags are common between RTL818X chips */ - -enum rtl818x_tx_desc_flags { - RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), - RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), - RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), - RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), - RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), - RTL818X_TX_DESC_FLAG_CTS = (1 << 18), - RTL818X_TX_DESC_FLAG_RTS = (1 << 23), - RTL818X_TX_DESC_FLAG_LS = (1 << 28), - RTL818X_TX_DESC_FLAG_FS = (1 << 29), - RTL818X_TX_DESC_FLAG_DMA = (1 << 30), - RTL818X_TX_DESC_FLAG_OWN = (1 << 31) -}; - -enum rtl818x_rx_desc_flags { - RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), - RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), - RTL818X_RX_DESC_FLAG_PM = (1 << 14), - RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), - RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), - RTL818X_RX_DESC_FLAG_PAM = (1 << 17), - RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), - RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ - RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ - RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), - RTL818X_RX_DESC_FLAG_FOF = (1 << 26), - RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), - RTL818X_RX_DESC_FLAG_LS = (1 << 28), - RTL818X_RX_DESC_FLAG_FS = (1 << 29), - RTL818X_RX_DESC_FLAG_EOR = (1 << 30), - RTL818X_RX_DESC_FLAG_OWN = (1 << 31) -}; - -#endif /* RTL818X_H */ diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile new file mode 100644 index 00000000000..c113b3e6904 --- /dev/null +++ b/drivers/net/wireless/rtl818x/Makefile @@ -0,0 +1,7 @@ +rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o + +obj-$(CONFIG_RTL8180) += rtl8180.o +obj-$(CONFIG_RTL8187) += rtl8187.o + + diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h new file mode 100644 index 00000000000..8721282a818 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180.h @@ -0,0 +1,120 @@ +#ifndef RTL8180_H +#define RTL8180_H + +#include "rtl818x.h" + +#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD + +#define RF_PARAM_ANALOGPHY (1 << 0) +#define RF_PARAM_ANTBDEFAULT (1 << 1) +#define RF_PARAM_CARRIERSENSE1 (1 << 2) +#define RF_PARAM_CARRIERSENSE2 (1 << 3) + +#define BB_ANTATTEN_CHAN14 0x0C +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1 << 30) +#define BB_HOST_BANG_EN (1 << 2) +#define BB_HOST_BANG_CLK (1 << 1) +#define BB_HOST_BANG_DATA 1 + +#define ANAPARAM_TXDACOFF_SHIFT 27 +#define ANAPARAM_PWR0_SHIFT 28 +#define ANAPARAM_PWR0_MASK (0x07 << ANAPARAM_PWR0_SHIFT) +#define ANAPARAM_PWR1_SHIFT 20 +#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) + +struct rtl8180_tx_desc { + __le32 flags; + __le16 rts_duration; + __le16 plcp_len; + __le32 tx_buf; + __le32 frame_len; + __le32 next_tx_desc; + u8 cw; + u8 retry_limit; + u8 agc; + u8 flags2; + u32 reserved[2]; +} __attribute__ ((packed)); + +struct rtl8180_rx_desc { + __le32 flags; + __le32 flags2; + union { + __le32 rx_buf; + __le64 tsft; + }; +} __attribute__ ((packed)); + +struct rtl8180_tx_ring { + struct rtl8180_tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; +}; + +struct rtl8180_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr __iomem *map; + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; + int mode; + + /* rtl8180 driver specific */ + spinlock_t lock; + struct rtl8180_rx_desc *rx_ring; + dma_addr_t rx_ring_dma; + unsigned int rx_idx; + struct sk_buff *rx_buf[32]; + struct rtl8180_tx_ring tx_ring[4]; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct pci_dev *pdev; + u32 rx_conf; + + int r8185; + u32 anaparam; + u16 rfparam; + u8 csthreshold; +}; + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam); + +static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr) +{ + return ioread8(addr); +} + +static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr) +{ + return ioread16(addr); +} + +static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr) +{ + return ioread32(addr); +} + +static inline void rtl818x_iowrite8(struct rtl8180_priv *priv, + u8 __iomem *addr, u8 val) +{ + iowrite8(val, addr); +} + +static inline void rtl818x_iowrite16(struct rtl8180_priv *priv, + __le16 __iomem *addr, u16 val) +{ + iowrite16(val, addr); +} + +static inline void rtl818x_iowrite32(struct rtl8180_priv *priv, + __le32 __iomem *addr, u32 val) +{ + iowrite32(val, addr); +} + +#endif /* RTL8180_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c new file mode 100644 index 00000000000..6c226c024dd --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -0,0 +1,1081 @@ + +/* + * Linux device driver for RTL8180 / RTL8185 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello , et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" +#include "rtl8180_sa2400.h" +#include "rtl8180_max2820.h" +#include "rtl8180_grf5101.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Andrea Merello "); +MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); +MODULE_LICENSE("GPL"); + +static struct pci_device_id rtl8180_table[] __devinitdata = { + /* rtl8185 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, + { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x700f) }, + { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, + + /* rtl8180 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, + { PCI_DEVICE(0x1799, 0x6001) }, + { PCI_DEVICE(0x1799, 0x6020) }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, rtl8180_table); + +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + + + + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + int i = 10; + u32 buf; + + buf = (data << 8) | addr; + + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); + while (i--) { + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); + if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) + return; + } +} + +static void rtl8180_handle_rx(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + unsigned int count = 32; + + while (count--) { + struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; + struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL818X_RX_DESC_FLAG_OWN) + return; + + if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL | + RTL818X_RX_DESC_FLAG_FOF | + RTL818X_RX_DESC_FLAG_RX_ERR))) + goto done; + else { + u32 flags2 = le32_to_cpu(entry->flags2); + struct ieee80211_rx_status rx_status = {0}; + struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); + + if (unlikely(!new_skb)) + goto done; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + skb_put(skb, flags & 0xFFF); + + rx_status.antenna = (flags2 >> 15) & 1; + /* TODO: improve signal/rssi reporting */ + rx_status.qual = flags2 & 0xFF; + rx_status.signal = (flags2 >> 8) & 0x7F; + /* XXX: is this correct? */ + rx_status.rate_idx = (flags >> 20) & 0xF; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; + rx_status.mactime = le64_to_cpu(entry->tsft); + rx_status.flag |= RX_FLAG_TSFT; + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = new_skb; + priv->rx_buf[priv->rx_idx] = skb; + *((dma_addr_t *) skb->cb) = + pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + } + + done: + entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + if (priv->rx_idx == 31) + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); + priv->rx_idx = (priv->rx_idx + 1) % 32; + } +} + +static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_info *info; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL818X_TX_DESC_FLAG_OWN) + return; + + ring->idx = (ring->idx + 1) % ring->entries; + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; + + ieee80211_tx_status_irqsafe(dev, skb); + if (ring->entries - skb_queue_len(&ring->queue) == 2) + ieee80211_wake_queue(dev, prio); + } +} + +static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *dev = dev_id; + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + spin_lock(&priv->lock); + reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); + if (unlikely(reg == 0xFFFF)) { + spin_unlock(&priv->lock); + return IRQ_HANDLED; + } + + rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); + + if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) + rtl8180_handle_tx(dev, 3); + + if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) + rtl8180_handle_tx(dev, 2); + + if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) + rtl8180_handle_tx(dev, 1); + + if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) + rtl8180_handle_tx(dev, 0); + + if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) + rtl8180_handle_rx(dev); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring; + struct rtl8180_tx_desc *entry; + unsigned long flags; + unsigned int idx, prio; + dma_addr_t mapping; + u32 tx_flags; + u8 rc_flags; + u16 plcp_len = 0; + __le16 rts_duration = 0; + + prio = skb_get_queue_mapping(skb); + ring = &priv->tx_ring[prio]; + + mapping = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + tx_flags = RTL818X_TX_DESC_FLAG_OWN | RTL818X_TX_DESC_FLAG_FS | + RTL818X_TX_DESC_FLAG_LS | + (ieee80211_get_tx_rate(dev, info)->hw_value << 24) | + skb->len; + + if (priv->r8185) + tx_flags |= RTL818X_TX_DESC_FLAG_DMA | + RTL818X_TX_DESC_FLAG_NO_ENC; + + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_flags |= RTL818X_TX_DESC_FLAG_RTS; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + tx_flags |= RTL818X_TX_DESC_FLAG_CTS; + tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } + + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, + info); + + if (!priv->r8185) { + unsigned int remainder; + + plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), + (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); + remainder = (16 * (skb->len + 4)) % + ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10); + if (remainder > 0 && remainder <= 6) + plcp_len |= 1 << 15; + } + + spin_lock_irqsave(&priv->lock, flags); + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + entry = &ring->desc[idx]; + + entry->rts_duration = rts_duration; + entry->plcp_len = cpu_to_le16(plcp_len); + entry->tx_buf = cpu_to_le32(mapping); + entry->frame_len = cpu_to_le32(skb->len); + entry->flags2 = info->control.rates[1].idx >= 0 ? + ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; + entry->retry_limit = info->control.rates[0].count; + entry->flags = cpu_to_le32(tx_flags); + __skb_queue_tail(&ring->queue, skb); + if (ring->entries - skb_queue_len(&ring->queue) < 2) + ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); + spin_unlock_irqrestore(&priv->lock, flags); + + rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); + + return 0; +} + +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) +{ + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static int rtl8180_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + rtl818x_iowrite8(priv, &priv->map->CMD, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(10); + + /* reset */ + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + /* check success of reset */ + if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { + printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { + /* For cardbus */ + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= 1 << 1; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + reg = rtl818x_ioread16(priv, &priv->map->FEMR); + reg |= (1 << 15) | (1 << 14) | (1 << 4); + rtl818x_iowrite16(priv, &priv->map->FEMR, reg); + } + + rtl818x_iowrite8(priv, &priv->map->MSR, 0); + + if (!priv->r8185) + rtl8180_set_anaparam(priv, priv->anaparam); + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + /* TODO: necessary? specs indicate not */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); + } + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ + + /* TODO: turn off hw wep on rtl8180 */ + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + + if (priv->r8185) { + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* TODO: set ClkRun enable? necessary? */ + reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + } else { + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); + rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); + + rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); + } + + priv->rf->init(dev); + if (priv->r8185) + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + return 0; +} + +static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_rx_desc *entry; + int i; + + priv->rx_ring = pci_alloc_consistent(priv->pdev, + sizeof(*priv->rx_ring) * 32, + &priv->rx_ring_dma); + + if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate RX ring\n", + wiphy_name(dev->wiphy)); + return -ENOMEM; + } + + memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32); + priv->rx_idx = 0; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); + dma_addr_t *mapping; + entry = &priv->rx_ring[i]; + if (!skb) + return 0; + + priv->rx_buf[i] = skb; + mapping = (dma_addr_t *)skb->cb; + *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + entry->rx_buf = cpu_to_le32(*mapping); + entry->flags = cpu_to_le32(RTL818X_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + } + entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR); + return 0; +} + +static void rtl8180_free_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = priv->rx_buf[i]; + if (!skb) + continue; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32, + priv->rx_ring, priv->rx_ring_dma); + priv->rx_ring = NULL; +} + +static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, + unsigned int prio, unsigned int entries) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_desc *ring; + dma_addr_t dma; + int i; + + ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); + if (!ring || (unsigned long)ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n", + wiphy_name(dev->wiphy), prio); + return -ENOMEM; + } + + memset(ring, 0, sizeof(*ring)*entries); + priv->tx_ring[prio].desc = ring; + priv->tx_ring[prio].dma = dma; + priv->tx_ring[prio].idx = 0; + priv->tx_ring[prio].entries = entries; + skb_queue_head_init(&priv->tx_ring[prio].queue); + + for (i = 0; i < entries; i++) + ring[i].next_tx_desc = + cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); + + return 0; +} + +static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; +} + +static int rtl8180_start(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int ret, i; + u32 reg; + + ret = rtl8180_init_rx_ring(dev); + if (ret) + return ret; + + for (i = 0; i < 4; i++) + if ((ret = rtl8180_init_tx_ring(dev, i, 16))) + goto err_free_rings; + + ret = rtl8180_init_hw(dev); + if (ret) + goto err_free_rings; + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + goto err_free_rings; + } + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); + rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + (7 << 8 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC; + + if (priv->r8185) + reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; + else { + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) + ? RTL818X_RX_CONF_CSDM1 : 0; + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) + ? RTL818X_RX_CONF_CSDM2 : 0; + } + + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + /* disable early TX */ + rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); + } + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg |= (6 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + + if (priv->r8185) + reg &= ~RTL818X_TX_CONF_PROBE_DTS; + else + reg &= ~RTL818X_TX_CONF_HW_SEQNUM; + + /* different meaning, same value on both rtl8185 and rtl8180 */ + reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_RX_ENABLE; + reg |= RTL818X_CMD_TX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->mode = NL80211_IFTYPE_MONITOR; + return 0; + + err_free_rings: + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + if (priv->tx_ring[i].desc) + rtl8180_free_tx_ring(dev, i); + + return ret; +} + +static void rtl8180_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + int i; + + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->rf->stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + free_irq(priv->pdev->irq, dev); + + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + rtl8180_free_tx_ring(dev, i); +} + +static int rtl8180_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + + if (priv->mode != NL80211_IFTYPE_MONITOR) + return -EOPNOTSUPP; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->vif = conf->vif; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], + le32_to_cpu(*(__le32 *)conf->mac_addr)); + rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], + le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + return 0; +} + +static void rtl8180_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + priv->mode = NL80211_IFTYPE_MONITOR; + priv->vif = NULL; +} + +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) +{ + struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + + priv->rf->set_chan(dev, conf); + + return 0; +} + +static int rtl8180_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); + + return 0; +} + +static void rtl8180_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mclist) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + if (*total_flags & FIF_ALLMULTI || mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + else + priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; + + *total_flags = 0; + + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + + rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); +} + +static const struct ieee80211_ops rtl8180_ops = { + .tx = rtl8180_tx, + .start = rtl8180_start, + .stop = rtl8180_stop, + .add_interface = rtl8180_add_interface, + .remove_interface = rtl8180_remove_interface, + .config = rtl8180_config, + .config_interface = rtl8180_config_interface, + .configure_filter = rtl8180_configure_filter, +}; + +static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = 2 << 6; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); +} + +static int __devinit rtl8180_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *dev; + struct rtl8180_priv *priv; + unsigned long mem_addr, mem_len; + unsigned int io_addr, io_len; + int err, i; + struct eeprom_93cx6 eeprom; + const char *chip_name, *rf_name = NULL; + u32 reg; + u16 eeprom_val; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\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 (mem_len < sizeof(struct rtl818x_csr) || + io_len < sizeof(struct rtl818x_csr)) { + printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) || + (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) { + printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); + if (!dev) { + printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + priv = dev->priv; + priv->pdev = pdev; + + dev->max_rates = 2; + SET_IEEE80211_DEV(dev, &pdev->dev); + pci_set_drvdata(pdev, dev); + + 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 (rtl8180): Cannot map device memory\n", + pci_name(pdev)); + goto err_free_dev; + } + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = 4; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_UNSPEC; + dev->queues = 1; + dev->max_signal = 65; + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg) { + case RTL818X_TX_CONF_R8180_ABCD: + chip_name = "RTL8180"; + break; + case RTL818X_TX_CONF_R8180_F: + chip_name = "RTL8180vF"; + break; + case RTL818X_TX_CONF_R8185_ABC: + chip_name = "RTL8185"; + break; + case RTL818X_TX_CONF_R8185_D: + chip_name = "RTL8185vD"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", + pci_name(pdev), reg >> 25); + goto err_iounmap; + } + + priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; + if (priv->r8185) { + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + pci_try_set_mwi(pdev); + } + + eeprom.data = dev; + eeprom.register_read = rtl8180_eeprom_register_read; + eeprom.register_write = rtl8180_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); + eeprom_val &= 0xFF; + switch (eeprom_val) { + case 1: rf_name = "Intersil"; + break; + case 2: rf_name = "RFMD"; + break; + case 3: priv->rf = &sa2400_rf_ops; + break; + case 4: priv->rf = &max2820_rf_ops; + break; + case 5: priv->rf = &grf5101_rf_ops; + break; + case 9: priv->rf = rtl8180_detect_rf(dev); + break; + case 10: + rf_name = "RTL8255"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", + pci_name(pdev), eeprom_val); + goto err_iounmap; + } + + if (!priv->rf) { + printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", + pci_name(pdev), rf_name); + goto err_iounmap; + } + + eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); + priv->csthreshold = eeprom_val >> 8; + if (!priv->r8185) { + __le32 anaparam; + eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); + priv->anaparam = le32_to_cpu(anaparam); + eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); + } + + eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" + " randomly generated MAC addr\n", pci_name(pdev)); + random_ether_addr(dev->wiphy->perm_addr); + } + + /* CCK TX power */ + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); + priv->channels[i].hw_value = txpwr & 0xFF; + priv->channels[i + 1].hw_value = txpwr >> 8; + } + + /* OFDM TX power */ + if (priv->r8185) { + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); + priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].hw_value |= txpwr & 0xFF00; + } + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + spin_lock_init(&priv->lock); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot register device\n", + pci_name(pdev)); + goto err_iounmap; + } + + printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, + chip_name, priv->rf->name); + + return 0; + + err_iounmap: + iounmap(priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + pci_disable_device(pdev); + return err; +} + +static void __devexit rtl8180_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct rtl8180_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + + pci_iounmap(pdev, priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + +#ifdef CONFIG_PM +static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int rtl8180_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver rtl8180_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8180_table, + .probe = rtl8180_probe, + .remove = __devexit_p(rtl8180_remove), +#ifdef CONFIG_PM + .suspend = rtl8180_suspend, + .resume = rtl8180_resume, +#endif /* CONFIG_PM */ +}; + +static int __init rtl8180_init(void) +{ + return pci_register_driver(&rtl8180_driver); +} + +static void __exit rtl8180_exit(void) +{ + pci_unregister_driver(&rtl8180_driver); +} + +module_init(rtl8180_init); +module_exit(rtl8180_exit); diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c new file mode 100644 index 00000000000..947ee55f18b --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c @@ -0,0 +1,180 @@ + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_grf5101.h" + +static const int grf5101_encode[] = { + 0x0, 0x8, 0x4, 0xC, + 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, + 0x3, 0xB, 0x7, 0xF +}; + +static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = grf5101_encode[(data >> 8) & 0xF]; + phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4; + phy_config |= grf5101_encode[data & 0xF] << 8; + phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12; + phy_config |= (addr & 1) << 16; + phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24; + + /* MAC will bang bits to the chip */ + phy_config |= 0x90000000; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = GRF5101_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void grf5101_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = channel - 1; + + /* set TX power */ + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x06, txpw); + write_grf5101(dev, 0x15, 0x10); + write_grf5101(dev, 0x15, 0x0); + + /* set frequency */ + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x0B, chan); + write_grf5101(dev, 0x07, 0x1000); + + grf5101_write_phy_antenna(dev, channel); +} + +static void grf5101_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam; + + anaparam = priv->anaparam; + anaparam &= 0x000fffff; + anaparam |= 0x3f900000; + rtl8180_set_anaparam(priv, anaparam); + + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x1f, 0x45); + write_grf5101(dev, 0x1f, 0x5); + write_grf5101(dev, 0x00, 0x8e4); +} + +static void grf5101_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + rtl8180_set_anaparam(priv, priv->anaparam); + + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x40); + write_grf5101(dev, 0x1f, 0x60); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x00, 0xae4); + write_grf5101(dev, 0x1f, 0x1); + write_grf5101(dev, 0x1f, 0x41); + write_grf5101(dev, 0x1f, 0x61); + + write_grf5101(dev, 0x01, 0x1a23); + write_grf5101(dev, 0x02, 0x4971); + write_grf5101(dev, 0x03, 0x41de); + write_grf5101(dev, 0x04, 0x2d80); + write_grf5101(dev, 0x05, 0x68ff); /* 0x61ff original value */ + write_grf5101(dev, 0x06, 0x0); + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x08, 0x7533); + write_grf5101(dev, 0x09, 0xc401); + write_grf5101(dev, 0x0a, 0x0); + write_grf5101(dev, 0x0c, 0x1c7); + write_grf5101(dev, 0x0d, 0x29d3); + write_grf5101(dev, 0x0e, 0x2e8); + write_grf5101(dev, 0x10, 0x192); + write_grf5101(dev, 0x11, 0x248); + write_grf5101(dev, 0x12, 0x0); + write_grf5101(dev, 0x13, 0x20c4); + write_grf5101(dev, 0x14, 0xf4fc); + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x16, 0x1500); + + write_grf5101(dev, 0x07, 0x1000); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0xa8); + rtl8180_write_phy(dev, 3, 0x0); + rtl8180_write_phy(dev, 4, 0xc0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1e); + rtl8180_write_phy(dev, 7, 0x64); + + grf5101_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); + rtl8180_write_phy(dev, 0x1b, 0x44); +} + +const struct rtl818x_rf_ops grf5101_rf_ops = { + .name = "GCT", + .init = grf5101_rf_init, + .stop = grf5101_rf_stop, + .set_chan = grf5101_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h new file mode 100644 index 00000000000..76647111bcf --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_GRF5101_H +#define RTL8180_GRF5101_H + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define GRF5101_ANTENNA 0xA3 + +extern const struct rtl818x_rf_ops grf5101_rf_ops; + +#endif /* RTL8180_GRF5101_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c new file mode 100644 index 00000000000..6c825fd7f3b --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.c @@ -0,0 +1,152 @@ +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_max2820.h" + +static const u32 max2820_chan[] = { + 12, /* CH 1 */ + 17, + 22, + 27, + 32, + 37, + 42, + 47, + 52, + 57, + 62, + 67, + 72, + 84, /* CH 14 */ +}; + +static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = 0x90 + (data & 0xf); + phy_config <<= 16; + phy_config += addr; + phy_config <<= 8; + phy_config += (data >> 4) & 0xff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(1); +} + +static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant; + + ant = MAXIM_ANTENNA; + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void max2820_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = conf ? + ieee80211_frequency_to_channel(conf->channel->center_freq) : 1; + unsigned int chan_idx = channel - 1; + u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; + u32 chan = max2820_chan[chan_idx]; + + /* While philips SA2400 drive the PA bias from + * sa2400, for MAXIM we do this directly from BB */ + rtl8180_write_phy(dev, 3, txpw); + + max2820_write_phy_antenna(dev, channel); + write_max2820(dev, 3, chan); +} + +static void max2820_rf_stop(struct ieee80211_hw *dev) +{ + rtl8180_write_phy(dev, 3, 0x8); + write_max2820(dev, 1, 0); +} + + +static void max2820_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + /* MAXIM from netbsd driver */ + write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ + write_max2820(dev, 1, 0x01e); /* enable register */ + write_max2820(dev, 2, 0x001); /* synt register */ + + max2820_rf_set_channel(dev, NULL); + + write_max2820(dev, 4, 0x313); /* rx register */ + + /* PA is driven directly by the BB, we keep the MAXIM bias + * at the highest value in case that setting it to lower + * values may introduce some further attenuation somewhere.. + */ + write_max2820(dev, 5, 0x00f); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ + rtl8180_write_phy(dev, 3, 0x08); /* txagc */ + rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ + rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ + rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ + rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ + + max2820_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); + else + rtl8180_write_phy(dev, 0x12, 0x47); + + rtl8180_write_phy(dev, 0x13, 0x9b); + + rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ + rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ + + max2820_rf_set_channel(dev, NULL); +} + +const struct rtl818x_rf_ops max2820_rf_ops = { + .name = "Maxim", + .init = max2820_rf_init, + .stop = max2820_rf_stop, + .set_chan = max2820_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h new file mode 100644 index 00000000000..61cf6d1e7d5 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_max2820.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_MAX2820_H +#define RTL8180_MAX2820_H + +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define MAXIM_ANTENNA 0xb3 + +extern const struct rtl818x_rf_ops max2820_rf_ops; + +#endif /* RTL8180_MAX2820_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c new file mode 100644 index 00000000000..cd22781728a --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c @@ -0,0 +1,780 @@ + +/* + * Radio tuning for RTL8225 on RTL8180 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8180 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" + +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | !!(bangdata & (1 << i)); + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400; + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; + + cck_power = min(cck_power, (u8)35); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); /* FIXME: optional? */ + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +static void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8BE); + rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */ + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, rtl8225_chan[0]); + 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(1); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(100); + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + 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, 0x62); 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, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x00); 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, 0x03); 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_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, 0x93); 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, 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); + + rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1); + + 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 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + rtl8225_write(dev, 0x0c, 0x50); + /* set OFDM initial gain */ + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]); + /* set CCK threshold */ + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]); +} + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck_B[] = { + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck_A[] = { + 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else if (cck_power == 12) + tmp = rtl8225z2_tx_power_cck_B; + else if (cck_power == 13) + tmp = rtl8225z2_tx_power_cck_A; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + cck_power = min(cck_power, (u8)35); + if (cck_power == 13 || cck_power == 14) + cck_power = 12; + if (cck_power >= 15) + cck_power -= 2; + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power); + rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK); + msleep(1); + + ofdm_power = min(ofdm_power, (u8)35); + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power); + + rtl8225_write_phy_ofdm(dev, 2, 0x62); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, + 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, + 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, + 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, + 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, + 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, + 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, + 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + 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(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + /* TODO: readd calibration failure message when the calibration + check works */ + } + + rtl8225_write(dev, 0x0, 0x1B7); + rtl8225_write(dev, 0x3, 0x002); + rtl8225_write(dev, 0x5, 0x004); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x0B7); msleep(100); + rtl8225_write(dev, 0x2, 0xC4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + rtl8225_write(dev, 0x00, 0x2BF); + rtl8225_write(dev, 0xFF, 0xFFFF); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + 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, 0x62); 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, 0x18, 0xef); 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, 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, 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, 0x11); 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, 0xb3); 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, 0x23, 0x80); msleep(1); /* FIXME: not needed? */ + 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_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, 0x93); 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, 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, 0x8a); 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); + + rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 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 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static void rtl8225_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + + rtl8225_write(dev, 0x4, 0x1f); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); + + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, chan); + else + rtl8225z2_rf_set_tx_power(dev, chan); + + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); + msleep(10); + + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } +} + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg8, reg9; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(100); + + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; +} diff --git a/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h new file mode 100644 index 00000000000..310013a2d72 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h @@ -0,0 +1,23 @@ +#ifndef RTL8180_RTL8225_H +#define RTL8180_RTL8225_H + +#define RTL8225_ANAPARAM_ON 0xa0000b59 +#define RTL8225_ANAPARAM2_ON 0x860dec11 +#define RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8225_ANAPARAM2_OFF 0x840dec11 + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *); + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8180_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c new file mode 100644 index 00000000000..cea4e0ccb92 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c @@ -0,0 +1,202 @@ + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include "rtl8180.h" +#include "rtl8180_sa2400.h" + +static const u32 sa2400_chan[] = { + 0x00096c, /* ch1 */ + 0x080970, + 0x100974, + 0x180978, + 0x000980, + 0x080984, + 0x100988, + 0x18098c, + 0x000994, + 0x080998, + 0x10099c, + 0x1809a0, + 0x0009a8, + 0x0009b4, /* ch 14 */ +}; + +static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ + phy_config = 0xb0000000; + + phy_config |= ((u32)(addr & 0xf)) << 24; + phy_config |= data & 0xffffff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = SA2400_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); + +} + +static void sa2400_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = sa2400_chan[channel - 1]; + + write_sa2400(dev, 7, txpw); + + sa2400_write_phy_antenna(dev, channel); + + write_sa2400(dev, 0, chan); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); +} + +static void sa2400_rf_stop(struct ieee80211_hw *dev) +{ + write_sa2400(dev, 4, 0); +} + +static void sa2400_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam, txconf; + u8 firdac; + int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; + + anaparam = priv->anaparam; + anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); + anaparam &= ~ANAPARAM_PWR1_MASK; + anaparam &= ~ANAPARAM_PWR0_MASK; + + if (analogphy) { + anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; + firdac = 0; + } else { + anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); + anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); + firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; + } + + rtl8180_set_anaparam(priv, anaparam); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19340 | firdac); + write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); + write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ + + if (!analogphy) + write_sa2400(dev, 4, 0x1938c); /*???*/ + + write_sa2400(dev, 4, 0x19340 | firdac); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ + + /* new from rtl8180 embedded driver (rtl8181 project) */ + write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ + write_sa2400(dev, 8, 0); /* VCO */ + + if (analogphy) { + rtl8180_set_anaparam(priv, anaparam | + (1 << ANAPARAM_TXDACOFF_SHIFT)); + + txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + txconf | RTL818X_TX_CONF_LOOPBACK_CONT); + + write_sa2400(dev, 4, 0x19341); /* calibrates DC */ + + /* a 5us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + write_sa2400(dev, 4, 0x19345); + + /* a 20us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); + + rtl8180_set_anaparam(priv, anaparam); + } + /* end new code */ + + write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x98); + rtl8180_write_phy(dev, 3, 0x38); + rtl8180_write_phy(dev, 4, 0xe0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1a); + rtl8180_write_phy(dev, 7, 0x64); + + sa2400_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x80); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); +} + +const struct rtl818x_rf_ops sa2400_rf_ops = { + .name = "Philips", + .init = sa2400_rf_init, + .stop = sa2400_rf_stop, + .set_chan = sa2400_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl818x/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h new file mode 100644 index 00000000000..a4aaa0d413f --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h @@ -0,0 +1,36 @@ +#ifndef RTL8180_SA2400_H +#define RTL8180_SA2400_H + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define SA2400_ANTENNA 0x91 +#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 +#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 +#define SA2400_ANAPARAM_PWR0_ON 0x3 + +/* RX sensitivity in dbm */ +#define SA2400_MAX_SENS 85 + +#define SA2400_REG4_FIRDAC_SHIFT 7 + +extern const struct rtl818x_rf_ops sa2400_rf_ops; + +#endif /* RTL8180_SA2400_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h new file mode 100644 index 00000000000..33725d0978b --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -0,0 +1,220 @@ +/* + * Definitions for RTL8187 hardware + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * 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. + */ + +#ifndef RTL8187_H +#define RTL8187_H + +#include "rtl818x.h" + +#define RTL8187_EEPROM_TXPWR_BASE 0x05 +#define RTL8187_EEPROM_MAC_ADDR 0x07 +#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */ +#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */ + +#define RTL8187_REQT_READ 0xC0 +#define RTL8187_REQT_WRITE 0x40 +#define RTL8187_REQ_GET_REG 0x05 +#define RTL8187_REQ_SET_REG 0x05 + +#define RTL8187_MAX_RX 0x9C4 + +struct rtl8187_rx_info { + struct urb *urb; + struct ieee80211_hw *dev; +}; + +struct rtl8187_rx_hdr { + __le32 flags; + u8 noise; + u8 signal; + u8 agc; + u8 reserved; + __le64 mac_time; +} __attribute__((packed)); + +struct rtl8187b_rx_hdr { + __le32 flags; + __le64 mac_time; + u8 sq; + u8 rssi; + u8 agc; + u8 flags2; + __le16 snr_long2end; + s8 pwdb_g12; + u8 fot; +} __attribute__((packed)); + +/* {rtl8187,rtl8187b}_tx_info is in skb */ + +struct rtl8187_tx_hdr { + __le32 flags; + __le16 rts_duration; + __le16 len; + __le32 retry; +} __attribute__((packed)); + +struct rtl8187b_tx_hdr { + __le32 flags; + __le16 rts_duration; + __le16 len; + __le32 unused_1; + __le16 unused_2; + __le16 tx_duration; + __le32 unused_3; + __le32 retry; + __le32 unused_4[2]; +} __attribute__((packed)); + +enum { + DEVICE_RTL8187, + DEVICE_RTL8187B +}; + +struct rtl8187_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr *map; + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; + int mode; + /* The mutex protects the TX loopback state. + * Any attempt to set channels concurrently locks the device. + */ + struct mutex conf_mutex; + + /* rtl8187 specific */ + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_supported_band band; + struct usb_device *udev; + u32 rx_conf; + u16 txpwr_base; + u8 asic_rev; + u8 is_rtl8187b; + enum { + RTL8187BvB, + RTL8187BvD, + RTL8187BvE + } hw_rev; + struct sk_buff_head rx_queue; + u8 signal; + u8 quality; + u8 noise; +}; + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); + +static inline u8 rtl818x_ioread8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 idx) +{ + u8 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return val; +} + +static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr) +{ + return rtl818x_ioread8_idx(priv, addr, 0); +} + +static inline u16 rtl818x_ioread16_idx(struct rtl8187_priv *priv, + __le16 *addr, u8 idx) +{ + __le16 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return le16_to_cpu(val); +} + +static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr) +{ + return rtl818x_ioread16_idx(priv, addr, 0); +} + +static inline u32 rtl818x_ioread32_idx(struct rtl8187_priv *priv, + __le32 *addr, u8 idx) +{ + __le32 val; + + usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0), + RTL8187_REQ_GET_REG, RTL8187_REQT_READ, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); + + return le32_to_cpu(val); +} + +static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr) +{ + return rtl818x_ioread32_idx(priv, addr, 0); +} + +static inline void rtl818x_iowrite8_idx(struct rtl8187_priv *priv, + u8 *addr, u8 val, u8 idx) +{ + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &val, + sizeof(val), HZ / 2); +} + +static inline void rtl818x_iowrite8(struct rtl8187_priv *priv, u8 *addr, u8 val) +{ + rtl818x_iowrite8_idx(priv, addr, val, 0); +} + +static inline void rtl818x_iowrite16_idx(struct rtl8187_priv *priv, + __le16 *addr, u16 val, u8 idx) +{ + __le16 buf = cpu_to_le16(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); +} + +static inline void rtl818x_iowrite16(struct rtl8187_priv *priv, __le16 *addr, + u16 val) +{ + rtl818x_iowrite16_idx(priv, addr, val, 0); +} + +static inline void rtl818x_iowrite32_idx(struct rtl8187_priv *priv, + __le32 *addr, u32 val, u8 idx) +{ + __le32 buf = cpu_to_le32(val); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + (unsigned long)addr, idx & 0x03, &buf, sizeof(buf), + HZ / 2); +} + +static inline void rtl818x_iowrite32(struct rtl8187_priv *priv, __le32 *addr, + u32 val) +{ + rtl818x_iowrite32_idx(priv, addr, val, 0); +} + +#endif /* RTL8187_H */ diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c new file mode 100644 index 00000000000..e1399d0b55d --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -0,0 +1,1298 @@ +/* + * Linux device driver for RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Magic delays and register offsets below are taken from the original + * r8187 driver sources. Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +MODULE_AUTHOR("Michael Wu "); +MODULE_AUTHOR("Andrea Merello "); +MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); +MODULE_LICENSE("GPL"); + +static struct usb_device_id rtl8187_table[] __devinitdata = { + /* Asus */ + {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, + /* Belkin */ + {USB_DEVICE(0x050d, 0x705e), .driver_info = DEVICE_RTL8187B}, + /* Realtek */ + {USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B}, + {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B}, + /* Netgear */ + {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B}, + /* HP */ + {USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187}, + /* Sitecom */ + {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187}, + {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B}, + /* Abocom */ + {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187}, + {} +}; + +MODULE_DEVICE_TABLE(usb, rtl8187_table); + +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + +static void rtl8187_iowrite_async_cb(struct urb *urb) +{ + kfree(urb->context); + usb_free_urb(urb); +} + +static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, + void *data, u16 len) +{ + struct usb_ctrlrequest *dr; + struct urb *urb; + struct rtl8187_async_write_data { + u8 data[4]; + struct usb_ctrlrequest dr; + } *buf; + int rc; + + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) + return; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree(buf); + return; + } + + dr = &buf->dr; + + dr->bRequestType = RTL8187_REQT_WRITE; + dr->bRequest = RTL8187_REQ_SET_REG; + dr->wValue = addr; + dr->wIndex = 0; + dr->wLength = cpu_to_le16(len); + + memcpy(buf, data, len); + + usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), + (unsigned char *)dr, buf, len, + rtl8187_iowrite_async_cb, buf); + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) { + kfree(buf); + usb_free_urb(urb); + } +} + +static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, + __le32 *addr, u32 val) +{ + __le32 buf = cpu_to_le32(val); + + rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr), + &buf, sizeof(buf)); +} + +void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8187_priv *priv = dev->priv; + + data <<= 8; + data |= addr | 0x80; + + rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); + rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); +} + +static void rtl8187_tx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw = info->rate_driver_data[0]; + struct rtl8187_priv *priv = hw->priv; + + usb_free_urb(info->rate_driver_data[1]); + skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : + sizeof(struct rtl8187_tx_hdr)); + ieee80211_tx_info_clear_status(info); + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); +} + +static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + unsigned int ep; + void *buf; + struct urb *urb; + __le16 rts_dur = 0; + u32 flags; + int rc; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + kfree_skb(skb); + return 0; + } + + flags = skb->len; + flags |= RTL818X_TX_DESC_FLAG_NO_ENC; + + flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; + if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) + flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + flags |= RTL818X_TX_DESC_FLAG_RTS; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + rts_dur = ieee80211_rts_duration(dev, priv->vif, + skb->len, info); + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + flags |= RTL818X_TX_DESC_FLAG_CTS; + flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; + } + + if (!priv->is_rtl8187b) { + struct rtl8187_tx_hdr *hdr = + (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->len = 0; + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + buf = hdr; + + ep = 2; + } else { + /* fc needs to be calculated before skb_push() */ + unsigned int epmap[4] = { 6, 7, 5, 4 }; + struct ieee80211_hdr *tx_hdr = + (struct ieee80211_hdr *)(skb->data); + u16 fc = le16_to_cpu(tx_hdr->frame_control); + + struct rtl8187b_tx_hdr *hdr = + (struct rtl8187b_tx_hdr *)skb_push(skb, sizeof(*hdr)); + struct ieee80211_rate *txrate = + ieee80211_get_tx_rate(dev, info); + memset(hdr, 0, sizeof(*hdr)); + hdr->flags = cpu_to_le32(flags); + hdr->rts_duration = rts_dur; + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); + hdr->tx_duration = + ieee80211_generic_frame_duration(dev, priv->vif, + skb->len, txrate); + buf = hdr; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) + ep = 12; + else + ep = epmap[skb_get_queue_mapping(skb)]; + } + + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; + + usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), + buf, skb->len, rtl8187_tx_cb, skb); + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc < 0) { + usb_free_urb(urb); + kfree_skb(skb); + } + + return 0; +} + +static void rtl8187_rx_cb(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb; + struct ieee80211_hw *dev = info->dev; + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_rx_status rx_status = { 0 }; + int rate, signal; + u32 flags; + u32 quality; + + spin_lock(&priv->rx_queue.lock); + if (skb->next) + __skb_unlink(skb, &priv->rx_queue); + else { + spin_unlock(&priv->rx_queue.lock); + return; + } + spin_unlock(&priv->rx_queue.lock); + + if (unlikely(urb->status)) { + usb_free_urb(urb); + dev_kfree_skb_irq(skb); + return; + } + + skb_put(skb, urb->actual_length); + if (!priv->is_rtl8187b) { + struct rtl8187_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + flags = le32_to_cpu(hdr->flags); + signal = hdr->signal & 0x7f; + rx_status.antenna = (hdr->signal >> 7) & 1; + rx_status.noise = hdr->noise; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + priv->quality = signal; + rx_status.qual = priv->quality; + priv->noise = hdr->noise; + rate = (flags >> 20) & 0xF; + if (rate > 3) { /* OFDM rate */ + if (signal > 90) + signal = 90; + else if (signal < 25) + signal = 25; + signal = 90 - signal; + } else { /* CCK rate */ + if (signal > 95) + signal = 95; + else if (signal < 30) + signal = 30; + signal = 95 - signal; + } + rx_status.signal = signal; + priv->signal = signal; + } else { + struct rtl8187b_rx_hdr *hdr = + (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); + /* The Realtek datasheet for the RTL8187B shows that the RX + * header contains the following quantities: signal quality, + * RSSI, AGC, the received power in dB, and the measured SNR. + * In testing, none of these quantities show qualitative + * agreement with AP signal strength, except for the AGC, + * which is inversely proportional to the strength of the + * signal. In the following, the quality and signal strength + * are derived from the AGC. The arbitrary scaling constants + * are chosen to make the results close to the values obtained + * for a BCM4312 using b43 as the driver. The noise is ignored + * for now. + */ + flags = le32_to_cpu(hdr->flags); + quality = 170 - hdr->agc; + if (quality > 100) + quality = 100; + signal = 14 - hdr->agc / 2; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rx_status.antenna = (hdr->rssi >> 7) & 1; + rx_status.mactime = le64_to_cpu(hdr->mac_time); + rate = (flags >> 20) & 0xF; + } + + skb_trim(skb, flags & 0x0FFF); + rx_status.rate_idx = rate; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; + rx_status.flag |= RX_FLAG_TSFT; + if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = dev_alloc_skb(RTL8187_MAX_RX); + if (unlikely(!skb)) { + usb_free_urb(urb); + /* TODO check rx queue length and refill *somewhere* */ + return; + } + + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = urb; + info->dev = dev; + urb->transfer_buffer = skb_tail_pointer(skb); + urb->context = skb; + skb_queue_tail(&priv->rx_queue, skb); + + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int rtl8187_init_urbs(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + struct sk_buff *skb; + struct rtl8187_rx_info *info; + + while (skb_queue_len(&priv->rx_queue) < 8) { + skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); + if (!skb) + break; + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) { + kfree_skb(skb); + break; + } + usb_fill_bulk_urb(entry, priv->udev, + usb_rcvbulkpipe(priv->udev, + priv->is_rtl8187b ? 3 : 1), + skb_tail_pointer(skb), + RTL8187_MAX_RX, rtl8187_rx_cb, skb); + info = (struct rtl8187_rx_info *)skb->cb; + info->urb = entry; + info->dev = dev; + skb_queue_tail(&priv->rx_queue, skb); + usb_submit_urb(entry, GFP_KERNEL); + } + + return 0; +} + +static int rtl8187_cmd_reset(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int i; + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + i = 10; + do { + msleep(2); + if (!(rtl818x_ioread8(priv, &priv->map->CMD) & + RTL818X_CMD_RESET)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + /* reload registers from eeprom */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + + i = 10; + do { + msleep(4); + if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) & + RTL818X_EEPROM_CMD_CONFIG)) + break; + } while (--i); + + if (!i) { + printk(KERN_ERR "%s: eeprom reset timeout!\n", + wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtl8187_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u8 reg; + int res; + + /* reset */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | + RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & + ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + msleep(200); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11); + rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00); + msleep(200); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* setup card */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 1); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + + rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + reg &= 0x3F; + reg |= 0x80; + rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + + // TODO: set RESP_RATE and BRSR properly + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* host_usb_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0); + reg = rtl818x_ioread8(priv, (u8 *)0xFE53); + rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8)); + rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80); + msleep(100); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); + msleep(100); + + priv->rf->init(dev); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); + rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); + rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); + rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + + return 0; +} + +static const u8 rtl8187b_reg_table[][3] = { + {0xF0, 0x32, 0}, {0xF1, 0x32, 0}, {0xF2, 0x00, 0}, {0xF3, 0x00, 0}, + {0xF4, 0x32, 0}, {0xF5, 0x43, 0}, {0xF6, 0x00, 0}, {0xF7, 0x00, 0}, + {0xF8, 0x46, 0}, {0xF9, 0xA4, 0}, {0xFA, 0x00, 0}, {0xFB, 0x00, 0}, + {0xFC, 0x96, 0}, {0xFD, 0xA4, 0}, {0xFE, 0x00, 0}, {0xFF, 0x00, 0}, + + {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, + {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, + {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, + {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, + {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, + {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, + + {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, + {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, + {0x27, 0x8D, 2}, {0x4D, 0x08, 2}, {0x50, 0x05, 2}, {0x51, 0xF5, 2}, + {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, + {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, + {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, + {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, + {0x73, 0x9A, 2}, + + {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, + {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, + {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, + {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, + {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x91, 0x03, 0}, + + {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, + {0x8E, 0x08, 0}, {0x8F, 0x00, 0} +}; + +static int rtl8187b_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int res, i; + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_ON); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_ON); + + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); + reg = rtl818x_ioread8(priv, (u8 *)0xFF62); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); + + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + res = rtl8187_cmd_reset(dev); + if (res) + return res; + + rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | + RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); + reg = rtl818x_ioread8(priv, &priv->map->RATE_FALLBACK); + reg |= RTL818X_RATE_FALLBACK_ENABLE; + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, reg); + + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG1); + rtl818x_iowrite8(priv, &priv->map->CONFIG1, (reg & 0x3F) | 0x80); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + for (i = 0; i < ARRAY_SIZE(rtl8187b_reg_table); i++) { + rtl818x_iowrite8_idx(priv, + (u8 *)(uintptr_t) + (rtl8187b_reg_table[i][0] | 0xFF00), + rtl8187b_reg_table[i][1], + rtl8187b_reg_table[i][2]); + } + + rtl818x_iowrite16(priv, &priv->map->TID_AC_MAP, 0xFA50); + rtl818x_iowrite16(priv, &priv->map->INT_MIG, 0); + + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF0, 0, 1); + rtl818x_iowrite32_idx(priv, (__le32 *)0xFFF4, 0, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFFF8, 0, 1); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + msleep(100); + + priv->rf->init(dev); + + reg = RTL818X_CMD_TX_ENABLE | RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite8(priv, (u8 *)0xFE41, 0xF4); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + rtl818x_iowrite8(priv, (u8 *)0xFE40, 0x0F); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x00); + rtl818x_iowrite8(priv, (u8 *)0xFE42, 0x01); + + reg = rtl818x_ioread8(priv, (u8 *)0xFFDB); + rtl818x_iowrite8(priv, (u8 *)0xFFDB, reg | (1 << 2)); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x59FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF74, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF76, 0x59D2, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF78, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7A, 0x19FA, 3); + rtl818x_iowrite16_idx(priv, (__le16 *)0xFF7C, 0x00D0, 3); + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF80, 0x0F, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF83, 0x03, 1); + rtl818x_iowrite8(priv, (u8 *)0xFFDA, 0x10); + rtl818x_iowrite8_idx(priv, (u8 *)0xFF4D, 0x08, 2); + + rtl818x_iowrite32(priv, &priv->map->HSSI_PARA, 0x0600321B); + + rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + + return 0; +} + +static int rtl8187_start(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + u32 reg; + int ret; + + ret = (!priv->is_rtl8187b) ? rtl8187_init_hw(dev) : + rtl8187b_init_hw(dev); + if (ret) + return ret; + + mutex_lock(&priv->conf_mutex); + if (priv->is_rtl8187b) { + reg = RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC | + RTL818X_RX_CONF_BSSID | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_MULTICAST; + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + RTL818X_TX_CONF_HW_SEQNUM | + RTL818X_TX_CONF_DISREQQSIZE | + (7 << 8 /* short retry limit */) | + (7 << 0 /* long retry limit */) | + (7 << 21 /* MAX TX DMA */)); + rtl8187_init_urbs(dev); + mutex_unlock(&priv->conf_mutex); + return 0; + } + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); + rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); + + rtl8187_init_urbs(dev); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_BSSID | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + (7 << 13 /* RX FIFO threshold NONE */) | + (7 << 10 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC; + + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + reg = RTL818X_TX_CONF_CW_MIN | + (7 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_TX_ENABLE; + reg |= RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + mutex_unlock(&priv->conf_mutex); + + return 0; +} + +static void rtl8187_stop(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct rtl8187_rx_info *info; + struct sk_buff *skb; + u32 reg; + + mutex_lock(&priv->conf_mutex); + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->rf->stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + while ((skb = skb_dequeue(&priv->rx_queue))) { + info = (struct rtl8187_rx_info *)skb->cb; + usb_kill_urb(info->urb); + kfree_skb(skb); + } + mutex_unlock(&priv->conf_mutex); +} + +static int rtl8187_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + if (priv->mode != NL80211_IFTYPE_MONITOR) + return -EOPNOTSUPP; + + switch (conf->type) { + case NL80211_IFTYPE_STATION: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + mutex_lock(&priv->conf_mutex); + priv->vif = conf->vif; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->MAC[i], + ((u8 *)conf->mac_addr)[i]); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void rtl8187_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_MONITOR; + priv->vif = NULL; + mutex_unlock(&priv->conf_mutex); +} + +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; + u32 reg; + + mutex_lock(&priv->conf_mutex); + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + /* Enable TX loopback on MAC level to avoid TX during channel + * changes, as this has be seen to causes problems and the + * card will stop work until next reset + */ + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + reg | RTL818X_TX_CONF_LOOPBACK_MAC); + priv->rf->set_chan(dev, conf); + msleep(10); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); + rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); + rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100); + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static int rtl8187_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + u8 reg; + + mutex_lock(&priv->conf_mutex); + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) { + reg = RTL818X_MSR_INFRA; + if (priv->is_rtl8187b) + reg |= RTL818X_MSR_ENEDCA; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } else { + reg = RTL818X_MSR_NO_LINK; + rtl818x_iowrite8(priv, &priv->map->MSR, reg); + } + + mutex_unlock(&priv->conf_mutex); + return 0; +} + +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, + bool use_short_preamble) +{ + if (priv->is_rtl8187b) { + u8 difs, eifs, slot_time; + u16 ack_timeout; + + if (use_short_slot) { + slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0xa); + rtl818x_iowrite8(priv, &priv->map->SLOT, slot_time); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* + * BRSR+1 on 8187B is in fact EIFS register + * Value in units of 4 us + */ + rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); + + /* + * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout + * register. In units of 4 us like eifs register + * ack_timeout = ack duration + plcp + difs + preamble + */ + ack_timeout = 112 + 48 + difs; + if (use_short_preamble) + ack_timeout += 72; + else + ack_timeout += 144; + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, + DIV_ROUND_UP(ack_timeout, 4)); + } else { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + if (use_short_slot) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } + } +} + +static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) + rtl8187_conf_erp(priv, info->use_short_slot, + info->use_short_preamble); +} + +static void rtl8187_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mclist) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + if (*total_flags & FIF_ALLMULTI || mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + else + priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; + + *total_flags = 0; + + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + + rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); +} + +static const struct ieee80211_ops rtl8187_ops = { + .tx = rtl8187_tx, + .start = rtl8187_start, + .stop = rtl8187_stop, + .add_interface = rtl8187_add_interface, + .remove_interface = rtl8187_remove_interface, + .config = rtl8187_config, + .config_interface = rtl8187_config_interface, + .bss_info_changed = rtl8187_bss_info_changed, + .configure_filter = rtl8187_configure_filter, +}; + +static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8187_priv *priv = dev->priv; + u8 reg = RTL818X_EEPROM_CMD_PROGRAM; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + udelay(10); +} + +static int __devinit rtl8187_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct ieee80211_hw *dev; + struct rtl8187_priv *priv; + struct eeprom_93cx6 eeprom; + struct ieee80211_channel *channel; + const char *chip_name; + u16 txpwr, reg; + int err, i; + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); + if (!dev) { + printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n"); + return -ENOMEM; + } + + priv = dev->priv; + priv->is_rtl8187b = (id->driver_info == DEVICE_RTL8187B); + + SET_IEEE80211_DEV(dev, &intf->dev); + usb_set_intfdata(intf, dev); + priv->udev = udev; + + usb_get_dev(udev); + + skb_queue_head_init(&priv->rx_queue); + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + priv->map = (struct rtl818x_csr *)0xFF00; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + + priv->mode = NL80211_IFTYPE_MONITOR; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS; + + eeprom.data = dev; + eeprom.register_read = rtl8187_eeprom_register_read; + eeprom.register_write = rtl8187_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + udelay(10); + + eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR, + (__le16 __force *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly " + "generated MAC address\n"); + random_ether_addr(dev->wiphy->perm_addr); + } + + channel = priv->channels; + for (i = 0; i < 3; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, + &priv->txpwr_base); + + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); + /* 0 means asic B-cut, we should use SW 3 wire + * bit-by-bit banging for radio. 1 means we can use + * USB specific request to write radio registers */ + priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + if (!priv->is_rtl8187b) { + u32 reg32; + reg32 = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg32 &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg32) { + case RTL818X_TX_CONF_R8187vD_B: + /* Some RTL8187B devices have a USB ID of 0x8187 + * detect them here */ + chip_name = "RTL8187BvB(early)"; + priv->is_rtl8187b = 1; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_TX_CONF_R8187vD: + chip_name = "RTL8187vD"; + break; + default: + chip_name = "RTL8187vB (default)"; + } + } else { + /* + * Force USB request to write radio registers for 8187B, Realtek + * only uses it in their sources + */ + /*if (priv->asic_rev == 0) { + printk(KERN_WARNING "rtl8187: Forcing use of USB " + "requests to write to radio registers\n"); + priv->asic_rev = 1; + }*/ + switch (rtl818x_ioread8(priv, (u8 *)0xFFE1)) { + case RTL818X_R8187B_B: + chip_name = "RTL8187BvB"; + priv->hw_rev = RTL8187BvB; + break; + case RTL818X_R8187B_D: + chip_name = "RTL8187BvD"; + priv->hw_rev = RTL8187BvD; + break; + case RTL818X_R8187B_E: + chip_name = "RTL8187BvE"; + priv->hw_rev = RTL8187BvE; + break; + default: + chip_name = "RTL8187BvB (default)"; + priv->hw_rev = RTL8187BvB; + } + } + + if (!priv->is_rtl8187b) { + for (i = 0; i < 2; i++) { + eeprom_93cx6_read(&eeprom, + RTL8187_EEPROM_TXPWR_CHAN_6 + i, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + } else { + eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6, + &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x0A, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + + eeprom_93cx6_read(&eeprom, 0x1C, &txpwr); + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; + } + + if (priv->is_rtl8187b) { + printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " + "is EXPERIMENTAL, and could damage your\n" + " hardware, use at your own risk\n"); + dev->flags |= IEEE80211_HW_SIGNAL_DBM; + } else { + dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; + dev->max_signal = 65; + } + + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) + printk(KERN_INFO "rtl8187: inconsistency between id with OEM" + " info!\n"); + + priv->rf = rtl8187_detect_rf(dev); + dev->extra_tx_headroom = (!priv->is_rtl8187b) ? + sizeof(struct rtl8187_tx_hdr) : + sizeof(struct rtl8187b_tx_hdr); + if (!priv->is_rtl8187b) + dev->queues = 1; + else + dev->queues = 4; + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "rtl8187: Cannot register device\n"); + goto err_free_dev; + } + mutex_init(&priv->conf_mutex); + + printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, + chip_name, priv->asic_rev, priv->rf->name); + + return 0; + + err_free_dev: + ieee80211_free_hw(dev); + usb_set_intfdata(intf, NULL); + usb_put_dev(udev); + return err; +} + +static void __devexit rtl8187_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *dev = usb_get_intfdata(intf); + struct rtl8187_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + usb_put_dev(interface_to_usbdev(intf)); + ieee80211_free_hw(dev); +} + +static struct usb_driver rtl8187_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8187_table, + .probe = rtl8187_probe, + .disconnect = __devexit_p(rtl8187_disconnect), +}; + +static int __init rtl8187_init(void) +{ + return usb_register(&rtl8187_driver); +} + +static void __exit rtl8187_exit(void) +{ + usb_deregister(&rtl8187_driver); +} + +module_init(rtl8187_init); +module_exit(rtl8187_exit); diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c new file mode 100644 index 00000000000..69030be62b3 --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -0,0 +1,977 @@ +/* + * Radio tuning for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * Magic delays, register offsets, and phy value tables below are + * taken from the original r8187 driver sources. Thanks to Realtek + * for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "rtl8187.h" +#include "rtl8187_rtl8225.h" + +static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | (bangdata & (1 << i)) >> i; + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); +} + +static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~(0x3 << 2); + reg84 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(10); + + usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE, + addr, 0x8225, &data, sizeof(data), HZ / 2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); +} + +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8187_priv *priv = dev->priv; + + if (priv->asic_rev) + rtl8225_write_8051(dev, addr, cpu_to_le16(data)); + else + rtl8225_write_bitbang(dev, addr, data); +} + +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8187_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dBm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dBm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dBm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dBm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + cck_power = min(cck_power, (u8)11); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); // FIXME: optional? + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 6, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x00); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +static void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + 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); + rtl8225_write(dev, 0x2, 0x44D); msleep(200); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0c4d); + msleep(200); + rtl8225_write(dev, 0x02, 0x044d); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + } + + 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); + 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); + 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); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); + + /* set sensitivity */ + rtl8225_write(dev, 0x0c, 0x50); + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]); +} + +static const u8 rtl8225z2_agc[] = { + 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57, 0x55, 0x53, 0x51, 0x4f, + 0x4d, 0x4b, 0x49, 0x47, 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37, + 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27, 0x25, 0x23, 0x21, 0x1f, + 0x1d, 0x1b, 0x19, 0x17, 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07, + 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x27, 0x28, + 0x28, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31 +}; +static const u8 rtl8225z2_ofdm[] = { + 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26, + 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3, + 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f, + 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00, + 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e, + 0x6d, 0x3c, 0xfb, 0x07 +}; + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04, + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 +}; + +static const u8 rtl8225z2_tx_power_ofdm[] = { + 0x42, 0x00, 0x40, 0x00, 0x40 +}; + +static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + cck_power = min(cck_power, (u8)15); + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + ofdm_power = min(ofdm_power, (u8)15); + ofdm_power += priv->txpwr_base >> 4; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power]); + msleep(1); + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write_phy_ofdm(dev, 2, 0x42); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power]); + msleep(1); +} + +static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; + + if (cck_power > 15) + cck_power = (priv->hw_rev == RTL8187BvB) ? 15 : 22; + else + cck_power += (priv->hw_rev == RTL8187BvB) ? 0 : 7; + cck_power += priv->txpwr_base & 0xF; + cck_power = min(cck_power, (u8)35); + + if (ofdm_power > 15) + ofdm_power = (priv->hw_rev == RTL8187BvB) ? 17 : 25; + else + ofdm_power += (priv->hw_rev == RTL8187BvB) ? 2 : 10; + ofdm_power += (priv->txpwr_base >> 4) & 0xF; + ofdm_power = min(ofdm_power, (u8)35); + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else + tmp = rtl8225z2_tx_power_cck; + + if (priv->hw_rev == RTL8187BvB) { + if (cck_power <= 6) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else + tmp += 16; + } else { + if (cck_power <= 5) + ; /* do nothing */ + else if (cck_power <= 11) + tmp += 8; + else if (cck_power <= 17) + tmp += 16; + else + tmp += 24; + } + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); + msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225z2_tx_gain_cck_ofdm[ofdm_power] << 1); + if (priv->hw_rev == RTL8187BvB) { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x60); + rtl8225_write_phy_ofdm(dev, 0x89, 0x60); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } + } else { + if (ofdm_power <= 11) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x5c); + rtl8225_write_phy_ofdm(dev, 0x89, 0x5c); + } else if (ofdm_power <= 17) { + rtl8225_write_phy_ofdm(dev, 0x87, 0x54); + rtl8225_write_phy_ofdm(dev, 0x89, 0x54); + } else { + rtl8225_write_phy_ofdm(dev, 0x87, 0x50); + rtl8225_write_phy_ofdm(dev, 0x89, 0x50); + } + } + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static const u8 rtl8225z2_gain_bg[] = { + 0x23, 0x15, 0xa5, /* -82-1dBm */ + 0x23, 0x15, 0xb5, /* -82-2dBm */ + 0x23, 0x15, 0xc5, /* -82-3dBm */ + 0x33, 0x15, 0xc5, /* -78dBm */ + 0x43, 0x15, 0xc5, /* -74dBm */ + 0x53, 0x15, 0xc5, /* -70dBm */ + 0x63, 0x15, 0xc5 /* -66dBm */ +}; + +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + 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); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x2, 0xc4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + if (!(rtl8225_read(dev, 6) & (1 << 7))) + printk(KERN_WARNING "%s: RF Calibration Failed! %x\n", + wiphy_name(dev->wiphy), rtl8225_read(dev, 6)); + } + + msleep(200); + + rtl8225_write(dev, 0x0, 0x2BF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + } + + 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); + 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); + 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); + 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); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); +} + +static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + int i; + + 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); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); + + rtl8225_write(dev, 0x2, 0xC4D); + + 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); + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); + + rtl8225_write_phy_ofdm(dev, 0x80, 0x12); + for (i = 0; i < ARRAY_SIZE(rtl8225z2_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xF, rtl8225z2_agc[i]); + rtl8225_write_phy_ofdm(dev, 0xE, 0x80 + i); + rtl8225_write_phy_ofdm(dev, 0xE, 0); + } + rtl8225_write_phy_ofdm(dev, 0x80, 0x10); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) + rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); + + rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); + rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); + 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); + 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) +{ + u8 reg; + struct rtl8187_priv *priv = dev->priv; + + rtl8225_write(dev, 0x4, 0x1f); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + if (!priv->is_rtl8187b) { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187_RTL8225_ANAPARAM_OFF); + } else { + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, + RTL8187B_RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, + RTL8187B_RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, + RTL8187B_RTL8225_ANAPARAM3_OFF); + } + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8187_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); + + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, chan); + else if (priv->rf->init == rtl8225z2_rf_init) + rtl8225z2_rf_set_tx_power(dev, chan); + else + rtl8225z2_b_rf_set_tx_power(dev, chan); + + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); + msleep(10); +} + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_b_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_b_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) +{ + u16 reg8, reg9; + struct rtl8187_priv *priv = dev->priv; + + if (!priv->is_rtl8187b) { + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; + } else + return &rtl8225z2_b_ops; +} diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h new file mode 100644 index 00000000000..20c5b6ead0f --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h @@ -0,0 +1,44 @@ +/* + * Radio tuning definitions for RTL8225 on RTL8187 + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * 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. + */ + +#ifndef RTL8187_RTL8225_H +#define RTL8187_RTL8225_H + +#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59 +#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312 +#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11 + +#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658 +#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52 +#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00 +#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658 +#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50 +#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00 + +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u32 data) +{ + rtl8187_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8187_RTL8225_H */ diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h new file mode 100644 index 00000000000..3538b15211b --- /dev/null +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -0,0 +1,231 @@ +/* + * Definitions for RTL818x hardware + * + * Copyright 2007 Michael Wu + * Copyright 2007 Andrea Merello + * + * Based on the r8187 driver, which is: + * Copyright 2005 Andrea Merello , et al. + * + * 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. + */ + +#ifndef RTL818X_H +#define RTL818X_H + +struct rtl818x_csr { + u8 MAC[6]; + u8 reserved_0[2]; + __le32 MAR[2]; + u8 RX_FIFO_COUNT; + u8 reserved_1; + u8 TX_FIFO_COUNT; + u8 BQREQ; + u8 reserved_2[4]; + __le32 TSFT[2]; + __le32 TLPDA; + __le32 TNPDA; + __le32 THPDA; + __le16 BRSR; + u8 BSSID[6]; + u8 RESP_RATE; + u8 EIFS; + u8 reserved_3[1]; + u8 CMD; +#define RTL818X_CMD_TX_ENABLE (1 << 2) +#define RTL818X_CMD_RX_ENABLE (1 << 3) +#define RTL818X_CMD_RESET (1 << 4) + u8 reserved_4[4]; + __le16 INT_MASK; + __le16 INT_STATUS; +#define RTL818X_INT_RX_OK (1 << 0) +#define RTL818X_INT_RX_ERR (1 << 1) +#define RTL818X_INT_TXL_OK (1 << 2) +#define RTL818X_INT_TXL_ERR (1 << 3) +#define RTL818X_INT_RX_DU (1 << 4) +#define RTL818X_INT_RX_FO (1 << 5) +#define RTL818X_INT_TXN_OK (1 << 6) +#define RTL818X_INT_TXN_ERR (1 << 7) +#define RTL818X_INT_TXH_OK (1 << 8) +#define RTL818X_INT_TXH_ERR (1 << 9) +#define RTL818X_INT_TXB_OK (1 << 10) +#define RTL818X_INT_TXB_ERR (1 << 11) +#define RTL818X_INT_ATIM (1 << 12) +#define RTL818X_INT_BEACON (1 << 13) +#define RTL818X_INT_TIME_OUT (1 << 14) +#define RTL818X_INT_TX_FO (1 << 15) + __le32 TX_CONF; +#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) +#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17) +#define RTL818X_TX_CONF_NO_ICV (1 << 19) +#define RTL818X_TX_CONF_DISCW (1 << 20) +#define RTL818X_TX_CONF_SAT_HWPLCP (1 << 24) +#define RTL818X_TX_CONF_R8180_ABCD (2 << 25) +#define RTL818X_TX_CONF_R8180_F (3 << 25) +#define RTL818X_TX_CONF_R8185_ABC (4 << 25) +#define RTL818X_TX_CONF_R8185_D (5 << 25) +#define RTL818X_TX_CONF_R8187vD (5 << 25) +#define RTL818X_TX_CONF_R8187vD_B (6 << 25) +#define RTL818X_TX_CONF_HWVER_MASK (7 << 25) +#define RTL818X_TX_CONF_DISREQQSIZE (1 << 28) +#define RTL818X_TX_CONF_PROBE_DTS (1 << 29) +#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) +#define RTL818X_TX_CONF_CW_MIN (1 << 31) + __le32 RX_CONF; +#define RTL818X_RX_CONF_MONITOR (1 << 0) +#define RTL818X_RX_CONF_NICMAC (1 << 1) +#define RTL818X_RX_CONF_MULTICAST (1 << 2) +#define RTL818X_RX_CONF_BROADCAST (1 << 3) +#define RTL818X_RX_CONF_FCS (1 << 5) +#define RTL818X_RX_CONF_DATA (1 << 18) +#define RTL818X_RX_CONF_CTRL (1 << 19) +#define RTL818X_RX_CONF_MGMT (1 << 20) +#define RTL818X_RX_CONF_ADDR3 (1 << 21) +#define RTL818X_RX_CONF_PM (1 << 22) +#define RTL818X_RX_CONF_BSSID (1 << 23) +#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) +#define RTL818X_RX_CONF_CSDM1 (1 << 29) +#define RTL818X_RX_CONF_CSDM2 (1 << 30) +#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) + __le32 INT_TIMEOUT; + __le32 TBDA; + u8 EEPROM_CMD; +#define RTL818X_EEPROM_CMD_READ (1 << 0) +#define RTL818X_EEPROM_CMD_WRITE (1 << 1) +#define RTL818X_EEPROM_CMD_CK (1 << 2) +#define RTL818X_EEPROM_CMD_CS (1 << 3) +#define RTL818X_EEPROM_CMD_NORMAL (0 << 6) +#define RTL818X_EEPROM_CMD_LOAD (1 << 6) +#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6) +#define RTL818X_EEPROM_CMD_CONFIG (3 << 6) + u8 CONFIG0; + u8 CONFIG1; + u8 CONFIG2; +#define RTL818X_CONFIG2_ANTENNA_DIV (1 << 6) + __le32 ANAPARAM; + u8 MSR; +#define RTL818X_MSR_NO_LINK (0 << 2) +#define RTL818X_MSR_ADHOC (1 << 2) +#define RTL818X_MSR_INFRA (2 << 2) +#define RTL818X_MSR_MASTER (3 << 2) +#define RTL818X_MSR_ENEDCA (4 << 2) + u8 CONFIG3; +#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6) +#define RTL818X_CONFIG3_GNT_SELECT (1 << 7) + u8 CONFIG4; +#define RTL818X_CONFIG4_POWEROFF (1 << 6) +#define RTL818X_CONFIG4_VCOOFF (1 << 7) + u8 TESTR; + u8 reserved_9[2]; + u8 PGSELECT; + u8 SECURITY; + __le32 ANAPARAM2; + u8 reserved_10[12]; + __le16 BEACON_INTERVAL; + __le16 ATIM_WND; + __le16 BEACON_INTERVAL_TIME; + __le16 ATIMTR_INTERVAL; + u8 PHY_DELAY; + u8 CARRIER_SENSE_COUNTER; + u8 reserved_11[2]; + u8 PHY[4]; + __le16 RFPinsOutput; + __le16 RFPinsEnable; + __le16 RFPinsSelect; + __le16 RFPinsInput; + __le32 RF_PARA; + __le32 RF_TIMING; + u8 GP_ENABLE; + u8 GPIO; + u8 reserved_12[2]; + __le32 HSSI_PARA; + u8 reserved_13[4]; + u8 TX_AGC_CTL; +#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0) +#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1) +#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2) + u8 TX_GAIN_CCK; + u8 TX_GAIN_OFDM; + u8 TX_ANTENNA; + u8 reserved_14[16]; + u8 WPA_CONF; + u8 reserved_15[3]; + u8 SIFS; + u8 DIFS; + u8 SLOT; + u8 reserved_16[5]; + u8 CW_CONF; +#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0) +#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1) + u8 CW_VAL; + u8 RATE_FALLBACK; +#define RTL818X_RATE_FALLBACK_ENABLE (1 << 7) + u8 ACM_CONTROL; + u8 reserved_17[24]; + u8 CONFIG5; + u8 TX_DMA_POLLING; + u8 reserved_18[2]; + __le16 CWR; + u8 RETRY_CTR; + u8 reserved_19[3]; + __le16 INT_MIG; +/* RTL818X_R8187B_*: magic numbers from ioregisters */ +#define RTL818X_R8187B_B 0 +#define RTL818X_R8187B_D 1 +#define RTL818X_R8187B_E 2 + __le32 RDSAR; + __le16 TID_AC_MAP; + u8 reserved_20[4]; + u8 ANAPARAM3; + u8 reserved_21[5]; + __le16 FEMR; + u8 reserved_22[4]; + __le16 TALLY_CNT; + u8 TALLY_SEL; +} __attribute__((packed)); + +struct rtl818x_rf_ops { + char *name; + void (*init)(struct ieee80211_hw *); + void (*stop)(struct ieee80211_hw *); + void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); +}; + +/* Tx/Rx flags are common between RTL818X chips */ + +enum rtl818x_tx_desc_flags { + RTL818X_TX_DESC_FLAG_NO_ENC = (1 << 15), + RTL818X_TX_DESC_FLAG_TX_OK = (1 << 15), + RTL818X_TX_DESC_FLAG_SPLCP = (1 << 16), + RTL818X_TX_DESC_FLAG_RX_UNDER = (1 << 16), + RTL818X_TX_DESC_FLAG_MOREFRAG = (1 << 17), + RTL818X_TX_DESC_FLAG_CTS = (1 << 18), + RTL818X_TX_DESC_FLAG_RTS = (1 << 23), + RTL818X_TX_DESC_FLAG_LS = (1 << 28), + RTL818X_TX_DESC_FLAG_FS = (1 << 29), + RTL818X_TX_DESC_FLAG_DMA = (1 << 30), + RTL818X_TX_DESC_FLAG_OWN = (1 << 31) +}; + +enum rtl818x_rx_desc_flags { + RTL818X_RX_DESC_FLAG_ICV_ERR = (1 << 12), + RTL818X_RX_DESC_FLAG_CRC32_ERR = (1 << 13), + RTL818X_RX_DESC_FLAG_PM = (1 << 14), + RTL818X_RX_DESC_FLAG_RX_ERR = (1 << 15), + RTL818X_RX_DESC_FLAG_BCAST = (1 << 16), + RTL818X_RX_DESC_FLAG_PAM = (1 << 17), + RTL818X_RX_DESC_FLAG_MCAST = (1 << 18), + RTL818X_RX_DESC_FLAG_QOS = (1 << 19), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_TRSW = (1 << 24), /* RTL8187(B) only */ + RTL818X_RX_DESC_FLAG_SPLCP = (1 << 25), + RTL818X_RX_DESC_FLAG_FOF = (1 << 26), + RTL818X_RX_DESC_FLAG_DMA_FAIL = (1 << 27), + RTL818X_RX_DESC_FLAG_LS = (1 << 28), + RTL818X_RX_DESC_FLAG_FS = (1 << 29), + RTL818X_RX_DESC_FLAG_EOR = (1 << 30), + RTL818X_RX_DESC_FLAG_OWN = (1 << 31) +}; + +#endif /* RTL818X_H */ -- cgit v1.2.3