blob: 49ab9fa9ffa784833e08b170d009046c7dd7370a [file] [log] [blame]
/*
This is part of rtl818x pci OpenSource driver - v 0.1
Copyright (C) Andrea Merello 2004-2005 <andreamrl@tiscali.it>
Released under the terms of GPL (General Public License)
Parts of this driver are based on the GPL part of the official
Realtek driver.
Parts of this driver are based on the rtl8180 driver skeleton
from Patric Schenke & Andres Salomon.
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
Parts of BB/RF code are derived from David Young rtl8180 netbsd driver.
RSSI calc function from 'The Deuce'
Some ideas borrowed from the 8139too.c driver included in linux kernel.
We (I?) want to thanks the Authors of those projecs and also the
Ndiswrapper's project Authors.
A big big thanks goes also to Realtek corp. for their help in my attempt to
add RTL8185 and RTL8225 support, and to David Young also.
Power management interface routines.
Written by Mariusz Matuszek.
*/
#undef RX_DONT_PASS_UL
#undef DUMMY_RX
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/eeprom_93cx6.h>
#include "r8180_hw.h"
#include "r8180.h"
#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
#include "r8180_93cx6.h" /* Card EEPROM */
#include "r8180_wx.h"
#include "r8180_dm.h"
#include "ieee80211/dot11d.h"
static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = {
{
.vendor = PCI_VENDOR_ID_REALTEK,
.device = 0x8199,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = 0,
},
{
.vendor = 0,
.device = 0,
.subvendor = 0,
.subdevice = 0,
.driver_data = 0,
}
};
static char *ifname = "wlan%d";
static int hwseqnum = 0;
static int hwwep = 0;
static int channels = 0x3fff;
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards");
module_param(ifname, charp, S_IRUGO|S_IWUSR);
module_param(hwseqnum, int, S_IRUGO|S_IWUSR);
module_param(hwwep, int, S_IRUGO|S_IWUSR);
module_param(channels, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(devname, " Net interface name, wlan%d=default");
MODULE_PARM_DESC(hwseqnum, " Try to use hardware 802.11 header sequence numbers. Zero=default");
MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support. Still broken and not available on all cards");
MODULE_PARM_DESC(channels, " Channel bitmask for specific locales. NYI");
static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void __devexit rtl8180_pci_remove(struct pci_dev *pdev);
static void rtl8180_shutdown(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (dev->netdev_ops->ndo_stop)
dev->netdev_ops->ndo_stop(dev);
pci_disable_device(pdev);
}
static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (!netif_running(dev))
goto out_pci_suspend;
if (dev->netdev_ops->ndo_stop)
dev->netdev_ops->ndo_stop(dev);
netif_device_detach(dev);
out_pci_suspend:
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
}
static int rtl8180_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
int err;
u32 val;
pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
dev->name);
return err;
}
pci_restore_state(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
* from interfering with C3 CPU state. pci_restore_state won't help
* here since it only restores the first 64 bytes pci config header.
*/
pci_read_config_dword(pdev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
if (!netif_running(dev))
goto out;
if (dev->netdev_ops->ndo_open)
dev->netdev_ops->ndo_open(dev);
netif_device_attach(dev);
out:
return 0;
}
static struct pci_driver rtl8180_pci_driver = {
.name = RTL8180_MODULE_NAME,
.id_table = rtl8180_pci_id_tbl,
.probe = rtl8180_pci_probe,
.remove = __devexit_p(rtl8180_pci_remove),
.suspend = rtl8180_suspend,
.resume = rtl8180_resume,
.shutdown = rtl8180_shutdown,
};
u8 read_nic_byte(struct net_device *dev, int x)
{
return 0xff&readb((u8 *)dev->mem_start + x);
}
u32 read_nic_dword(struct net_device *dev, int x)
{
return readl((u8 *)dev->mem_start + x);
}
u16 read_nic_word(struct net_device *dev, int x)
{
return readw((u8 *)dev->mem_start + x);
}
void write_nic_byte(struct net_device *dev, int x, u8 y)
{
writeb(y, (u8 *)dev->mem_start + x);
udelay(20);
}
void write_nic_dword(struct net_device *dev, int x, u32 y)
{
writel(y, (u8 *)dev->mem_start + x);
udelay(20);
}
void write_nic_word(struct net_device *dev, int x, u16 y)
{
writew(y, (u8 *)dev->mem_start + x);
udelay(20);
}
inline void force_pci_posting(struct net_device *dev)
{
read_nic_byte(dev, EPROM_CMD);
mb();
}
irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs);
void set_nic_rxring(struct net_device *dev);
void set_nic_txring(struct net_device *dev);
static struct net_device_stats *rtl8180_stats(struct net_device *dev);
void rtl8180_commit(struct net_device *dev);
void rtl8180_start_tx_beacon(struct net_device *dev);
static struct proc_dir_entry *rtl8180_proc = NULL;
static int proc_get_registers(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
int len = 0;
int i, n;
int max = 0xff;
/* This dump the current register page */
for (n = 0; n <= max;) {
len += snprintf(page + len, count - len, "\nD: %2x > ", n);
for (i = 0; i < 16 && n <= max; i++, n++)
len += snprintf(page + len, count - len, "%2x ",
read_nic_byte(dev, n));
}
len += snprintf(page + len, count - len, "\n");
*eof = 1;
return len;
}
int get_curr_tx_free_desc(struct net_device *dev, int priority);
static int proc_get_stats_hw(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
int len = 0;
*eof = 1;
return len;
}
static int proc_get_stats_rx(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int len = 0;
len += snprintf(page + len, count - len,
"RX OK: %lu\n"
"RX Retry: %lu\n"
"RX CRC Error(0-500): %lu\n"
"RX CRC Error(500-1000): %lu\n"
"RX CRC Error(>1000): %lu\n"
"RX ICV Error: %lu\n",
priv->stats.rxint,
priv->stats.rxerr,
priv->stats.rxcrcerrmin,
priv->stats.rxcrcerrmid,
priv->stats.rxcrcerrmax,
priv->stats.rxicverr
);
*eof = 1;
return len;
}
static int proc_get_stats_tx(char *page, char **start,
off_t offset, int count,
int *eof, void *data)
{
struct net_device *dev = data;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int len = 0;
unsigned long totalOK;
totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
len += snprintf(page + len, count - len,
"TX OK: %lu\n"
"TX Error: %lu\n"
"TX Retry: %lu\n"
"TX beacon OK: %lu\n"
"TX beacon error: %lu\n",
totalOK,
priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr,
priv->stats.txretry,
priv->stats.txbeacon,
priv->stats.txbeaconerr
);
*eof = 1;
return len;
}
void rtl8180_proc_module_init(void)
{
DMESG("Initializing proc filesystem");
rtl8180_proc = create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, init_net.proc_net);
}
void rtl8180_proc_module_remove(void)
{
remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net);
}
void rtl8180_proc_remove_one(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
if (priv->dir_dev) {
remove_proc_entry("stats-hw", priv->dir_dev);
remove_proc_entry("stats-tx", priv->dir_dev);
remove_proc_entry("stats-rx", priv->dir_dev);
remove_proc_entry("registers", priv->dir_dev);
remove_proc_entry(dev->name, rtl8180_proc);
priv->dir_dev = NULL;
}
}
void rtl8180_proc_init_one(struct net_device *dev)
{
struct proc_dir_entry *e;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
priv->dir_dev = rtl8180_proc;
if (!priv->dir_dev) {
DMESGE("Unable to initialize /proc/net/r8180/%s\n",
dev->name);
return;
}
e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO,
priv->dir_dev, proc_get_stats_hw, dev);
if (!e) {
DMESGE("Unable to initialize "
"/proc/net/r8180/%s/stats-hw\n",
dev->name);
}
e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO,
priv->dir_dev, proc_get_stats_rx, dev);
if (!e) {
DMESGE("Unable to initialize "
"/proc/net/r8180/%s/stats-rx\n",
dev->name);
}
e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO,
priv->dir_dev, proc_get_stats_tx, dev);
if (!e) {
DMESGE("Unable to initialize "
"/proc/net/r8180/%s/stats-tx\n",
dev->name);
}
e = create_proc_read_entry("registers", S_IFREG | S_IRUGO,
priv->dir_dev, proc_get_registers, dev);
if (!e) {
DMESGE("Unable to initialize "
"/proc/net/r8180/%s/registers\n",
dev->name);
}
}
/*
FIXME: check if we can use some standard already-existent
data type+functions in kernel
*/
short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma,
struct buffer **bufferhead)
{
struct buffer *tmp;
if (!*buffer) {
*buffer = kmalloc(sizeof(struct buffer), GFP_KERNEL);
if (*buffer == NULL) {
DMESGE("Failed to kmalloc head of TX/RX struct");
return -1;
}
(*buffer)->next = *buffer;
(*buffer)->buf = buf;
(*buffer)->dma = dma;
if (bufferhead != NULL)
(*bufferhead) = (*buffer);
return 0;
}
tmp = *buffer;
while (tmp->next != (*buffer))
tmp = tmp->next;
tmp->next = kmalloc(sizeof(struct buffer), GFP_KERNEL);
if (tmp->next == NULL) {
DMESGE("Failed to kmalloc TX/RX struct");
return -1;
}
tmp->next->buf = buf;
tmp->next->dma = dma;
tmp->next->next = *buffer;
return 0;
}
void buffer_free(struct net_device *dev, struct buffer **buffer, int len, short consistent)
{
struct buffer *tmp, *next;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
if (!*buffer)
return;
tmp = *buffer;
do {
next = tmp->next;
if (consistent) {
pci_free_consistent(pdev, len,
tmp->buf, tmp->dma);
} else {
pci_unmap_single(pdev, tmp->dma,
len, PCI_DMA_FROMDEVICE);
kfree(tmp->buf);
}
kfree(tmp);
tmp = next;
}
while (next != *buffer);
*buffer = NULL;
}
void print_buffer(u32 *buffer, int len)
{
int i;
u8 *buf = (u8 *)buffer;
printk("ASCII BUFFER DUMP (len: %x):\n", len);
for (i = 0; i < len; i++)
printk("%c", buf[i]);
printk("\nBINARY BUFFER DUMP (len: %x):\n", len);
for (i = 0; i < len; i++)
printk("%02x", buf[i]);
printk("\n");
}
int get_curr_tx_free_desc(struct net_device *dev, int priority)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *tail;
u32 *head;
int ret;
switch (priority) {
case MANAGE_PRIORITY:
head = priv->txmapringhead;
tail = priv->txmapringtail;
break;
case BK_PRIORITY:
head = priv->txbkpringhead;
tail = priv->txbkpringtail;
break;
case BE_PRIORITY:
head = priv->txbepringhead;
tail = priv->txbepringtail;
break;
case VI_PRIORITY:
head = priv->txvipringhead;
tail = priv->txvipringtail;
break;
case VO_PRIORITY:
head = priv->txvopringhead;
tail = priv->txvopringtail;
break;
case HI_PRIORITY:
head = priv->txhpringhead;
tail = priv->txhpringtail;
break;
default:
return -1;
}
if (head <= tail)
ret = priv->txringcount - (tail - head)/8;
else
ret = (head - tail)/8;
if (ret > priv->txringcount)
DMESG("BUG");
return ret;
}
short check_nic_enought_desc(struct net_device *dev, int priority)
{
struct r8180_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = netdev_priv(dev);
int requiredbyte, required;
requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
if (ieee->current_network.QoS_Enable)
requiredbyte += 2;
required = requiredbyte / (priv->txbuffsize-4);
if (requiredbyte % priv->txbuffsize)
required++;
/* for now we keep two free descriptor as a safety boundary
* between the tail and the head
*/
return (required+2 < get_curr_tx_free_desc(dev, priority));
}
void fix_tx_fifo(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 *tmp;
int i;
for (tmp = priv->txmapring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbkpring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbepring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txvipring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txvopring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txhpring, i = 0;
i < priv->txringcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
for (tmp = priv->txbeaconring, i = 0;
i < priv->txbeaconcount;
tmp += 8, i++) {
*tmp = *tmp & ~(1<<31);
}
priv->txmapringtail = priv->txmapring;
priv->txmapringhead = priv->txmapring;
priv->txmapbufstail = priv->txmapbufs;
priv->txbkpringtail = priv->txbkpring;
priv->txbkpringhead = priv->txbkpring;
priv->txbkpbufstail = priv->txbkpbufs;
priv->txbepringtail = priv->txbepring;
priv->txbepringhead = priv->txbepring;
priv->txbepbufstail = priv->txbepbufs;
priv->txvipringtail = priv->txvipring;
priv->txvipringhead = priv->txvipring;
priv->txvipbufstail = priv->txvipbufs;
priv->txvopringtail = priv->txvopring;
priv->txvopringhead = priv->txvopring;
priv->txvopbufstail = priv->txvopbufs;
priv->txhpringtail = priv->txhpring;
priv->txhpringhead = priv->txhpring;
priv->txhpbufstail = priv->txhpbufs;
priv->txbeaconringtail = priv->txbeaconring;
priv->txbeaconbufstail = priv->txbeaconbufs;
set_nic_txring(dev);
ieee80211_reset_queue(priv->ieee80211);
priv->ack_tx_to_ieee = 0;
}
void fix_rx_fifo(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u32 *tmp;
struct buffer *rxbuf;
u8 rx_desc_size;
rx_desc_size = 8; /* 4*8 = 32 bytes */
for (tmp = priv->rxring, rxbuf = priv->rxbufferhead;
(tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size);
tmp += rx_desc_size, rxbuf = rxbuf->next) {
*(tmp+2) = rxbuf->dma;
*tmp = *tmp & ~0xfff;
*tmp = *tmp | priv->rxbuffersize;
*tmp |= (1<<31);
}
priv->rxringtail = priv->rxring;
priv->rxbuffer = priv->rxbufferhead;
priv->rx_skb_complete = 1;
set_nic_rxring(dev);
}
unsigned char QUALITY_MAP[] = {
0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61,
0x61, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5c,
0x5b, 0x5a, 0x59, 0x57, 0x56, 0x54, 0x52, 0x4f,
0x4c, 0x49, 0x45, 0x41, 0x3c, 0x37, 0x31, 0x29,
0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e,
0x1d, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x19,
0x18, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, 0x0f,
0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x01, 0x00
};
unsigned char STRENGTH_MAP[] = {
0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00
};
void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual)
{
u32 temp;
u32 temp2;
u32 q;
u32 orig_qual;
u8 _rssi;
q = *qual;
orig_qual = *qual;
_rssi = 0; /* avoid gcc complains.. */
if (q <= 0x4e) {
temp = QUALITY_MAP[q];
} else {
if (q & 0x80)
temp = 0x32;
else
temp = 1;
}
*qual = temp;
temp2 = *rssi;
if (_rssi < 0x64) {
if (_rssi == 0)
*rssi = 1;
} else {
*rssi = 0x64;
}
return;
}
void rtl8180_irq_enable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
priv->irq_enabled = 1;
write_nic_word(dev, INTA_MASK, priv->irq_mask);
}
void rtl8180_irq_disable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, IMR, 0);
force_pci_posting(dev);
priv->irq_enabled = 0;
}
void rtl8180_set_mode(struct net_device *dev, int mode)
{
u8 ecmd;
ecmd = read_nic_byte(dev, EPROM_CMD);
ecmd = ecmd & ~EPROM_CMD_OPERATING_MODE_MASK;
ecmd = ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT);
ecmd = ecmd & ~(1<<EPROM_CS_SHIFT);
ecmd = ecmd & ~(1<<EPROM_CK_SHIFT);
write_nic_byte(dev, EPROM_CMD, ecmd);
}
void rtl8180_adapter_start(struct net_device *dev);
void rtl8180_beacon_tx_enable(struct net_device *dev);
void rtl8180_update_msr(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u8 msr;
u32 rxconf;
msr = read_nic_byte(dev, MSR);
msr &= ~MSR_LINK_MASK;
rxconf = read_nic_dword(dev, RX_CONF);
if (priv->ieee80211->state == IEEE80211_LINKED) {
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT);
else if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT);
else if (priv->ieee80211->iw_mode == IW_MODE_INFRA)
msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT);
else
msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
rxconf |= (1<<RX_CHECK_BSSID_SHIFT);
} else {
msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
rxconf &= ~(1<<RX_CHECK_BSSID_SHIFT);
}
write_nic_byte(dev, MSR, msr);
write_nic_dword(dev, RX_CONF, rxconf);
}
void rtl8180_set_chan(struct net_device *dev, short ch)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
if ((ch > 14) || (ch < 1)) {
printk("In %s: Invalid chnanel %d\n", __func__, ch);
return;
}
priv->chan = ch;
priv->rf_set_chan(dev, priv->chan);
}
void rtl8180_rx_enable(struct net_device *dev)
{
u8 cmd;
u32 rxconf;
/* for now we accept data, management & ctl frame*/
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rxconf = read_nic_dword(dev, RX_CONF);
rxconf = rxconf & ~MAC_FILTER_MASK;
rxconf = rxconf | (1<<ACCEPT_MNG_FRAME_SHIFT);
rxconf = rxconf | (1<<ACCEPT_DATA_FRAME_SHIFT);
rxconf = rxconf | (1<<ACCEPT_BCAST_FRAME_SHIFT);
rxconf = rxconf | (1<<ACCEPT_MCAST_FRAME_SHIFT);
if (dev->flags & IFF_PROMISC)
DMESG("NIC in promisc mode");
if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \
dev->flags & IFF_PROMISC) {
rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT);
} else {
rxconf = rxconf | (1<<ACCEPT_NICMAC_FRAME_SHIFT);
}
if (priv->ieee80211->iw_mode == IW_MODE_MONITOR) {
rxconf = rxconf | (1<<ACCEPT_CTL_FRAME_SHIFT);
rxconf = rxconf | (1<<ACCEPT_ICVERR_FRAME_SHIFT);
rxconf = rxconf | (1<<ACCEPT_PWR_FRAME_SHIFT);
}
if (priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR)
rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT);
rxconf = rxconf & ~RX_FIFO_THRESHOLD_MASK;
rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE << RX_FIFO_THRESHOLD_SHIFT);
rxconf = rxconf | (1<<RX_AUTORESETPHY_SHIFT);
rxconf = rxconf & ~MAX_RX_DMA_MASK;
rxconf = rxconf | (MAX_RX_DMA_2048<<MAX_RX_DMA_SHIFT);
rxconf = rxconf | RCR_ONLYERLPKT;
rxconf = rxconf & ~RCR_CS_MASK;
write_nic_dword(dev, RX_CONF, rxconf);
fix_rx_fifo(dev);
cmd = read_nic_byte(dev, CMD);
write_nic_byte(dev, CMD, cmd | (1<<CMD_RX_ENABLE_SHIFT));
}
void set_nic_txring(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma);
write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma);
write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma);
write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma);
write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma);
write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma);
write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma);
}
void rtl8180_conttx_enable(struct net_device *dev)
{
u32 txconf;
txconf = read_nic_dword(dev, TX_CONF);
txconf = txconf & ~TX_LOOPBACK_MASK;
txconf = txconf | (TX_LOOPBACK_CONTINUE<<TX_LOOPBACK_SHIFT);
write_nic_dword(dev, TX_CONF, txconf);
}
void rtl8180_conttx_disable(struct net_device *dev)
{
u32 txconf;
txconf = read_nic_dword(dev, TX_CONF);
txconf = txconf & ~TX_LOOPBACK_MASK;
txconf = txconf | (TX_LOOPBACK_NONE<<TX_LOOPBACK_SHIFT);
write_nic_dword(dev, TX_CONF, txconf);
}
void rtl8180_tx_enable(struct net_device *dev)
{
u8 cmd;
u8 tx_agc_ctl;
u8 byte;
u32 txconf;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
txconf = read_nic_dword(dev, TX_CONF);
byte = read_nic_byte(dev, CW_CONF);
byte &= ~(1<<CW_CONF_PERPACKET_CW_SHIFT);
byte &= ~(1<<CW_CONF_PERPACKET_RETRY_SHIFT);
write_nic_byte(dev, CW_CONF, byte);
tx_agc_ctl = read_nic_byte(dev, TX_AGC_CTL);
tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_GAIN_SHIFT);
tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT);
tx_agc_ctl |= (1<<TX_AGC_CTL_FEEDBACK_ANT);
write_nic_byte(dev, TX_AGC_CTL, tx_agc_ctl);
write_nic_byte(dev, 0xec, 0x3f); /* Disable early TX */
txconf = txconf & ~(1<<TCR_PROBE_NOTIMESTAMP_SHIFT);
txconf = txconf & ~TX_LOOPBACK_MASK;
txconf = txconf | (TX_LOOPBACK_NONE<<TX_LOOPBACK_SHIFT);
txconf = txconf & ~TCR_DPRETRY_MASK;
txconf = txconf & ~TCR_RTSRETRY_MASK;
txconf = txconf | (priv->retry_data<<TX_DPRETRY_SHIFT);
txconf = txconf | (priv->retry_rts<<TX_RTSRETRY_SHIFT);
txconf = txconf & ~(1<<TX_NOCRC_SHIFT);
if (priv->hw_plcp_len)
txconf = txconf & ~TCR_PLCP_LEN;
else
txconf = txconf | TCR_PLCP_LEN;
txconf = txconf & ~TCR_MXDMA_MASK;
txconf = txconf | (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT);
txconf = txconf | TCR_CWMIN;
txconf = txconf | TCR_DISCW;
txconf = txconf | (1 << TX_NOICV_SHIFT);
write_nic_dword(dev, TX_CONF, txconf);
fix_tx_fifo(dev);
cmd = read_nic_byte(dev, CMD);
write_nic_byte(dev, CMD, cmd | (1<<CMD_TX_ENABLE_SHIFT));
write_nic_dword(dev, TX_CONF, txconf);
}
void rtl8180_beacon_tx_enable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);
write_nic_byte(dev, TPPollStop, priv->dma_poll_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
void rtl8180_beacon_tx_disable(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ;
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
void rtl8180_rtx_disable(struct net_device *dev)
{
u8 cmd;
struct r8180_priv *priv = ieee80211_priv(dev);
cmd = read_nic_byte(dev, CMD);
write_nic_byte(dev, CMD, cmd & ~\
((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT)));
force_pci_posting(dev);
mdelay(10);
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
}
short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
int addr)
{
int i;
u32 *desc;
u32 *tmp;
dma_addr_t dma_desc, dma_tmp;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
void *buf;
if ((bufsize & 0xfff) != bufsize) {
DMESGE("TX buffer allocation too large");
return 0;
}
desc = (u32 *)pci_alloc_consistent(pdev,
sizeof(u32)*8*count+256, &dma_desc);
if (desc == NULL)
return -1;
if (dma_desc & 0xff)
/*
* descriptor's buffer must be 256 byte aligned
* we shouldn't be here, since we set DMA mask !
*/
WARN(1, "DMA buffer is not aligned\n");
tmp = desc;
for (i = 0; i < count; i++) {
buf = (void *)pci_alloc_consistent(pdev, bufsize, &dma_tmp);
if (buf == NULL)
return -ENOMEM;
switch (addr) {
case TX_MANAGEPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_BKPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_BEPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_VIPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer LP");
return -ENOMEM;
}
break;
case TX_VOPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer NP");
return -ENOMEM;
}
break;
case TX_HIGHPRIORITY_RING_ADDR:
if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer HP");
return -ENOMEM;
}
break;
case TX_BEACON_RING_ADDR:
if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) {
DMESGE("Unable to allocate mem for buffer BP");
return -ENOMEM;
}
break;
}
*tmp = *tmp & ~(1<<31); /* descriptor empty, owned by the drv */
*(tmp+2) = (u32)dma_tmp;
*(tmp+3) = bufsize;
if (i+1 < count)
*(tmp+4) = (u32)dma_desc+((i+1)*8*4);
else
*(tmp+4) = (u32)dma_desc;
tmp = tmp+8;
}
switch (addr) {
case TX_MANAGEPRIORITY_RING_ADDR:
priv->txmapringdma = dma_desc;
priv->txmapring = desc;
break;
case TX_BKPRIORITY_RING_ADDR:
priv->txbkpringdma = dma_desc;
priv->txbkpring = desc;
break;
case TX_BEPRIORITY_RING_ADDR:
priv->txbepringdma = dma_desc;
priv->txbepring = desc;
break;
case TX_VIPRIORITY_RING_ADDR:
priv->txvipringdma = dma_desc;
priv->txvipring = desc;
break;
case TX_VOPRIORITY_RING_ADDR:
priv->txvopringdma = dma_desc;
priv->txvopring = desc;
break;
case TX_HIGHPRIORITY_RING_ADDR:
priv->txhpringdma = dma_desc;
priv->txhpring = desc;
break;
case TX_BEACON_RING_ADDR:
priv->txbeaconringdma = dma_desc;
priv->txbeaconring = desc;
break;
}
return 0;
}
void free_tx_desc_rings(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
int count = priv->txringcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txmapring, priv->txmapringdma);
buffer_free(dev, &(priv->txmapbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbkpring, priv->txbkpringdma);
buffer_free(dev, &(priv->txbkpbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbepring, priv->txbepringdma);
buffer_free(dev, &(priv->txbepbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txvipring, priv->txvipringdma);
buffer_free(dev, &(priv->txvipbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txvopring, priv->txvopringdma);
buffer_free(dev, &(priv->txvopbufs), priv->txbuffsize, 1);
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txhpring, priv->txhpringdma);
buffer_free(dev, &(priv->txhpbufs), priv->txbuffsize, 1);
count = priv->txbeaconcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->txbeaconring, priv->txbeaconringdma);
buffer_free(dev, &(priv->txbeaconbufs), priv->txbuffsize, 1);
}
void free_rx_desc_ring(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
int count = priv->rxringcount;
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
priv->rxring, priv->rxringdma);
buffer_free(dev, &(priv->rxbuffer), priv->rxbuffersize, 0);
}
short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
{
int i;
u32 *desc;
u32 *tmp;
dma_addr_t dma_desc, dma_tmp;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct pci_dev *pdev = priv->pdev;
void *buf;
u8 rx_desc_size;
rx_desc_size = 8; /* 4*8 = 32 bytes */
if ((bufsize & 0xfff) != bufsize) {
DMESGE("RX buffer allocation too large");
return -1;
}
desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256,
&dma_desc);
if (dma_desc & 0xff)
/*
* descriptor's buffer must be 256 byte aligned
* should never happen since we specify the DMA mask
*/
WARN(1, "DMA buffer is not aligned\n");
priv->rxring = desc;
priv->rxringdma = dma_desc;
tmp = desc;
for (i = 0; i < count; i++) {
buf = kmalloc(bufsize * sizeof(u8), GFP_ATOMIC);
if (buf == NULL) {
DMESGE("Failed to kmalloc RX buffer");
return -1;
}
dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8),
PCI_DMA_FROMDEVICE);
if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp,
&(priv->rxbufferhead))) {
DMESGE("Unable to allocate mem RX buf");
return -1;
}
*tmp = 0; /* zero pads the header of the descriptor */
*tmp = *tmp | (bufsize&0xfff);
*(tmp+2) = (u32)dma_tmp;
*tmp = *tmp | (1<<31); /* descriptor void, owned by the NIC */
tmp = tmp+rx_desc_size;
}
*(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */
return 0;
}
void set_nic_rxring(struct net_device *dev)
{
u8 pgreg;
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
pgreg = read_nic_byte(dev, PGSELECT);
write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
write_nic_dword(dev, RXRING_ADDR, priv->rxringdma);
}
void rtl8180_reset(struct net_device *dev)
{
u8 cr;
rtl8180_irq_disable(dev);
cr = read_nic_byte(dev, CMD);
cr = cr & 2;
cr = cr | (1<<CMD_RST_SHIFT);
write_nic_byte(dev, CMD, cr);
force_pci_posting(dev);
mdelay(200);
if (read_nic_byte(dev, CMD) & (1<<CMD_RST_SHIFT))
DMESGW("Card reset timeout!");
else
DMESG("Card successfully reset");
rtl8180_set_mode(dev, EPROM_CMD_LOAD);
force_pci_posting(dev);
mdelay(200);
}
inline u16 ieeerate2rtlrate(int rate)
{
switch (rate) {
case 10:
return 0;
case 20:
return 1;
case 55:
return 2;
case 110:
return 3;
case 60:
return 4;
case 90:
return 5;
case 120:
return 6;
case 180:
return 7;
case 240:
return 8;
case 360:
return 9;
case 480:
return 10;
case 540:
return 11;
default:
return 3;
}
}
static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720};
inline u16 rtl8180_rate2rate(short rate)
{
if (rate > 12)
return 10;
return rtl_rate[rate];
}
inline u8 rtl8180_IsWirelessBMode(u16 rate)
{
if (((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220))
return 1;
else
return 0;
}
u16 N_DBPSOfRate(u16 DataRate);
u16 ComputeTxTime(u16 FrameLength, u16 DataRate, u8 bManagementFrame,
u8 bShortPreamble)
{
u16 FrameTime;
u16 N_DBPS;
u16 Ceiling;
if (rtl8180_IsWirelessBMode(DataRate)) {
if (bManagementFrame || !bShortPreamble || DataRate == 10)
/* long preamble */
FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10)));
else
/* short preamble */
FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10)));
if ((FrameLength*8 % (DataRate/10)) != 0) /* get the ceilling */
FrameTime++;
} else { /* 802.11g DSSS-OFDM PLCP length field calculation. */
N_DBPS = N_DBPSOfRate(DataRate);
Ceiling = (16 + 8*FrameLength + 6) / N_DBPS
+ (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0);
FrameTime = (u16)(16 + 4 + 4*Ceiling + 6);
}
return FrameTime;
}
u16 N_DBPSOfRate(u16 DataRate)
{
u16 N_DBPS = 24;
switch (DataRate) {
case 60:
N_DBPS = 24;
break;
case 90:
N_DBPS = 36;
break;
case 120:
N_DBPS = 48;
break;
case 180:
N_DBPS = 72;
break;
case 240:
N_DBPS = 96;
break;
case 360:
N_DBPS = 144;
break;
case 480:
N_DBPS = 192;
break;
case 540:
N_DBPS = 216;
break;
default:
break;
}
return N_DBPS;
}
/*
* For Netgear case, they want good-looking singal strength.
*/
long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
{
long RetSS;
/* Step 1. Scale mapping. */
if (CurrSS >= 71 && CurrSS <= 100)
RetSS = 90 + ((CurrSS - 70) / 3);
else if (CurrSS >= 41 && CurrSS <= 70)
RetSS = 78 + ((CurrSS - 40) / 3);
else if (CurrSS >= 31 && CurrSS <= 40)
RetSS = 66 + (CurrSS - 30);
else if (CurrSS >= 21 && CurrSS <= 30)
RetSS = 54 + (CurrSS - 20);
else if (CurrSS >= 5 && CurrSS <= 20)
RetSS = 42 + (((CurrSS - 5) * 2) / 3);
else if (CurrSS == 4)
RetSS = 36;
else if (CurrSS == 3)
RetSS = 27;
else if (CurrSS == 2)
RetSS = 18;
else if (CurrSS == 1)
RetSS = 9;
else
RetSS = CurrSS;
/* Step 2. Smoothing. */
if (LastSS > 0)
RetSS = ((LastSS * 5) + (RetSS) + 5) / 6;
return RetSS;
}
/*
* Translate 0-100 signal strength index into dBm.
*/
long TranslateToDbm8185(u8 SignalStrengthIndex)
{
long SignalPower;
/* Translate to dBm (x=0.5y-95). */
SignalPower = (long)((SignalStrengthIndex + 1) >> 1);
SignalPower -= 95;
return SignalPower;
}
/*
* Perform signal smoothing for dynamic mechanism.
* This is different with PerformSignalSmoothing8185 in smoothing fomula.
* No dramatic adjustion is apply because dynamic mechanism need some degree
* of correctness. Ported from 8187B.
*/
void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
bool bCckRate)
{
/* Determin the current packet is CCK rate. */
priv->bCurCCKPkt = bCckRate;
if (priv->UndecoratedSmoothedSS >= 0)
priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10)) / 6;
else
priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower * 11)) / 60;
if (bCckRate)
priv->CurCCKRSSI = priv->RSSI;
else
priv->CurCCKRSSI = 0;
}
/*
* This is rough RX isr handling routine
*/
void rtl8180_rx(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct sk_buff *tmp_skb;
short first, last;
u32 len;
int lastlen;
unsigned char quality, signal;
u8 rate;
u32 *tmp, *tmp2;
u8 rx_desc_size;
u8 padding;
char rxpower = 0;
u32 RXAGC = 0;
long RxAGC_dBm = 0;
u8 LNA = 0, BB = 0;
u8 LNA_gain[4] = {02, 17, 29, 39};
u8 Antenna = 0;
struct ieee80211_hdr_4addr *hdr;
u16 fc, type;
u8 bHwError = 0, bCRC = 0, bICV = 0;
bool bCckRate = false;
u8 RSSI = 0;
long SignalStrengthIndex = 0;
struct ieee80211_rx_stats stats = {
.signal = 0,
.noise = -98,
.rate = 0,
.freq = IEEE80211_24GHZ_BAND,
};
stats.nic_type = NIC_8185B;
rx_desc_size = 8;
if ((*(priv->rxringtail)) & (1<<31)) {
/* we have got an RX int, but the descriptor
* we are pointing is empty */
priv->stats.rxnodata++;
priv->ieee80211->stats.rx_errors++;
tmp2 = NULL;
tmp = priv->rxringtail;
do {
if (tmp == priv->rxring)
tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
else
tmp -= rx_desc_size;
if (!(*tmp & (1<<31)))
tmp2 = tmp;
} while (tmp != priv->rxring);
if (tmp2)
priv->rxringtail = tmp2;
}
/* while there are filled descriptors */
while (!(*(priv->rxringtail) & (1<<31))) {
if (*(priv->rxringtail) & (1<<26))
DMESGW("RX buffer overflow");
if (*(priv->rxringtail) & (1<<12))
priv->stats.rxicverr++;
if (*(priv->rxringtail) & (1<<27)) {
priv->stats.rxdmafail++;
/* DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); */
goto drop;
}
pci_dma_sync_single_for_cpu(priv->pdev,
priv->rxbuffer->dma,
priv->rxbuffersize * \
sizeof(u8),
PCI_DMA_FROMDEVICE);
first = *(priv->rxringtail) & (1<<29) ? 1 : 0;
if (first)
priv->rx_prevlen = 0;
last = *(priv->rxringtail) & (1<<28) ? 1 : 0;
if (last) {
lastlen = ((*priv->rxringtail) & 0xfff);
/* if the last descriptor (that should
* tell us the total packet len) tell
* us something less than the descriptors
* len we had until now, then there is some
* problem..
* workaround to prevent kernel panic
*/
if (lastlen < priv->rx_prevlen)
len = 0;
else
len = lastlen-priv->rx_prevlen;
if (*(priv->rxringtail) & (1<<13)) {
if ((*(priv->rxringtail) & 0xfff) < 500)
priv->stats.rxcrcerrmin++;
else if ((*(priv->rxringtail) & 0x0fff) > 1000)
priv->stats.rxcrcerrmax++;
else
priv->stats.rxcrcerrmid++;
}
} else {
len = priv->rxbuffersize;
}
if (first && last) {
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
} else if (first) {
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
if (padding)
len -= 2;
} else {
padding = 0;
}
padding = 0;
priv->rx_prevlen += len;
if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) {
/* HW is probably passing several buggy frames
* without FD or LD flag set.
* Throw this garbage away to prevent skb
* memory exausting
*/
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb_complete = 1;
}
signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16);
signal = (signal & 0xfe) >> 1;
quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff));
stats.mac_time[0] = *(priv->rxringtail+1);
stats.mac_time[1] = *(priv->rxringtail+2);
rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42;
RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f);
rate = ((*(priv->rxringtail)) &
((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
stats.rate = rtl8180_rate2rate(rate);
Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1;
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
RxAGC_dBm = rxpower+1; /* bias */
} else { /* CCK rate. */
RxAGC_dBm = signal; /* bit 0 discard */
LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */
BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */
RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
RxAGC_dBm += 4; /* bias */
}
if (RxAGC_dBm & 0x80) /* absolute value */
RXAGC = ~(RxAGC_dBm)+1;
bCckRate = rtl8180_IsWirelessBMode(stats.rate);
/* Translate RXAGC into 1-100. */
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
if (RXAGC > 90)
RXAGC = 90;
else if (RXAGC < 25)
RXAGC = 25;
RXAGC = (90-RXAGC)*100/65;
} else { /* CCK rate. */
if (RXAGC > 95)
RXAGC = 95;
else if (RXAGC < 30)
RXAGC = 30;
RXAGC = (95-RXAGC)*100/65;
}
priv->SignalStrength = (u8)RXAGC;
priv->RecvSignalPower = RxAGC_dBm;
priv->RxPower = rxpower;
priv->RSSI = RSSI;
/* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
if (quality >= 127)
quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk aroud now; */
else if (quality < 27)
quality = 100;
else
quality = 127 - quality;
priv->SignalQuality = quality;
stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */
stats.signalstrength = RXAGC;
if (stats.signalstrength > 100)
stats.signalstrength = 100;
stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
/* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) | (((*(priv->rxringtail)) & (0x04000000)) != 0)
| (((*(priv->rxringtail)) & (0x08000000)) != 0) | (((~(*(priv->rxringtail))) & (0x10000000)) != 0) | (((~(*(priv->rxringtail))) & (0x20000000)) != 0);
bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf;
fc = le16_to_cpu(hdr->frame_ctl);
type = WLAN_FC_GET_TYPE(fc);
if ((IEEE80211_FTYPE_CTL != type) &&
(eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : hdr->addr3))
&& (!bHwError) && (!bCRC) && (!bICV)) {
/* Perform signal smoothing for dynamic
* mechanism on demand. This is different
* with PerformSignalSmoothing8185 in smoothing
* fomula. No dramatic adjustion is apply
* because dynamic mechanism need some degree
* of correctness. */
PerformUndecoratedSignalSmoothing8185(priv, bCckRate);
/* For good-looking singal strength. */
SignalStrengthIndex = NetgearSignalStrengthTranslate(
priv->LastSignalStrengthInPercent,
priv->SignalStrength);
priv->LastSignalStrengthInPercent = SignalStrengthIndex;
priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
/*
* We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
* so we record the correct power here.
*/
priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
/* Figure out which antenna that received the lasted packet. */
priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
if (first) {
if (!priv->rx_skb_complete) {
/* seems that HW sometimes fails to reiceve and
doesn't provide the last descriptor */
dev_kfree_skb_any(priv->rx_skb);
priv->stats.rxnolast++;
}
/* support for prism header has been originally added by Christian */
if (priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR) {
} else {
priv->rx_skb = dev_alloc_skb(len+2);
if (!priv->rx_skb)
goto drop;
}
priv->rx_skb_complete = 0;
priv->rx_skb->dev = dev;
} else {
/* if we are here we should have already RXed
* the first frame.
* If we get here and the skb is not allocated then
* we have just throw out garbage (skb not allocated)
* and we are still rxing garbage....
*/
if (!priv->rx_skb_complete) {
tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2);
if (!tmp_skb)
goto drop;
tmp_skb->dev = dev;
memcpy(skb_put(tmp_skb, priv->rx_skb->len),
priv->rx_skb->data,
priv->rx_skb->len);
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb = tmp_skb;
}
}
if (!priv->rx_skb_complete) {
if (padding) {
memcpy(skb_put(priv->rx_skb, len),
(((unsigned char *)priv->rxbuffer->buf) + 2), len);
} else {
memcpy(skb_put(priv->rx_skb, len),
priv->rxbuffer->buf, len);
}
}
if (last && !priv->rx_skb_complete) {
if (priv->rx_skb->len > 4)
skb_trim(priv->rx_skb, priv->rx_skb->len-4);
if (!ieee80211_rtl_rx(priv->ieee80211,
priv->rx_skb, &stats))
dev_kfree_skb_any(priv->rx_skb);
priv->rx_skb_complete = 1;
}
pci_dma_sync_single_for_device(priv->pdev,
priv->rxbuffer->dma,
priv->rxbuffersize * \
sizeof(u8),
PCI_DMA_FROMDEVICE);
drop: /* this is used when we have not enough mem */
/* restore the descriptor */
*(priv->rxringtail+2) = priv->rxbuffer->dma;
*(priv->rxringtail) = *(priv->rxringtail) & ~0xfff;
*(priv->rxringtail) =
*(priv->rxringtail) | priv->rxbuffersize;
*(priv->rxringtail) =
*(priv->rxringtail) | (1<<31);
priv->rxringtail += rx_desc_size;
if (priv->rxringtail >=
(priv->rxring)+(priv->rxringcount)*rx_desc_size)
priv->rxringtail = priv->rxring;
priv->rxbuffer = (priv->rxbuffer->next);
}
}
void rtl8180_dma_kick(struct net_device *dev, int priority)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
write_nic_byte(dev, TX_DMA_POLLING,
(1 << (priority + 1)) | priv->dma_poll_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
force_pci_posting(dev);
}
void rtl8180_data_hard_stop(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ;
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
void rtl8180_data_hard_resume(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ);
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
}
/*
* This function TX data frames when the ieee80211 stack requires this.
* It checks also if we need to stop the ieee tx queue, eventually do it
*/
void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int
rate) {
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
int mode;
struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
unsigned long flags;
int priority;
mode = priv->ieee80211->iw_mode;
rate = ieeerate2rtlrate(rate);
/*
* This function doesn't require lock because we make
* sure it's called with the tx_lock already acquired.
* this come from the kernel's hard_xmit callback (through
* the ieee stack, or from the try_wake_queue (again through
* the ieee stack.
*/
priority = AC2Q(skb->priority);
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->ieee80211->bHwRadioOff) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
return;
}
if (!check_nic_enought_desc(dev, priority)) {
DMESGW("Error: no descriptor left by previous TX (avail %d) ",
get_curr_tx_free_desc(dev, priority));
ieee80211_rtl_stop_queue(priv->ieee80211);
}
rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate);
if (!check_nic_enought_desc(dev, priority))
ieee80211_rtl_stop_queue(priv->ieee80211);
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
/*
* This is a rough attempt to TX a frame
* This is called by the ieee 80211 stack to TX management frames.
* If the ring is full packet are dropped (for data frame the queue
* is stopped before this can happen). For this reason it is better
* if the descriptors are larger than the largest management frame
* we intend to TX: i'm unsure what the HW does if it will not found
* the last fragment of a frame because it has been dropped...
* Since queues for Management and Data frames are different we
* might use a different lock than tx_lock (for example mgmt_tx_lock)
*/
/* these function may loops if invoked with 0 descriptors or 0 len buffer */
int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
unsigned long flags;
int priority;
priority = MANAGE_PRIORITY;
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->ieee80211->bHwRadioOff) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
rtl8180_tx(dev, skb->data, skb->len, priority,
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
priv->ieee80211->stats.tx_bytes += skb->len;
priv->ieee80211->stats.tx_packets++;
spin_unlock_irqrestore(&priv->tx_lock, flags);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
/* longpre 144+48 shortpre 72+24 */
u16 rtl8180_len2duration(u32 len, short rate, short *ext)
{
u16 duration;
u16 drift;
*ext = 0;
switch (rate) {
case 0: /* 1mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x2;
drift = ((len+4)<<4) % 0x2;
if (drift == 0)
break;
duration++;
break;
case 1: /* 2mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x4;
drift = ((len+4)<<4) % 0x4;
if (drift == 0)
break;
duration++;
break;
case 2: /* 5.5mbps */
*ext = 0;
duration = ((len+4)<<4) / 0xb;
drift = ((len+4)<<4) % 0xb;
if (drift == 0)
break;
duration++;
break;
default:
case 3: /* 11mbps */
*ext = 0;
duration = ((len+4)<<4) / 0x16;
drift = ((len+4)<<4) % 0x16;
if (drift == 0)
break;
duration++;
if (drift > 6)
break;
*ext = 1;
break;
}
return duration;
}
void rtl8180_prepare_beacon(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
struct sk_buff *skb;
u16 word = read_nic_word(dev, BcnItv);
word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
write_nic_word(dev, BcnItv, word);
skb = ieee80211_get_beacon(priv->ieee80211);
if (skb) {
rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY,
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
dev_kfree_skb_any(skb);
}
}
/*
* This function do the real dirty work: it enqueues a TX command
* descriptor in the ring buffer, copyes the frame in a TX buffer
* and kicks the NIC to ensure it does the DMA transfer.
*/
short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
short morefrag, short descfrag, int rate)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *tail, *temp_tail;
u32 *begin;
u32 *buf;
int i;
int remain;
int buflen;
int count;
u16 duration;
short ext;
struct buffer *buflist;
struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
u8 dest[ETH_ALEN];
u8 bUseShortPreamble = 0;
u8 bCTSEnable = 0;
u8 bRTSEnable = 0;
u16 Duration = 0;
u16 RtsDur = 0;
u16 ThisFrameTime = 0;
u16 TxDescDuration = 0;
u8 ownbit_flag = false;
switch (priority) {
case MANAGE_PRIORITY:
tail = priv->txmapringtail;
begin = priv->txmapring;
buflist = priv->txmapbufstail;
count = priv->txringcount;
break;
case BK_PRIORITY:
tail = priv->txbkpringtail;
begin = priv->txbkpring;
buflist = priv->txbkpbufstail;
count = priv->txringcount;
break;
case BE_PRIORITY:
tail = priv->txbepringtail;
begin = priv->txbepring;
buflist = priv->txbepbufstail;
count = priv->txringcount;
break;
case VI_PRIORITY:
tail = priv->txvipringtail;
begin = priv->txvipring;
buflist = priv->txvipbufstail;
count = priv->txringcount;
break;
case VO_PRIORITY:
tail = priv->txvopringtail;
begin = priv->txvopring;
buflist = priv->txvopbufstail;
count = priv->txringcount;
break;
case HI_PRIORITY:
tail = priv->txhpringtail;
begin = priv->txhpring;
buflist = priv->txhpbufstail;
count = priv->txringcount;
break;
case BEACON_PRIORITY:
tail = priv->txbeaconringtail;
begin = priv->txbeaconring;
buflist = priv->txbeaconbufstail;
count = priv->txbeaconcount;
break;
default:
return -1;
break;
}
memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
if (is_multicast_ether_addr(dest) ||
is_broadcast_ether_addr(dest)) {
Duration = 0;
RtsDur = 0;
bRTSEnable = 0;
bCTSEnable = 0;
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
TxDescDuration = ThisFrameTime;
} else { /* Unicast packet */
u16 AckTime;
/* YJ,add,080828,for Keep alive */
priv->NumTxUnicast++;
/* Figure out ACK rate according to BSS basic rate
* and Tx rate. */
AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
u16 RtsTime, CtsTime;
/* u16 CtsRate; */
bRTSEnable = 1;
bCTSEnable = 0;
/* Rate and time required for RTS. */
RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
/* Rate and time required for CTS. */
CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
/* Figure out time required to transmit this frame. */
ThisFrameTime = ComputeTxTime(len + sCrcLng,
rtl8180_rate2rate(rate),
0,
bUseShortPreamble);
/* RTS-CTS-ThisFrame-ACK. */
RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
TxDescDuration = RtsTime + RtsDur;
} else { /* Normal case. */
bCTSEnable = 0;
bRTSEnable = 0;
RtsDur = 0;
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
}
if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
/* ThisFrame-ACK. */
Duration = aSifsTime + AckTime;
} else { /* One or more fragments remained. */
u16 NextFragTime;
NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
rtl8180_rate2rate(rate),
0,
bUseShortPreamble);
/* ThisFrag-ACk-NextFrag-ACK. */
Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
}
} /* End of Unicast packet */
frag_hdr->duration_id = Duration;
buflen = priv->txbuffsize;
remain = len;
temp_tail = tail;
while (remain != 0) {
mb();
if (!buflist) {
DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
return -1;
}
buf = buflist->buf;
if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) {
DMESGW("No more TX desc, returning %x of %x",
remain, len);
priv->stats.txrdu++;
return remain;
}
*tail = 0; /* zeroes header */
*(tail+1) = 0;
*(tail+3) = 0;
*(tail+5) = 0;
*(tail+6) = 0;
*(tail+7) = 0;
/* FIXME: this should be triggered by HW encryption parameters.*/
*tail |= (1<<15); /* no encrypt */
if (remain == len && !descfrag) {
ownbit_flag = false;
*tail = *tail | (1<<29) ; /* fist segment of the packet */
*tail = *tail | (len);
} else {
ownbit_flag = true;
}
for (i = 0; i < buflen && remain > 0; i++, remain--) {
((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
if (remain == 4 && i+4 >= buflen)
break;
/* ensure the last desc has at least 4 bytes payload */
}
txbuf = txbuf + i;
*(tail+3) = *(tail+3) & ~0xfff;
*(tail+3) = *(tail+3) | i; /* buffer length */
/* Use short preamble or not */
if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
; /* *tail |= (1<<16); */ /* enable short preamble mode. */
if (bCTSEnable)
*tail |= (1<<18);
if (bRTSEnable) { /* rts enable */
*tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
*tail |= (1<<23); /* rts enable */
*(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
}
*(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
/* *(tail+3) |= (0xe6<<16); */
*(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
*tail = *tail | ((rate&0xf) << 24);
/* hw_plcp_len is not used for rtl8180 chip */
/* FIXME */
if (!priv->hw_plcp_len) {
duration = rtl8180_len2duration(len, rate, &ext);
*(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16);
if (ext)
*(tail+1) = *(tail+1) | (1<<31); /* plcp length extension */
}
if (morefrag)
*tail = (*tail) | (1<<17); /* more fragment */
if (!remain)
*tail = (*tail) | (1<<28); /* last segment of frame */
*(tail+5) = *(tail+5)|(2<<27);
*(tail+7) = *(tail+7)|(1<<4);
wmb();
if (ownbit_flag)
*tail = *tail | (1<<31); /* descriptor ready to be txed */
if ((tail - begin)/8 == count-1)
tail = begin;
else
tail = tail+8;
buflist = buflist->next;
mb();
switch (priority) {
case MANAGE_PRIORITY:
priv->txmapringtail = tail;
priv->txmapbufstail = buflist;
break;
case BK_PRIORITY:
priv->txbkpringtail = tail;
priv->txbkpbufstail = buflist;
break;
case BE_PRIORITY:
priv->txbepringtail = tail;
priv->txbepbufstail = buflist;
break;
case VI_PRIORITY:
priv->txvipringtail = tail;
priv->txvipbufstail = buflist;
break;
case VO_PRIORITY:
priv->txvopringtail = tail;
priv->txvopbufstail = buflist;
break;
case HI_PRIORITY:
priv->txhpringtail = tail;
priv->txhpbufstail = buflist;
break;
case BEACON_PRIORITY:
/*
* The HW seems to be happy with the 1st
* descriptor filled and the 2nd empty...
* So always update descriptor 1 and never
* touch 2nd
*/
break;
}
}
*temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */
rtl8180_dma_kick(dev, priority);
return 0;
}
void rtl8180_irq_rx_tasklet(struct r8180_priv *priv);
void rtl8180_link_change(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u16 beacon_interval;
struct ieee80211_network *net = &priv->ieee80211->current_network;
rtl8180_update_msr(dev);
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]);
write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]);
beacon_interval = read_nic_dword(dev, BEACON_INTERVAL);
beacon_interval &= ~BEACON_INTERVAL_MASK;
beacon_interval |= net->beacon_interval;
write_nic_dword(dev, BEACON_INTERVAL, beacon_interval);
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
rtl8180_set_chan(dev, priv->chan);
}
void rtl8180_rq_tx_ack(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
priv->ack_tx_to_ieee = 1;
}
short rtl8180_is_tx_queue_empty(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 *d;
for (d = priv->txmapring;
d < priv->txmapring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txbkpring;
d < priv->txbkpring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txbepring;
d < priv->txbepring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txvipring;
d < priv->txvipring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txvopring;
d < priv->txvopring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
for (d = priv->txhpring;
d < priv->txhpring + priv->txringcount; d += 8)
if (*d & (1<<31))
return 0;
return 1;
}
/* FIXME FIXME 5msecs is random */
#define HW_WAKE_DELAY 5
void rtl8180_hw_wakeup(struct net_device *dev)
{
unsigned long flags;
struct r8180_priv *priv = ieee80211_priv(dev);
spin_lock_irqsave(&priv->ps_lock, flags);
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
if (priv->rf_wakeup)
priv->rf_wakeup(dev);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
void rtl8180_hw_sleep_down(struct net_device *dev)
{
unsigned long flags;
struct r8180_priv *priv = ieee80211_priv(dev);
spin_lock_irqsave(&priv->ps_lock, flags);
if (priv->rf_sleep)
priv->rf_sleep(dev);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
{
struct r8180_priv *priv = ieee80211_priv(dev);
u32 rb = jiffies;
unsigned long flags;
spin_lock_irqsave(&priv->ps_lock, flags);
/*
* Writing HW register with 0 equals to disable
* the timer, that is not really what we want
*/
tl -= MSECS(4+16+7);
/*
* If the interval in witch we are requested to sleep is too
* short then give up and remain awake
*/
if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
|| ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
spin_unlock_irqrestore(&priv->ps_lock, flags);
printk("too short to sleep\n");
return;
}
{
u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); /* as tl may be less than rb */
}
/*
* If we suspect the TimerInt is gone beyond tl
* while setting it, then give up
*/
if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) ||
((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
spin_unlock_irqrestore(&priv->ps_lock, flags);
return;
}
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
spin_unlock_irqrestore(&priv->ps_lock, flags);
}
void rtl8180_wmm_param_update(struct work_struct *work)
{
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
struct net_device *dev = ieee->dev;
u8 *ac_param = (u8 *)(ieee->current_network.wmm_param);
u8 mode = ieee->current_network.mode;
AC_CODING eACI;
AC_PARAM AcParam;
PAC_PARAM pAcParam;
u8 i;
if (!ieee->current_network.QoS_Enable) {
/* legacy ac_xx_param update */
AcParam.longData = 0;
AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
AcParam.f.AciAifsn.f.ACM = 0;
AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
AcParam.f.TXOPLimit = 0;
for (eACI = 0; eACI < AC_MAX; eACI++) {
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
{
u8 u1bAIFS;
u32 u4bAcParam;
pAcParam = (PAC_PARAM)(&AcParam);
/* Retrive paramters to udpate. */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
switch (eACI) {
case AC1_BK:
write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
break;
case AC0_BE:
write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
break;
case AC2_VI:
write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
break;
case AC3_VO:
write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
break;
default:
printk(KERN_WARNING "SetHwReg8185():invalid ACI: %d!\n", eACI);
break;
}
}
}
return;
}
for (i = 0; i < AC_MAX; i++) {
/* AcParam.longData = 0; */
pAcParam = (AC_PARAM *)ac_param;
{
AC_CODING eACI;
u8 u1bAIFS;
u32 u4bAcParam;
/* Retrive paramters to udpate. */
eACI = pAcParam->f.AciAifsn.f.ACI;
/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
(((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
(((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
switch (eACI) {
case AC1_BK:
write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
break;
case AC0_BE:
write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
break;
case AC2_VI:
write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
break;
case AC3_VO:
write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
break;
default:
printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI);
break;
}
}
ac_param += (sizeof(AC_PARAM));
}
}
void rtl8180_tx_irq_wq(struct work_struct *work);
void rtl8180_restart_wq(struct work_struct *work);
/* void rtl8180_rq_tx_ack(struct work_struct *work); */
void rtl8180_watch_dog_wq(struct work_struct *work);
void rtl8180_hw_wakeup_wq(struct work_struct *work);
void rtl8180_hw_sleep_wq(struct work_struct *work);
void rtl8180_sw_antenna_wq(struct work_struct *work);
void rtl8180_watch_dog(struct net_device *dev);
void watch_dog_adaptive(unsigned long data)
{
struct r8180_priv* priv = ieee80211_priv((struct net_device *)data);
if (!priv->up) {
DMESG("<----watch_dog_adaptive():driver is not up!\n");
return;
}
/* Tx High Power Mechanism. */
if (CheckHighPower((struct net_device *)data))
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
/* Tx Power Tracking on 87SE. */
if (CheckTxPwrTracking((struct net_device *)data))
TxPwrTracking87SE((struct net_device *)data);
/* Perform DIG immediately. */
if (CheckDig((struct net_device *)data) == true)
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
rtl8180_watch_dog((struct net_device *)data);
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
add_timer(&priv->watch_dog_timer);
}
static CHANNEL_LIST ChannelPlan[] = {
{{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */
{{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Spain. Change to ETSI. */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* France. Change to ETSI. */
{{14,36,40,44,48,52,56,60,64},9}, /* MKK */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */
{{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, /* For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 */
{{1,2,3,4,5,6,7,8,9,10,11,12,13},13} /* world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 */
};
static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
{
int i;
/* lzm add 080826 */
ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1;
ieee->IbssStartChnl = 0;
switch (channel_plan) {
case COUNTRY_CODE_FCC:
case COUNTRY_CODE_IC:
case COUNTRY_CODE_ETSI:
case COUNTRY_CODE_SPAIN:
case COUNTRY_CODE_FRANCE:
case COUNTRY_CODE_MKK:
case COUNTRY_CODE_MKK1:
case COUNTRY_CODE_ISRAEL:
case COUNTRY_CODE_TELEC:
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
if (ChannelPlan[channel_plan].Len != 0) {
/* Clear old channel map */
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
/* Set new channel map */
for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
if (ChannelPlan[channel_plan].Channel[i] <= 14)
GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
}
}
break;
}
case COUNTRY_CODE_GLOBAL_DOMAIN:
{
GET_DOT11D_INFO(ieee)->bEnabled = 0;
Dot11d_Reset(ieee);
ieee->bGlobalDomain = true;
break;
}
case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
{
ieee->MinPassiveChnlNum = 12;
ieee->IbssStartChnl = 10;
break;
}
default:
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
for (i = 1; i <= 14; i++)
GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
break;
}
}
}
void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
/* YJ,add,080828 */
static void rtl8180_statistics_init(struct Stats *pstats)
{
memset(pstats, 0, sizeof(struct Stats));
}
static void rtl8180_link_detect_init(plink_detect_t plink_detect)
{
memset(plink_detect, 0, sizeof(link_detect_t));
plink_detect->SlotNum = DEFAULT_SLOT_NUM;
}
/* YJ,add,080828,end */
static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
{