Commit f6532111 authored by Michael Wu's avatar Michael Wu Committed by David S. Miller

Add rtl8180 wireless driver

This patch adds a mac80211 based wireless driver for the rtl8180 and
rtl8185 PCI wireless cards.  Also included are some rtl8187 changes
required due to the relationship between that driver and this one.

Michael Wu is primarily responsible for the initial driver and rtl8185
support.  Andreas Merello provided the additional rtl8180 support.

Thanks to Jukka Ruohonen for the donating a rtl8185 card! It was very
helpful for the rtl8225z2 code.

The Signed-off-by information below is collected from the individual
patches submitted to wireless-2.6 before merging this driver upstream.
Signed-off-by: default avatarAndrea Merello <andreamrl@tiscali.it>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarPavel Roskin <proski@gnu.org>
Signed-off-by: default avatarMichael Wu <flamingice@sourmilk.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent fa1c114f
......@@ -545,6 +545,62 @@ config USB_ZD1201
To compile this driver as a module, choose M here: the
module will be called zd1201.
config RTL8180
tristate "Realtek 8180/8185 PCI support"
depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
select EEPROM_93CX6
---help---
This is a driver for RTL8180 and RTL8185 based cards.
These are PCI based chips found in cards such as:
(RTL8185 802.11g)
A-Link WL54PC
(RTL8180 802.11b)
Belkin F5D6020 v3
Belkin F5D6020 v3
Dlink DWL-610
Dlink DWL-510
Netgear MA521
Level-One WPC-0101
Acer Aspire 1357 LMi
VCTnet PC-11B1
Ovislink AirLive WL-1120PCM
Mentor WL-PCI
Linksys WPC11 v4
TrendNET TEW-288PI
D-Link DWL-520 Rev D
Repotec RP-WP7126
TP-Link TL-WN250/251
Zonet ZEW1000
Longshine LCS-8031-R
HomeLine HLW-PCC200
GigaFast WF721-AEX
Planet WL-3553
Encore ENLWI-PCI1-NT
TrendNET TEW-266PC
Gigabyte GN-WLMR101
Siemens-fujitsu Amilo D1840W
Edimax EW-7126
PheeNet WL-11PCIR
Tonze PC-2100T
Planet WL-8303
Dlink DWL-650 v M1
Edimax EW-7106
Q-Tec 770WC
Topcom Skyr@cer 4011b
Roper FreeLan 802.11b (edition 2004)
Wistron Neweb Corp CB-200B
Pentagram HorNET
QTec 775WC
TwinMOS Booming B Series
Micronet SP906BB
Sweex LC700010
Surecom EP-9428
Safecom SWLCR-1100
Thanks to Realtek for their support!
config RTL8187
tristate "Realtek 8187 USB support"
depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
......
......@@ -47,7 +47,10 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
obj-$(CONFIG_LIBERTAS) += libertas/
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
......
#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)
enum rtl8180_tx_desc_flags {
RTL8180_TX_DESC_FLAG_NO_ENC = (1 << 15),
RTL8180_TX_DESC_FLAG_TX_OK = (1 << 15),
RTL8180_TX_DESC_FLAG_SPLCP = (1 << 16),
RTL8180_TX_DESC_FLAG_RX_UNDER = (1 << 16),
RTL8180_TX_DESC_FLAG_MOREFRAG = (1 << 17),
RTL8180_TX_DESC_FLAG_CTS = (1 << 18),
RTL8180_TX_DESC_FLAG_RTS = (1 << 23),
RTL8180_TX_DESC_FLAG_LS = (1 << 28),
RTL8180_TX_DESC_FLAG_FS = (1 << 29),
RTL8180_TX_DESC_FLAG_DMA = (1 << 30),
RTL8180_TX_DESC_FLAG_OWN = (1 << 31)
};
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));
enum rtl8180_rx_desc_flags {
RTL8180_RX_DESC_FLAG_ICV_ERR = (1 << 12),
RTL8180_RX_DESC_FLAG_CRC32_ERR = (1 << 13),
RTL8180_RX_DESC_FLAG_PM = (1 << 14),
RTL8180_RX_DESC_FLAG_RX_ERR = (1 << 15),
RTL8180_RX_DESC_FLAG_BCAST = (1 << 16),
RTL8180_RX_DESC_FLAG_PAM = (1 << 17),
RTL8180_RX_DESC_FLAG_MCAST = (1 << 18),
RTL8180_RX_DESC_FLAG_SPLCP = (1 << 25),
RTL8180_RX_DESC_FLAG_FOF = (1 << 26),
RTL8180_RX_DESC_FLAG_DMA_FAIL = (1 << 27),
RTL8180_RX_DESC_FLAG_LS = (1 << 28),
RTL8180_RX_DESC_FLAG_FS = (1 << 29),
RTL8180_RX_DESC_FLAG_EOR = (1 << 30),
RTL8180_RX_DESC_FLAG_OWN = (1 << 31)
};
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;
int mode;
int if_id;
/* 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_hw_mode modes[2];
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 */
This diff is collapsed.
/*
* Radio tuning for GCT GRF5101 on RTL8180
*
* Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
*
* 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 <linux/init.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <net/mac80211.h>
#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;
u32 txpw = priv->channels[conf->channel - 1].val & 0xFF;
u32 chan = conf->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, chan);
}
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
};
#ifndef RTL8180_GRF5101_H
#define RTL8180_GRF5101_H
/*
* Radio tuning for GCT GRF5101 on RTL8180
*
* Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
*
* 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 */
/*
* Radio tuning for Maxim max2820 on RTL8180
*
* Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
*
* 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 <linux/init.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <net/mac80211.h>
#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;
unsigned int chan_idx = conf ? conf->channel - 1 : 0;
u32 txpw = priv->channels[chan_idx].val & 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, chan);
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
};
#ifndef RTL8180_MAX2820_H
#define RTL8180_MAX2820_H
/*
* Radio tuning for Maxim max2820 on RTL8180
*
* Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
*
* 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 */
This diff is collapsed.
#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)
{