2008-12-05 04:01:41 +00:00
|
|
|
/*
|
|
|
|
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.
|
2009-06-28 14:20:10 +00:00
|
|
|
|
|
|
|
Power management interface routines.
|
|
|
|
Written by Mariusz Matuszek.
|
2008-12-05 04:01:41 +00:00
|
|
|
*/
|
|
|
|
|
2012-11-22 00:07:04 +00:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
#undef RX_DONT_PASS_UL
|
|
|
|
#undef DUMMY_RX
|
|
|
|
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2008-12-05 04:01:41 +00:00
|
|
|
#include <linux/syscalls.h>
|
2010-02-11 18:07:35 +00:00
|
|
|
#include <linux/eeprom_93cx6.h>
|
2011-06-20 05:41:59 +00:00
|
|
|
#include <linux/interrupt.h>
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
#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"
|
|
|
|
|
2009-06-12 16:28:35 +00:00
|
|
|
#include "ieee80211/dot11d.h"
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-11-19 18:24:44 +00:00
|
|
|
static struct pci_device_id rtl8180_pci_id_tbl[] = {
|
2010-04-08 21:04:17 +00:00
|
|
|
{
|
|
|
|
.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,
|
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
};
|
|
|
|
|
2010-08-12 05:04:21 +00:00
|
|
|
static char ifname[IFNAMSIZ] = "wlan%d";
|
2012-11-22 00:05:53 +00:00
|
|
|
static int hwwep;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
|
|
|
|
MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
|
2012-11-13 17:28:13 +00:00
|
|
|
MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards");
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-08-12 05:04:21 +00:00
|
|
|
module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
|
2010-05-13 17:38:43 +00:00
|
|
|
module_param(hwwep, int, S_IRUGO|S_IWUSR);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support. Still broken and not available on all cards");
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-11-19 18:22:08 +00:00
|
|
|
static int rtl8180_pci_probe(struct pci_dev *pdev,
|
2008-12-05 04:01:41 +00:00
|
|
|
const struct pci_device_id *id);
|
|
|
|
|
2012-11-19 18:26:44 +00:00
|
|
|
static void rtl8180_pci_remove(struct pci_dev *pdev);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
static void rtl8180_shutdown(struct pci_dev *pdev)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
struct net_device *dev = pci_get_drvdata(pdev);
|
2009-05-09 23:06:54 +00:00
|
|
|
if (dev->netdev_ops->ndo_stop)
|
|
|
|
dev->netdev_ops->ndo_stop(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
pci_disable_device(pdev);
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:10 +00:00
|
|
|
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) {
|
2012-11-22 00:07:04 +00:00
|
|
|
dev_err(&pdev->dev, "pci_enable_device failed on resume\n");
|
2009-06-28 14:20:10 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
static struct pci_driver rtl8180_pci_driver = {
|
2009-06-28 14:20:38 +00:00
|
|
|
.name = RTL8180_MODULE_NAME,
|
|
|
|
.id_table = rtl8180_pci_id_tbl,
|
|
|
|
.probe = rtl8180_pci_probe,
|
2012-11-19 18:20:56 +00:00
|
|
|
.remove = rtl8180_pci_remove,
|
2009-06-28 14:20:38 +00:00
|
|
|
.suspend = rtl8180_suspend,
|
|
|
|
.resume = rtl8180_resume,
|
2008-12-05 04:01:41 +00:00
|
|
|
.shutdown = rtl8180_shutdown,
|
|
|
|
};
|
|
|
|
|
|
|
|
u8 read_nic_byte(struct net_device *dev, int x)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
return 0xff&readb((u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 read_nic_dword(struct net_device *dev, int x)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
return readl((u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u16 read_nic_word(struct net_device *dev, int x)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
return readw((u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void write_nic_byte(struct net_device *dev, int x, u8 y)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
writeb(y, (u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
udelay(20);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void write_nic_dword(struct net_device *dev, int x, u32 y)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
writel(y, (u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
udelay(20);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void write_nic_word(struct net_device *dev, int x, u16 y)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
writew(y, (u8 *)dev->mem_start + x);
|
2008-12-05 04:01:41 +00:00
|
|
|
udelay(20);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void force_pci_posting(struct net_device *dev)
|
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
read_nic_byte(dev, EPROM_CMD);
|
2008-12-05 04:01:41 +00:00
|
|
|
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);
|
|
|
|
|
2012-11-22 00:05:53 +00:00
|
|
|
static struct proc_dir_entry *rtl8180_proc;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
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;
|
2010-05-13 17:38:43 +00:00
|
|
|
int i, n;
|
2009-06-28 14:20:38 +00:00
|
|
|
int max = 0xff;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
/* This dump the current register page */
|
2009-06-28 14:20:38 +00:00
|
|
|
for (n = 0; n <= max;) {
|
|
|
|
len += snprintf(page + len, count - len, "\nD: %2x > ", n);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
for (i = 0; i < 16 && n <= max; i++, n++)
|
|
|
|
len += snprintf(page + len, count - len, "%2x ",
|
|
|
|
read_nic_byte(dev, n));
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
len += snprintf(page + len, count - len, "\n");
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
*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;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
|
2008-12-05 04:01:41 +00:00
|
|
|
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");
|
2011-07-24 06:07:46 +00:00
|
|
|
rtl8180_proc = proc_mkdir(RTL8180_MODULE_NAME, init_net.proc_net);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_proc_module_remove(void)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2009-04-19 02:09:08 +00:00
|
|
|
priv->dir_dev = rtl8180_proc;
|
2008-12-05 04:01:41 +00:00
|
|
|
if (!priv->dir_dev) {
|
2009-04-19 02:09:08 +00:00
|
|
|
DMESGE("Unable to initialize /proc/net/r8180/%s\n",
|
2008-12-05 04:01:41 +00:00
|
|
|
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 "
|
2009-04-19 02:09:08 +00:00
|
|
|
"/proc/net/r8180/%s/stats-hw\n",
|
2008-12-05 04:01:41 +00:00
|
|
|
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 "
|
2009-04-19 02:09:08 +00:00
|
|
|
"/proc/net/r8180/%s/stats-rx\n",
|
2008-12-05 04:01:41 +00:00
|
|
|
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 "
|
2009-04-19 02:09:08 +00:00
|
|
|
"/proc/net/r8180/%s/stats-tx\n",
|
2008-12-05 04:01:41 +00:00
|
|
|
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 "
|
2009-04-19 02:09:08 +00:00
|
|
|
"/proc/net/r8180/%s/registers\n",
|
2008-12-05 04:01:41 +00:00
|
|
|
dev->name);
|
|
|
|
}
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
/*
|
|
|
|
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)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
struct buffer *tmp;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!*buffer) {
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
*buffer = kmalloc(sizeof(struct buffer), GFP_KERNEL);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
if (*buffer == NULL) {
|
|
|
|
DMESGE("Failed to kmalloc head of TX/RX struct");
|
|
|
|
return -1;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
(*buffer)->next = *buffer;
|
|
|
|
(*buffer)->buf = buf;
|
|
|
|
(*buffer)->dma = dma;
|
|
|
|
if (bufferhead != NULL)
|
2008-12-05 04:01:41 +00:00
|
|
|
(*bufferhead) = (*buffer);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp = *buffer;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
while (tmp->next != (*buffer))
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp->next = kmalloc(sizeof(struct buffer), GFP_KERNEL);
|
2010-03-25 05:17:01 +00:00
|
|
|
if (tmp->next == NULL) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Failed to kmalloc TX/RX struct");
|
|
|
|
return -1;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp->next->buf = buf;
|
|
|
|
tmp->next->dma = dma;
|
|
|
|
tmp->next->next = *buffer;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void buffer_free(struct net_device *dev, struct buffer **buffer, int len, short consistent)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
struct buffer *tmp, *next;
|
2008-12-05 04:01:41 +00:00
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
struct pci_dev *pdev = priv->pdev;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (!*buffer)
|
|
|
|
return;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
tmp = *buffer;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
do {
|
|
|
|
next = tmp->next;
|
|
|
|
if (consistent) {
|
|
|
|
pci_free_consistent(pdev, len,
|
|
|
|
tmp->buf, tmp->dma);
|
|
|
|
} else {
|
2008-12-05 04:01:41 +00:00
|
|
|
pci_unmap_single(pdev, tmp->dma,
|
2010-05-13 17:38:43 +00:00
|
|
|
len, PCI_DMA_FROMDEVICE);
|
2008-12-05 04:01:41 +00:00
|
|
|
kfree(tmp->buf);
|
|
|
|
}
|
|
|
|
kfree(tmp);
|
|
|
|
tmp = next;
|
2012-03-14 22:26:58 +00:00
|
|
|
} while (next != *buffer);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
*buffer = NULL;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int get_curr_tx_free_desc(struct net_device *dev, int priority)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
u32 *tail;
|
|
|
|
u32 *head;
|
2008-12-05 04:01:41 +00:00
|
|
|
int ret;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
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;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (head <= tail)
|
2008-12-05 04:01:41 +00:00
|
|
|
ret = priv->txringcount - (tail - head)/8;
|
|
|
|
else
|
|
|
|
ret = (head - tail)/8;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (ret > priv->txringcount)
|
|
|
|
DMESG("BUG");
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (ieee->current_network.QoS_Enable)
|
2008-12-05 04:01:41 +00:00
|
|
|
requiredbyte += 2;
|
|
|
|
|
|
|
|
required = requiredbyte / (priv->txbuffsize-4);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
if (requiredbyte % priv->txbuffsize)
|
|
|
|
required++;
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
/* for now we keep two free descriptor as a safety boundary
|
|
|
|
* between the tail and the head
|
|
|
|
*/
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
return (required+2 < get_curr_tx_free_desc(dev, priority));
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void fix_tx_fifo(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
u32 *tmp;
|
|
|
|
int i;
|
2009-06-28 14:19:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txmapring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txbkpring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txbepring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txvipring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txvopring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txhpring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txringcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->txbeaconring, i = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
i < priv->txbeaconcount;
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += 8, i++) {
|
|
|
|
*tmp = *tmp & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2009-06-28 14:19:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
rx_desc_size = 8; /* 4*8 = 32 bytes */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (tmp = priv->rxring, rxbuf = priv->rxbufferhead;
|
2008-12-05 04:01:41 +00:00
|
|
|
(tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size);
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp += rx_desc_size, rxbuf = rxbuf->next) {
|
2008-12-05 04:01:41 +00:00
|
|
|
*(tmp+2) = rxbuf->dma;
|
2010-05-13 17:38:43 +00:00
|
|
|
*tmp = *tmp & ~0xfff;
|
|
|
|
*tmp = *tmp | priv->rxbuffersize;
|
2008-12-05 04:01:41 +00:00
|
|
|
*tmp |= (1<<31);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rxringtail = priv->rxring;
|
|
|
|
priv->rxbuffer = priv->rxbufferhead;
|
|
|
|
priv->rx_skb_complete = 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
set_nic_rxring(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_irq_disable(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_dword(dev, IMR, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
force_pci_posting(dev);
|
|
|
|
priv->irq_enabled = 0;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_set_mode(struct net_device *dev, int mode)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
u8 ecmd;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
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);
|
2008-12-05 04:01:41 +00:00
|
|
|
write_nic_byte(dev, EPROM_CMD, ecmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2010-05-13 17:38:43 +00:00
|
|
|
msr &= ~MSR_LINK_MASK;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rxconf = read_nic_dword(dev, RX_CONF);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->state == IEEE80211_LINKED) {
|
|
|
|
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
2008-12-05 04:01:41 +00:00
|
|
|
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);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
} else {
|
2008-12-05 04:01:41 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_set_chan(struct net_device *dev, short ch)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if ((ch > 14) || (ch < 1)) {
|
2009-01-07 22:31:57 +00:00
|
|
|
printk("In %s: Invalid chnanel %d\n", __func__, ch);
|
2008-12-05 04:01:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->chan = ch;
|
|
|
|
priv->rf_set_chan(dev, priv->chan);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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_beacon_tx_enable(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, TPPollStop, priv->dma_poll_mask);
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_beacon_tx_disable(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ;
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_rtx_disable(struct net_device *dev)
|
|
|
|
{
|
|
|
|
u8 cmd;
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
cmd = read_nic_byte(dev, CMD);
|
2012-11-22 00:06:37 +00:00
|
|
|
write_nic_byte(dev, CMD, cmd &
|
|
|
|
~((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT)));
|
2008-12-05 04:01:41 +00:00
|
|
|
force_pci_posting(dev);
|
|
|
|
mdelay(10);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!priv->rx_skb_complete)
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((bufsize & 0xfff) != bufsize) {
|
|
|
|
DMESGE("TX buffer allocation too large");
|
2008-12-05 04:01:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
desc = (u32 *)pci_alloc_consistent(pdev,
|
2008-12-05 04:01:41 +00:00
|
|
|
sizeof(u32)*8*count+256, &dma_desc);
|
2009-06-28 14:20:38 +00:00
|
|
|
if (desc == NULL)
|
|
|
|
return -1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (dma_desc & 0xff)
|
2008-12-05 04:01:41 +00:00
|
|
|
/*
|
|
|
|
* descriptor's buffer must be 256 byte aligned
|
|
|
|
* we shouldn't be here, since we set DMA mask !
|
|
|
|
*/
|
2009-04-19 02:09:08 +00:00
|
|
|
WARN(1, "DMA buffer is not aligned\n");
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
tmp = desc;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
buf = (void *)pci_alloc_consistent(pdev, bufsize, &dma_tmp);
|
|
|
|
if (buf == NULL)
|
|
|
|
return -ENOMEM;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (addr) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case TX_MANAGEPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer NP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_BKPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer LP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_BEPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer NP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_VIPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer LP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_VOPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer NP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_HIGHPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Unable to allocate mem for buffer HP");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TX_BEACON_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) {
|
|
|
|
DMESGE("Unable to allocate mem for buffer BP");
|
2008-12-05 04:01:41 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
*tmp = *tmp & ~(1<<31); /* descriptor empty, owned by the drv */
|
2008-12-05 04:01:41 +00:00
|
|
|
*(tmp+2) = (u32)dma_tmp;
|
|
|
|
*(tmp+3) = bufsize;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (i+1 < count)
|
2008-12-05 04:01:41 +00:00
|
|
|
*(tmp+4) = (u32)dma_desc+((i+1)*8*4);
|
|
|
|
else
|
|
|
|
*(tmp+4) = (u32)dma_desc;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp = tmp+8;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (addr) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case TX_MANAGEPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txmapringdma = dma_desc;
|
|
|
|
priv->txmapring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_BKPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txbkpringdma = dma_desc;
|
|
|
|
priv->txbkpring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_BEPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txbepringdma = dma_desc;
|
|
|
|
priv->txbepring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_VIPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txvipringdma = dma_desc;
|
|
|
|
priv->txvipring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_VOPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txvopringdma = dma_desc;
|
|
|
|
priv->txvopring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_HIGHPRIORITY_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txhpringdma = dma_desc;
|
|
|
|
priv->txhpring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
case TX_BEACON_RING_ADDR:
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->txbeaconringdma = dma_desc;
|
|
|
|
priv->txbeaconring = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_tx_desc_rings(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
struct pci_dev *pdev = priv->pdev;
|
2008-12-05 04:01:41 +00:00
|
|
|
int count = priv->txringcount;
|
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txmapring, priv->txmapringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txmapbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txbkpring, priv->txbkpringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txbkpbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txbepring, priv->txbepringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txbepbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txvipring, priv->txvipringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txvipbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txvopring, priv->txvopringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txvopbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txhpring, priv->txhpringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txhpbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
count = priv->txbeaconcount;
|
|
|
|
pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
|
priv->txbeaconring, priv->txbeaconringdma);
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->txbeaconbufs), priv->txbuffsize, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
buffer_free(dev, &(priv->rxbuffer), priv->rxbuffersize, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
u32 *desc;
|
|
|
|
u32 *tmp;
|
2010-05-13 17:38:43 +00:00
|
|
|
dma_addr_t dma_desc, dma_tmp;
|
2008-12-05 04:01:41 +00:00
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
struct pci_dev *pdev = priv->pdev;
|
2008-12-05 04:01:41 +00:00
|
|
|
void *buf;
|
|
|
|
u8 rx_desc_size;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
rx_desc_size = 8; /* 4*8 = 32 bytes */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((bufsize & 0xfff) != bufsize) {
|
|
|
|
DMESGE("RX buffer allocation too large");
|
2008-12-05 04:01:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256,
|
2008-12-05 04:01:41 +00:00
|
|
|
&dma_desc);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (dma_desc & 0xff)
|
2008-12-05 04:01:41 +00:00
|
|
|
/*
|
|
|
|
* descriptor's buffer must be 256 byte aligned
|
|
|
|
* should never happen since we specify the DMA mask
|
|
|
|
*/
|
2009-04-19 02:09:08 +00:00
|
|
|
WARN(1, "DMA buffer is not aligned\n");
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rxring = desc;
|
|
|
|
priv->rxringdma = dma_desc;
|
|
|
|
tmp = desc;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
2010-05-13 17:38:43 +00:00
|
|
|
buf = kmalloc(bufsize * sizeof(u8), GFP_ATOMIC);
|
2010-03-25 05:17:01 +00:00
|
|
|
if (buf == NULL) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("Failed to kmalloc RX buffer");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8),
|
2008-12-05 04:01:41 +00:00
|
|
|
PCI_DMA_FROMDEVICE);
|
2012-12-27 02:51:13 +00:00
|
|
|
if (pci_dma_mapping_error(pdev, dma_tmp))
|
|
|
|
return -1;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp,
|
|
|
|
&(priv->rxbufferhead))) {
|
|
|
|
DMESGE("Unable to allocate mem RX buf");
|
|
|
|
return -1;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
*tmp = 0; /* zero pads the header of the descriptor */
|
2010-05-13 17:38:43 +00:00
|
|
|
*tmp = *tmp | (bufsize&0xfff);
|
2008-12-05 04:01:41 +00:00
|
|
|
*(tmp+2) = (u32)dma_tmp;
|
2010-05-13 17:39:08 +00:00
|
|
|
*tmp = *tmp | (1<<31); /* descriptor void, owned by the NIC */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp = tmp+rx_desc_size;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
*(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void set_nic_rxring(struct net_device *dev)
|
|
|
|
{
|
|
|
|
u8 pgreg;
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
pgreg = read_nic_byte(dev, PGSELECT);
|
|
|
|
write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_dword(dev, RXRING_ADDR, priv->rxringdma);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_reset(struct net_device *dev)
|
|
|
|
{
|
|
|
|
u8 cr;
|
|
|
|
|
|
|
|
rtl8180_irq_disable(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
cr = read_nic_byte(dev, CMD);
|
2008-12-05 04:01:41 +00:00
|
|
|
cr = cr & 2;
|
|
|
|
cr = cr | (1<<CMD_RST_SHIFT);
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, CMD, cr);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
force_pci_posting(dev);
|
|
|
|
|
|
|
|
mdelay(200);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (read_nic_byte(dev, CMD) & (1<<CMD_RST_SHIFT))
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGW("Card reset timeout!");
|
|
|
|
else
|
|
|
|
DMESG("Card successfully reset");
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_LOAD);
|
2008-12-05 04:01:41 +00:00
|
|
|
force_pci_posting(dev);
|
|
|
|
mdelay(200);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline u16 ieeerate2rtlrate(int rate)
|
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (rate) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case 10:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 20:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 55:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 2;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 110:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 3;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 60:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 4;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 90:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 5;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 120:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 6;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 180:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 7;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 240:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 8;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 360:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 9;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 480:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 10;
|
2008-12-05 04:01:41 +00:00
|
|
|
case 540:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 11;
|
2008-12-05 04:01:41 +00:00
|
|
|
default:
|
2009-06-28 14:20:38 +00:00
|
|
|
return 3;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720};
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
inline u16 rtl8180_rate2rate(short rate)
|
|
|
|
{
|
2009-06-28 14:20:38 +00:00
|
|
|
if (rate > 12)
|
|
|
|
return 10;
|
2008-12-05 04:01:41 +00:00
|
|
|
return rtl_rate[rate];
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
inline u8 rtl8180_IsWirelessBMode(u16 rate)
|
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
if (((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220))
|
2008-12-05 04:01:41 +00:00
|
|
|
return 1;
|
2009-06-28 14:20:38 +00:00
|
|
|
else
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 N_DBPSOfRate(u16 DataRate);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
u16 ComputeTxTime(u16 FrameLength, u16 DataRate, u8 bManagementFrame,
|
|
|
|
u8 bShortPreamble)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
u16 FrameTime;
|
|
|
|
u16 N_DBPS;
|
|
|
|
u16 Ceiling;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (rtl8180_IsWirelessBMode(DataRate)) {
|
|
|
|
if (bManagementFrame || !bShortPreamble || DataRate == 10)
|
|
|
|
/* long preamble */
|
2008-12-05 04:01:41 +00:00
|
|
|
FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10)));
|
|
|
|
else
|
2009-06-28 14:20:38 +00:00
|
|
|
/* short preamble */
|
2008-12-05 04:01:41 +00:00
|
|
|
FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10)));
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
if ((FrameLength*8 % (DataRate/10)) != 0) /* get the ceilling */
|
|
|
|
FrameTime++;
|
|
|
|
} else { /* 802.11g DSSS-OFDM PLCP length field calculation. */
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 N_DBPSOfRate(u16 DataRate)
|
|
|
|
{
|
|
|
|
u16 N_DBPS = 24;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
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;
|
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
return N_DBPS;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
2012-04-17 13:56:43 +00:00
|
|
|
* For Netgear case, they want good-looking signal strength.
|
2010-05-13 17:39:08 +00:00
|
|
|
*/
|
2009-06-28 14:20:38 +00:00
|
|
|
long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
long RetSS;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Step 1. Scale mapping. */
|
2009-06-28 14:20:38 +00:00
|
|
|
if (CurrSS >= 71 && CurrSS <= 100)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 90 + ((CurrSS - 70) / 3);
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS >= 41 && CurrSS <= 70)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 78 + ((CurrSS - 40) / 3);
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS >= 31 && CurrSS <= 40)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 66 + (CurrSS - 30);
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS >= 21 && CurrSS <= 30)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 54 + (CurrSS - 20);
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS >= 5 && CurrSS <= 20)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 42 + (((CurrSS - 5) * 2) / 3);
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS == 4)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 36;
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS == 3)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 27;
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS == 2)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 18;
|
2009-06-28 14:20:38 +00:00
|
|
|
else if (CurrSS == 1)
|
2008-12-05 04:01:41 +00:00
|
|
|
RetSS = 9;
|
|
|
|
else
|
|
|
|
RetSS = CurrSS;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Step 2. Smoothing. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (LastSS > 0)
|
|
|
|
RetSS = ((LastSS * 5) + (RetSS) + 5) / 6;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return RetSS;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* Translate 0-100 signal strength index into dBm.
|
|
|
|
*/
|
2009-06-28 14:20:38 +00:00
|
|
|
long TranslateToDbm8185(u8 SignalStrengthIndex)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2009-06-28 14:20:38 +00:00
|
|
|
long SignalPower;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Translate to dBm (x=0.5y-95). */
|
2008-12-05 04:01:41 +00:00
|
|
|
SignalPower = (long)((SignalStrengthIndex + 1) >> 1);
|
|
|
|
SignalPower -= 95;
|
|
|
|
|
|
|
|
return SignalPower;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* Perform signal smoothing for dynamic mechanism.
|
2012-04-17 13:56:43 +00:00
|
|
|
* This is different with PerformSignalSmoothing8185 in smoothing formula.
|
2010-05-13 17:39:08 +00:00
|
|
|
* No dramatic adjustion is apply because dynamic mechanism need some degree
|
|
|
|
* of correctness. Ported from 8187B.
|
|
|
|
*/
|
2009-06-28 14:20:38 +00:00
|
|
|
void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv,
|
|
|
|
bool bCckRate)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Determin the current packet is CCK rate. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->bCurCCKPkt = bCckRate;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->UndecoratedSmoothedSS >= 0)
|
2012-03-14 22:26:59 +00:00
|
|
|
priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) +
|
|
|
|
(priv->SignalStrength * 10)) / 6;
|
2008-12-05 04:01:41 +00:00
|
|
|
else
|
|
|
|
priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
|
|
|
|
|
2012-03-14 22:26:59 +00:00
|
|
|
priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) +
|
|
|
|
(priv->RxPower * 11)) / 60;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (bCckRate)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->CurCCKRSSI = priv->RSSI;
|
|
|
|
else
|
|
|
|
priv->CurCCKRSSI = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* This is rough RX isr handling routine
|
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
void rtl8180_rx(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
struct sk_buff *tmp_skb;
|
2010-05-13 17:38:43 +00:00
|
|
|
short first, last;
|
2008-12-05 04:01:41 +00:00
|
|
|
u32 len;
|
|
|
|
int lastlen;
|
|
|
|
unsigned char quality, signal;
|
|
|
|
u8 rate;
|
2010-05-13 17:38:43 +00:00
|
|
|
u32 *tmp, *tmp2;
|
2008-12-05 04:01:41 +00:00
|
|
|
u8 rx_desc_size;
|
|
|
|
u8 padding;
|
|
|
|
char rxpower = 0;
|
|
|
|
u32 RXAGC = 0;
|
|
|
|
long RxAGC_dBm = 0;
|
2010-05-13 17:38:43 +00:00
|
|
|
u8 LNA = 0, BB = 0;
|
2010-04-08 21:04:17 +00:00
|
|
|
u8 LNA_gain[4] = {02, 17, 29, 39};
|
2008-12-05 04:01:41 +00:00
|
|
|
u8 Antenna = 0;
|
2009-07-13 18:01:44 +00:00
|
|
|
struct ieee80211_hdr_4addr *hdr;
|
2010-05-13 17:38:43 +00:00
|
|
|
u16 fc, type;
|
|
|
|
u8 bHwError = 0, bCRC = 0, bICV = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
bool bCckRate = false;
|
|
|
|
u8 RSSI = 0;
|
2009-06-28 14:20:38 +00:00
|
|
|
long SignalStrengthIndex = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
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
|
2010-05-13 17:39:08 +00:00
|
|
|
* we are pointing is empty */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->stats.rxnodata++;
|
|
|
|
priv->ieee80211->stats.rx_errors++;
|
|
|
|
|
|
|
|
tmp2 = NULL;
|
|
|
|
tmp = priv->rxringtail;
|
2010-05-13 17:38:43 +00:00
|
|
|
do {
|
|
|
|
if (tmp == priv->rxring)
|
2008-12-05 04:01:41 +00:00
|
|
|
tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
|
|
|
|
else
|
|
|
|
tmp -= rx_desc_size;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!(*tmp & (1<<31)))
|
2008-12-05 04:01:41 +00:00
|
|
|
tmp2 = tmp;
|
2010-05-13 17:38:43 +00:00
|
|
|
} while (tmp != priv->rxring);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (tmp2)
|
|
|
|
priv->rxringtail = tmp2;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* while there are filled descriptors */
|
2010-05-13 17:38:43 +00:00
|
|
|
while (!(*(priv->rxringtail) & (1<<31))) {
|
|
|
|
if (*(priv->rxringtail) & (1<<26))
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGW("RX buffer overflow");
|
2010-05-13 17:38:43 +00:00
|
|
|
if (*(priv->rxringtail) & (1<<12))
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxicverr++;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (*(priv->rxringtail) & (1<<27)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxdmafail++;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail); */
|
2008-12-05 04:01:41 +00:00
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
|
|
|
|
pci_dma_sync_single_for_cpu(priv->pdev,
|
|
|
|
priv->rxbuffer->dma,
|
2012-11-22 00:06:37 +00:00
|
|
|
priv->rxbuffersize * sizeof(u8),
|
2008-12-05 04:01:41 +00:00
|
|
|
PCI_DMA_FROMDEVICE);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
first = *(priv->rxringtail) & (1<<29) ? 1 : 0;
|
|
|
|
if (first)
|
|
|
|
priv->rx_prevlen = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
last = *(priv->rxringtail) & (1<<28) ? 1 : 0;
|
|
|
|
if (last) {
|
|
|
|
lastlen = ((*priv->rxringtail) & 0xfff);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
if (lastlen < priv->rx_prevlen)
|
|
|
|
len = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
else
|
2010-05-13 17:38:43 +00:00
|
|
|
len = lastlen-priv->rx_prevlen;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (*(priv->rxringtail) & (1<<13)) {
|
|
|
|
if ((*(priv->rxringtail) & 0xfff) < 500)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxcrcerrmin++;
|
2010-05-13 17:38:43 +00:00
|
|
|
else if ((*(priv->rxringtail) & 0x0fff) > 1000)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxcrcerrmax++;
|
|
|
|
else
|
|
|
|
priv->stats.rxcrcerrmid++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
} else {
|
2008-12-05 04:01:41 +00:00
|
|
|
len = priv->rxbuffersize;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (first && last) {
|
2008-12-05 04:01:41 +00:00
|
|
|
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
|
2010-05-13 17:38:43 +00:00
|
|
|
} else if (first) {
|
2008-12-05 04:01:41 +00:00
|
|
|
padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (padding)
|
2008-12-05 04:01:41 +00:00
|
|
|
len -= 2;
|
2010-05-13 17:38:43 +00:00
|
|
|
} else {
|
2008-12-05 04:01:41 +00:00
|
|
|
padding = 0;
|
|
|
|
}
|
2010-04-08 21:04:17 +00:00
|
|
|
padding = 0;
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rx_prevlen += len;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) {
|
2008-12-05 04:01:41 +00:00
|
|
|
/* HW is probably passing several buggy frames
|
|
|
|
* without FD or LD flag set.
|
|
|
|
* Throw this garbage away to prevent skb
|
2012-04-17 13:56:43 +00:00
|
|
|
* memory exhausting
|
2008-12-05 04:01:41 +00:00
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!priv->rx_skb_complete)
|
2008-12-05 04:01:41 +00:00
|
|
|
dev_kfree_skb_any(priv->rx_skb);
|
|
|
|
priv->rx_skb_complete = 1;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16);
|
2010-01-25 19:11:49 +00:00
|
|
|
signal = (signal & 0xfe) >> 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff));
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
stats.mac_time[0] = *(priv->rxringtail+1);
|
|
|
|
stats.mac_time[1] = *(priv->rxringtail+2);
|
2010-05-13 17:38:43 +00:00
|
|
|
rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42;
|
|
|
|
RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rate = ((*(priv->rxringtail)) &
|
2008-12-05 04:01:41 +00:00
|
|
|
((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
|
|
|
|
|
|
|
|
stats.rate = rtl8180_rate2rate(rate);
|
2010-05-13 17:38:43 +00:00
|
|
|
Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1;
|
2010-05-13 17:39:08 +00:00
|
|
|
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
|
|
|
|
RxAGC_dBm = rxpower+1; /* bias */
|
|
|
|
} else { /* CCK rate. */
|
|
|
|
RxAGC_dBm = signal; /* bit 0 discard */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */
|
|
|
|
BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
RxAGC_dBm += 4; /* bias */
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (RxAGC_dBm & 0x80) /* absolute value */
|
2010-05-13 17:38:43 +00:00
|
|
|
RXAGC = ~(RxAGC_dBm)+1;
|
2008-12-05 04:01:41 +00:00
|
|
|
bCckRate = rtl8180_IsWirelessBMode(stats.rate);
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Translate RXAGC into 1-100. */
|
|
|
|
if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (RXAGC > 90)
|
|
|
|
RXAGC = 90;
|
|
|
|
else if (RXAGC < 25)
|
|
|
|
RXAGC = 25;
|
|
|
|
RXAGC = (90-RXAGC)*100/65;
|
2010-05-13 17:39:08 +00:00
|
|
|
} else { /* CCK rate. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (RXAGC > 95)
|
|
|
|
RXAGC = 95;
|
|
|
|
else if (RXAGC < 30)
|
|
|
|
RXAGC = 30;
|
|
|
|
RXAGC = (95-RXAGC)*100/65;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
priv->SignalStrength = (u8)RXAGC;
|
2010-01-25 19:11:49 +00:00
|
|
|
priv->RecvSignalPower = RxAGC_dBm;
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->RxPower = rxpower;
|
|
|
|
priv->RSSI = RSSI;
|
2010-01-25 19:11:49 +00:00
|
|
|
/* SQ translation formula is provided by SD3 DZ. 2006.06.27 */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (quality >= 127)
|
2011-03-31 01:57:33 +00:00
|
|
|
quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */
|
2010-05-13 17:38:43 +00:00
|
|
|
else if (quality < 27)
|
2008-12-05 04:01:41 +00:00
|
|
|
quality = 100;
|
|
|
|
else
|
|
|
|
quality = 127 - quality;
|
|
|
|
priv->SignalQuality = quality;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */
|
2008-12-05 04:01:41 +00:00
|
|
|
stats.signalstrength = RXAGC;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (stats.signalstrength > 100)
|
2008-12-05 04:01:41 +00:00
|
|
|
stats.signalstrength = 100;
|
|
|
|
stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */
|
2008-12-05 04:01:41 +00:00
|
|
|
stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
|
2010-05-13 17:38:43 +00:00
|
|
|
stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual;
|
2012-03-14 22:26:59 +00:00
|
|
|
bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) |
|
|
|
|
(((*(priv->rxringtail)) & (0x04000000)) != 0) |
|
|
|
|
(((*(priv->rxringtail)) & (0x08000000)) != 0) |
|
|
|
|
(((~(*(priv->rxringtail))) & (0x10000000)) != 0) |
|
|
|
|
(((~(*(priv->rxringtail))) & (0x20000000)) != 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
|
|
|
|
bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
|
2009-07-13 18:01:44 +00:00
|
|
|
hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf;
|
2008-12-05 04:01:41 +00:00
|
|
|
fc = le16_to_cpu(hdr->frame_ctl);
|
2010-04-08 21:04:17 +00:00
|
|
|
type = WLAN_FC_GET_TYPE(fc);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-03-14 14:36:51 +00:00
|
|
|
if (IEEE80211_FTYPE_CTL != type &&
|
|
|
|
!bHwError && !bCRC && !bICV &&
|
|
|
|
eqMacAddr(priv->ieee80211->current_network.bssid,
|
2012-03-14 22:26:58 +00:00
|
|
|
fc & IEEE80211_FCTL_TODS ? hdr->addr1 :
|
|
|
|
fc & IEEE80211_FCTL_FROMDS ? hdr->addr2 :
|
|
|
|
hdr->addr3)) {
|
2012-03-14 22:26:57 +00:00
|
|
|
|
2012-03-14 14:36:51 +00:00
|
|
|
/* 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);
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
|
|
|
|
* so we record the correct power here.
|
|
|
|
*/
|
2012-03-14 14:36:51 +00:00
|
|
|
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;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-04-17 13:56:43 +00:00
|
|
|
/* Figure out which antenna that received the last packet. */
|
2012-03-14 14:36:51 +00:00
|
|
|
priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
|
|
|
|
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
|
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (first) {
|
|
|
|
if (!priv->rx_skb_complete) {
|
2012-04-17 13:56:43 +00:00
|
|
|
/* seems that HW sometimes fails to receive and
|
2008-12-05 04:01:41 +00:00
|
|
|
doesn't provide the last descriptor */
|
|
|
|
dev_kfree_skb_any(priv->rx_skb);
|
|
|
|
priv->stats.rxnolast++;
|
|
|
|
}
|
2012-11-13 17:28:21 +00:00
|
|
|
priv->rx_skb = dev_alloc_skb(len+2);
|
|
|
|
if (!priv->rx_skb)
|
|
|
|
goto drop;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rx_skb_complete = 0;
|
|
|
|
priv->rx_skb->dev = dev;
|
|
|
|
} else {
|
2012-04-17 13:56:43 +00:00
|
|
|
/* if we are here we should have already RXed
|
2008-12-05 04:01:41 +00:00
|
|
|
* 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....
|
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!priv->rx_skb_complete) {
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!tmp_skb)
|
|
|
|
goto drop;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
tmp_skb->dev = dev;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
memcpy(skb_put(tmp_skb, priv->rx_skb->len),
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->rx_skb->data,
|
|
|
|
priv->rx_skb->len);
|
|
|
|
|
|
|
|
dev_kfree_skb_any(priv->rx_skb);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rx_skb = tmp_skb;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-28 14:19:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!priv->rx_skb_complete) {
|
|
|
|
if (padding) {
|
|
|
|
memcpy(skb_put(priv->rx_skb, len),
|
|
|
|
(((unsigned char *)priv->rxbuffer->buf) + 2), len);
|
2008-12-05 04:01:41 +00:00
|
|
|
} else {
|
2010-05-13 17:38:43 +00:00
|
|
|
memcpy(skb_put(priv->rx_skb, len),
|
|
|
|
priv->rxbuffer->buf, len);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
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,
|
2010-01-25 19:11:49 +00:00
|
|
|
priv->rx_skb, &stats))
|
2008-12-05 04:01:41 +00:00
|
|
|
dev_kfree_skb_any(priv->rx_skb);
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rx_skb_complete = 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pci_dma_sync_single_for_device(priv->pdev,
|
|
|
|
priv->rxbuffer->dma,
|
2012-11-22 00:06:37 +00:00
|
|
|
priv->rxbuffersize * sizeof(u8),
|
2008-12-05 04:01:41 +00:00
|
|
|
PCI_DMA_FROMDEVICE);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
drop: /* this is used when we have not enough mem */
|
2008-12-05 04:01:41 +00:00
|
|
|
/* restore the descriptor */
|
2010-05-13 17:38:43 +00:00
|
|
|
*(priv->rxringtail+2) = priv->rxbuffer->dma;
|
|
|
|
*(priv->rxringtail) = *(priv->rxringtail) & ~0xfff;
|
|
|
|
*(priv->rxringtail) =
|
2008-12-05 04:01:41 +00:00
|
|
|
*(priv->rxringtail) | priv->rxbuffersize;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
*(priv->rxringtail) =
|
2008-12-05 04:01:41 +00:00
|
|
|
*(priv->rxringtail) | (1<<31);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rxringtail += rx_desc_size;
|
|
|
|
if (priv->rxringtail >=
|
|
|
|
(priv->rxring)+(priv->rxringcount)*rx_desc_size)
|
|
|
|
priv->rxringtail = priv->rxring;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->rxbuffer = (priv->rxbuffer->next);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rtl8180_dma_kick(struct net_device *dev, int priority)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
write_nic_byte(dev, TX_DMA_POLLING,
|
|
|
|
(1 << (priority + 1)) | priv->dma_poll_mask);
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
force_pci_posting(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_data_hard_stop(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ;
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_data_hard_resume(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ);
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask);
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* This function TX data frames when the ieee80211 stack requires this.
|
2008-12-05 04:01:41 +00:00
|
|
|
* It checks also if we need to stop the ieee tx queue, eventually do it
|
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int
|
|
|
|
rate) {
|
2008-12-05 04:01:41 +00:00
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
int mode;
|
2010-05-13 17:38:43 +00:00
|
|
|
struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
|
2010-01-14 19:13:47 +00:00
|
|
|
short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS;
|
2008-12-05 04:01:41 +00:00
|
|
|
unsigned long flags;
|
|
|
|
int priority;
|
|
|
|
|
|
|
|
mode = priv->ieee80211->iw_mode;
|
|
|
|
|
|
|
|
rate = ieeerate2rtlrate(rate);
|
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
priority = AC2Q(skb->priority);
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->bHwRadioOff) {
|
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!check_nic_enought_desc(dev, priority)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGW("Error: no descriptor left by previous TX (avail %d) ",
|
|
|
|
get_curr_tx_free_desc(dev, priority));
|
2009-12-16 23:16:00 +00:00
|
|
|
ieee80211_rtl_stop_queue(priv->ieee80211);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate);
|
2008-12-05 04:01:41 +00:00
|
|
|
if (!check_nic_enought_desc(dev, priority))
|
2009-12-16 23:16:00 +00:00
|
|
|
ieee80211_rtl_stop_queue(priv->ieee80211);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* This is a rough attempt to TX a frame
|
2008-12-05 04:01:41 +00:00
|
|
|
* This is called by the ieee 80211 stack to TX management frames.
|
2012-04-17 13:56:43 +00:00
|
|
|
* If the ring is full packets are dropped (for data frame the queue
|
2008-12-05 04:01:41 +00:00
|
|
|
* is stopped before this can happen). For this reason it is better
|
|
|
|
* if the descriptors are larger than the largest management frame
|
2012-04-17 13:56:43 +00:00
|
|
|
* we intend to TX: i'm unsure what the HW does if it will not find
|
2008-12-05 04:01:41 +00:00
|
|
|
* 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)
|
|
|
|
*/
|
2012-04-17 13:56:43 +00:00
|
|
|
/* these function may loop if invoked with 0 descriptors or 0 len buffer */
|
2010-05-13 17:38:43 +00:00
|
|
|
int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
unsigned long flags;
|
|
|
|
int priority;
|
|
|
|
|
|
|
|
priority = MANAGE_PRIORITY;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->ieee80211->bHwRadioOff) {
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
dev_kfree_skb_any(skb);
|
2009-07-06 02:23:38 +00:00
|
|
|
return NETDEV_TX_OK;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rtl8180_tx(dev, skb->data, skb->len, priority,
|
2010-05-13 17:38:43 +00:00
|
|
|
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->ieee80211->stats.tx_bytes += skb->len;
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->stats.tx_packets++;
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
dev_kfree_skb_any(skb);
|
2009-07-06 02:23:38 +00:00
|
|
|
return NETDEV_TX_OK;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* longpre 144+48 shortpre 72+24 */
|
2010-05-13 17:38:43 +00:00
|
|
|
u16 rtl8180_len2duration(u32 len, short rate, short *ext)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
u16 duration;
|
|
|
|
u16 drift;
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (rate) {
|
2010-05-13 17:39:08 +00:00
|
|
|
case 0: /* 1mbps */
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 0;
|
|
|
|
duration = ((len+4)<<4) / 0x2;
|
2008-12-05 04:01:41 +00:00
|
|
|
drift = ((len+4)<<4) % 0x2;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (drift == 0)
|
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
duration++;
|
|
|
|
break;
|
2010-05-13 17:39:08 +00:00
|
|
|
case 1: /* 2mbps */
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 0;
|
|
|
|
duration = ((len+4)<<4) / 0x4;
|
2008-12-05 04:01:41 +00:00
|
|
|
drift = ((len+4)<<4) % 0x4;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (drift == 0)
|
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
duration++;
|
|
|
|
break;
|
2010-05-13 17:39:08 +00:00
|
|
|
case 2: /* 5.5mbps */
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 0;
|
|
|
|
duration = ((len+4)<<4) / 0xb;
|
2008-12-05 04:01:41 +00:00
|
|
|
drift = ((len+4)<<4) % 0xb;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (drift == 0)
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
duration++;
|
|
|
|
break;
|
|
|
|
default:
|
2010-05-13 17:39:08 +00:00
|
|
|
case 3: /* 11mbps */
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 0;
|
|
|
|
duration = ((len+4)<<4) / 0x16;
|
2008-12-05 04:01:41 +00:00
|
|
|
drift = ((len+4)<<4) % 0x16;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (drift == 0)
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
|
|
|
duration++;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (drift > 6)
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
2010-05-13 17:38:43 +00:00
|
|
|
*ext = 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
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);
|
2010-05-13 17:39:08 +00:00
|
|
|
word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */
|
|
|
|
word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */
|
2008-12-05 04:01:41 +00:00
|
|
|
write_nic_word(dev, BcnItv, word);
|
|
|
|
|
|
|
|
skb = ieee80211_get_beacon(priv->ieee80211);
|
2010-05-13 17:38:43 +00:00
|
|
|
if (skb) {
|
|
|
|
rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY,
|
|
|
|
0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate));
|
2008-12-05 04:01:41 +00:00
|
|
|
dev_kfree_skb_any(skb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* This function do the real dirty work: it enqueues a TX command
|
2008-12-05 04:01:41 +00:00
|
|
|
* descriptor in the ring buffer, copyes the frame in a TX buffer
|
|
|
|
* and kicks the NIC to ensure it does the DMA transfer.
|
|
|
|
*/
|
2012-11-22 00:06:50 +00:00
|
|
|
short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority,
|
2008-12-05 04:01:41 +00:00
|
|
|
short morefrag, short descfrag, int rate)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
u32 *tail, *temp_tail;
|
2008-12-05 04:01:41 +00:00
|
|
|
u32 *begin;
|
|
|
|
u32 *buf;
|
|
|
|
int i;
|
|
|
|
int remain;
|
|
|
|
int buflen;
|
|
|
|
int count;
|
2010-05-13 17:38:43 +00:00
|
|
|
struct buffer *buflist;
|
2008-12-05 04:01:41 +00:00
|
|
|
struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
|
|
|
|
u8 dest[ETH_ALEN];
|
|
|
|
u8 bUseShortPreamble = 0;
|
|
|
|
u8 bCTSEnable = 0;
|
|
|
|
u8 bRTSEnable = 0;
|
2010-04-08 21:04:17 +00:00
|
|
|
u16 Duration = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 RtsDur = 0;
|
|
|
|
u16 ThisFrameTime = 0;
|
|
|
|
u16 TxDescDuration = 0;
|
2010-04-08 21:04:17 +00:00
|
|
|
u8 ownbit_flag = false;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (priority) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case MANAGE_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txmapringtail;
|
|
|
|
begin = priv->txmapring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txmapbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case BK_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txbkpringtail;
|
|
|
|
begin = priv->txbkpring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txbkpbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case BE_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txbepringtail;
|
|
|
|
begin = priv->txbepring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txbepbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case VI_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txvipringtail;
|
|
|
|
begin = priv->txvipring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txvipbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case VO_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txvopringtail;
|
|
|
|
begin = priv->txvopring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txvopbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case HI_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txhpringtail;
|
|
|
|
begin = priv->txhpring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txhpbufstail;
|
|
|
|
count = priv->txringcount;
|
|
|
|
break;
|
|
|
|
case BEACON_PRIORITY:
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = priv->txbeaconringtail;
|
|
|
|
begin = priv->txbeaconring;
|
2008-12-05 04:01:41 +00:00
|
|
|
buflist = priv->txbeaconbufstail;
|
|
|
|
count = priv->txbeaconcount;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
break;
|
2010-04-08 21:04:17 +00:00
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
|
2012-05-08 17:11:56 +00:00
|
|
|
if (is_multicast_ether_addr(dest)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
Duration = 0;
|
|
|
|
RtsDur = 0;
|
|
|
|
bRTSEnable = 0;
|
|
|
|
bCTSEnable = 0;
|
|
|
|
|
2012-03-14 22:26:59 +00:00
|
|
|
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
|
|
|
|
0, bUseShortPreamble);
|
2008-12-05 04:01:41 +00:00
|
|
|
TxDescDuration = ThisFrameTime;
|
2010-05-13 17:39:08 +00:00
|
|
|
} else { /* Unicast packet */
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 AckTime;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828,for Keep alive */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->NumTxUnicast++;
|
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* Figure out ACK rate according to BSS basic rate
|
|
|
|
* and Tx rate. */
|
2010-05-13 17:39:08 +00:00
|
|
|
AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 RtsTime, CtsTime;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* u16 CtsRate; */
|
2008-12-05 04:01:41 +00:00
|
|
|
bRTSEnable = 1;
|
|
|
|
bCTSEnable = 0;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Rate and time required for RTS. */
|
2010-05-13 17:38:43 +00:00
|
|
|
RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0);
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Rate and time required for CTS. */
|
|
|
|
CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Figure out time required to transmit this frame. */
|
2008-12-05 04:01:41 +00:00
|
|
|
ThisFrameTime = ComputeTxTime(len + sCrcLng,
|
|
|
|
rtl8180_rate2rate(rate),
|
|
|
|
0,
|
|
|
|
bUseShortPreamble);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* RTS-CTS-ThisFrame-ACK. */
|
2008-12-05 04:01:41 +00:00
|
|
|
RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
|
|
|
|
|
|
|
|
TxDescDuration = RtsTime + RtsDur;
|
2010-05-13 17:39:08 +00:00
|
|
|
} else { /* Normal case. */
|
2008-12-05 04:01:41 +00:00
|
|
|
bCTSEnable = 0;
|
|
|
|
bRTSEnable = 0;
|
|
|
|
RtsDur = 0;
|
|
|
|
|
2012-03-14 22:26:59 +00:00
|
|
|
ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate),
|
|
|
|
0, bUseShortPreamble);
|
2008-12-05 04:01:41 +00:00
|
|
|
TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
|
|
|
|
}
|
|
|
|
|
2010-01-14 19:13:47 +00:00
|
|
|
if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) {
|
2010-05-13 17:39:08 +00:00
|
|
|
/* ThisFrame-ACK. */
|
2008-12-05 04:01:41 +00:00
|
|
|
Duration = aSifsTime + AckTime;
|
2010-05-13 17:39:08 +00:00
|
|
|
} else { /* One or more fragments remained. */
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 NextFragTime;
|
2010-05-13 17:39:08 +00:00
|
|
|
NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_rate2rate(rate),
|
|
|
|
0,
|
2010-05-13 17:38:43 +00:00
|
|
|
bUseShortPreamble);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* ThisFrag-ACk-NextFrag-ACK. */
|
2008-12-05 04:01:41 +00:00
|
|
|
Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
} /* End of Unicast packet */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
frag_hdr->duration_id = Duration;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
buflen = priv->txbuffsize;
|
|
|
|
remain = len;
|
2008-12-05 04:01:41 +00:00
|
|
|
temp_tail = tail;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
while (remain != 0) {
|
2008-12-05 04:01:41 +00:00
|
|
|
mb();
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!buflist) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
|
|
|
|
return -1;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
buf = buflist->buf;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) {
|
|
|
|
DMESGW("No more TX desc, returning %x of %x",
|
|
|
|
remain, len);
|
|
|
|
priv->stats.txrdu++;
|
2008-12-05 04:01:41 +00:00
|
|
|
return remain;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
*tail = 0; /* zeroes header */
|
2008-12-05 04:01:41 +00:00
|
|
|
*(tail+1) = 0;
|
|
|
|
*(tail+3) = 0;
|
|
|
|
*(tail+5) = 0;
|
|
|
|
*(tail+6) = 0;
|
|
|
|
*(tail+7) = 0;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* FIXME: this should be triggered by HW encryption parameters.*/
|
2009-11-09 16:53:20 +00:00
|
|
|
*tail |= (1<<15); /* no encrypt */
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (remain == len && !descfrag) {
|
2010-01-25 19:11:49 +00:00
|
|
|
ownbit_flag = false;
|
2010-05-13 17:39:08 +00:00
|
|
|
*tail = *tail | (1<<29) ; /* fist segment of the packet */
|
2010-05-13 17:38:43 +00:00
|
|
|
*tail = *tail | (len);
|
2008-12-05 04:01:41 +00:00
|
|
|
} else {
|
|
|
|
ownbit_flag = true;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 0; i < buflen && remain > 0; i++, remain--) {
|
2010-05-13 17:39:08 +00:00
|
|
|
((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (remain == 4 && i+4 >= buflen)
|
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
/* ensure the last desc has at least 4 bytes payload */
|
|
|
|
|
|
|
|
}
|
|
|
|
txbuf = txbuf + i;
|
2010-05-13 17:38:43 +00:00
|
|
|
*(tail+3) = *(tail+3) & ~0xfff;
|
2010-05-13 17:39:08 +00:00
|
|
|
*(tail+3) = *(tail+3) | i; /* buffer length */
|
|
|
|
/* Use short preamble or not */
|
2008-12-05 04:01:41 +00:00
|
|
|
if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
|
2010-05-13 17:39:08 +00:00
|
|
|
if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */
|
|
|
|
; /* *tail |= (1<<16); */ /* enable short preamble mode. */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (bCTSEnable)
|
2008-12-05 04:01:41 +00:00
|
|
|
*tail |= (1<<18);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (bRTSEnable) { /* rts enable */
|
|
|
|
*tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */
|
|
|
|
*tail |= (1<<23); /* rts enable */
|
|
|
|
*(tail+1) |= (RtsDur&0xffff); /* RTS Duration */
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
*(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */
|
|
|
|
/* *(tail+3) |= (0xe6<<16); */
|
|
|
|
*(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
*tail = *tail | ((rate&0xf) << 24);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (morefrag)
|
2010-05-13 17:39:08 +00:00
|
|
|
*tail = (*tail) | (1<<17); /* more fragment */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!remain)
|
2010-05-13 17:39:08 +00:00
|
|
|
*tail = (*tail) | (1<<28); /* last segment of frame */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-04-08 21:04:17 +00:00
|
|
|
*(tail+5) = *(tail+5)|(2<<27);
|
|
|
|
*(tail+7) = *(tail+7)|(1<<4);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
wmb();
|
2010-05-13 17:38:43 +00:00
|
|
|
if (ownbit_flag)
|
2010-05-13 17:39:08 +00:00
|
|
|
*tail = *tail | (1<<31); /* descriptor ready to be txed */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((tail - begin)/8 == count-1)
|
|
|
|
tail = begin;
|
2008-12-05 04:01:41 +00:00
|
|
|
else
|
2010-05-13 17:38:43 +00:00
|
|
|
tail = tail+8;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
buflist = buflist->next;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
mb();
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
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:
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* The HW seems to be happy with the 1st
|
2010-05-13 17:38:43 +00:00
|
|
|
* descriptor filled and the 2nd empty...
|
|
|
|
* So always update descriptor 1 and never
|
|
|
|
* touch 2nd
|
|
|
|
*/
|
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
*temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_dma_kick(dev, priority);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_irq_rx_tasklet(struct r8180_priv *priv);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
rtl8180_update_msr(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]);
|
|
|
|
write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-11-13 17:28:22 +00:00
|
|
|
beacon_interval = read_nic_word(dev, BEACON_INTERVAL);
|
2010-05-13 17:38:43 +00:00
|
|
|
beacon_interval &= ~BEACON_INTERVAL_MASK;
|
2008-12-05 04:01:41 +00:00
|
|
|
beacon_interval |= net->beacon_interval;
|
2012-11-13 17:28:22 +00:00
|
|
|
write_nic_word(dev, BEACON_INTERVAL, beacon_interval);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
|
|
2009-11-09 16:53:20 +00:00
|
|
|
rtl8180_set_chan(dev, priv->chan);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_rq_tx_ack(struct net_device *dev)
|
|
|
|
{
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ack_tx_to_ieee = 1;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
short rtl8180_is_tx_queue_empty(struct net_device *dev)
|
|
|
|
{
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
u32 *d;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txmapring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txmapring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txbkpring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txbkpring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txbepring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txbepring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txvipring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txvipring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txvopring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txvopring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
for (d = priv->txhpring;
|
2010-05-13 17:38:43 +00:00
|
|
|
d < priv->txhpring + priv->txringcount; d += 8)
|
|
|
|
if (*d & (1<<31))
|
|
|
|
return 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_hw_wakeup(struct net_device *dev)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->ps_lock, flags);
|
|
|
|
write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT);
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->rf_wakeup)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->rf_wakeup(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_hw_sleep_down(struct net_device *dev)
|
|
|
|
{
|
2010-04-08 21:04:17 +00:00
|
|
|
unsigned long flags;
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-04-08 21:04:17 +00:00
|
|
|
spin_lock_irqsave(&priv->ps_lock, flags);
|
|
|
|
if (priv->rf_sleep)
|
|
|
|
priv->rf_sleep(dev);
|
|
|
|
spin_unlock_irqrestore(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* Writing HW register with 0 equals to disable
|
2008-12-05 04:01:41 +00:00
|
|
|
* the timer, that is not really what we want
|
|
|
|
*/
|
|
|
|
tl -= MSECS(4+16+7);
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* If the interval in witch we are requested to sleep is too
|
2008-12-05 04:01:41 +00:00
|
|
|
* short then give up and remain awake
|
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME))
|
|
|
|
|| ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
|
|
|
|
spin_unlock_irqrestore(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
printk("too short to sleep\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
|
2012-03-14 22:26:59 +00:00
|
|
|
/* as tl may be less than rb */
|
|
|
|
queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* If we suspect the TimerInt is gone beyond tl
|
2008-12-05 04:01:41 +00:00
|
|
|
* while setting it, then give up
|
|
|
|
*/
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) ||
|
2008-12-05 04:01:41 +00:00
|
|
|
((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->ps_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_wmm_param_update(struct work_struct *work)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq);
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!ieee->current_network.QoS_Enable) {
|
2010-05-13 17:39:08 +00:00
|
|
|
/* legacy ac_xx_param update */
|
2008-12-05 04:01:41 +00:00
|
|
|
AcParam.longData = 0;
|
2010-05-13 17:39:08 +00:00
|
|
|
AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
|
2008-12-05 04:01:41 +00:00
|
|
|
AcParam.f.AciAifsn.f.ACM = 0;
|
2010-05-13 17:39:08 +00:00
|
|
|
AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */
|
|
|
|
AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */
|
2008-12-05 04:01:41 +00:00
|
|
|
AcParam.f.TXOPLimit = 0;
|
2010-05-13 17:38:43 +00:00
|
|
|
for (eACI = 0; eACI < AC_MAX; eACI++) {
|
2008-12-05 04:01:41 +00:00
|
|
|
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
|
|
|
|
{
|
|
|
|
u8 u1bAIFS;
|
|
|
|
u32 u4bAcParam;
|
|
|
|
pAcParam = (PAC_PARAM)(&AcParam);
|
2012-08-09 16:06:54 +00:00
|
|
|
/* Retrieve parameters to update. */
|
2010-05-13 17:38:43 +00:00
|
|
|
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
|
2008-12-05 04:01:41 +00:00
|
|
|
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));
|
2010-05-13 17:38:43 +00:00
|
|
|
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:
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_warn("SetHwReg8185():invalid ACI: %d!\n",
|
|
|
|
eACI);
|
2010-05-13 17:38:43 +00:00
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 0; i < AC_MAX; i++) {
|
2010-05-13 17:39:08 +00:00
|
|
|
/* AcParam.longData = 0; */
|
2010-05-13 17:38:43 +00:00
|
|
|
pAcParam = (AC_PARAM *)ac_param;
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
AC_CODING eACI;
|
|
|
|
u8 u1bAIFS;
|
|
|
|
u32 u4bAcParam;
|
|
|
|
|
2012-08-09 16:06:54 +00:00
|
|
|
/* Retrieve parameters to update. */
|
2008-12-05 04:01:41 +00:00
|
|
|
eACI = pAcParam->f.AciAifsn.f.ACI;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
|
2010-05-13 17:38:43 +00:00
|
|
|
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
|
|
|
|
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
|
2008-12-05 04:01:41 +00:00
|
|
|
(((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));
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
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:
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_warn("SetHwReg8185(): invalid ACI: %d !\n",
|
|
|
|
eACI);
|
2010-05-13 17:38:43 +00:00
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ac_param += (sizeof(AC_PARAM));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_restart_wq(struct work_struct *work);
|
2010-05-13 17:39:08 +00:00
|
|
|
/* void rtl8180_rq_tx_ack(struct work_struct *work); */
|
2008-12-05 04:01:41 +00:00
|
|
|
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);
|
2009-06-13 16:30:28 +00:00
|
|
|
void rtl8180_watch_dog(struct net_device *dev);
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
void watch_dog_adaptive(unsigned long data)
|
|
|
|
{
|
2012-11-22 00:06:50 +00:00
|
|
|
struct r8180_priv *priv = ieee80211_priv((struct net_device *)data);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
if (!priv->up) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("<----watch_dog_adaptive():driver is not up!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Tx High Power Mechanism. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (CheckHighPower((struct net_device *)data))
|
2008-12-05 04:01:41 +00:00
|
|
|
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Tx Power Tracking on 87SE. */
|
2010-01-18 11:23:20 +00:00
|
|
|
if (CheckTxPwrTracking((struct net_device *)data))
|
2008-12-05 04:01:41 +00:00
|
|
|
TxPwrTracking87SE((struct net_device *)data);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Perform DIG immediately. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (CheckDig((struct net_device *)data) == true)
|
2008-12-05 04:01:41 +00:00
|
|
|
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_watch_dog((struct net_device *)data);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
|
2008-12-05 04:01:41 +00:00
|
|
|
add_timer(&priv->watch_dog_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CHANNEL_LIST ChannelPlan[] = {
|
2010-05-13 17:39:08 +00:00
|
|
|
{{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 */
|
2008-12-05 04:01:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* lzm add 080826 */
|
2010-05-13 17:38:43 +00:00
|
|
|
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:
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
Dot11d_Init(ieee);
|
|
|
|
ieee->bGlobalDomain = false;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (ChannelPlan[channel_plan].Len != 0) {
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Clear old channel map */
|
2008-12-05 04:01:41 +00:00
|
|
|
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Set new channel map */
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 0; i < ChannelPlan[channel_plan].Len; i++) {
|
|
|
|
if (ChannelPlan[channel_plan].Channel[i] <= 14)
|
2008-12-05 04:01:41 +00:00
|
|
|
GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
case COUNTRY_CODE_GLOBAL_DOMAIN:
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
GET_DOT11D_INFO(ieee)->bEnabled = 0;
|
|
|
|
Dot11d_Reset(ieee);
|
|
|
|
ieee->bGlobalDomain = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
case COUNTRY_CODE_WORLD_WIDE_13_INDEX:/* lzm add 080826 */
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
ieee->MinPassiveChnlNum = 12;
|
|
|
|
ieee->IbssStartChnl = 10;
|
|
|
|
break;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
default:
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
Dot11d_Init(ieee);
|
|
|
|
ieee->bGlobalDomain = false;
|
|
|
|
memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 1; i <= 14; i++)
|
2008-12-05 04:01:41 +00:00
|
|
|
GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828 */
|
2008-12-05 04:01:41 +00:00
|
|
|
static void rtl8180_statistics_init(struct Stats *pstats)
|
|
|
|
{
|
|
|
|
memset(pstats, 0, sizeof(struct Stats));
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828,end */
|
2010-02-11 18:07:35 +00:00
|
|
|
static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom)
|
|
|
|
{
|
|
|
|
struct net_device *dev = eeprom->data;
|
|
|
|
u8 reg = read_nic_byte(dev, EPROM_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 rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom)
|
|
|
|
{
|
|
|
|
struct net_device *dev = eeprom->data;
|
|
|
|
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;
|
|
|
|
|
|
|
|
write_nic_byte(dev, EPROM_CMD, reg);
|
|
|
|
read_nic_byte(dev, EPROM_CMD);
|
|
|
|
udelay(10);
|
|
|
|
}
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
short rtl8180_init(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
u16 word;
|
2012-11-13 17:28:20 +00:00
|
|
|
u16 usValue;
|
2008-12-05 04:01:41 +00:00
|
|
|
u16 tmpu16;
|
|
|
|
int i, j;
|
2010-02-11 18:07:35 +00:00
|
|
|
struct eeprom_93cx6 eeprom;
|
|
|
|
u16 eeprom_val;
|
|
|
|
|
|
|
|
eeprom.data = dev;
|
|
|
|
eeprom.register_read = rtl8187se_eeprom_register_read;
|
|
|
|
eeprom.register_write = rtl8187se_eeprom_register_write;
|
|
|
|
eeprom.width = PCI_EEPROM_WIDTH_93C46;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-02-11 18:07:35 +00:00
|
|
|
eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val);
|
|
|
|
priv->channel_plan = eeprom_val & 0xFF;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) {
|
2008-12-05 04:01:41 +00:00
|
|
|
printk("rtl8180_init:Error channel plan! Set to default.\n");
|
|
|
|
priv->channel_plan = 0;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
DMESG("Channel plan is %d\n", priv->channel_plan);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* FIXME: these constants are placed in a bad pleace. */
|
|
|
|
priv->txbuffsize = 2048; /* 1024; */
|
|
|
|
priv->txringcount = 32; /* 32; */
|
|
|
|
priv->rxbuffersize = 2048; /* 1024; */
|
|
|
|
priv->rxringcount = 64; /* 32; */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->txbeaconcount = 2;
|
|
|
|
priv->rx_skb_complete = 1;
|
|
|
|
|
|
|
|
priv->RFChangeInProgress = false;
|
|
|
|
priv->SetRFPowerStateInProgress = false;
|
|
|
|
priv->RFProgType = 0;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->irq_enabled = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
rtl8180_statistics_init(&priv->stats);
|
|
|
|
rtl8180_link_detect_init(&priv->link_detect);
|
|
|
|
|
|
|
|
priv->ack_tx_to_ieee = 0;
|
|
|
|
priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL;
|
|
|
|
priv->ieee80211->iw_mode = IW_MODE_INFRA;
|
|
|
|
priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN |
|
|
|
|
IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ |
|
|
|
|
IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE;
|
|
|
|
priv->ieee80211->active_scan = 1;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->ieee80211->rate = 110; /* 11 mbps */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->modulation = IEEE80211_CCK_MODULATION;
|
|
|
|
priv->ieee80211->host_encrypt = 1;
|
|
|
|
priv->ieee80211->host_decrypt = 1;
|
|
|
|
priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup;
|
|
|
|
priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack;
|
|
|
|
priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep;
|
|
|
|
priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty;
|
|
|
|
|
|
|
|
priv->hw_wep = hwwep;
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->dev = dev;
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->retry_rts = DEFAULT_RETRY_RTS;
|
|
|
|
priv->retry_data = DEFAULT_RETRY_DATA;
|
|
|
|
priv->RFChangeInProgress = false;
|
|
|
|
priv->SetRFPowerStateInProgress = false;
|
|
|
|
priv->RFProgType = 0;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->bInactivePs = true; /* false; */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->bInactivePs = priv->bInactivePs;
|
|
|
|
priv->bSwRfProcessing = false;
|
|
|
|
priv->eRFPowerState = eRfOff;
|
|
|
|
priv->RfOffReason = 0;
|
|
|
|
priv->LedStrategy = SW_LED_MODE0;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->TxPollingTimes = 0; /* lzm add 080826 */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->bLeisurePs = true;
|
|
|
|
priv->dot11PowerSaveMode = eActive;
|
|
|
|
priv->AdMinCheckPeriod = 5;
|
|
|
|
priv->AdMaxCheckPeriod = 10;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->AdMaxRxSsThreshold = 30; /* 60->30 */
|
|
|
|
priv->AdRxSsThreshold = 20; /* 50->20 */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->AdCheckPeriod = priv->AdMinCheckPeriod;
|
|
|
|
priv->AdTickCount = 0;
|
|
|
|
priv->AdRxSignalStrength = -1;
|
|
|
|
priv->RegSwAntennaDiversityMechanism = 0;
|
|
|
|
priv->RegDefaultAntenna = 0;
|
|
|
|
priv->SignalStrength = 0;
|
|
|
|
priv->AdRxOkCnt = 0;
|
|
|
|
priv->CurrAntennaIndex = 0;
|
|
|
|
priv->AdRxSsBeforeSwitched = 0;
|
|
|
|
init_timer(&priv->SwAntennaDiversityTimer);
|
|
|
|
priv->SwAntennaDiversityTimer.data = (unsigned long)dev;
|
|
|
|
priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback;
|
|
|
|
priv->bDigMechanism = 1;
|
|
|
|
priv->InitialGain = 6;
|
|
|
|
priv->bXtalCalibration = false;
|
|
|
|
priv->XtalCal_Xin = 0;
|
|
|
|
priv->XtalCal_Xout = 0;
|
|
|
|
priv->bTxPowerTrack = false;
|
|
|
|
priv->ThermalMeter = 0;
|
|
|
|
priv->FalseAlarmRegValue = 0;
|
2012-04-17 13:56:43 +00:00
|
|
|
priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->DIG_NumberFallbackVote = 0;
|
|
|
|
priv->DIG_NumberUpgradeVote = 0;
|
|
|
|
priv->LastSignalStrengthInPercent = 0;
|
|
|
|
priv->Stats_SignalStrength = 0;
|
|
|
|
priv->LastRxPktAntenna = 0;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->SignalQuality = 0; /* in 0-100 index. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->Stats_SignalQuality = 0;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->RecvSignalPower = 0; /* in dBm. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->Stats_RecvSignalPower = 0;
|
|
|
|
priv->AdMainAntennaRxOkCnt = 0;
|
|
|
|
priv->AdAuxAntennaRxOkCnt = 0;
|
|
|
|
priv->bHWAdSwitched = false;
|
|
|
|
priv->bRegHighPowerMechanism = true;
|
|
|
|
priv->RegHiPwrUpperTh = 77;
|
|
|
|
priv->RegHiPwrLowerTh = 75;
|
|
|
|
priv->RegRSSIHiPwrUpperTh = 70;
|
|
|
|
priv->RegRSSIHiPwrLowerTh = 20;
|
|
|
|
priv->bCurCCKPkt = false;
|
|
|
|
priv->UndecoratedSmoothedSS = -1;
|
|
|
|
priv->bToUpdateTxPwr = false;
|
|
|
|
priv->CurCCKRSSI = 0;
|
|
|
|
priv->RxPower = 0;
|
|
|
|
priv->RSSI = 0;
|
|
|
|
priv->NumTxOkTotal = 0;
|
|
|
|
priv->NumTxUnicast = 0;
|
|
|
|
priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
|
2010-01-25 19:11:49 +00:00
|
|
|
priv->CurrRetryCnt = 0;
|
|
|
|
priv->LastRetryCnt = 0;
|
|
|
|
priv->LastTxokCnt = 0;
|
|
|
|
priv->LastRxokCnt = 0;
|
|
|
|
priv->LastRetryRate = 0;
|
|
|
|
priv->bTryuping = 0;
|
|
|
|
priv->CurrTxRate = 0;
|
|
|
|
priv->CurrRetryRate = 0;
|
|
|
|
priv->TryupingCount = 0;
|
|
|
|
priv->TryupingCountNoData = 0;
|
|
|
|
priv->TryDownCountLowData = 0;
|
|
|
|
priv->LastTxOKBytes = 0;
|
|
|
|
priv->LastFailTxRate = 0;
|
|
|
|
priv->LastFailTxRateSS = 0;
|
|
|
|
priv->FailTxRateCount = 0;
|
|
|
|
priv->LastTxThroughput = 0;
|
|
|
|
priv->NumTxOkBytesTotal = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ForcedDataRate = 0;
|
|
|
|
priv->RegBModeGainStage = 1;
|
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
spin_lock_init(&priv->irq_th_lock);
|
|
|
|
spin_lock_init(&priv->tx_lock);
|
|
|
|
spin_lock_init(&priv->ps_lock);
|
|
|
|
spin_lock_init(&priv->rf_ps_lock);
|
2010-01-25 19:11:49 +00:00
|
|
|
sema_init(&priv->wx_sem, 1);
|
|
|
|
INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq,
|
|
|
|
(void *)rtl8180_hw_wakeup_wq);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq,
|
|
|
|
(void *)rtl8180_hw_sleep_wq);
|
|
|
|
INIT_WORK(&priv->ieee80211->wmm_param_update_wq,
|
|
|
|
(void *)rtl8180_wmm_param_update);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq,
|
|
|
|
(void *)rtl8180_rate_adapter);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,
|
|
|
|
(void *)rtl8180_hw_dig_wq);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,
|
|
|
|
(void *)rtl8180_tx_pw_wq);
|
|
|
|
INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,
|
|
|
|
(void *) GPIOChangeRFWorkItemCallBack);
|
2008-12-05 04:01:41 +00:00
|
|
|
tasklet_init(&priv->irq_rx_tasklet,
|
|
|
|
(void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
|
|
|
|
(unsigned long)priv);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
init_timer(&priv->watch_dog_timer);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->watch_dog_timer.data = (unsigned long)dev;
|
|
|
|
priv->watch_dog_timer.function = watch_dog_adaptive;
|
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
init_timer(&priv->rateadapter_timer);
|
|
|
|
priv->rateadapter_timer.data = (unsigned long)dev;
|
|
|
|
priv->rateadapter_timer.function = timer_rate_adaptive;
|
|
|
|
priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD;
|
|
|
|
priv->bEnhanceTxPwr = false;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit;
|
|
|
|
priv->ieee80211->set_chan = rtl8180_set_chan;
|
|
|
|
priv->ieee80211->link_change = rtl8180_link_change;
|
|
|
|
priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit;
|
|
|
|
priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop;
|
|
|
|
priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume;
|
|
|
|
|
2010-04-08 21:04:17 +00:00
|
|
|
priv->ieee80211->init_wmmparam_flag = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon;
|
|
|
|
priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable;
|
|
|
|
priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
|
|
|
|
|
|
|
|
priv->ShortRetryLimit = 7;
|
|
|
|
priv->LongRetryLimit = 7;
|
|
|
|
priv->EarlyRxThreshold = 7;
|
|
|
|
|
2012-11-13 17:28:16 +00:00
|
|
|
priv->TransmitConfig = (1<<TCR_DurProcMode_OFFSET) |
|
2010-01-25 19:11:49 +00:00
|
|
|
(7<<TCR_MXDMA_OFFSET) |
|
|
|
|
(priv->ShortRetryLimit<<TCR_SRL_OFFSET) |
|
2012-11-13 17:28:16 +00:00
|
|
|
(priv->LongRetryLimit<<TCR_LRL_OFFSET);
|
2010-01-25 19:11:49 +00:00
|
|
|
|
|
|
|
priv->ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF |
|
|
|
|
RCR_AB | RCR_AM | RCR_APM |
|
|
|
|
(7<<RCR_MXDMA_OFFSET) |
|
|
|
|
(priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) |
|
|
|
|
(priv->EarlyRxThreshold == 7 ?
|
|
|
|
RCR_ONLYERLPKT : 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER |
|
2010-01-25 19:11:49 +00:00
|
|
|
IMR_THPDER | IMR_THPDOK |
|
|
|
|
IMR_TVODER | IMR_TVODOK |
|
|
|
|
IMR_TVIDER | IMR_TVIDOK |
|
|
|
|
IMR_TBEDER | IMR_TBEDOK |
|
|
|
|
IMR_TBKDER | IMR_TBKDOK |
|
|
|
|
IMR_RDU |
|
|
|
|
IMR_RER | IMR_ROK |
|
|
|
|
IMR_RQoSOK;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->InitialGain = 6;
|
|
|
|
|
2009-11-09 16:53:20 +00:00
|
|
|
DMESG("MAC controller is a RTL8187SE b/g");
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-11-09 16:53:20 +00:00
|
|
|
priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION;
|
|
|
|
priv->ieee80211->short_slot = 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-11-13 17:28:20 +00:00
|
|
|
eeprom_93cx6_read(&eeprom, EEPROM_SW_REVD_OFFSET, &usValue);
|
|
|
|
DMESG("usValue is %#hx\n", usValue);
|
2010-05-13 17:39:08 +00:00
|
|
|
/* 3Read AntennaDiversity */
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* SW Antenna Diversity. */
|
2012-11-13 17:28:20 +00:00
|
|
|
priv->EEPROMSwAntennaDiversity = (usValue & EEPROM_SW_AD_MASK) ==
|
|
|
|
EEPROM_SW_AD_ENABLE;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Default Antenna to use. */
|
2012-11-13 17:28:20 +00:00
|
|
|
priv->EEPROMDefaultAntenna1 = (usValue & EEPROM_DEF_ANT_MASK) ==
|
|
|
|
EEPROM_DEF_ANT_1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (priv->RegSwAntennaDiversityMechanism == 0) /* Auto */
|
2009-06-28 14:20:38 +00:00
|
|
|
/* 0: default from EEPROM. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity;
|
|
|
|
else
|
2009-06-28 14:20:38 +00:00
|
|
|
/* 1:disable antenna diversity, 2: enable antenna diversity. */
|
2012-11-13 17:28:20 +00:00
|
|
|
priv->bSwAntennaDiverity = priv->RegSwAntennaDiversityMechanism == 2;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->RegDefaultAntenna == 0)
|
|
|
|
/* 0: default from EEPROM. */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1;
|
|
|
|
else
|
2009-06-28 14:20:38 +00:00
|
|
|
/* 1: main, 2: aux. */
|
2012-11-13 17:28:20 +00:00
|
|
|
priv->bDefaultAntenna1 = priv->RegDefaultAntenna == 2;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->plcp_preamble_mode = 2;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* the eeprom type is stored in RCR register bit #6 */
|
2009-06-28 14:20:38 +00:00
|
|
|
if (RCR_9356SEL & read_nic_dword(dev, RCR))
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->epromtype = EPROM_93c56;
|
2009-06-28 14:20:38 +00:00
|
|
|
else
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->epromtype = EPROM_93c46;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-02-11 18:07:35 +00:00
|
|
|
eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)
|
|
|
|
dev->dev_addr, 3);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 1, j = 0; i < 14; i += 2, j++) {
|
2010-02-11 18:07:35 +00:00
|
|
|
eeprom_93cx6_read(&eeprom, EPROM_TXPW_CH1_2 + j, &word);
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->chtxpwr[i] = word & 0xff;
|
|
|
|
priv->chtxpwr[i+1] = (word & 0xff00)>>8;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2009-11-09 16:53:20 +00:00
|
|
|
for (i = 1, j = 0; i < 14; i += 2, j++) {
|
2010-02-11 18:07:35 +00:00
|
|
|
eeprom_93cx6_read(&eeprom, EPROM_TXPW_OFDM_CH1_2 + j, &word);
|
2009-11-09 16:53:20 +00:00
|
|
|
priv->chtxpwr_ofdm[i] = word & 0xff;
|
2010-01-25 19:11:49 +00:00
|
|
|
priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2012-04-17 13:56:43 +00:00
|
|
|
/* 3Read crystal calibration and thermal meter indication on 87SE. */
|
2010-02-11 18:07:35 +00:00
|
|
|
eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* Crystal calibration for Xin and Xout resp. */
|
|
|
|
priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK;
|
|
|
|
priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK) >> 4;
|
|
|
|
if ((tmpu16 & EEPROM_XTAL_CAL_ENABLE) >> 12)
|
|
|
|
priv->bXtalCalibration = true;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* Thermal meter reference indication. */
|
|
|
|
priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK) >> 8);
|
|
|
|
if ((tmpu16 & EEPROM_THERMAL_METER_ENABLE) >> 13)
|
|
|
|
priv->bTxPowerTrack = true;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->rf_sleep = rtl8225z4_rf_sleep;
|
|
|
|
priv->rf_wakeup = rtl8225z4_rf_wakeup;
|
|
|
|
DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!");
|
|
|
|
|
|
|
|
priv->rf_close = rtl8225z2_rf_close;
|
|
|
|
priv->rf_init = rtl8225z2_rf_init;
|
|
|
|
priv->rf_set_chan = rtl8225z2_rf_set_chan;
|
|
|
|
priv->rf_set_sens = NULL;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount))
|
2008-12-05 04:01:41 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_MANAGEPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_BKPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_BEPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_VIPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_VOPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_HIGHPRIORITY_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount,
|
2008-12-05 04:01:41 +00:00
|
|
|
TX_BEACON_RING_ADDR))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
|
2010-04-08 21:04:17 +00:00
|
|
|
DMESGE("Error allocating IRQ %d", dev->irq);
|
|
|
|
return -1;
|
2010-05-13 17:38:43 +00:00
|
|
|
} else {
|
|
|
|
priv->irq = dev->irq;
|
|
|
|
DMESG("IRQ %d", dev->irq);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_no_hw_wep(struct net_device *dev)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_set_hw_wep(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
u8 pgreg;
|
|
|
|
u8 security;
|
|
|
|
u32 key0_word4;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
pgreg = read_nic_byte(dev, PGSELECT);
|
|
|
|
write_nic_byte(dev, PGSELECT, pgreg & ~(1<<PGSELECT_PG_SHIFT));
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
key0_word4 = read_nic_dword(dev, KEY0+4+4+4);
|
2010-05-13 17:38:43 +00:00
|
|
|
key0_word4 &= ~0xff;
|
|
|
|
key0_word4 |= priv->key0[3] & 0xff;
|
|
|
|
write_nic_dword(dev, KEY0, (priv->key0[0]));
|
|
|
|
write_nic_dword(dev, KEY0+4, (priv->key0[1]));
|
|
|
|
write_nic_dword(dev, KEY0+4+4, (priv->key0[2]));
|
|
|
|
write_nic_dword(dev, KEY0+4+4+4, (key0_word4));
|
|
|
|
|
|
|
|
security = read_nic_byte(dev, SECURITY);
|
2008-12-05 04:01:41 +00:00
|
|
|
security |= (1<<SECURITY_WEP_TX_ENABLE_SHIFT);
|
|
|
|
security |= (1<<SECURITY_WEP_RX_ENABLE_SHIFT);
|
2010-05-13 17:38:43 +00:00
|
|
|
security &= ~SECURITY_ENCRYP_MASK;
|
2008-12-05 04:01:41 +00:00
|
|
|
security |= (SECURITY_ENCRYP_104<<SECURITY_ENCRYP_SHIFT);
|
|
|
|
|
|
|
|
write_nic_byte(dev, SECURITY, security);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
DMESG("key %x %x %x %x", read_nic_dword(dev, KEY0+4+4+4),
|
|
|
|
read_nic_dword(dev, KEY0+4+4), read_nic_dword(dev, KEY0+4),
|
|
|
|
read_nic_dword(dev, KEY0));
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rtl8185_rf_pins_enable(struct net_device *dev)
|
|
|
|
{
|
2010-05-13 17:39:08 +00:00
|
|
|
/* u16 tmp; */
|
|
|
|
/* tmp = read_nic_word(dev, RFPinsEnable); */
|
|
|
|
write_nic_word(dev, RFPinsEnable, 0x1fff); /* | tmp); */
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8185_set_anaparam2(struct net_device *dev, u32 a)
|
|
|
|
{
|
|
|
|
u8 conf3;
|
|
|
|
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
|
|
|
|
|
conf3 = read_nic_byte(dev, CONFIG3);
|
|
|
|
write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
|
|
|
|
write_nic_dword(dev, ANAPARAM2, a);
|
|
|
|
|
|
|
|
conf3 = read_nic_byte(dev, CONFIG3);
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_set_anaparam(struct net_device *dev, u32 a)
|
|
|
|
{
|
|
|
|
u8 conf3;
|
|
|
|
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
|
|
|
|
|
conf3 = read_nic_byte(dev, CONFIG3);
|
|
|
|
write_nic_byte(dev, CONFIG3, conf3 | (1<<CONFIG3_ANAPARAM_W_SHIFT));
|
|
|
|
write_nic_dword(dev, ANAPARAM, a);
|
|
|
|
|
|
|
|
conf3 = read_nic_byte(dev, CONFIG3);
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, CONFIG3, conf3 & ~(1<<CONFIG3_ANAPARAM_W_SHIFT));
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8185_tx_antenna(struct net_device *dev, u8 ant)
|
|
|
|
{
|
|
|
|
write_nic_byte(dev, TX_ANTENNA, ant);
|
|
|
|
force_pci_posting(dev);
|
|
|
|
mdelay(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data)
|
|
|
|
{
|
|
|
|
u32 phyw;
|
|
|
|
|
|
|
|
adr |= 0x80;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
phyw = ((data<<8) | adr);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */
|
2008-12-05 04:01:41 +00:00
|
|
|
write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
|
|
|
|
write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));
|
|
|
|
write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));
|
2010-05-13 17:38:43 +00:00
|
|
|
write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff)));
|
2009-06-28 14:19:23 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
/* this is ok to fail when we write AGC table. check for AGC table might be
|
|
|
|
* done by masking with 0x7f instead of 0xff
|
|
|
|
*/
|
2010-05-13 17:39:08 +00:00
|
|
|
/* if (phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
data = data & 0xff;
|
|
|
|
rtl8185_write_phy(dev, adr, data);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void write_phy_cck(struct net_device *dev, u8 adr, u32 data)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
data = data & 0xff;
|
|
|
|
rtl8185_write_phy(dev, adr, data | 0x10000);
|
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* This configures registers for beacon tx and enables it via
|
2008-12-05 04:01:41 +00:00
|
|
|
* rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might
|
|
|
|
* be used to stop beacon transmission
|
|
|
|
*/
|
|
|
|
void rtl8180_start_tx_beacon(struct net_device *dev)
|
|
|
|
{
|
|
|
|
u16 word;
|
|
|
|
|
|
|
|
DMESG("Enabling beacon TX");
|
|
|
|
rtl8180_prepare_beacon(dev);
|
|
|
|
rtl8180_irq_disable(dev);
|
|
|
|
rtl8180_beacon_tx_enable(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
word = read_nic_word(dev, AtimWnd) & ~AtimWnd_AtimWnd;
|
2010-05-13 17:39:08 +00:00
|
|
|
write_nic_word(dev, AtimWnd, word); /* word |= */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
word = read_nic_word(dev, BintrItv);
|
|
|
|
word &= ~BintrItv_BintrItv;
|
2010-05-13 17:39:08 +00:00
|
|
|
word |= 1000; /* priv->ieee80211->current_network.beacon_interval *
|
2008-12-05 04:01:41 +00:00
|
|
|
((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1);
|
|
|
|
// FIXME: check if correct ^^ worked with 0x3e8;
|
|
|
|
*/
|
|
|
|
write_nic_word(dev, BintrItv, word);
|
|
|
|
|
|
|
|
rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
|
|
2010-04-08 21:04:17 +00:00
|
|
|
rtl8185b_irq_enable(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct net_device_stats *rtl8180_stats(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
|
|
|
return &priv->ieee80211->stats;
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Change current and default preamble mode.
|
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
bool
|
|
|
|
MgntActSet_802_11_PowerSaveMode(
|
|
|
|
struct r8180_priv *priv,
|
|
|
|
RT_PS_MODE rtPsMode
|
|
|
|
)
|
|
|
|
{
|
2010-05-13 17:39:08 +00:00
|
|
|
/* Currently, we do not change power save mode on IBSS mode. */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
2008-12-05 04:01:41 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
priv->ieee80211->ps = rtPsMode;
|
2009-06-28 14:19:23 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
void LeisurePSEnter(struct r8180_priv *priv)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->bLeisurePs) {
|
2008-12-05 04:01:41 +00:00
|
|
|
if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
|
2012-03-14 22:26:59 +00:00
|
|
|
/* IEEE80211_PS_ENABLE */
|
|
|
|
MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
void LeisurePSLeave(struct r8180_priv *priv)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->bLeisurePs) {
|
2008-12-05 04:01:41 +00:00
|
|
|
if (priv->ieee80211->ps != IEEE80211_PS_DISABLED)
|
|
|
|
MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED);
|
|
|
|
}
|
|
|
|
}
|
2009-06-13 16:30:28 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_hw_wakeup_wq(struct work_struct *work)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2009-04-02 23:56:54 +00:00
|
|
|
struct delayed_work *dwork = to_delayed_work(work);
|
2010-05-13 17:38:43 +00:00
|
|
|
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_wakeup_wq);
|
2008-12-05 04:01:41 +00:00
|
|
|
struct net_device *dev = ieee->dev;
|
|
|
|
|
|
|
|
rtl8180_hw_wakeup(dev);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_hw_sleep_wq(struct work_struct *work)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
2009-04-02 23:56:54 +00:00
|
|
|
struct delayed_work *dwork = to_delayed_work(work);
|
2010-05-13 17:38:43 +00:00
|
|
|
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_sleep_wq);
|
2010-04-08 21:04:17 +00:00
|
|
|
struct net_device *dev = ieee->dev;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-04-08 21:04:17 +00:00
|
|
|
rtl8180_hw_sleep_down(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
static void MgntLinkKeepAlive(struct r8180_priv *priv)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
if (priv->keepAliveLevel == 0)
|
|
|
|
return;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->state == IEEE80211_LINKED) {
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* Keep-Alive.
|
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((priv->keepAliveLevel == 2) ||
|
2008-12-05 04:01:41 +00:00
|
|
|
(priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast &&
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast)
|
|
|
|
) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->link_detect.IdleCount++;
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/*
|
|
|
|
* Send a Keep-Alive packet packet to AP if we had been idle for a while.
|
|
|
|
*/
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->link_detect.IdleCount = 0;
|
|
|
|
ieee80211_sta_ps_send_null_frame(priv->ieee80211, false);
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
} else {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->link_detect.IdleCount = 0;
|
|
|
|
}
|
|
|
|
priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast;
|
|
|
|
priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_watch_dog(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
bool bEnterPS = false;
|
|
|
|
bool bBusyTraffic = false;
|
|
|
|
u32 TotalRxNum = 0;
|
|
|
|
u16 SlotIndex = 0;
|
|
|
|
u16 i = 0;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->actscanning == false) {
|
2012-03-14 22:26:59 +00:00
|
|
|
if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) &&
|
|
|
|
(priv->ieee80211->state == IEEE80211_NOLINK) &&
|
|
|
|
(priv->ieee80211->beinretry == false) &&
|
|
|
|
(priv->eRFPowerState == eRfOn))
|
2008-12-05 04:01:41 +00:00
|
|
|
IPSEnter(dev);
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828,for link state check */
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum;
|
|
|
|
priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod;
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 0; i < priv->link_detect.SlotNum; i++)
|
|
|
|
TotalRxNum += priv->link_detect.RxFrameNum[i];
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (TotalRxNum == 0) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->state = IEEE80211_ASSOCIATING;
|
|
|
|
queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828,for KeepAlive */
|
2008-12-05 04:01:41 +00:00
|
|
|
MgntLinkKeepAlive(priv);
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* YJ,add,080828,for LPS */
|
2012-11-13 17:28:23 +00:00
|
|
|
LeisurePSLeave(priv);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->state == IEEE80211_LINKED) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->link_detect.NumRxOkInPeriod > 666 ||
|
|
|
|
priv->link_detect.NumTxOkInPeriod > 666) {
|
2008-12-05 04:01:41 +00:00
|
|
|
bBusyTraffic = true;
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
if (((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8)
|
2008-12-05 04:01:41 +00:00
|
|
|
|| (priv->link_detect.NumRxOkInPeriod > 2)) {
|
2010-05-13 17:38:43 +00:00
|
|
|
bEnterPS = false;
|
2009-06-28 14:20:38 +00:00
|
|
|
} else
|
2010-05-13 17:38:43 +00:00
|
|
|
bEnterPS = true;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (bEnterPS)
|
2008-12-05 04:01:41 +00:00
|
|
|
LeisurePSEnter(priv);
|
2009-06-28 14:20:38 +00:00
|
|
|
else
|
2008-12-05 04:01:41 +00:00
|
|
|
LeisurePSLeave(priv);
|
2009-06-28 14:20:38 +00:00
|
|
|
} else
|
2008-12-05 04:01:41 +00:00
|
|
|
LeisurePSLeave(priv);
|
|
|
|
priv->link_detect.bBusyTraffic = bBusyTraffic;
|
|
|
|
priv->link_detect.NumRxOkInPeriod = 0;
|
|
|
|
priv->link_detect.NumTxOkInPeriod = 0;
|
|
|
|
priv->ieee80211->NumRxDataInPeriod = 0;
|
|
|
|
priv->ieee80211->NumRxBcnInPeriod = 0;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
int _rtl8180_up(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->up = 1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
DMESG("Bringing up iface");
|
|
|
|
rtl8185b_adapter_start(dev);
|
|
|
|
rtl8185b_rx_enable(dev);
|
|
|
|
rtl8185b_tx_enable(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->bInactivePs) {
|
|
|
|
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
2008-12-05 04:01:41 +00:00
|
|
|
IPSLeave(dev);
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
timer_rate_adaptive((unsigned long)dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
watch_dog_adaptive((unsigned long)dev);
|
2010-04-08 21:04:17 +00:00
|
|
|
if (priv->bSwAntennaDiverity)
|
2008-12-05 04:01:41 +00:00
|
|
|
SwAntennaDiversityTimerCallback(dev);
|
|
|
|
ieee80211_softmac_start_protocol(priv->ieee80211);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtl8180_open(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
down(&priv->wx_sem);
|
|
|
|
ret = rtl8180_up(dev);
|
|
|
|
up(&priv->wx_sem);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtl8180_up(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->up == 1)
|
|
|
|
return -1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return _rtl8180_up(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtl8180_close(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
down(&priv->wx_sem);
|
|
|
|
ret = rtl8180_down(dev);
|
|
|
|
up(&priv->wx_sem);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtl8180_down(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->up == 0)
|
|
|
|
return -1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->up = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
ieee80211_softmac_stop_protocol(priv->ieee80211);
|
|
|
|
/* FIXME */
|
|
|
|
if (!netif_queue_stopped(dev))
|
|
|
|
netif_stop_queue(dev);
|
|
|
|
rtl8180_rtx_disable(dev);
|
|
|
|
rtl8180_irq_disable(dev);
|
|
|
|
del_timer_sync(&priv->watch_dog_timer);
|
2009-06-28 14:20:38 +00:00
|
|
|
del_timer_sync(&priv->rateadapter_timer);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
|
2008-12-05 04:01:41 +00:00
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
|
|
|
|
del_timer_sync(&priv->SwAntennaDiversityTimer);
|
2010-05-13 17:38:43 +00:00
|
|
|
SetZebraRFPowerState8185(dev, eRfOff);
|
|
|
|
memset(&(priv->ieee80211->current_network), 0, sizeof(struct ieee80211_network));
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->state = IEEE80211_NOLINK;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_restart_wq(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
|
|
|
|
struct net_device *dev = priv->dev;
|
2009-06-13 16:30:28 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
down(&priv->wx_sem);
|
|
|
|
|
|
|
|
rtl8180_commit(dev);
|
|
|
|
|
|
|
|
up(&priv->wx_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_restart(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
schedule_work(&priv->reset_wq);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_commit(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (priv->up == 0)
|
|
|
|
return ;
|
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
del_timer_sync(&priv->watch_dog_timer);
|
2009-06-28 14:20:38 +00:00
|
|
|
del_timer_sync(&priv->rateadapter_timer);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
|
2008-12-05 04:01:41 +00:00
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_sleep_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->hw_dig_wq);
|
|
|
|
cancel_delayed_work(&priv->ieee80211->tx_pw_wq);
|
|
|
|
del_timer_sync(&priv->SwAntennaDiversityTimer);
|
|
|
|
ieee80211_softmac_stop_protocol(priv->ieee80211);
|
|
|
|
rtl8180_irq_disable(dev);
|
|
|
|
rtl8180_rtx_disable(dev);
|
|
|
|
_rtl8180_up(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void r8180_set_multicast(struct net_device *dev)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
short promisc;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
if (promisc != priv->promisc)
|
|
|
|
rtl8180_restart(dev);
|
|
|
|
|
|
|
|
priv->promisc = promisc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int r8180_set_mac_adr(struct net_device *dev, void *mac)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
struct sockaddr *addr = mac;
|
|
|
|
|
|
|
|
down(&priv->wx_sem);
|
|
|
|
|
|
|
|
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
|
2008-12-05 04:01:41 +00:00
|
|
|
memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN);
|
|
|
|
|
|
|
|
if (priv->up) {
|
|
|
|
rtl8180_down(dev);
|
|
|
|
rtl8180_up(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
up(&priv->wx_sem);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* based on ipw2200 driver */
|
|
|
|
int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
struct iwreq *wrq = (struct iwreq *) rq;
|
2010-05-13 17:38:43 +00:00
|
|
|
int ret = -1;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2008-12-05 04:01:41 +00:00
|
|
|
switch (cmd) {
|
2009-06-28 14:20:38 +00:00
|
|
|
case RTL_IOCTL_WPA_SUPPLICANT:
|
2008-12-05 04:01:41 +00:00
|
|
|
ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data);
|
|
|
|
return ret;
|
2009-06-28 14:20:38 +00:00
|
|
|
default:
|
2008-12-05 04:01:41 +00:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2009-05-09 23:06:54 +00:00
|
|
|
static const struct net_device_ops rtl8180_netdev_ops = {
|
|
|
|
.ndo_open = rtl8180_open,
|
|
|
|
.ndo_stop = rtl8180_close,
|
|
|
|
.ndo_get_stats = rtl8180_stats,
|
|
|
|
.ndo_tx_timeout = rtl8180_restart,
|
|
|
|
.ndo_do_ioctl = rtl8180_ioctl,
|
2011-08-16 06:29:01 +00:00
|
|
|
.ndo_set_rx_mode = r8180_set_multicast,
|
2009-05-09 23:06:54 +00:00
|
|
|
.ndo_set_mac_address = r8180_set_mac_adr,
|
|
|
|
.ndo_validate_addr = eth_validate_addr,
|
|
|
|
.ndo_change_mtu = eth_change_mtu,
|
2009-12-16 23:16:00 +00:00
|
|
|
.ndo_start_xmit = ieee80211_rtl_xmit,
|
2009-05-09 23:06:54 +00:00
|
|
|
};
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2012-11-19 18:22:08 +00:00
|
|
|
static int rtl8180_pci_probe(struct pci_dev *pdev,
|
2008-12-05 04:01:41 +00:00
|
|
|
const struct pci_device_id *id)
|
|
|
|
{
|
|
|
|
unsigned long ioaddr = 0;
|
|
|
|
struct net_device *dev = NULL;
|
2010-05-13 17:38:43 +00:00
|
|
|
struct r8180_priv *priv = NULL;
|
2008-12-05 04:01:41 +00:00
|
|
|
u8 unit = 0;
|
2010-08-09 19:51:52 +00:00
|
|
|
int ret = -ENODEV;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
unsigned long pmem_start, pmem_len, pmem_flags;
|
|
|
|
|
|
|
|
DMESG("Configuring chip resources");
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (pci_enable_device(pdev)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("Failed to enable PCI device");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
pci_set_master(pdev);
|
|
|
|
pci_set_dma_mask(pdev, 0xffffff00ULL);
|
2010-05-13 17:38:43 +00:00
|
|
|
pci_set_consistent_dma_mask(pdev, 0xffffff00ULL);
|
2008-12-05 04:01:41 +00:00
|
|
|
dev = alloc_ieee80211(sizeof(struct r8180_priv));
|
2010-08-09 19:51:52 +00:00
|
|
|
if (!dev) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto fail_free;
|
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
priv = ieee80211_priv(dev);
|
|
|
|
priv->ieee80211 = netdev_priv(dev);
|
|
|
|
|
|
|
|
pci_set_drvdata(pdev, dev);
|
|
|
|
SET_NETDEV_DEV(dev, &pdev->dev);
|
|
|
|
|
|
|
|
priv = ieee80211_priv(dev);
|
2009-06-28 14:20:38 +00:00
|
|
|
priv->pdev = pdev;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pmem_start = pci_resource_start(pdev, 1);
|
|
|
|
pmem_len = pci_resource_len(pdev, 1);
|
2010-05-13 17:38:43 +00:00
|
|
|
pmem_flags = pci_resource_flags(pdev, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
if (!(pmem_flags & IORESOURCE_MEM)) {
|
|
|
|
DMESG("region #1 not a MMIO resource, aborting");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("request_mem_region failed!");
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
ioaddr = (unsigned long)ioremap_nocache(pmem_start, pmem_len);
|
|
|
|
if (ioaddr == (unsigned long)NULL) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("ioremap failed!");
|
|
|
|
goto fail1;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
dev->mem_start = ioaddr; /* shared mem start */
|
|
|
|
dev->mem_end = ioaddr + pci_resource_len(pdev, 0); /* shared mem end */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
pci_read_config_byte(pdev, 0x05, &unit);
|
|
|
|
pci_write_config_byte(pdev, 0x05, unit & (~0x04));
|
|
|
|
|
|
|
|
dev->irq = pdev->irq;
|
|
|
|
priv->irq = 0;
|
|
|
|
|
2009-05-09 23:06:54 +00:00
|
|
|
dev->netdev_ops = &rtl8180_netdev_ops;
|
2008-12-05 04:01:41 +00:00
|
|
|
dev->wireless_handlers = &r8180_wx_handlers_def;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
dev->type = ARPHRD_ETHER;
|
2010-01-25 19:11:49 +00:00
|
|
|
dev->watchdog_timeo = HZ*3;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (dev_alloc_name(dev, ifname) < 0) {
|
2010-04-08 21:04:17 +00:00
|
|
|
DMESG("Oops: devname already taken! Trying wlan%%d...\n");
|
2010-08-12 05:04:21 +00:00
|
|
|
strcpy(ifname, "wlan%d");
|
2008-12-05 04:01:41 +00:00
|
|
|
dev_alloc_name(dev, ifname);
|
2010-04-08 21:04:17 +00:00
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (rtl8180_init(dev) != 0) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("Initialization failed");
|
|
|
|
goto fail1;
|
|
|
|
}
|
|
|
|
|
|
|
|
netif_carrier_off(dev);
|
|
|
|
|
2012-11-14 10:00:57 +00:00
|
|
|
if (register_netdev(dev))
|
|
|
|
goto fail1;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
rtl8180_proc_init_one(dev);
|
|
|
|
|
|
|
|
DMESG("Driver probe completed\n");
|
|
|
|
return 0;
|
|
|
|
fail1:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (dev->mem_start != (unsigned long)NULL) {
|
|
|
|
iounmap((void *)dev->mem_start);
|
|
|
|
release_mem_region(pci_resource_start(pdev, 1),
|
|
|
|
pci_resource_len(pdev, 1));
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
fail:
|
2010-05-13 17:38:43 +00:00
|
|
|
if (dev) {
|
2008-12-05 04:01:41 +00:00
|
|
|
if (priv->irq) {
|
|
|
|
free_irq(dev->irq, dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
dev->irq = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
free_ieee80211(dev);
|
|
|
|
}
|
|
|
|
|
2010-08-09 19:51:52 +00:00
|
|
|
fail_free:
|
2008-12-05 04:01:41 +00:00
|
|
|
pci_disable_device(pdev);
|
|
|
|
|
|
|
|
DMESG("wlan driver load failed\n");
|
|
|
|
pci_set_drvdata(pdev, NULL);
|
2010-08-09 19:51:52 +00:00
|
|
|
return ret;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2012-11-19 18:26:44 +00:00
|
|
|
static void rtl8180_pci_remove(struct pci_dev *pdev)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
struct r8180_priv *priv;
|
|
|
|
struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (dev) {
|
2008-12-05 04:01:41 +00:00
|
|
|
unregister_netdev(dev);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
priv = ieee80211_priv(dev);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
rtl8180_proc_remove_one(dev);
|
|
|
|
rtl8180_down(dev);
|
|
|
|
priv->rf_close(dev);
|
|
|
|
rtl8180_reset(dev);
|
|
|
|
mdelay(10);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->irq) {
|
|
|
|
DMESG("Freeing irq %d", dev->irq);
|
2008-12-05 04:01:41 +00:00
|
|
|
free_irq(dev->irq, dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
priv->irq = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free_rx_desc_ring(dev);
|
|
|
|
free_tx_desc_rings(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (dev->mem_start != (unsigned long)NULL) {
|
|
|
|
iounmap((void *)dev->mem_start);
|
|
|
|
release_mem_region(pci_resource_start(pdev, 1),
|
|
|
|
pci_resource_len(pdev, 1));
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free_ieee80211(dev);
|
|
|
|
}
|
|
|
|
pci_disable_device(pdev);
|
|
|
|
|
|
|
|
DMESG("wlan driver removed\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fun with the built-in ieee80211 stack... */
|
|
|
|
extern int ieee80211_crypto_init(void);
|
|
|
|
extern void ieee80211_crypto_deinit(void);
|
|
|
|
extern int ieee80211_crypto_tkip_init(void);
|
|
|
|
extern void ieee80211_crypto_tkip_exit(void);
|
|
|
|
extern int ieee80211_crypto_ccmp_init(void);
|
|
|
|
extern void ieee80211_crypto_ccmp_exit(void);
|
|
|
|
extern int ieee80211_crypto_wep_init(void);
|
|
|
|
extern void ieee80211_crypto_wep_exit(void);
|
|
|
|
|
|
|
|
static int __init rtl8180_pci_module_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = ieee80211_crypto_init();
|
|
|
|
if (ret) {
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_err("ieee80211_crypto_init() failed %d\n", ret);
|
2008-12-05 04:01:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = ieee80211_crypto_tkip_init();
|
|
|
|
if (ret) {
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_err("ieee80211_crypto_tkip_init() failed %d\n", ret);
|
2008-12-05 04:01:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = ieee80211_crypto_ccmp_init();
|
|
|
|
if (ret) {
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_err("ieee80211_crypto_ccmp_init() failed %d\n", ret);
|
2008-12-05 04:01:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
ret = ieee80211_crypto_wep_init();
|
|
|
|
if (ret) {
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_err("ieee80211_crypto_wep_init() failed %d\n", ret);
|
2008-12-05 04:01:41 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-11-22 00:07:04 +00:00
|
|
|
pr_info("\nLinux kernel driver for RTL8180 / RTL8185 based WLAN cards\n");
|
|
|
|
pr_info("Copyright (c) 2004-2005, Andrea Merello\n");
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("Initializing module");
|
|
|
|
DMESG("Wireless extensions version %d", WIRELESS_EXT);
|
|
|
|
rtl8180_proc_module_init();
|
|
|
|
|
2012-03-14 22:26:58 +00:00
|
|
|
if (pci_register_driver(&rtl8180_pci_driver)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("No device found");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit rtl8180_pci_module_exit(void)
|
|
|
|
{
|
2010-05-13 17:38:43 +00:00
|
|
|
pci_unregister_driver(&rtl8180_pci_driver);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_proc_module_remove();
|
|
|
|
ieee80211_crypto_tkip_exit();
|
|
|
|
ieee80211_crypto_ccmp_exit();
|
|
|
|
ieee80211_crypto_wep_exit();
|
2009-02-17 16:16:26 +00:00
|
|
|
ieee80211_crypto_deinit();
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESG("Exiting");
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtl8180_try_wake_queue(struct net_device *dev, int pri)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
short enough_desc;
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->tx_lock, flags);
|
|
|
|
enough_desc = check_nic_enought_desc(dev, pri);
|
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (enough_desc)
|
2009-12-16 23:16:00 +00:00
|
|
|
ieee80211_rtl_wake_queue(priv->ieee80211);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_tx_isr(struct net_device *dev, int pri, short error)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
2010-05-13 17:39:08 +00:00
|
|
|
u32 *tail; /* tail virtual addr */
|
|
|
|
u32 *head; /* head virtual addr */
|
|
|
|
u32 *begin; /* start of ring virtual addr */
|
|
|
|
u32 *nicv; /* nic pointer virtual addr */
|
|
|
|
u32 nic; /* nic pointer physical addr */
|
|
|
|
u32 nicbegin; /* start of ring physical addr */
|
2008-12-05 04:01:41 +00:00
|
|
|
unsigned long flag;
|
2010-05-13 17:39:08 +00:00
|
|
|
/* physical addr are ok on 32 bits since we set DMA mask */
|
2008-12-05 04:01:41 +00:00
|
|
|
int offs;
|
2010-05-13 17:38:43 +00:00
|
|
|
int j, i;
|
2008-12-05 04:01:41 +00:00
|
|
|
int hd;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (error)
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->stats.txretry++; /* tony 20060601 */
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->tx_lock, flag);
|
|
|
|
switch (pri) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case MANAGE_PRIORITY:
|
|
|
|
tail = priv->txmapringtail;
|
|
|
|
begin = priv->txmapring;
|
|
|
|
head = priv->txmapringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txmapringdma;
|
|
|
|
break;
|
|
|
|
case BK_PRIORITY:
|
|
|
|
tail = priv->txbkpringtail;
|
|
|
|
begin = priv->txbkpring;
|
|
|
|
head = priv->txbkpringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_BKPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txbkpringdma;
|
|
|
|
break;
|
|
|
|
case BE_PRIORITY:
|
|
|
|
tail = priv->txbepringtail;
|
|
|
|
begin = priv->txbepring;
|
|
|
|
head = priv->txbepringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_BEPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txbepringdma;
|
|
|
|
break;
|
|
|
|
case VI_PRIORITY:
|
|
|
|
tail = priv->txvipringtail;
|
|
|
|
begin = priv->txvipring;
|
|
|
|
head = priv->txvipringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_VIPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txvipringdma;
|
|
|
|
break;
|
|
|
|
case VO_PRIORITY:
|
|
|
|
tail = priv->txvopringtail;
|
|
|
|
begin = priv->txvopring;
|
|
|
|
head = priv->txvopringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_VOPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txvopringdma;
|
|
|
|
break;
|
|
|
|
case HI_PRIORITY:
|
|
|
|
tail = priv->txhpringtail;
|
|
|
|
begin = priv->txhpring;
|
|
|
|
head = priv->txhpringhead;
|
2010-05-13 17:38:43 +00:00
|
|
|
nic = read_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR);
|
2008-12-05 04:01:41 +00:00
|
|
|
nicbegin = priv->txhpringdma;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flag);
|
2008-12-05 04:01:41 +00:00
|
|
|
return ;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2012-11-22 00:06:50 +00:00
|
|
|
nicv = (u32 *)((nic - nicbegin) + (u8 *)begin);
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((head <= tail && (nicv > tail || nicv < head)) ||
|
|
|
|
(head > tail && (nicv > tail && nicv < head))) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGW("nic has lost pointer");
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flag);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_restart(dev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* We check all the descriptors between the head and the nic,
|
2009-11-14 15:09:06 +00:00
|
|
|
* but not the currently pointed by the nic (the next to be txed)
|
2008-12-05 04:01:41 +00:00
|
|
|
* and the previous of the pointed (might be in process ??)
|
2010-05-13 17:39:08 +00:00
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
offs = (nic - nicbegin);
|
2010-05-13 17:38:43 +00:00
|
|
|
offs = offs / 8 / 4;
|
|
|
|
hd = (head - begin) / 8;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (offs >= hd)
|
2008-12-05 04:01:41 +00:00
|
|
|
j = offs - hd;
|
|
|
|
else
|
2010-05-13 17:38:43 +00:00
|
|
|
j = offs + (priv->txringcount-1-hd);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
j -= 2;
|
|
|
|
if (j < 0)
|
|
|
|
j = 0;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
for (i = 0; i < j; i++) {
|
|
|
|
if ((*head) & (1<<31))
|
2008-12-05 04:01:41 +00:00
|
|
|
break;
|
2010-05-13 17:38:43 +00:00
|
|
|
if (((*head)&(0x10000000)) != 0) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->CurrRetryCnt += (u16)((*head) & (0x000000ff));
|
2009-06-28 14:20:38 +00:00
|
|
|
if (!error)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->NumTxOkTotal++;
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
|
|
|
if (!error)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff);
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
*head = *head & ~(1<<31);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if ((head - begin)/8 == priv->txringcount-1)
|
|
|
|
head = begin;
|
2008-12-05 04:01:41 +00:00
|
|
|
else
|
2010-05-13 17:38:43 +00:00
|
|
|
head += 8;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2012-03-14 22:26:57 +00:00
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* The head has been moved to the last certainly TXed
|
2008-12-05 04:01:41 +00:00
|
|
|
* (or at least processed by the nic) packet.
|
|
|
|
* The driver take forcefully owning of all these packets
|
|
|
|
* If the packet previous of the nic pointer has been
|
|
|
|
* processed this doesn't matter: it will be checked
|
|
|
|
* here at the next round. Anyway if no more packet are
|
2011-03-31 01:57:33 +00:00
|
|
|
* TXed no memory leak occur at all.
|
2008-12-05 04:01:41 +00:00
|
|
|
*/
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
switch (pri) {
|
2008-12-05 04:01:41 +00:00
|
|
|
case MANAGE_PRIORITY:
|
|
|
|
priv->txmapringhead = head;
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->ack_tx_to_ieee) {
|
|
|
|
if (rtl8180_is_tx_queue_empty(dev)) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ack_tx_to_ieee = 0;
|
2010-05-13 17:38:43 +00:00
|
|
|
ieee80211_ps_tx_ack(priv->ieee80211, !error);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BK_PRIORITY:
|
|
|
|
priv->txbkpringhead = head;
|
|
|
|
break;
|
|
|
|
case BE_PRIORITY:
|
|
|
|
priv->txbepringhead = head;
|
|
|
|
break;
|
|
|
|
case VI_PRIORITY:
|
|
|
|
priv->txvipringhead = head;
|
|
|
|
break;
|
|
|
|
case VO_PRIORITY:
|
|
|
|
priv->txvopringhead = head;
|
|
|
|
break;
|
|
|
|
case HI_PRIORITY:
|
|
|
|
priv->txhpringhead = head;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->tx_lock, flag);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
|
|
|
|
{
|
|
|
|
struct net_device *dev = (struct net_device *) netdev;
|
|
|
|
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
|
unsigned long flags;
|
|
|
|
u32 inta;
|
|
|
|
|
|
|
|
/* We should return IRQ_NONE, but for now let me keep this */
|
2010-05-13 17:38:43 +00:00
|
|
|
if (priv->irq_enabled == 0)
|
|
|
|
return IRQ_HANDLED;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_lock_irqsave(&priv->irq_th_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
/* ISR: 4bytes */
|
|
|
|
inta = read_nic_dword(dev, ISR); /* & priv->IntrMask; */
|
|
|
|
write_nic_dword(dev, ISR, inta); /* reset int situation */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
priv->stats.shints++;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!inta) {
|
|
|
|
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
/*
|
2010-05-13 17:39:08 +00:00
|
|
|
* most probably we can safely return IRQ_NONE,
|
|
|
|
* but for now is better to avoid problems
|
|
|
|
*/
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta == 0xffff) {
|
2012-04-17 13:56:43 +00:00
|
|
|
/* HW disappeared */
|
2009-06-28 14:20:38 +00:00
|
|
|
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
|
|
|
|
return IRQ_HANDLED;
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
priv->stats.ints++;
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (!netif_running(dev)) {
|
|
|
|
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta & ISR_TimeOut)
|
2008-12-05 04:01:41 +00:00
|
|
|
write_nic_dword(dev, TimerInt, 0);
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta & ISR_TBDOK)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbeacon++;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta & ISR_TBDER)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbeaconerr++;
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta & IMR_TMGDOK)
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, MANAGE_PRIORITY, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_THPDER) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txhperr++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, HI_PRIORITY, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->ieee80211->stats.tx_errors++;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_THPDOK) { /* High priority tx ok */
|
|
|
|
priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txhpokint++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, HI_PRIORITY, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_RER)
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxerr++;
|
2010-05-13 17:38:43 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TBKDER) { /* corresponding to BK_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbkperr++;
|
|
|
|
priv->ieee80211->stats.tx_errors++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, BK_PRIORITY, 1);
|
2012-11-13 17:28:10 +00:00
|
|
|
rtl8180_try_wake_queue(dev, BK_PRIORITY);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TBEDER) { /* corresponding to BE_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbeperr++;
|
|
|
|
priv->ieee80211->stats.tx_errors++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, BE_PRIORITY, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
|
}
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TNPDER) { /* corresponding to VO_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txnperr++;
|
|
|
|
priv->ieee80211->stats.tx_errors++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, NORM_PRIORITY, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, NORM_PRIORITY);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TLPDER) { /* corresponding to VI_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txlperr++;
|
|
|
|
priv->ieee80211->stats.tx_errors++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, LOW_PRIORITY, 1);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, LOW_PRIORITY);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_ROK) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxint++;
|
|
|
|
tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_RQoSOK) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxint++;
|
|
|
|
tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
|
}
|
2010-05-13 17:38:43 +00:00
|
|
|
|
|
|
|
if (inta & ISR_BcnInt)
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_prepare_beacon(dev);
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_RDU) {
|
2008-12-05 04:01:41 +00:00
|
|
|
DMESGW("No RX descriptor available");
|
|
|
|
priv->stats.rxrdu++;
|
|
|
|
tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
|
}
|
2009-06-28 14:20:38 +00:00
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
if (inta & ISR_RXFOVW) {
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.rxoverflow++;
|
|
|
|
tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
|
}
|
|
|
|
|
2009-06-28 14:20:38 +00:00
|
|
|
if (inta & ISR_TXFOVW)
|
|
|
|
priv->stats.txoverflow++;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TNPDOK) { /* Normal priority tx ok */
|
|
|
|
priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txnpokint++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, NORM_PRIORITY, 0);
|
2012-11-13 17:28:10 +00:00
|
|
|
rtl8180_try_wake_queue(dev, NORM_PRIORITY);
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TLPDOK) { /* Low priority tx ok */
|
|
|
|
priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txlpokint++;
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, LOW_PRIORITY, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, LOW_PRIORITY);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TBKDOK) { /* corresponding to BK_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbkpokint++;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, BK_PRIORITY, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:39:08 +00:00
|
|
|
if (inta & ISR_TBEDOK) { /* corresponding to BE_PRIORITY */
|
2008-12-05 04:01:41 +00:00
|
|
|
priv->stats.txbeperr++;
|
2010-05-13 17:39:08 +00:00
|
|
|
priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */
|
2010-05-13 17:38:43 +00:00
|
|
|
rtl8180_tx_isr(dev, BE_PRIORITY, 0);
|
2008-12-05 04:01:41 +00:00
|
|
|
rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
|
}
|
|
|
|
force_pci_posting(dev);
|
2010-05-13 17:38:43 +00:00
|
|
|
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2010-05-13 17:38:43 +00:00
|
|
|
void rtl8180_irq_rx_tasklet(struct r8180_priv *priv)
|
2008-12-05 04:01:41 +00:00
|
|
|
{
|
|
|
|
rtl8180_rx(priv->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work);
|
|
|
|
struct net_device *dev = ieee->dev;
|
|
|
|
struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
|
u8 btPSR;
|
|
|
|
u8 btConfig0;
|
|
|
|
RT_RF_POWER_STATE eRfPowerStateToSet;
|
2010-04-08 21:04:17 +00:00
|
|
|
bool bActuallySet = false;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
char *argv[3];
|
2010-04-08 21:04:17 +00:00
|
|
|
static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh";
|
2010-05-13 17:38:43 +00:00
|
|
|
static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL};
|
2012-11-22 00:05:53 +00:00
|
|
|
static int readf_count;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
|
|
|
readf_count = (readf_count+1)%0xffff;
|
2010-01-25 19:11:49 +00:00
|
|
|
/* We should turn off LED before polling FF51[4]. */
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* Turn off LED. */
|
|
|
|
btPSR = read_nic_byte(dev, PSR);
|
|
|
|
write_nic_byte(dev, PSR, (btPSR & ~BIT3));
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* It need to delay 4us suggested by Jong, 2008-01-16 */
|
|
|
|
udelay(4);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
/* HW radio On/Off according to the value of FF51[4](config0) */
|
|
|
|
btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-02-11 20:41:24 +00:00
|
|
|
/* Turn LED back on when radio enabled */
|
|
|
|
if (eRfPowerStateToSet == eRfOn)
|
|
|
|
write_nic_byte(dev, PSR, btPSR | BIT3);
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
if ((priv->ieee80211->bHwRadioOff == true) &&
|
|
|
|
(eRfPowerStateToSet == eRfOn)) {
|
|
|
|
priv->ieee80211->bHwRadioOff = false;
|
|
|
|
bActuallySet = true;
|
|
|
|
} else if ((priv->ieee80211->bHwRadioOff == false) &&
|
|
|
|
(eRfPowerStateToSet == eRfOff)) {
|
|
|
|
priv->ieee80211->bHwRadioOff = true;
|
|
|
|
bActuallySet = true;
|
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
|
2010-01-25 19:11:49 +00:00
|
|
|
if (bActuallySet) {
|
|
|
|
MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW);
|
|
|
|
|
|
|
|
/* To update the UI status for Power status changed */
|
|
|
|
if (priv->ieee80211->bHwRadioOff == true)
|
|
|
|
argv[1] = "RFOFF";
|
|
|
|
else
|
|
|
|
argv[1] = "RFON";
|
|
|
|
argv[0] = RadioPowerPath;
|
|
|
|
argv[2] = NULL;
|
|
|
|
|
2012-03-23 22:02:46 +00:00
|
|
|
call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC);
|
2010-01-25 19:11:49 +00:00
|
|
|
}
|
2008-12-05 04:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(rtl8180_pci_module_init);
|
|
|
|
module_exit(rtl8180_pci_module_exit);
|