/*
* Linux device driver for RTL8180 / RTL8185
*
*
*
* 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/slab.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/eeprom_93cx6.h>
#include <net/mac80211.h>
#include "rtl8180.h"
#include "rtl8225.h"
#include "sa2400.h"
#include "max2820.h"
#include "grf5101.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
MODULE_LICENSE("GPL");
static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = {
/* 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;
u8 signal, agc, sq;
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;
rx_status.rate_idx = (flags >> 20) & 0xF;
agc = (flags2 >> 17) & 0x7F;
if (priv->r8185) {
if (rx_status.rate_idx > 3)
signal = 90 - clamp_t(u8, agc, 25, 90);
else
signal = 95 - clamp_t(u8, agc, 30, 95);
} else {
sq = flags2 & 0xff;
signal = priv->rf->calc_rssi(agc, sq);
}
rx_status.signal = signal;
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_MACTIME_MPDU;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(dev, skb);
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;
info->status.rates[1].idx = -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 void rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
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);
remain