|
@@ -0,0 +1,6826 @@
|
|
|
+/*
|
|
|
+ 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.
|
|
|
+*/
|
|
|
+
|
|
|
+#if 0
|
|
|
+double __floatsidf (int i) { return i; }
|
|
|
+unsigned int __fixunsdfsi (double d) { return d; }
|
|
|
+double __adddf3(double a, double b) { return a+b; }
|
|
|
+double __addsf3(float a, float b) { return a+b; }
|
|
|
+double __subdf3(double a, double b) { return a-b; }
|
|
|
+double __extendsfdf2(float a) {return a;}
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+#undef DEBUG_TX_DESC2
|
|
|
+#undef RX_DONT_PASS_UL
|
|
|
+#undef DEBUG_EPROM
|
|
|
+#undef DEBUG_RX_VERBOSE
|
|
|
+#undef DUMMY_RX
|
|
|
+#undef DEBUG_ZERO_RX
|
|
|
+#undef DEBUG_RX_SKB
|
|
|
+#undef DEBUG_TX_FRAG
|
|
|
+#undef DEBUG_RX_FRAG
|
|
|
+#undef DEBUG_TX_FILLDESC
|
|
|
+#undef DEBUG_TX
|
|
|
+#undef DEBUG_IRQ
|
|
|
+#undef DEBUG_RX
|
|
|
+#undef DEBUG_RXALLOC
|
|
|
+#undef DEBUG_REGISTERS
|
|
|
+#undef DEBUG_RING
|
|
|
+#undef DEBUG_IRQ_TASKLET
|
|
|
+#undef DEBUG_TX_ALLOC
|
|
|
+#undef DEBUG_TX_DESC
|
|
|
+
|
|
|
+//#define DEBUG_TX
|
|
|
+//#define DEBUG_TX_DESC2
|
|
|
+//#define DEBUG_RX
|
|
|
+//#define DEBUG_RX_SKB
|
|
|
+
|
|
|
+//#define CONFIG_RTL8180_IO_MAP
|
|
|
+#include <linux/syscalls.h>
|
|
|
+//#include <linux/fcntl.h>
|
|
|
+//#include <asm/uaccess.h>
|
|
|
+#include "r8180_hw.h"
|
|
|
+#include "r8180.h"
|
|
|
+#include "r8180_sa2400.h" /* PHILIPS Radio frontend */
|
|
|
+#include "r8180_max2820.h" /* MAXIM Radio frontend */
|
|
|
+#include "r8180_gct.h" /* GCT Radio frontend */
|
|
|
+#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
|
|
|
+#include "r8180_rtl8255.h" /* RTL8255 Radio frontend */
|
|
|
+#include "r8180_93cx6.h" /* Card EEPROM */
|
|
|
+#include "r8180_wx.h"
|
|
|
+#include "r8180_dm.h"
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_PM
|
|
|
+#include "r8180_pm.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef ENABLE_DOT11D
|
|
|
+#include "dot11d.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+//#define CONFIG_RTL8180_IO_MAP
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef PCI_VENDOR_ID_BELKIN
|
|
|
+ #define PCI_VENDOR_ID_BELKIN 0x1799
|
|
|
+#endif
|
|
|
+#ifndef PCI_VENDOR_ID_DLINK
|
|
|
+ #define PCI_VENDOR_ID_DLINK 0x1186
|
|
|
+#endif
|
|
|
+
|
|
|
+static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = {
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_REALTEK,
|
|
|
+// .device = 0x8180,
|
|
|
+ .device = 0x8199,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = 0,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_BELKIN,
|
|
|
+ .device = 0x6001,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = 1,
|
|
|
+ },
|
|
|
+ { /* Belkin F5D6020 v3 */
|
|
|
+ .vendor = PCI_VENDOR_ID_BELKIN,
|
|
|
+ .device = 0x6020,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = 2,
|
|
|
+ },
|
|
|
+ { /* D-Link DWL-610 */
|
|
|
+ .vendor = PCI_VENDOR_ID_DLINK,
|
|
|
+ .device = 0x3300,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = 3,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .vendor = PCI_VENDOR_ID_REALTEK,
|
|
|
+ .device = 0x8185,
|
|
|
+ .subvendor = PCI_ANY_ID,
|
|
|
+ .subdevice = PCI_ANY_ID,
|
|
|
+ .driver_data = 4,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .vendor = 0,
|
|
|
+ .device = 0,
|
|
|
+ .subvendor = 0,
|
|
|
+ .subdevice = 0,
|
|
|
+ .driver_data = 0,
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static char* ifname = "wlan%d";
|
|
|
+static int hwseqnum = 0;
|
|
|
+//static char* ifname = "ath%d";
|
|
|
+static int hwwep = 0;
|
|
|
+static int channels = 0x3fff;
|
|
|
+
|
|
|
+#define eqMacAddr(a,b) ( ((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0 )
|
|
|
+#define cpMacAddr(des,src) ((des)[0]=(src)[0],(des)[1]=(src)[1],(des)[2]=(src)[2],(des)[3]=(src)[3],(des)[4]=(src)[4],(des)[5]=(src)[5])
|
|
|
+MODULE_LICENSE("GPL");
|
|
|
+MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
|
|
|
+MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
|
|
|
+MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards");
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+MODULE_PARM(ifname, "s");
|
|
|
+MODULE_PARM_DESC(devname," Net interface name, wlan%d=default");
|
|
|
+
|
|
|
+MODULE_PARM(hwseqnum,"i");
|
|
|
+MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default");
|
|
|
+
|
|
|
+MODULE_PARM(hwwep,"i");
|
|
|
+MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards");
|
|
|
+
|
|
|
+MODULE_PARM(channels,"i");
|
|
|
+MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI");
|
|
|
+*/
|
|
|
+
|
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
|
|
|
+module_param(ifname, charp, S_IRUGO|S_IWUSR );
|
|
|
+module_param(hwseqnum,int, S_IRUGO|S_IWUSR);
|
|
|
+module_param(hwwep,int, S_IRUGO|S_IWUSR);
|
|
|
+module_param(channels,int, S_IRUGO|S_IWUSR);
|
|
|
+#else
|
|
|
+MODULE_PARM(ifname, "s");
|
|
|
+MODULE_PARM(hwseqnum,"i");
|
|
|
+MODULE_PARM(hwwep,"i");
|
|
|
+MODULE_PARM(channels,"i");
|
|
|
+#endif
|
|
|
+
|
|
|
+MODULE_PARM_DESC(devname," Net interface name, wlan%d=default");
|
|
|
+//MODULE_PARM_DESC(devname," Net interface name, ath%d=default");
|
|
|
+MODULE_PARM_DESC(hwseqnum," Try to use hardware 802.11 header sequence numbers. Zero=default");
|
|
|
+MODULE_PARM_DESC(hwwep," Try to use hardware WEP support. Still broken and not available on all cards");
|
|
|
+MODULE_PARM_DESC(channels," Channel bitmask for specific locales. NYI");
|
|
|
+
|
|
|
+
|
|
|
+static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
|
|
|
+ const struct pci_device_id *id);
|
|
|
+
|
|
|
+static void __devexit rtl8180_pci_remove(struct pci_dev *pdev);
|
|
|
+
|
|
|
+static void rtl8180_shutdown (struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
+ dev->stop(dev);
|
|
|
+ pci_disable_device(pdev);
|
|
|
+}
|
|
|
+
|
|
|
+static struct pci_driver rtl8180_pci_driver = {
|
|
|
+ .name = RTL8180_MODULE_NAME, /* Driver name */
|
|
|
+ .id_table = rtl8180_pci_id_tbl, /* PCI_ID table */
|
|
|
+ .probe = rtl8180_pci_probe, /* probe fn */
|
|
|
+ .remove = __devexit_p(rtl8180_pci_remove),/* remove fn */
|
|
|
+#ifdef CONFIG_RTL8180_PM
|
|
|
+ .suspend = rtl8180_suspend, /* PM suspend fn */
|
|
|
+ .resume = rtl8180_resume, /* PM resume fn */
|
|
|
+#else
|
|
|
+ .suspend = NULL, /* PM suspend fn */
|
|
|
+ .resume = NULL, /* PM resume fn */
|
|
|
+#endif
|
|
|
+ .shutdown = rtl8180_shutdown,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_IO_MAP
|
|
|
+
|
|
|
+u8 read_nic_byte(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return 0xff&inb(dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+u32 read_nic_dword(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return inl(dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+u16 read_nic_word(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return inw(dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_byte(struct net_device *dev, int x,u8 y)
|
|
|
+{
|
|
|
+ outb(y&0xff,dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_word(struct net_device *dev, int x,u16 y)
|
|
|
+{
|
|
|
+ outw(y,dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_dword(struct net_device *dev, int x,u32 y)
|
|
|
+{
|
|
|
+ outl(y,dev->base_addr +x);
|
|
|
+}
|
|
|
+
|
|
|
+#else /* RTL_IO_MAP */
|
|
|
+
|
|
|
+u8 read_nic_byte(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return 0xff&readb((u8*)dev->mem_start +x);
|
|
|
+}
|
|
|
+
|
|
|
+u32 read_nic_dword(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return readl((u8*)dev->mem_start +x);
|
|
|
+}
|
|
|
+
|
|
|
+u16 read_nic_word(struct net_device *dev, int x)
|
|
|
+{
|
|
|
+ return readw((u8*)dev->mem_start +x);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_byte(struct net_device *dev, int x,u8 y)
|
|
|
+{
|
|
|
+ writeb(y,(u8*)dev->mem_start +x);
|
|
|
+ udelay(20);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_dword(struct net_device *dev, int x,u32 y)
|
|
|
+{
|
|
|
+ writel(y,(u8*)dev->mem_start +x);
|
|
|
+ udelay(20);
|
|
|
+}
|
|
|
+
|
|
|
+void write_nic_word(struct net_device *dev, int x,u16 y)
|
|
|
+{
|
|
|
+ writew(y,(u8*)dev->mem_start +x);
|
|
|
+ udelay(20);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* RTL_IO_MAP */
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+inline void force_pci_posting(struct net_device *dev)
|
|
|
+{
|
|
|
+ read_nic_byte(dev,EPROM_CMD);
|
|
|
+#ifndef CONFIG_RTL8180_IO_MAP
|
|
|
+ mb();
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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);
|
|
|
+
|
|
|
+/****************************************************************************
|
|
|
+ -----------------------------PROCFS STUFF-------------------------
|
|
|
+*****************************************************************************/
|
|
|
+
|
|
|
+static struct proc_dir_entry *rtl8180_proc = NULL;
|
|
|
+
|
|
|
+static int proc_get_registers(char *page, char **start,
|
|
|
+ off_t offset, int count,
|
|
|
+ int *eof, void *data)
|
|
|
+{
|
|
|
+ struct net_device *dev = data;
|
|
|
+// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ int len = 0;
|
|
|
+ int i,n;
|
|
|
+
|
|
|
+ int max=0xff;
|
|
|
+
|
|
|
+ /* This dump the current register page */
|
|
|
+ for(n=0;n<=max;)
|
|
|
+ {
|
|
|
+ //printk( "\nD: %2x> ", n);
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ "\nD: %2x > ",n);
|
|
|
+
|
|
|
+ for(i=0;i<16 && n<=max;i++,n++)
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ "%2x ",read_nic_byte(dev,n));
|
|
|
+
|
|
|
+ // printk("%2x ",read_nic_byte(dev,n));
|
|
|
+ }
|
|
|
+ len += snprintf(page + len, count - len,"\n");
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ *eof = 1;
|
|
|
+ return len;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int get_curr_tx_free_desc(struct net_device *dev, int priority);
|
|
|
+
|
|
|
+static int proc_get_stats_hw(char *page, char **start,
|
|
|
+ off_t offset, int count,
|
|
|
+ int *eof, void *data)
|
|
|
+{
|
|
|
+ //struct net_device *dev = data;
|
|
|
+ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ int len = 0;
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+
|
|
|
+#else
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ "NIC int: %lu\n"
|
|
|
+ "Total int: %lu\n"
|
|
|
+ "--------------------\n"
|
|
|
+ "LP avail desc %d\n"
|
|
|
+ "NP avail desc %d\n"
|
|
|
+ "--------------------\n"
|
|
|
+ "LP phys dma addr %x\n"
|
|
|
+ "LP NIC ptr %x\n"
|
|
|
+ "LP virt 32base %x\n"
|
|
|
+ "LP virt 32tail %x\n"
|
|
|
+ "--------------------\n"
|
|
|
+ "NP phys dma addr %x\n"
|
|
|
+ "NP NIC ptr %x\n"
|
|
|
+ "NP virt 32base %x\n"
|
|
|
+ "NP virt 32tail %x\n"
|
|
|
+ "--------------------\n"
|
|
|
+ "BP phys dma addr %x\n"
|
|
|
+ "BP NIC ptr %x\n"
|
|
|
+ "BP virt 32base %x\n"
|
|
|
+ "BP virt 32tail %x\n",
|
|
|
+ priv->stats.ints,
|
|
|
+ priv->stats.shints,
|
|
|
+ get_curr_tx_free_desc(dev,LOW_PRIORITY),
|
|
|
+ get_curr_tx_free_desc(dev,NORM_PRIORITY),
|
|
|
+ (u32)priv->txvipringdma,
|
|
|
+ read_nic_dword(dev,TLPDA),
|
|
|
+ (u32)priv->txvipring,
|
|
|
+ (u32)priv->txvipringtail,
|
|
|
+ (u32)priv->txvopringdma,
|
|
|
+ read_nic_dword(dev,TNPDA),
|
|
|
+ (u32)priv->txvopring,
|
|
|
+ (u32)priv->txvopringtail,
|
|
|
+ (u32)priv->txbeaconringdma,
|
|
|
+ read_nic_dword(dev,TBDA),
|
|
|
+ (u32)priv->txbeaconring,
|
|
|
+ (u32)priv->txbeaconringtail);
|
|
|
+#endif
|
|
|
+ *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 descriptor not available: %lu\n"
|
|
|
+ "RX incomplete (missing last descriptor): %lu\n"
|
|
|
+ "RX not data: %lu\n"
|
|
|
+ //"RX descriptor pointer reset: %lu\n"
|
|
|
+ "RX descriptor pointer lost: %lu\n"
|
|
|
+ //"RX pointer workaround: %lu\n"
|
|
|
+ "RX error int: %lu\n"
|
|
|
+ "RX fifo overflow: %lu\n"
|
|
|
+ "RX int: %lu\n"
|
|
|
+ "RX packet: %lu\n"
|
|
|
+ "RX bytes: %lu\n"
|
|
|
+ "RX DMA fail: %lu\n",
|
|
|
+ priv->stats.rxrdu,
|
|
|
+ priv->stats.rxnolast,
|
|
|
+ priv->stats.rxnodata,
|
|
|
+ //priv->stats.rxreset,
|
|
|
+ priv->stats.rxnopointer,
|
|
|
+ //priv->stats.rxwrkaround,
|
|
|
+ priv->stats.rxerr,
|
|
|
+ priv->stats.rxoverflow,
|
|
|
+ priv->stats.rxint,
|
|
|
+ priv->ieee80211->stats.rx_packets,
|
|
|
+ priv->ieee80211->stats.rx_bytes,
|
|
|
+ priv->stats.rxdmafail */
|
|
|
+ "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;
|
|
|
+}
|
|
|
+
|
|
|
+#if 0
|
|
|
+static int proc_get_stats_ieee(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,
|
|
|
+ "TXed association requests: %u\n"
|
|
|
+ "TXed authentication requests: %u\n"
|
|
|
+ "RXed successful association response: %u\n"
|
|
|
+ "RXed failed association response: %u\n"
|
|
|
+ "RXed successful authentication response: %u\n"
|
|
|
+ "RXed failed authentication response: %u\n"
|
|
|
+ "Association requests without response: %u\n"
|
|
|
+ "Authentication requests without response: %u\n"
|
|
|
+ "TX probe response: %u\n"
|
|
|
+ "RX probe request: %u\n"
|
|
|
+ "TX probe request: %lu\n"
|
|
|
+ "RX authentication requests: %lu\n"
|
|
|
+ "RX association requests: %lu\n"
|
|
|
+ "Reassociations: %lu\n",
|
|
|
+ priv->ieee80211->ieee_stats.tx_ass,
|
|
|
+ priv->ieee80211->ieee_stats.tx_aut,
|
|
|
+ priv->ieee80211->ieee_stats.rx_ass_ok,
|
|
|
+ priv->ieee80211->ieee_stats.rx_ass_err,
|
|
|
+ priv->ieee80211->ieee_stats.rx_aut_ok,
|
|
|
+ priv->ieee80211->ieee_stats.rx_aut_err,
|
|
|
+ priv->ieee80211->ieee_stats.ass_noresp,
|
|
|
+ priv->ieee80211->ieee_stats.aut_noresp,
|
|
|
+ priv->ieee80211->ieee_stats.tx_probe,
|
|
|
+ priv->ieee80211->ieee_stats.rx_probe,
|
|
|
+ priv->ieee80211->ieee_stats.tx_probe_rq,
|
|
|
+ priv->ieee80211->ieee_stats.rx_auth_rq,
|
|
|
+ priv->ieee80211->ieee_stats.rx_assoc_rq,
|
|
|
+ priv->ieee80211->ieee_stats.reassoc);
|
|
|
+
|
|
|
+ *eof = 1;
|
|
|
+ return len;
|
|
|
+}
|
|
|
+#endif
|
|
|
+#if 0
|
|
|
+static int proc_get_stats_ap(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);
|
|
|
+ struct mac_htable_t *list;
|
|
|
+ int i;
|
|
|
+ int len = 0;
|
|
|
+
|
|
|
+ if(priv->ieee80211->iw_mode != IW_MODE_MASTER){
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ "Card is not acting as AP...\n"
|
|
|
+ );
|
|
|
+ }else{
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ "List of associated STA:\n"
|
|
|
+ );
|
|
|
+
|
|
|
+ for(i=0;i<MAC_HTABLE_ENTRY;i++)
|
|
|
+ for (list = priv->ieee80211->assoc_htable[i]; list!=NULL; list = list->next){
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ MACSTR"\n",MAC2STR(list->adr));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ *eof = 1;
|
|
|
+ return len;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static int proc_get_stats_tx(char *page, char **start,
|
|
|
+ off_t offset, int count,
|
|
|
+ int *eof, void *data)
|
|
|
+{
|
|
|
+ struct net_device *dev = data;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ int len = 0;
|
|
|
+ unsigned long totalOK;
|
|
|
+
|
|
|
+ totalOK=priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint;
|
|
|
+ len += snprintf(page + len, count - len,
|
|
|
+ /* "TX normal priority ok int: %lu\n"
|
|
|
+ "TX normal priority error int: %lu\n"
|
|
|
+ "TX high priority ok int: %lu\n"
|
|
|
+ "TX high priority failed error int: %lu\n"
|
|
|
+ "TX low priority ok int: %lu\n"
|
|
|
+ "TX low priority failed error int: %lu\n"
|
|
|
+ "TX bytes: %lu\n"
|
|
|
+ "TX packets: %lu\n"
|
|
|
+ "TX queue resume: %lu\n"
|
|
|
+ "TX queue stopped?: %d\n"
|
|
|
+ "TX fifo overflow: %lu\n"
|
|
|
+ //"SW TX stop: %lu\n"
|
|
|
+ //"SW TX wake: %lu\n"
|
|
|
+ "TX beacon: %lu\n"
|
|
|
+ "TX beacon aborted: %lu\n",
|
|
|
+ priv->stats.txnpokint,
|
|
|
+ priv->stats.txnperr,
|
|
|
+ priv->stats.txhpokint,
|
|
|
+ priv->stats.txhperr,
|
|
|
+ priv->stats.txlpokint,
|
|
|
+ priv->stats.txlperr,
|
|
|
+ priv->ieee80211->stats.tx_bytes,
|
|
|
+ priv->ieee80211->stats.tx_packets,
|
|
|
+ priv->stats.txresumed,
|
|
|
+ netif_queue_stopped(dev),
|
|
|
+ priv->stats.txoverflow,
|
|
|
+ //priv->ieee80211->ieee_stats.swtxstop,
|
|
|
+ //priv->ieee80211->ieee_stats.swtxawake,
|
|
|
+ priv->stats.txbeacon,
|
|
|
+ priv->stats.txbeaconerr */
|
|
|
+ "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;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#if WIRELESS_EXT < 17
|
|
|
+static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ return &priv->wstats;
|
|
|
+}
|
|
|
+#endif
|
|
|
+void rtl8180_proc_module_init(void)
|
|
|
+{
|
|
|
+ DMESG("Initializing proc filesystem");
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
|
|
+ rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, proc_net);
|
|
|
+#else
|
|
|
+ rtl8180_proc=create_proc_entry(RTL8180_MODULE_NAME, S_IFDIR, init_net.proc_net);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_proc_module_remove(void)
|
|
|
+{
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
|
|
+ remove_proc_entry(RTL8180_MODULE_NAME, proc_net);
|
|
|
+#else
|
|
|
+ remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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("stats-ieee", priv->dir_dev);
|
|
|
+// remove_proc_entry("stats-ap", priv->dir_dev);
|
|
|
+ remove_proc_entry("registers", priv->dir_dev);
|
|
|
+ remove_proc_entry(dev->name, rtl8180_proc);
|
|
|
+ priv->dir_dev = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_proc_init_one(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct proc_dir_entry *e;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ priv->dir_dev = create_proc_entry(dev->name,
|
|
|
+ S_IFDIR | S_IRUGO | S_IXUGO,
|
|
|
+ rtl8180_proc);
|
|
|
+ if (!priv->dir_dev) {
|
|
|
+ DMESGE("Unable to initialize /proc/net/rtl8180/%s\n",
|
|
|
+ dev->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_stats_hw, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/stats-hw\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+
|
|
|
+ e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_stats_rx, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/stats-rx\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_stats_tx, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/stats-tx\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+ #if 0
|
|
|
+ e = create_proc_read_entry("stats-ieee", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_stats_ieee, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/stats-ieee\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ #if 0
|
|
|
+ e = create_proc_read_entry("stats-ap", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_stats_ap, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/stats-ap\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ e = create_proc_read_entry("registers", S_IFREG | S_IRUGO,
|
|
|
+ priv->dir_dev, proc_get_registers, dev);
|
|
|
+
|
|
|
+ if (!e) {
|
|
|
+ DMESGE("Unable to initialize "
|
|
|
+ "/proc/net/rtl8180/%s/registers\n",
|
|
|
+ dev->name);
|
|
|
+ }
|
|
|
+}
|
|
|
+/****************************************************************************
|
|
|
+ -----------------------------MISC STUFF-------------------------
|
|
|
+*****************************************************************************/
|
|
|
+/*
|
|
|
+ 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)
|
|
|
+{
|
|
|
+#ifdef DEBUG_RING
|
|
|
+ DMESG("adding buffer to TX/RX struct");
|
|
|
+#endif
|
|
|
+
|
|
|
+ struct buffer *tmp;
|
|
|
+
|
|
|
+ if(! *buffer){
|
|
|
+
|
|
|
+ *buffer = kmalloc(sizeof(struct buffer),GFP_KERNEL);
|
|
|
+
|
|
|
+ if (*buffer == NULL) {
|
|
|
+ DMESGE("Failed to kmalloc head of TX/RX struct");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ (*buffer)->next=*buffer;
|
|
|
+ (*buffer)->buf=buf;
|
|
|
+ (*buffer)->dma=dma;
|
|
|
+ if(bufferhead !=NULL)
|
|
|
+ (*bufferhead) = (*buffer);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ tmp=*buffer;
|
|
|
+
|
|
|
+ while(tmp->next!=(*buffer)) tmp=tmp->next;
|
|
|
+ if ((tmp->next= kmalloc(sizeof(struct buffer),GFP_KERNEL)) == NULL){
|
|
|
+ DMESGE("Failed to kmalloc TX/RX struct");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ tmp->next->buf=buf;
|
|
|
+ tmp->next->dma=dma;
|
|
|
+ tmp->next->next=*buffer;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void buffer_free(struct net_device *dev,struct buffer **buffer,int len,short
|
|
|
+consistent)
|
|
|
+{
|
|
|
+
|
|
|
+ struct buffer *tmp,*next;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct pci_dev *pdev=priv->pdev;
|
|
|
+ //int i;
|
|
|
+
|
|
|
+ if(! *buffer) return;
|
|
|
+
|
|
|
+ /*for(tmp=*buffer; tmp->next != *buffer; tmp=tmp->next)
|
|
|
+
|
|
|
+ */
|
|
|
+ tmp=*buffer;
|
|
|
+ do{
|
|
|
+ next=tmp->next;
|
|
|
+ if(consistent){
|
|
|
+ pci_free_consistent(pdev,len,
|
|
|
+ tmp->buf,tmp->dma);
|
|
|
+ }else{
|
|
|
+ pci_unmap_single(pdev, tmp->dma,
|
|
|
+ len,PCI_DMA_FROMDEVICE);
|
|
|
+ kfree(tmp->buf);
|
|
|
+ }
|
|
|
+ kfree(tmp);
|
|
|
+ tmp = next;
|
|
|
+ }
|
|
|
+ while(next != *buffer);
|
|
|
+
|
|
|
+ *buffer=NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void print_buffer(u32 *buffer, int len)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u8 *buf =(u8*)buffer;
|
|
|
+
|
|
|
+ printk("ASCII BUFFER DUMP (len: %x):\n",len);
|
|
|
+
|
|
|
+ for(i=0;i<len;i++)
|
|
|
+ printk("%c",buf[i]);
|
|
|
+
|
|
|
+ printk("\nBINARY BUFFER DUMP (len: %x):\n",len);
|
|
|
+
|
|
|
+ for(i=0;i<len;i++)
|
|
|
+ printk("%02x",buf[i]);
|
|
|
+
|
|
|
+ printk("\n");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int get_curr_tx_free_desc(struct net_device *dev, int priority)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u32* tail;
|
|
|
+ u32* head;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ switch (priority){
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ head = priv->txmapringhead;
|
|
|
+ tail = priv->txmapringtail;
|
|
|
+ break;
|
|
|
+ case BK_PRIORITY:
|
|
|
+ head = priv->txbkpringhead;
|
|
|
+ tail = priv->txbkpringtail;
|
|
|
+ break;
|
|
|
+ case BE_PRIORITY:
|
|
|
+ head = priv->txbepringhead;
|
|
|
+ tail = priv->txbepringtail;
|
|
|
+ break;
|
|
|
+ case VI_PRIORITY:
|
|
|
+ head = priv->txvipringhead;
|
|
|
+ tail = priv->txvipringtail;
|
|
|
+ break;
|
|
|
+ case VO_PRIORITY:
|
|
|
+ head = priv->txvopringhead;
|
|
|
+ tail = priv->txvopringtail;
|
|
|
+ break;
|
|
|
+ case HI_PRIORITY:
|
|
|
+ head = priv->txhpringhead;
|
|
|
+ tail = priv->txhpringtail;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ //DMESG("%x %x", head, tail);
|
|
|
+
|
|
|
+ /* FIXME FIXME FIXME FIXME */
|
|
|
+
|
|
|
+#if 0
|
|
|
+ if( head <= tail ) return priv->txringcount-1 - (tail - head)/8;
|
|
|
+ return (head - tail)/8/4;
|
|
|
+#else
|
|
|
+ if( head <= tail )
|
|
|
+ ret = priv->txringcount - (tail - head)/8;
|
|
|
+ else
|
|
|
+ ret = (head - tail)/8;
|
|
|
+
|
|
|
+ if(ret > priv->txringcount ) DMESG("BUG");
|
|
|
+ return ret;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+short check_nic_enought_desc(struct net_device *dev, int priority)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ struct ieee80211_device *ieee = netdev_priv(dev);
|
|
|
+
|
|
|
+ int requiredbyte, required;
|
|
|
+ requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data);
|
|
|
+
|
|
|
+ if(ieee->current_network.QoS_Enable) {
|
|
|
+ requiredbyte += 2;
|
|
|
+ };
|
|
|
+
|
|
|
+ required = requiredbyte / (priv->txbuffsize-4);
|
|
|
+ if (requiredbyte % priv->txbuffsize) required++;
|
|
|
+ /* for now we keep two free descriptor as a safety boundary
|
|
|
+ * between the tail and the head
|
|
|
+ */
|
|
|
+
|
|
|
+ return (required+2 < get_curr_tx_free_desc(dev,priority));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* This function is only for debuging purpose */
|
|
|
+void check_tx_ring(struct net_device *dev, int pri)
|
|
|
+{
|
|
|
+ static int maxlog =3;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u32* tmp;
|
|
|
+ struct buffer *buf;
|
|
|
+ int i;
|
|
|
+ int nic;
|
|
|
+ u32* tail;
|
|
|
+ u32* head;
|
|
|
+ u32* begin;
|
|
|
+ u32 nicbegin;
|
|
|
+ struct buffer* buffer;
|
|
|
+
|
|
|
+ maxlog --;
|
|
|
+ if (maxlog <0 ) return;
|
|
|
+
|
|
|
+ switch(pri) {
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ tail = priv->txmapringtail;
|
|
|
+ begin = priv->txmapring;
|
|
|
+ head = priv->txmapringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txmapbufs;
|
|
|
+ nicbegin = priv->txmapringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case BK_PRIORITY:
|
|
|
+ tail = priv->txbkpringtail;
|
|
|
+ begin = priv->txbkpring;
|
|
|
+ head = priv->txbkpringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txbkpbufs;
|
|
|
+ nicbegin = priv->txbkpringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BE_PRIORITY:
|
|
|
+ tail = priv->txbepringtail;
|
|
|
+ begin = priv->txbepring;
|
|
|
+ head = priv->txbepringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txbepbufs;
|
|
|
+ nicbegin = priv->txbepringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VI_PRIORITY:
|
|
|
+ tail = priv->txvipringtail;
|
|
|
+ begin = priv->txvipring;
|
|
|
+ head = priv->txvipringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txvipbufs;
|
|
|
+ nicbegin = priv->txvipringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case VO_PRIORITY:
|
|
|
+ tail = priv->txvopringtail;
|
|
|
+ begin = priv->txvopring;
|
|
|
+ head = priv->txvopringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txvopbufs;
|
|
|
+ nicbegin = priv->txvopringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HI_PRIORITY:
|
|
|
+ tail = priv->txhpringtail;
|
|
|
+ begin = priv->txhpring;
|
|
|
+ head = priv->txhpringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR);
|
|
|
+ buffer = priv->txhpbufs;
|
|
|
+ nicbegin = priv->txhpringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return ;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!priv->txvopbufs)
|
|
|
+ DMESGE ("NIC TX ack, but TX queue corrupted!");
|
|
|
+ else{
|
|
|
+
|
|
|
+ for(i=0,buf=buffer, tmp=begin;
|
|
|
+ tmp<begin+(priv->txringcount)*8;
|
|
|
+ tmp+=8,buf=buf->next,i++)
|
|
|
+
|
|
|
+ DMESG("BUF%d %s %x %s. Next : %x",i,
|
|
|
+ *tmp & (1<<31) ? "filled" : "empty",
|
|
|
+ *(buf->buf),
|
|
|
+ *tmp & (1<<15)? "ok": "err", *(tmp+4));
|
|
|
+ }
|
|
|
+
|
|
|
+ DMESG("nic at %d",
|
|
|
+ (nic-nicbegin) / 8 /4);
|
|
|
+ DMESG("tail at %d", ((int)tail - (int)begin) /8 /4);
|
|
|
+ DMESG("head at %d", ((int)head - (int)begin) /8 /4);
|
|
|
+ DMESG("check free desc returns %d", check_nic_enought_desc(dev,pri));
|
|
|
+ DMESG("free desc is %d\n", get_curr_tx_free_desc(dev,pri));
|
|
|
+ //rtl8180_reset(dev);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/* this function is only for debugging purpose */
|
|
|
+void check_rxbuf(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u32* tmp;
|
|
|
+ struct buffer *buf;
|
|
|
+ u8 rx_desc_size;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rx_desc_size = 8;
|
|
|
+#else
|
|
|
+ rx_desc_size = 4;
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(!priv->rxbuffer)
|
|
|
+ DMESGE ("NIC RX ack, but RX queue corrupted!");
|
|
|
+
|
|
|
+ else{
|
|
|
+
|
|
|
+ for(buf=priv->rxbuffer, tmp=priv->rxring;
|
|
|
+ tmp < priv->rxring+(priv->rxringcount)*rx_desc_size;
|
|
|
+ tmp+=rx_desc_size, buf=buf->next)
|
|
|
+
|
|
|
+ DMESG("BUF %s %x",
|
|
|
+ *tmp & (1<<31) ? "empty" : "filled",
|
|
|
+ *(buf->buf));
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void dump_eprom(struct net_device *dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ for(i=0; i<63; i++)
|
|
|
+ DMESG("EEPROM addr %x : %x", i, eprom_read(dev,i));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_dump_reg(struct net_device *dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int n;
|
|
|
+ int max=0xff;
|
|
|
+
|
|
|
+ DMESG("Dumping NIC register map");
|
|
|
+
|
|
|
+ for(n=0;n<=max;)
|
|
|
+ {
|
|
|
+ printk( "\nD: %2x> ", n);
|
|
|
+ for(i=0;i<16 && n<=max;i++,n++)
|
|
|
+ printk("%2x ",read_nic_byte(dev,n));
|
|
|
+ }
|
|
|
+ printk("\n");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void fix_tx_fifo(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u32 *tmp;
|
|
|
+ int i;
|
|
|
+#ifdef DEBUG_TX_ALLOC
|
|
|
+ DMESG("FIXING TX FIFOs");
|
|
|
+#endif
|
|
|
+ for (tmp=priv->txmapring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8, i++){
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tmp=priv->txbkpring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8, i++) {
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tmp=priv->txbepring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8, i++){
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+ for (tmp=priv->txvipring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8, i++) {
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tmp=priv->txvopring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8, i++){
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tmp=priv->txhpring, i=0;
|
|
|
+ i < priv->txringcount;
|
|
|
+ tmp+=8,i++){
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (tmp=priv->txbeaconring, i=0;
|
|
|
+ i < priv->txbeaconcount;
|
|
|
+ tmp+=8, i++){
|
|
|
+ *tmp = *tmp &~ (1<<31);
|
|
|
+ }
|
|
|
+#ifdef DEBUG_TX_ALLOC
|
|
|
+ DMESG("TX FIFOs FIXED");
|
|
|
+#endif
|
|
|
+ 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;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rx_desc_size = 8; // 4*8 = 32 bytes
|
|
|
+#else
|
|
|
+ rx_desc_size = 4;
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef DEBUG_RXALLOC
|
|
|
+ DMESG("FIXING RX FIFO");
|
|
|
+ check_rxbuf(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ for (tmp=priv->rxring, rxbuf=priv->rxbufferhead;
|
|
|
+ (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size);
|
|
|
+ tmp+=rx_desc_size,rxbuf=rxbuf->next){
|
|
|
+ *(tmp+2) = rxbuf->dma;
|
|
|
+ *tmp=*tmp &~ 0xfff;
|
|
|
+ *tmp=*tmp | priv->rxbuffersize;
|
|
|
+ *tmp |= (1<<31);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_RXALLOC
|
|
|
+ DMESG("RX FIFO FIXED");
|
|
|
+ check_rxbuf(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ priv->rxringtail=priv->rxring;
|
|
|
+ priv->rxbuffer=priv->rxbufferhead;
|
|
|
+ priv->rx_skb_complete=1;
|
|
|
+ set_nic_rxring(dev);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/****************************************************************************
|
|
|
+ ------------------------------HW STUFF---------------------------
|
|
|
+*****************************************************************************/
|
|
|
+
|
|
|
+unsigned char QUALITY_MAP[] = {
|
|
|
+ 0x64, 0x64, 0x64, 0x63, 0x63, 0x62, 0x62, 0x61,
|
|
|
+ 0x61, 0x60, 0x60, 0x5f, 0x5f, 0x5e, 0x5d, 0x5c,
|
|
|
+ 0x5b, 0x5a, 0x59, 0x57, 0x56, 0x54, 0x52, 0x4f,
|
|
|
+ 0x4c, 0x49, 0x45, 0x41, 0x3c, 0x37, 0x31, 0x29,
|
|
|
+ 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
|
|
+ 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
|
|
|
+ 0x20, 0x20, 0x20, 0x1f, 0x1f, 0x1e, 0x1e, 0x1e,
|
|
|
+ 0x1d, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a, 0x19, 0x19,
|
|
|
+ 0x18, 0x17, 0x16, 0x15, 0x14, 0x12, 0x11, 0x0f,
|
|
|
+ 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x01, 0x00
|
|
|
+};
|
|
|
+
|
|
|
+unsigned char STRENGTH_MAP[] = {
|
|
|
+ 0x64, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e,
|
|
|
+ 0x5d, 0x5c, 0x5b, 0x5a, 0x57, 0x54, 0x52, 0x50,
|
|
|
+ 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x41, 0x3f,
|
|
|
+ 0x3c, 0x3a, 0x37, 0x36, 0x36, 0x1c, 0x1c, 0x1b,
|
|
|
+ 0x1b, 0x1a, 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17,
|
|
|
+ 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, 0x14, 0x13,
|
|
|
+ 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10, 0x0f,
|
|
|
+ 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
|
|
|
+ 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
|
|
|
+ 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x00
|
|
|
+};
|
|
|
+
|
|
|
+void rtl8180_RSSI_calc(struct net_device *dev, u8 *rssi, u8 *qual){
|
|
|
+ //void Mlme_UpdateRssiSQ(struct net_device *dev, u8 *rssi, u8 *qual){
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u32 temp;
|
|
|
+ u32 temp2;
|
|
|
+ u32 temp3;
|
|
|
+ u32 lsb;
|
|
|
+ u32 q;
|
|
|
+ u32 orig_qual;
|
|
|
+ u8 _rssi;
|
|
|
+
|
|
|
+ q = *qual;
|
|
|
+ orig_qual = *qual;
|
|
|
+ _rssi = 0; // avoid gcc complains..
|
|
|
+
|
|
|
+ if (q <= 0x4e) {
|
|
|
+ temp = QUALITY_MAP[q];
|
|
|
+ } else {
|
|
|
+ if( q & 0x80 ) {
|
|
|
+ temp = 0x32;
|
|
|
+ } else {
|
|
|
+ temp = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ *qual = temp;
|
|
|
+ temp2 = *rssi;
|
|
|
+
|
|
|
+ switch(priv->rf_chip){
|
|
|
+ case RFCHIPID_RFMD:
|
|
|
+ lsb = temp2 & 1;
|
|
|
+ temp2 &= 0x7e;
|
|
|
+ if ( !lsb || !(temp2 <= 0x3c) ) {
|
|
|
+ temp2 = 0x64;
|
|
|
+ } else {
|
|
|
+ temp2 = 100 * temp2 / 0x3c;
|
|
|
+ }
|
|
|
+ *rssi = temp2 & 0xff;
|
|
|
+ _rssi = temp2 & 0xff;
|
|
|
+ break;
|
|
|
+ case RFCHIPID_INTERSIL:
|
|
|
+ lsb = temp2;
|
|
|
+ temp2 &= 0xfffffffe;
|
|
|
+ temp2 *= 251;
|
|
|
+ temp3 = temp2;
|
|
|
+ temp2 <<= 6;
|
|
|
+ temp3 += temp2;
|
|
|
+ temp3 <<= 1;
|
|
|
+ temp2 = 0x4950df;
|
|
|
+ temp2 -= temp3;
|
|
|
+ lsb &= 1;
|
|
|
+ if ( temp2 <= 0x3e0000 ) {
|
|
|
+ if ( temp2 < 0xffef0000 )
|
|
|
+ temp2 = 0xffef0000;
|
|
|
+ } else {
|
|
|
+ temp2 = 0x3e0000;
|
|
|
+ }
|
|
|
+ if ( !lsb ) {
|
|
|
+ temp2 -= 0xf0000;
|
|
|
+ } else {
|
|
|
+ temp2 += 0xf0000;
|
|
|
+ }
|
|
|
+
|
|
|
+ temp3 = 0x4d0000;
|
|
|
+ temp3 -= temp2;
|
|
|
+ temp3 *= 100;
|
|
|
+ temp3 = temp3 / 0x6d;
|
|
|
+ temp3 >>= 0x10;
|
|
|
+ _rssi = temp3 & 0xff;
|
|
|
+ *rssi = temp3 & 0xff;
|
|
|
+ break;
|
|
|
+ case RFCHIPID_GCT:
|
|
|
+ lsb = temp2 & 1;
|
|
|
+ temp2 &= 0x7e;
|
|
|
+ if ( ! lsb || !(temp2 <= 0x3c) ){
|
|
|
+ temp2 = 0x64;
|
|
|
+ } else {
|
|
|
+ temp2 = (100 * temp2) / 0x3c;
|
|
|
+ }
|
|
|
+ *rssi = temp2 & 0xff;
|
|
|
+ _rssi = temp2 & 0xff;
|
|
|
+ break;
|
|
|
+ case RFCHIPID_PHILIPS:
|
|
|
+ if( orig_qual <= 0x4e ){
|
|
|
+ _rssi = STRENGTH_MAP[orig_qual];
|
|
|
+ *rssi = _rssi;
|
|
|
+ } else {
|
|
|
+ orig_qual -= 0x80;
|
|
|
+ if ( !orig_qual ){
|
|
|
+ _rssi = 1;
|
|
|
+ *rssi = 1;
|
|
|
+ } else {
|
|
|
+ _rssi = 0x32;
|
|
|
+ *rssi = 0x32;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* case 4 */
|
|
|
+ case RFCHIPID_MAXIM:
|
|
|
+ lsb = temp2 & 1;
|
|
|
+ temp2 &= 0x7e;
|
|
|
+ temp2 >>= 1;
|
|
|
+ temp2 += 0x42;
|
|
|
+ if( lsb != 0 ){
|
|
|
+ temp2 += 0xa;
|
|
|
+ }
|
|
|
+ *rssi = temp2 & 0xff;
|
|
|
+ _rssi = temp2 & 0xff;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( _rssi < 0x64 ){
|
|
|
+ if ( _rssi == 0 ) {
|
|
|
+ *rssi = 1;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ *rssi = 0x64;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_irq_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ priv->irq_enabled = 1;
|
|
|
+/*
|
|
|
+ write_nic_word(dev,INTA_MASK,INTA_RXOK | INTA_RXDESCERR | INTA_RXOVERFLOW |\
|
|
|
+ INTA_TXOVERFLOW | INTA_HIPRIORITYDESCERR | INTA_HIPRIORITYDESCOK |\
|
|
|
+ INTA_NORMPRIORITYDESCERR | INTA_NORMPRIORITYDESCOK |\
|
|
|
+ INTA_LOWPRIORITYDESCERR | INTA_LOWPRIORITYDESCOK | INTA_TIMEOUT);
|
|
|
+*/
|
|
|
+ write_nic_word(dev,INTA_MASK, priv->irq_mask);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_irq_disable(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ write_nic_dword(dev,IMR,0);
|
|
|
+#else
|
|
|
+ write_nic_word(dev,INTA_MASK,0);
|
|
|
+#endif
|
|
|
+ force_pci_posting(dev);
|
|
|
+ priv->irq_enabled = 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_set_mode(struct net_device *dev,int mode)
|
|
|
+{
|
|
|
+ u8 ecmd;
|
|
|
+ ecmd=read_nic_byte(dev, EPROM_CMD);
|
|
|
+ ecmd=ecmd &~ EPROM_CMD_OPERATING_MODE_MASK;
|
|
|
+ ecmd=ecmd | (mode<<EPROM_CMD_OPERATING_MODE_SHIFT);
|
|
|
+ ecmd=ecmd &~ (1<<EPROM_CS_SHIFT);
|
|
|
+ ecmd=ecmd &~ (1<<EPROM_CK_SHIFT);
|
|
|
+ write_nic_byte(dev, EPROM_CMD, ecmd);
|
|
|
+}
|
|
|
+
|
|
|
+void rtl8180_adapter_start(struct net_device *dev);
|
|
|
+void rtl8180_beacon_tx_enable(struct net_device *dev);
|
|
|
+
|
|
|
+void rtl8180_update_msr(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u8 msr;
|
|
|
+ u32 rxconf;
|
|
|
+
|
|
|
+ msr = read_nic_byte(dev, MSR);
|
|
|
+ msr &= ~ MSR_LINK_MASK;
|
|
|
+
|
|
|
+ rxconf=read_nic_dword(dev,RX_CONF);
|
|
|
+
|
|
|
+ if(priv->ieee80211->state == IEEE80211_LINKED)
|
|
|
+ {
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
|
|
+ msr |= (MSR_LINK_ADHOC<<MSR_LINK_SHIFT);
|
|
|
+ else if (priv->ieee80211->iw_mode == IW_MODE_MASTER)
|
|
|
+ msr |= (MSR_LINK_MASTER<<MSR_LINK_SHIFT);
|
|
|
+ else if (priv->ieee80211->iw_mode == IW_MODE_INFRA)
|
|
|
+ msr |= (MSR_LINK_MANAGED<<MSR_LINK_SHIFT);
|
|
|
+ else
|
|
|
+ msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
|
|
|
+ rxconf |= (1<<RX_CHECK_BSSID_SHIFT);
|
|
|
+
|
|
|
+ }else {
|
|
|
+ msr |= (MSR_LINK_NONE<<MSR_LINK_SHIFT);
|
|
|
+ rxconf &= ~(1<<RX_CHECK_BSSID_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ write_nic_byte(dev, MSR, msr);
|
|
|
+ write_nic_dword(dev, RX_CONF, rxconf);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_set_chan(struct net_device *dev,short ch)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ if((ch > 14) || (ch < 1))
|
|
|
+ {
|
|
|
+ printk("In %s: Invalid chnanel %d\n", __FUNCTION__, ch);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->chan=ch;
|
|
|
+ //printk("in %s:channel is %d\n",__FUNCTION__,ch);
|
|
|
+ priv->rf_set_chan(dev,priv->chan);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_rx_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+ u8 cmd;
|
|
|
+ u32 rxconf;
|
|
|
+ /* for now we accept data, management & ctl frame*/
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rxconf=read_nic_dword(dev,RX_CONF);
|
|
|
+ rxconf = rxconf &~ MAC_FILTER_MASK;
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_MNG_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_DATA_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_BCAST_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_MCAST_FRAME_SHIFT);
|
|
|
+// rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT);
|
|
|
+ if (dev->flags & IFF_PROMISC) DMESG ("NIC in promisc mode");
|
|
|
+
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || \
|
|
|
+ dev->flags & IFF_PROMISC){
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT);
|
|
|
+ }else{
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_NICMAC_FRAME_SHIFT);
|
|
|
+ if(priv->card_8185 == 0)
|
|
|
+ rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*if(priv->ieee80211->iw_mode == IW_MODE_MASTER){
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_ALLMAC_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<RX_CHECK_BSSID_SHIFT);
|
|
|
+ }*/
|
|
|
+
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_CTL_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_ICVERR_FRAME_SHIFT);
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_PWR_FRAME_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ if( priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR)
|
|
|
+ rxconf = rxconf | (1<<ACCEPT_CRCERR_FRAME_SHIFT);
|
|
|
+
|
|
|
+ //if(!priv->card_8185){
|
|
|
+ rxconf = rxconf &~ RX_FIFO_THRESHOLD_MASK;
|
|
|
+ rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE<<RX_FIFO_THRESHOLD_SHIFT);
|
|
|
+ //}
|
|
|
+
|
|
|
+ rxconf = rxconf | (1<<RX_AUTORESETPHY_SHIFT);
|
|
|
+ rxconf = rxconf &~ MAX_RX_DMA_MASK;
|
|
|
+ rxconf = rxconf | (MAX_RX_DMA_2048<<MAX_RX_DMA_SHIFT);
|
|
|
+
|
|
|
+ //if(!priv->card_8185)
|
|
|
+ rxconf = rxconf | RCR_ONLYERLPKT;
|
|
|
+
|
|
|
+ rxconf = rxconf &~ RCR_CS_MASK;
|
|
|
+ if(!priv->card_8185)
|
|
|
+ rxconf |= (priv->rcr_csense<<RCR_CS_SHIFT);
|
|
|
+// rxconf &=~ 0xfff00000;
|
|
|
+// rxconf |= 0x90100000;//9014f76f;
|
|
|
+ write_nic_dword(dev, RX_CONF, rxconf);
|
|
|
+
|
|
|
+ fix_rx_fifo(dev);
|
|
|
+
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESG("rxconf: %x %x",rxconf ,read_nic_dword(dev,RX_CONF));
|
|
|
+#endif
|
|
|
+ cmd=read_nic_byte(dev,CMD);
|
|
|
+ write_nic_byte(dev,CMD,cmd | (1<<CMD_RX_ENABLE_SHIFT));
|
|
|
+
|
|
|
+ /* In rtl8139 driver seems that DMA threshold has to be written
|
|
|
+ * after enabling RX, so we rewrite RX_CONFIG register
|
|
|
+ */
|
|
|
+ //mdelay(100);
|
|
|
+// write_nic_dword(dev, RX_CONF, rxconf);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void set_nic_txring(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+
|
|
|
+ write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+ write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+ write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+ write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+ write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+ write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma);
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+
|
|
|
+ write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_conttx_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+ u32 txconf;
|
|
|
+ txconf = read_nic_dword(dev,TX_CONF);
|
|
|
+ txconf = txconf &~ TX_LOOPBACK_MASK;
|
|
|
+ txconf = txconf | (TX_LOOPBACK_CONTINUE <<TX_LOOPBACK_SHIFT);
|
|
|
+ write_nic_dword(dev,TX_CONF,txconf);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_conttx_disable(struct net_device *dev)
|
|
|
+{
|
|
|
+ u32 txconf;
|
|
|
+ txconf = read_nic_dword(dev,TX_CONF);
|
|
|
+ txconf = txconf &~ TX_LOOPBACK_MASK;
|
|
|
+ txconf = txconf | (TX_LOOPBACK_NONE <<TX_LOOPBACK_SHIFT);
|
|
|
+ write_nic_dword(dev,TX_CONF,txconf);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_tx_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+ u8 cmd;
|
|
|
+ u8 tx_agc_ctl;
|
|
|
+ u8 byte;
|
|
|
+ u32 txconf;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ txconf= read_nic_dword(dev,TX_CONF);
|
|
|
+
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+
|
|
|
+
|
|
|
+ byte = read_nic_byte(dev,CW_CONF);
|
|
|
+ byte &= ~(1<<CW_CONF_PERPACKET_CW_SHIFT);
|
|
|
+ byte &= ~(1<<CW_CONF_PERPACKET_RETRY_SHIFT);
|
|
|
+ write_nic_byte(dev, CW_CONF, byte);
|
|
|
+
|
|
|
+ tx_agc_ctl = read_nic_byte(dev, TX_AGC_CTL);
|
|
|
+ tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_GAIN_SHIFT);
|
|
|
+ tx_agc_ctl &= ~(1<<TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT);
|
|
|
+ tx_agc_ctl |=(1<<TX_AGC_CTL_FEEDBACK_ANT);
|
|
|
+ write_nic_byte(dev, TX_AGC_CTL, tx_agc_ctl);
|
|
|
+ /*
|
|
|
+ write_nic_word(dev, 0x5e, 0x01);
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(1);
|
|
|
+ write_nic_word(dev, 0xfe, 0x10);
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(1);
|
|
|
+ write_nic_word(dev, 0x5e, 0x00);
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(1);
|
|
|
+ */
|
|
|
+ write_nic_byte(dev, 0xec, 0x3f); /* Disable early TX */
|
|
|
+ }
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+
|
|
|
+ txconf = txconf &~ (1<<TCR_PROBE_NOTIMESTAMP_SHIFT);
|
|
|
+
|
|
|
+ }else{
|
|
|
+
|
|
|
+ if(hwseqnum)
|
|
|
+ txconf= txconf &~ (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT);
|
|
|
+ else
|
|
|
+ txconf= txconf | (1<<TX_CONF_HEADER_AUTOICREMENT_SHIFT);
|
|
|
+ }
|
|
|
+
|
|
|
+ txconf = txconf &~ TX_LOOPBACK_MASK;
|
|
|
+ txconf = txconf | (TX_LOOPBACK_NONE <<TX_LOOPBACK_SHIFT);
|
|
|
+ txconf = txconf &~ TCR_DPRETRY_MASK;
|
|
|
+ txconf = txconf &~ TCR_RTSRETRY_MASK;
|
|
|
+ txconf = txconf | (priv->retry_data<<TX_DPRETRY_SHIFT);
|
|
|
+ txconf = txconf | (priv->retry_rts<<TX_RTSRETRY_SHIFT);
|
|
|
+ txconf = txconf &~ (1<<TX_NOCRC_SHIFT);
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ if(priv->hw_plcp_len)
|
|
|
+ txconf = txconf &~ TCR_PLCP_LEN;
|
|
|
+ else
|
|
|
+ txconf = txconf | TCR_PLCP_LEN;
|
|
|
+ }else{
|
|
|
+ txconf = txconf &~ TCR_SAT;
|
|
|
+ }
|
|
|
+ txconf = txconf &~ TCR_MXDMA_MASK;
|
|
|
+ txconf = txconf | (TCR_MXDMA_2048<<TCR_MXDMA_SHIFT);
|
|
|
+ txconf = txconf | TCR_CWMIN;
|
|
|
+ txconf = txconf | TCR_DISCW;
|
|
|
+
|
|
|
+// if(priv->ieee80211->hw_wep)
|
|
|
+// txconf=txconf &~ (1<<TX_NOICV_SHIFT);
|
|
|
+// else
|
|
|
+ txconf=txconf | (1<<TX_NOICV_SHIFT);
|
|
|
+
|
|
|
+ write_nic_dword(dev,TX_CONF,txconf);
|
|
|
+
|
|
|
+
|
|
|
+ fix_tx_fifo(dev);
|
|
|
+
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG("txconf: %x %x",txconf,read_nic_dword(dev,TX_CONF));
|
|
|
+#endif
|
|
|
+
|
|
|
+ cmd=read_nic_byte(dev,CMD);
|
|
|
+ write_nic_byte(dev,CMD,cmd | (1<<CMD_TX_ENABLE_SHIFT));
|
|
|
+
|
|
|
+// mdelay(100);
|
|
|
+ write_nic_dword(dev,TX_CONF,txconf);
|
|
|
+// #endif
|
|
|
+/*
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+ write_nic_byte(dev, TX_DMA_POLLING, priv->dma_poll_mask);
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+ */
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_beacon_tx_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ);
|
|
|
+ write_nic_byte(dev,TPPollStop, priv->dma_poll_mask);
|
|
|
+#else
|
|
|
+ priv->dma_poll_mask &=~(1<<TX_DMA_STOP_BEACON_SHIFT);
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask);
|
|
|
+#endif
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_beacon_tx_disable(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ;
|
|
|
+ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask);
|
|
|
+#else
|
|
|
+ priv->dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT);
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask);
|
|
|
+#endif
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_rtx_disable(struct net_device *dev)
|
|
|
+{
|
|
|
+ u8 cmd;
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ cmd=read_nic_byte(dev,CMD);
|
|
|
+ write_nic_byte(dev, CMD, cmd &~ \
|
|
|
+ ((1<<CMD_RX_ENABLE_SHIFT)|(1<<CMD_TX_ENABLE_SHIFT)));
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(10);
|
|
|
+ /*while (read_nic_byte(dev,CMD) & (1<<CMD_RX_ENABLE_SHIFT))
|
|
|
+ udelay(10);
|
|
|
+ */
|
|
|
+
|
|
|
+ if(!priv->rx_skb_complete)
|
|
|
+ dev_kfree_skb_any(priv->rx_skb);
|
|
|
+}
|
|
|
+
|
|
|
+#if 0
|
|
|
+int alloc_tx_beacon_desc_ring(struct net_device *dev, int count)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u32 *tmp;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ priv->txbeaconring = (u32*)pci_alloc_consistent(priv->pdev,
|
|
|
+ sizeof(u32)*8*count,
|
|
|
+ &priv->txbeaconringdma);
|
|
|
+ if (!priv->txbeaconring) return -1;
|
|
|
+ for (tmp=priv->txbeaconring,i=0;i<count;i++){
|
|
|
+ *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv
|
|
|
+ /*
|
|
|
+ *(tmp+2) = (u32)dma_tmp;
|
|
|
+ *(tmp+3) = bufsize;
|
|
|
+ */
|
|
|
+ if(i+1<count)
|
|
|
+ *(tmp+4) = (u32)priv->txbeaconringdma+((i+1)*8*4);
|
|
|
+ else
|
|
|
+ *(tmp+4) = (u32)priv->txbeaconringdma;
|
|
|
+
|
|
|
+ tmp=tmp+8;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count,
|
|
|
+ int addr)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u32 *desc;
|
|
|
+ u32 *tmp;
|
|
|
+ dma_addr_t dma_desc, dma_tmp;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct pci_dev *pdev = priv->pdev;
|
|
|
+ void *buf;
|
|
|
+
|
|
|
+ if((bufsize & 0xfff) != bufsize) {
|
|
|
+ DMESGE ("TX buffer allocation too large");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ desc = (u32*)pci_alloc_consistent(pdev,
|
|
|
+ sizeof(u32)*8*count+256, &dma_desc);
|
|
|
+ if(desc==NULL) return -1;
|
|
|
+ if(dma_desc & 0xff){
|
|
|
+
|
|
|
+ /*
|
|
|
+ * descriptor's buffer must be 256 byte aligned
|
|
|
+ * we shouldn't be here, since we set DMA mask !
|
|
|
+ */
|
|
|
+ DMESGW("Fixing TX alignment");
|
|
|
+ desc = (u32*)((u8*)desc + 256);
|
|
|
+#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR))
|
|
|
+ desc = (u32*)((u64)desc &~ 0xff);
|
|
|
+ dma_desc = (dma_addr_t)((u8*)dma_desc + 256);
|
|
|
+ dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff);
|
|
|
+#else
|
|
|
+ desc = (u32*)((u32)desc &~ 0xff);
|
|
|
+ dma_desc = (dma_addr_t)((u8*)dma_desc + 256);
|
|
|
+ dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ tmp=desc;
|
|
|
+ for (i=0;i<count;i++)
|
|
|
+ {
|
|
|
+ buf = (void*)pci_alloc_consistent(pdev,bufsize,&dma_tmp);
|
|
|
+ if (buf == NULL) return -ENOMEM;
|
|
|
+
|
|
|
+ switch(addr) {
|
|
|
+#if 0
|
|
|
+ case TX_NORMPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txnpbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer NP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_LOWPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txlpbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer LP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_HIGHPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer HP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+#else
|
|
|
+ case TX_MANAGEPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txmapbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer NP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_BKPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txbkpbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer LP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case TX_BEPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txbepbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer NP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_VIPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txvipbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer LP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case TX_VOPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txvopbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer NP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ case TX_HIGHPRIORITY_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txhpbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer HP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case TX_BEACON_RING_ADDR:
|
|
|
+ if(-1 == buffer_add(&(priv->txbeaconbufs),buf,dma_tmp,NULL)){
|
|
|
+ DMESGE("Unable to allocate mem for buffer BP");
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ *tmp = *tmp &~ (1<<31); // descriptor empty, owned by the drv
|
|
|
+ *(tmp+2) = (u32)dma_tmp;
|
|
|
+ *(tmp+3) = bufsize;
|
|
|
+
|
|
|
+ if(i+1<count)
|
|
|
+ *(tmp+4) = (u32)dma_desc+((i+1)*8*4);
|
|
|
+ else
|
|
|
+ *(tmp+4) = (u32)dma_desc;
|
|
|
+
|
|
|
+ tmp=tmp+8;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch(addr) {
|
|
|
+ case TX_MANAGEPRIORITY_RING_ADDR:
|
|
|
+ priv->txmapringdma=dma_desc;
|
|
|
+ priv->txmapring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_BKPRIORITY_RING_ADDR:
|
|
|
+ priv->txbkpringdma=dma_desc;
|
|
|
+ priv->txbkpring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_BEPRIORITY_RING_ADDR:
|
|
|
+ priv->txbepringdma=dma_desc;
|
|
|
+ priv->txbepring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_VIPRIORITY_RING_ADDR:
|
|
|
+ priv->txvipringdma=dma_desc;
|
|
|
+ priv->txvipring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_VOPRIORITY_RING_ADDR:
|
|
|
+ priv->txvopringdma=dma_desc;
|
|
|
+ priv->txvopring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_HIGHPRIORITY_RING_ADDR:
|
|
|
+ priv->txhpringdma=dma_desc;
|
|
|
+ priv->txhpring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case TX_BEACON_RING_ADDR:
|
|
|
+ priv->txbeaconringdma=dma_desc;
|
|
|
+ priv->txbeaconring=desc;
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG("Tx dma physical address: %x",dma_desc);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void free_tx_desc_rings(struct net_device *dev)
|
|
|
+{
|
|
|
+
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct pci_dev *pdev=priv->pdev;
|
|
|
+ int count = priv->txringcount;
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txmapring, priv->txmapringdma);
|
|
|
+ buffer_free(dev,&(priv->txmapbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txbkpring, priv->txbkpringdma);
|
|
|
+ buffer_free(dev,&(priv->txbkpbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txbepring, priv->txbepringdma);
|
|
|
+ buffer_free(dev,&(priv->txbepbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txvipring, priv->txvipringdma);
|
|
|
+ buffer_free(dev,&(priv->txvipbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txvopring, priv->txvopringdma);
|
|
|
+ buffer_free(dev,&(priv->txvopbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txhpring, priv->txhpringdma);
|
|
|
+ buffer_free(dev,&(priv->txhpbufs),priv->txbuffsize,1);
|
|
|
+
|
|
|
+ count = priv->txbeaconcount;
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txbeaconring, priv->txbeaconringdma);
|
|
|
+ buffer_free(dev,&(priv->txbeaconbufs),priv->txbuffsize,1);
|
|
|
+}
|
|
|
+
|
|
|
+#if 0
|
|
|
+void free_beacon_desc_ring(struct net_device *dev,int count)
|
|
|
+{
|
|
|
+
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct pci_dev *pdev=priv->pdev;
|
|
|
+
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->txbeaconring, priv->txbeaconringdma);
|
|
|
+
|
|
|
+ if (priv->beacon_buf)
|
|
|
+ pci_free_consistent(priv->pdev,
|
|
|
+ priv->master_beaconsize,priv->beacon_buf,priv->beacondmabuf);
|
|
|
+
|
|
|
+}
|
|
|
+#endif
|
|
|
+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;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*8*count+256,
|
|
|
+ priv->rxring, priv->rxringdma);
|
|
|
+#else
|
|
|
+ pci_free_consistent(pdev, sizeof(u32)*4*count+256,
|
|
|
+ priv->rxring, priv->rxringdma);
|
|
|
+#endif
|
|
|
+
|
|
|
+ buffer_free(dev,&(priv->rxbuffer),priv->rxbuffersize,0);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u32 *desc;
|
|
|
+ u32 *tmp;
|
|
|
+ dma_addr_t dma_desc,dma_tmp;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct pci_dev *pdev=priv->pdev;
|
|
|
+ void *buf;
|
|
|
+ u8 rx_desc_size;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rx_desc_size = 8; // 4*8 = 32 bytes
|
|
|
+#else
|
|
|
+ rx_desc_size = 4;
|
|
|
+#endif
|
|
|
+
|
|
|
+ if((bufsize & 0xfff) != bufsize){
|
|
|
+ DMESGE ("RX buffer allocation too large");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ desc = (u32*)pci_alloc_consistent(pdev,sizeof(u32)*rx_desc_size*count+256,
|
|
|
+ &dma_desc);
|
|
|
+
|
|
|
+ if(dma_desc & 0xff){
|
|
|
+
|
|
|
+ /*
|
|
|
+ * descriptor's buffer must be 256 byte aligned
|
|
|
+ * should never happen since we specify the DMA mask
|
|
|
+ */
|
|
|
+
|
|
|
+ DMESGW("Fixing RX alignment");
|
|
|
+ desc = (u32*)((u8*)desc + 256);
|
|
|
+#if (defined(CONFIG_HIGHMEM64G) || defined(CONFIG_64BIT_PHYS_ADDR))
|
|
|
+ desc = (u32*)((u64)desc &~ 0xff);
|
|
|
+ dma_desc = (dma_addr_t)((u8*)dma_desc + 256);
|
|
|
+ dma_desc = (dma_addr_t)((u64)dma_desc &~ 0xff);
|
|
|
+#else
|
|
|
+ desc = (u32*)((u32)desc &~ 0xff);
|
|
|
+ dma_desc = (dma_addr_t)((u8*)dma_desc + 256);
|
|
|
+ dma_desc = (dma_addr_t)((u32)dma_desc &~ 0xff);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->rxring=desc;
|
|
|
+ priv->rxringdma=dma_desc;
|
|
|
+ tmp=desc;
|
|
|
+
|
|
|
+ for (i=0;i<count;i++){
|
|
|
+
|
|
|
+ if ((buf= kmalloc(bufsize * sizeof(u8),GFP_ATOMIC)) == NULL){
|
|
|
+ DMESGE("Failed to kmalloc RX buffer");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ dma_tmp = pci_map_single(pdev,buf,bufsize * sizeof(u8),
|
|
|
+ PCI_DMA_FROMDEVICE);
|
|
|
+
|
|
|
+#ifdef DEBUG_ZERO_RX
|
|
|
+ int j;
|
|
|
+ for(j=0;j<bufsize;j++) ((u8*)buf)[i] = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+ //buf = (void*)pci_alloc_consistent(pdev,bufsize,&dma_tmp);
|
|
|
+ if(-1 == buffer_add(&(priv->rxbuffer), buf,dma_tmp,
|
|
|
+ &(priv->rxbufferhead))){
|
|
|
+ DMESGE("Unable to allocate mem RX buf");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *tmp = 0; //zero pads the header of the descriptor
|
|
|
+ *tmp = *tmp |( bufsize&0xfff);
|
|
|
+ *(tmp+2) = (u32)dma_tmp;
|
|
|
+ *tmp = *tmp |(1<<31); // descriptor void, owned by the NIC
|
|
|
+
|
|
|
+#ifdef DEBUG_RXALLOC
|
|
|
+ DMESG("Alloc %x size buffer, DMA mem @ %x, virtual mem @ %x",
|
|
|
+ (u32)(bufsize&0xfff), (u32)dma_tmp, (u32)buf);
|
|
|
+#endif
|
|
|
+
|
|
|
+ tmp=tmp+rx_desc_size;
|
|
|
+ }
|
|
|
+
|
|
|
+ *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); // this is the last descriptor
|
|
|
+
|
|
|
+
|
|
|
+#ifdef DEBUG_RXALLOC
|
|
|
+ DMESG("RX DMA physical address: %x",dma_desc);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void set_nic_rxring(struct net_device *dev)
|
|
|
+{
|
|
|
+ u8 pgreg;
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ //rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
+
|
|
|
+ pgreg=read_nic_byte(dev, PGSELECT);
|
|
|
+ write_nic_byte(dev, PGSELECT, pgreg &~ (1<<PGSELECT_PG_SHIFT));
|
|
|
+
|
|
|
+ //rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+ write_nic_dword(dev, RXRING_ADDR,priv->rxringdma);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_reset(struct net_device *dev)
|
|
|
+{
|
|
|
+ //u32 txconf = 0x80e00707; //FIXME: Make me understandable
|
|
|
+ u8 cr;
|
|
|
+
|
|
|
+ //write_nic_dword(dev,TX_CONF,txconf);
|
|
|
+
|
|
|
+ rtl8180_irq_disable(dev);
|
|
|
+
|
|
|
+ cr=read_nic_byte(dev,CMD);
|
|
|
+ cr = cr & 2;
|
|
|
+ cr = cr | (1<<CMD_RST_SHIFT);
|
|
|
+ write_nic_byte(dev,CMD,cr);
|
|
|
+
|
|
|
+ force_pci_posting(dev);
|
|
|
+
|
|
|
+ mdelay(200);
|
|
|
+
|
|
|
+ if(read_nic_byte(dev,CMD) & (1<<CMD_RST_SHIFT))
|
|
|
+ DMESGW("Card reset timeout!");
|
|
|
+ else
|
|
|
+ DMESG("Card successfully reset");
|
|
|
+
|
|
|
+//#ifndef CONFIG_RTL8185B
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_LOAD);
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(200);
|
|
|
+//#endif
|
|
|
+}
|
|
|
+
|
|
|
+inline u16 ieeerate2rtlrate(int rate)
|
|
|
+{
|
|
|
+ switch(rate){
|
|
|
+ case 10:
|
|
|
+ return 0;
|
|
|
+ case 20:
|
|
|
+ return 1;
|
|
|
+ case 55:
|
|
|
+ return 2;
|
|
|
+ case 110:
|
|
|
+ return 3;
|
|
|
+ case 60:
|
|
|
+ return 4;
|
|
|
+ case 90:
|
|
|
+ return 5;
|
|
|
+ case 120:
|
|
|
+ return 6;
|
|
|
+ case 180:
|
|
|
+ return 7;
|
|
|
+ case 240:
|
|
|
+ return 8;
|
|
|
+ case 360:
|
|
|
+ return 9;
|
|
|
+ case 480:
|
|
|
+ return 10;
|
|
|
+ case 540:
|
|
|
+ return 11;
|
|
|
+ default:
|
|
|
+ return 3;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static u16 rtl_rate[] = {10,20,55,110,60,90,120,180,240,360,480,540,720};
|
|
|
+inline u16 rtl8180_rate2rate(short rate)
|
|
|
+{
|
|
|
+ if (rate >12) return 10;
|
|
|
+ return rtl_rate[rate];
|
|
|
+}
|
|
|
+inline u8 rtl8180_IsWirelessBMode(u16 rate)
|
|
|
+{
|
|
|
+ if( ((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220) )
|
|
|
+ return 1;
|
|
|
+ else return 0;
|
|
|
+}
|
|
|
+u16 N_DBPSOfRate(u16 DataRate);
|
|
|
+u16 ComputeTxTime(
|
|
|
+ u16 FrameLength,
|
|
|
+ u16 DataRate,
|
|
|
+ u8 bManagementFrame,
|
|
|
+ u8 bShortPreamble
|
|
|
+)
|
|
|
+{
|
|
|
+ u16 FrameTime;
|
|
|
+ u16 N_DBPS;
|
|
|
+ u16 Ceiling;
|
|
|
+
|
|
|
+ if( rtl8180_IsWirelessBMode(DataRate) )
|
|
|
+ {
|
|
|
+ if( bManagementFrame || !bShortPreamble || DataRate == 10 )
|
|
|
+ { // long preamble
|
|
|
+ FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10)));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // Short preamble
|
|
|
+ FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10)));
|
|
|
+ }
|
|
|
+ if( ( FrameLength*8 % (DataRate/10) ) != 0 ) //Get the Ceilling
|
|
|
+ FrameTime ++;
|
|
|
+ } else { //802.11g DSSS-OFDM PLCP length field calculation.
|
|
|
+ N_DBPS = N_DBPSOfRate(DataRate);
|
|
|
+ Ceiling = (16 + 8*FrameLength + 6) / N_DBPS
|
|
|
+ + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0);
|
|
|
+ FrameTime = (u16)(16 + 4 + 4*Ceiling + 6);
|
|
|
+ }
|
|
|
+ return FrameTime;
|
|
|
+}
|
|
|
+u16 N_DBPSOfRate(u16 DataRate)
|
|
|
+{
|
|
|
+ u16 N_DBPS = 24;
|
|
|
+
|
|
|
+ switch(DataRate)
|
|
|
+ {
|
|
|
+ case 60:
|
|
|
+ N_DBPS = 24;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 90:
|
|
|
+ N_DBPS = 36;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 120:
|
|
|
+ N_DBPS = 48;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 180:
|
|
|
+ N_DBPS = 72;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 240:
|
|
|
+ N_DBPS = 96;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 360:
|
|
|
+ N_DBPS = 144;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 480:
|
|
|
+ N_DBPS = 192;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 540:
|
|
|
+ N_DBPS = 216;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return N_DBPS;
|
|
|
+}
|
|
|
+
|
|
|
+//{by amy 080312
|
|
|
+//
|
|
|
+// Description:
|
|
|
+// For Netgear case, they want good-looking singal strength.
|
|
|
+// 2004.12.05, by rcnjko.
|
|
|
+//
|
|
|
+long
|
|
|
+NetgearSignalStrengthTranslate(
|
|
|
+ long LastSS,
|
|
|
+ long CurrSS
|
|
|
+ )
|
|
|
+{
|
|
|
+ long RetSS;
|
|
|
+
|
|
|
+ // Step 1. Scale mapping.
|
|
|
+ if(CurrSS >= 71 && CurrSS <= 100)
|
|
|
+ {
|
|
|
+ RetSS = 90 + ((CurrSS - 70) / 3);
|
|
|
+ }
|
|
|
+ else if(CurrSS >= 41 && CurrSS <= 70)
|
|
|
+ {
|
|
|
+ RetSS = 78 + ((CurrSS - 40) / 3);
|
|
|
+ }
|
|
|
+ else if(CurrSS >= 31 && CurrSS <= 40)
|
|
|
+ {
|
|
|
+ RetSS = 66 + (CurrSS - 30);
|
|
|
+ }
|
|
|
+ else if(CurrSS >= 21 && CurrSS <= 30)
|
|
|
+ {
|
|
|
+ RetSS = 54 + (CurrSS - 20);
|
|
|
+ }
|
|
|
+ else if(CurrSS >= 5 && CurrSS <= 20)
|
|
|
+ {
|
|
|
+ RetSS = 42 + (((CurrSS - 5) * 2) / 3);
|
|
|
+ }
|
|
|
+ else if(CurrSS == 4)
|
|
|
+ {
|
|
|
+ RetSS = 36;
|
|
|
+ }
|
|
|
+ else if(CurrSS == 3)
|
|
|
+ {
|
|
|
+ RetSS = 27;
|
|
|
+ }
|
|
|
+ else if(CurrSS == 2)
|
|
|
+ {
|
|
|
+ RetSS = 18;
|
|
|
+ }
|
|
|
+ else if(CurrSS == 1)
|
|
|
+ {
|
|
|
+ RetSS = 9;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ RetSS = CurrSS;
|
|
|
+ }
|
|
|
+ //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS));
|
|
|
+
|
|
|
+ // Step 2. Smoothing.
|
|
|
+ if(LastSS > 0)
|
|
|
+ {
|
|
|
+ RetSS = ((LastSS * 5) + (RetSS)+ 5) / 6;
|
|
|
+ }
|
|
|
+ //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS));
|
|
|
+
|
|
|
+ return RetSS;
|
|
|
+}
|
|
|
+//
|
|
|
+// Description:
|
|
|
+// Translate 0-100 signal strength index into dBm.
|
|
|
+//
|
|
|
+long
|
|
|
+TranslateToDbm8185(
|
|
|
+ u8 SignalStrengthIndex // 0-100 index.
|
|
|
+ )
|
|
|
+{
|
|
|
+ long SignalPower; // in dBm.
|
|
|
+
|
|
|
+ // Translate to dBm (x=0.5y-95).
|
|
|
+ SignalPower = (long)((SignalStrengthIndex + 1) >> 1);
|
|
|
+ SignalPower -= 95;
|
|
|
+
|
|
|
+ return SignalPower;
|
|
|
+}
|
|
|
+//
|
|
|
+// Description:
|
|
|
+// Perform signal smoothing for dynamic mechanism.
|
|
|
+// This is different with PerformSignalSmoothing8185 in smoothing fomula.
|
|
|
+// No dramatic adjustion is apply because dynamic mechanism need some degree
|
|
|
+// of correctness. Ported from 8187B.
|
|
|
+// 2007-02-26, by Bruce.
|
|
|
+//
|
|
|
+void
|
|
|
+PerformUndecoratedSignalSmoothing8185(
|
|
|
+ struct r8180_priv *priv,
|
|
|
+ bool bCckRate
|
|
|
+ )
|
|
|
+{
|
|
|
+
|
|
|
+
|
|
|
+ // Determin the current packet is CCK rate.
|
|
|
+ priv->bCurCCKPkt = bCckRate;
|
|
|
+
|
|
|
+ if(priv->UndecoratedSmoothedSS >= 0)
|
|
|
+ {
|
|
|
+ priv->UndecoratedSmoothedSS = ( (priv->UndecoratedSmoothedSS * 5) + (priv->SignalStrength * 10) ) / 6;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->UndecoratedSmoothedSS = priv->SignalStrength * 10;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->UndercorateSmoothedRxPower = ( (priv->UndercorateSmoothedRxPower * 50) + (priv->RxPower* 11)) / 60;
|
|
|
+
|
|
|
+// printk("Sommthing SignalSterngth (%d) => UndecoratedSmoothedSS (%d)\n", priv->SignalStrength, priv->UndecoratedSmoothedSS);
|
|
|
+// printk("Sommthing RxPower (%d) => UndecoratedRxPower (%d)\n", priv->RxPower, priv->UndercorateSmoothedRxPower);
|
|
|
+
|
|
|
+ //if(priv->CurCCKRSSI >= 0 && bCckRate)
|
|
|
+ if(bCckRate)
|
|
|
+ {
|
|
|
+ priv->CurCCKRSSI = priv->RSSI;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->CurCCKRSSI = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Boundary checking.
|
|
|
+ // TODO: The overflow condition does happen, if we want to fix,
|
|
|
+ // we shall recalculate thresholds first.
|
|
|
+ if(priv->UndecoratedSmoothedSS > 100)
|
|
|
+ {
|
|
|
+// printk("UndecoratedSmoothedSS(%d) overflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength);
|
|
|
+ }
|
|
|
+ if(priv->UndecoratedSmoothedSS < 0)
|
|
|
+ {
|
|
|
+// printk("UndecoratedSmoothedSS(%d) underflow, SignalStrength(%d)\n", priv->UndecoratedSmoothedSS, priv->SignalStrength);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//by amy 080312}
|
|
|
+
|
|
|
+/* This is rough RX isr handling routine*/
|
|
|
+void rtl8180_rx(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ struct sk_buff *tmp_skb;
|
|
|
+
|
|
|
+ //struct sk_buff *skb;
|
|
|
+ short first,last;
|
|
|
+ u32 len;
|
|
|
+ int lastlen;
|
|
|
+ unsigned char quality, signal;
|
|
|
+ u8 rate;
|
|
|
+ //u32 *prism_hdr;
|
|
|
+ u32 *tmp,*tmp2;
|
|
|
+ u8 rx_desc_size;
|
|
|
+ u8 padding;
|
|
|
+ //u32 count=0;
|
|
|
+ char rxpower = 0;
|
|
|
+ u32 RXAGC = 0;
|
|
|
+ long RxAGC_dBm = 0;
|
|
|
+ u8 LNA=0, BB=0;
|
|
|
+ u8 LNA_gain[4]={02, 17, 29, 39};
|
|
|
+ u8 Antenna = 0;
|
|
|
+ struct ieee80211_hdr *hdr;//by amy
|
|
|
+ u16 fc,type;
|
|
|
+ u8 bHwError = 0,bCRC = 0,bICV = 0;
|
|
|
+ //bHwError = 0;
|
|
|
+ //bCRC = 0;
|
|
|
+ //bICV = 0;
|
|
|
+ bool bCckRate = false;
|
|
|
+ u8 RSSI = 0;
|
|
|
+ long SignalStrengthIndex = 0;//+by amy 080312
|
|
|
+// u8 SignalStrength = 0;
|
|
|
+ struct ieee80211_rx_stats stats = {
|
|
|
+ .signal = 0,
|
|
|
+ .noise = -98,
|
|
|
+ .rate = 0,
|
|
|
+ // .mac_time = jiffies,
|
|
|
+ .freq = IEEE80211_24GHZ_BAND,
|
|
|
+ };
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ stats.nic_type = NIC_8185B;
|
|
|
+ rx_desc_size = 8;
|
|
|
+
|
|
|
+#else
|
|
|
+ stats.nic_type = NIC_8185;
|
|
|
+ rx_desc_size = 4;
|
|
|
+#endif
|
|
|
+ //printk("receive frame!%d\n",count++);
|
|
|
+ //if (!priv->rxbuffer) DMESG ("EE: NIC RX ack, but RX queue corrupted!");
|
|
|
+ //else {
|
|
|
+
|
|
|
+ if ((*(priv->rxringtail)) & (1<<31)) {
|
|
|
+
|
|
|
+ /* we have got an RX int, but the descriptor
|
|
|
+ * we are pointing is empty*/
|
|
|
+
|
|
|
+ priv->stats.rxnodata++;
|
|
|
+ priv->ieee80211->stats.rx_errors++;
|
|
|
+
|
|
|
+ /* if (! *(priv->rxring) & (1<<31)) {
|
|
|
+
|
|
|
+ priv->stats.rxreset++;
|
|
|
+ priv->rxringtail=priv->rxring;
|
|
|
+ priv->rxbuffer=priv->rxbufferhead;
|
|
|
+
|
|
|
+ }else{*/
|
|
|
+
|
|
|
+ #if 0
|
|
|
+ /* Maybe it is possible that the NIC has skipped some descriptors or
|
|
|
+ * it has reset its internal pointer to the beginning of the ring
|
|
|
+ * we search for the first filled descriptor in the ring, or we break
|
|
|
+ * putting again the pointer in the old location if we do not found any.
|
|
|
+ * This is quite dangerous, what does happen if the nic writes
|
|
|
+ * two descriptor (say A and B) when we have just checked the descriptor
|
|
|
+ * A and we are going to check the descriptor B..This might happen if the
|
|
|
+ * interrupt was dummy, there was not really filled descriptors and
|
|
|
+ * the NIC didn't lose pointer
|
|
|
+ */
|
|
|
+
|
|
|
+ //priv->stats.rxwrkaround++;
|
|
|
+
|
|
|
+ tmp = priv->rxringtail;
|
|
|
+ while (*(priv->rxringtail) & (1<<31)){
|
|
|
+
|
|
|
+ priv->rxringtail+=4;
|
|
|
+
|
|
|
+ if(priv->rxringtail >=
|
|
|
+ (priv->rxring)+(priv->rxringcount )*4)
|
|
|
+ priv->rxringtail=priv->rxring;
|
|
|
+
|
|
|
+ priv->rxbuffer=(priv->rxbuffer->next);
|
|
|
+
|
|
|
+ if(priv->rxringtail == tmp ){
|
|
|
+ //DMESG("EE: Could not find RX pointer");
|
|
|
+ priv->stats.rxnopointer++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #else
|
|
|
+
|
|
|
+ tmp2 = NULL;
|
|
|
+ tmp = priv->rxringtail;
|
|
|
+ do{
|
|
|
+ if(tmp == priv->rxring)
|
|
|
+ //tmp = priv->rxring + (priv->rxringcount )*rx_desc_size; xiong-2006-11-15
|
|
|
+ tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size;
|
|
|
+ else
|
|
|
+ tmp -= rx_desc_size;
|
|
|
+
|
|
|
+ if(! (*tmp & (1<<31)))
|
|
|
+ tmp2 = tmp;
|
|
|
+ }while(tmp != priv->rxring);
|
|
|
+
|
|
|
+ if(tmp2) priv->rxringtail = tmp2;
|
|
|
+ #endif
|
|
|
+ //}
|
|
|
+ }
|
|
|
+
|
|
|
+ /* while there are filled descriptors */
|
|
|
+ while(!(*(priv->rxringtail) & (1<<31))){
|
|
|
+ if(*(priv->rxringtail) & (1<<26))
|
|
|
+ DMESGW("RX buffer overflow");
|
|
|
+ if(*(priv->rxringtail) & (1<<12))
|
|
|
+ priv->stats.rxicverr++;
|
|
|
+
|
|
|
+ if(*(priv->rxringtail) & (1<<27)){
|
|
|
+ priv->stats.rxdmafail++;
|
|
|
+ //DMESG("EE: RX DMA FAILED at buffer pointed by descriptor %x",(u32)priv->rxringtail);
|
|
|
+ goto drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_dma_sync_single_for_cpu(priv->pdev,
|
|
|
+ priv->rxbuffer->dma,
|
|
|
+ priv->rxbuffersize * \
|
|
|
+ sizeof(u8),
|
|
|
+ PCI_DMA_FROMDEVICE);
|
|
|
+
|
|
|
+ first = *(priv->rxringtail) & (1<<29) ? 1:0;
|
|
|
+ if(first) priv->rx_prevlen=0;
|
|
|
+
|
|
|
+ last = *(priv->rxringtail) & (1<<28) ? 1:0;
|
|
|
+ if(last){
|
|
|
+ lastlen=((*priv->rxringtail) &0xfff);
|
|
|
+
|
|
|
+ /* if the last descriptor (that should
|
|
|
+ * tell us the total packet len) tell
|
|
|
+ * us something less than the descriptors
|
|
|
+ * len we had until now, then there is some
|
|
|
+ * problem..
|
|
|
+ * workaround to prevent kernel panic
|
|
|
+ */
|
|
|
+ if(lastlen < priv->rx_prevlen)
|
|
|
+ len=0;
|
|
|
+ else
|
|
|
+ len=lastlen-priv->rx_prevlen;
|
|
|
+
|
|
|
+ if(*(priv->rxringtail) & (1<<13)) {
|
|
|
+//lastlen=((*priv->rxringtail) &0xfff);
|
|
|
+ if ((*(priv->rxringtail) & 0xfff) <500)
|
|
|
+ priv->stats.rxcrcerrmin++;
|
|
|
+ else if ((*(priv->rxringtail) & 0x0fff) >1000)
|
|
|
+ priv->stats.rxcrcerrmax++;
|
|
|
+ else
|
|
|
+ priv->stats.rxcrcerrmid++;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }else{
|
|
|
+ len = priv->rxbuffersize;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ if(first && last) {
|
|
|
+ padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
|
|
|
+ }else if(first) {
|
|
|
+ padding = ((*(priv->rxringtail+3))&(0x04000000))>>26;
|
|
|
+ if(padding) {
|
|
|
+ len -= 2;
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ padding = 0;
|
|
|
+ }
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ padding = 0;
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+ priv->rx_prevlen+=len;
|
|
|
+
|
|
|
+ if(priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100){
|
|
|
+ /* HW is probably passing several buggy frames
|
|
|
+ * without FD or LD flag set.
|
|
|
+ * Throw this garbage away to prevent skb
|
|
|
+ * memory exausting
|
|
|
+ */
|
|
|
+ if(!priv->rx_skb_complete)
|
|
|
+ dev_kfree_skb_any(priv->rx_skb);
|
|
|
+ priv->rx_skb_complete = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_RX_FRAG
|
|
|
+ DMESG("Iteration.. len %x",len);
|
|
|
+ if(first) DMESG ("First descriptor");
|
|
|
+ if(last) DMESG("Last descriptor");
|
|
|
+
|
|
|
+#endif
|
|
|
+#ifdef DEBUG_RX_VERBOSE
|
|
|
+ print_buffer( priv->rxbuffer->buf, len);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ signal=(unsigned char)(((*(priv->rxringtail+3))& (0x00ff0000))>>16);
|
|
|
+ signal=(signal&0xfe)>>1; // Modify by hikaru 6.6
|
|
|
+
|
|
|
+ quality=(unsigned char)((*(priv->rxringtail+3)) & (0xff));
|
|
|
+
|
|
|
+ stats.mac_time[0] = *(priv->rxringtail+1);
|
|
|
+ stats.mac_time[1] = *(priv->rxringtail+2);
|
|
|
+ rxpower =((char)(((*(priv->rxringtail+4))& (0x00ff0000))>>16))/2 - 42;
|
|
|
+ RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>> 8)) & (0x7f);
|
|
|
+
|
|
|
+#else
|
|
|
+ signal=((*(priv->rxringtail+1))& (0xff0000))>>16;
|
|
|
+ signal=(signal&0xfe)>>1; // Modify by hikaru 6.6
|
|
|
+
|
|
|
+ quality=((*(priv->rxringtail+1)) & (0xff));
|
|
|
+
|
|
|
+ stats.mac_time[0] = *(priv->rxringtail+2);
|
|
|
+ stats.mac_time[1] = *(priv->rxringtail+3);
|
|
|
+#endif
|
|
|
+ rate=((*(priv->rxringtail)) &
|
|
|
+ ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20;
|
|
|
+
|
|
|
+ stats.rate = rtl8180_rate2rate(rate);
|
|
|
+ //DMESG("%d",rate);
|
|
|
+ Antenna = (((*(priv->rxringtail +3))& (0x00008000)) == 0 )? 0:1 ;
|
|
|
+// printk("in rtl8180_rx():Antenna is %d\n",Antenna);
|
|
|
+//by amy for antenna
|
|
|
+ if(!rtl8180_IsWirelessBMode(stats.rate))
|
|
|
+ { // OFDM rate.
|
|
|
+
|
|
|
+ RxAGC_dBm = rxpower+1; //bias
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // CCK rate.
|
|
|
+ RxAGC_dBm = signal;//bit 0 discard
|
|
|
+
|
|
|
+ LNA = (u8) (RxAGC_dBm & 0x60 ) >> 5 ; //bit 6~ bit 5
|
|
|
+ BB = (u8) (RxAGC_dBm & 0x1F); // bit 4 ~ bit 0
|
|
|
+
|
|
|
+ RxAGC_dBm = -( LNA_gain[LNA] + (BB *2) ); //Pin_11b=-(LNA_gain+BB_gain) (dBm)
|
|
|
+
|
|
|
+ RxAGC_dBm +=4; //bias
|
|
|
+ }
|
|
|
+
|
|
|
+ if(RxAGC_dBm & 0x80) //absolute value
|
|
|
+ RXAGC= ~(RxAGC_dBm)+1;
|
|
|
+ bCckRate = rtl8180_IsWirelessBMode(stats.rate);
|
|
|
+ // Translate RXAGC into 1-100.
|
|
|
+ if(!rtl8180_IsWirelessBMode(stats.rate))
|
|
|
+ { // OFDM rate.
|
|
|
+ if(RXAGC>90)
|
|
|
+ RXAGC=90;
|
|
|
+ else if(RXAGC<25)
|
|
|
+ RXAGC=25;
|
|
|
+ RXAGC=(90-RXAGC)*100/65;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ { // CCK rate.
|
|
|
+ if(RXAGC>95)
|
|
|
+ RXAGC=95;
|
|
|
+ else if(RXAGC<30)
|
|
|
+ RXAGC=30;
|
|
|
+ RXAGC=(95-RXAGC)*100/65;
|
|
|
+ }
|
|
|
+ priv->SignalStrength = (u8)RXAGC;
|
|
|
+ priv->RecvSignalPower = RxAGC_dBm ; // It can use directly by SD3 CMLin
|
|
|
+ priv->RxPower = rxpower;
|
|
|
+ priv->RSSI = RSSI;
|
|
|
+//{by amy 080312
|
|
|
+ // SQ translation formular is provided by SD3 DZ. 2006.06.27, by rcnjko.
|
|
|
+ if(quality >= 127)
|
|
|
+ quality = 1;//0; //0 will cause epc to show signal zero , walk aroud now;
|
|
|
+ else if(quality < 27)
|
|
|
+ quality = 100;
|
|
|
+ else
|
|
|
+ quality = 127 - quality;
|
|
|
+ priv->SignalQuality = quality;
|
|
|
+ if(!priv->card_8185)
|
|
|
+ printk("check your card type\n");
|
|
|
+
|
|
|
+ stats.signal = (u8)quality;//priv->wstats.qual.level = priv->SignalStrength;
|
|
|
+ stats.signalstrength = RXAGC;
|
|
|
+ if(stats.signalstrength > 100)
|
|
|
+ stats.signalstrength = 100;
|
|
|
+ stats.signalstrength = (stats.signalstrength * 70)/100 + 30;
|
|
|
+ // printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength);
|
|
|
+ stats.rssi = priv->wstats.qual.qual = priv->SignalQuality;
|
|
|
+ stats.noise = priv->wstats.qual.noise = 100 - priv ->wstats.qual.qual;
|
|
|
+//by amy 080312}
|
|
|
+ bHwError = (((*(priv->rxringtail))& (0x00000fff)) == 4080)| (((*(priv->rxringtail))& (0x04000000)) != 0 )
|
|
|
+ | (((*(priv->rxringtail))& (0x08000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x10000000)) != 0 )| (((~(*(priv->rxringtail)))& (0x20000000)) != 0 );
|
|
|
+ bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13;
|
|
|
+ bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12;
|
|
|
+ hdr = (struct ieee80211_hdr *)priv->rxbuffer->buf;
|
|
|
+ fc = le16_to_cpu(hdr->frame_ctl);
|
|
|
+ type = WLAN_FC_GET_TYPE(fc);
|
|
|
+
|
|
|
+ if((IEEE80211_FTYPE_CTL != type) &&
|
|
|
+ (eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3))
|
|
|
+ && (!bHwError) && (!bCRC)&& (!bICV))
|
|
|
+ {
|
|
|
+//by amy 080312
|
|
|
+ // 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. 2007.01.23, by shien chang.
|
|
|
+ PerformUndecoratedSignalSmoothing8185(priv,bCckRate);
|
|
|
+ //
|
|
|
+ // For good-looking singal strength.
|
|
|
+ //
|
|
|
+ SignalStrengthIndex = NetgearSignalStrengthTranslate(
|
|
|
+ priv->LastSignalStrengthInPercent,
|
|
|
+ priv->SignalStrength);
|
|
|
+
|
|
|
+ priv->LastSignalStrengthInPercent = SignalStrengthIndex;
|
|
|
+ priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex);
|
|
|
+ //
|
|
|
+ // We need more correct power of received packets and the "SignalStrength" of RxStats is beautified,
|
|
|
+ // so we record the correct power here.
|
|
|
+ //
|
|
|
+ priv->Stats_SignalQuality =(long) (priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
|
|
|
+ priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower -1) / 6;
|
|
|
+
|
|
|
+ // Figure out which antenna that received the lasted packet.
|
|
|
+ priv->LastRxPktAntenna = Antenna ? 1 : 0; // 0: aux, 1: main.
|
|
|
+//by amy 080312
|
|
|
+ SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
|
|
|
+ }
|
|
|
+
|
|
|
+//by amy for antenna
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#ifndef DUMMY_RX
|
|
|
+ if(first){
|
|
|
+ if(!priv->rx_skb_complete){
|
|
|
+ /* seems that HW sometimes fails to reiceve and
|
|
|
+ doesn't provide the last descriptor */
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("going to free incomplete skb");
|
|
|
+#endif
|
|
|
+ dev_kfree_skb_any(priv->rx_skb);
|
|
|
+ priv->stats.rxnolast++;
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("free incomplete skb OK");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ /* support for prism header has been originally added by Christian */
|
|
|
+ if(priv->prism_hdr && priv->ieee80211->iw_mode == IW_MODE_MONITOR){
|
|
|
+
|
|
|
+#if 0
|
|
|
+ priv->rx_skb = dev_alloc_skb(len+2+PRISM_HDR_SIZE);
|
|
|
+ if(! priv->rx_skb) goto drop;
|
|
|
+
|
|
|
+ prism_hdr = (u32*) skb_put(priv->rx_skb,PRISM_HDR_SIZE);
|
|
|
+ prism_hdr[0]=htonl(0x80211001); //version
|
|
|
+ prism_hdr[1]=htonl(0x40); //length
|
|
|
+ prism_hdr[2]=htonl(stats.mac_time[1]); //mactime (HIGH)
|
|
|
+ prism_hdr[3]=htonl(stats.mac_time[0]); //mactime (LOW)
|
|
|
+ rdtsc(prism_hdr[5], prism_hdr[4]); //hostime (LOW+HIGH)
|
|
|
+ prism_hdr[4]=htonl(prism_hdr[4]); //Byte-Order aendern
|
|
|
+ prism_hdr[5]=htonl(prism_hdr[5]); //Byte-Order aendern
|
|
|
+ prism_hdr[6]=0x00; //phytype
|
|
|
+ prism_hdr[7]=htonl(priv->chan); //channel
|
|
|
+ prism_hdr[8]=htonl(stats.rate); //datarate
|
|
|
+ prism_hdr[9]=0x00; //antenna
|
|
|
+ prism_hdr[10]=0x00; //priority
|
|
|
+ prism_hdr[11]=0x00; //ssi_type
|
|
|
+ prism_hdr[12]=htonl(stats.signal); //ssi_signal
|
|
|
+ prism_hdr[13]=htonl(stats.noise); //ssi_noise
|
|
|
+ prism_hdr[14]=0x00; //preamble
|
|
|
+ prism_hdr[15]=0x00; //encoding
|
|
|
+
|
|
|
+#endif
|
|
|
+ }else{
|
|
|
+ priv->rx_skb = dev_alloc_skb(len+2);
|
|
|
+ if( !priv->rx_skb) goto drop;
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("Alloc initial skb %x",len+2);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->rx_skb_complete=0;
|
|
|
+ priv->rx_skb->dev=dev;
|
|
|
+ }else{
|
|
|
+ /* if we are here we should have already RXed
|
|
|
+ * the first frame.
|
|
|
+ * If we get here and the skb is not allocated then
|
|
|
+ * we have just throw out garbage (skb not allocated)
|
|
|
+ * and we are still rxing garbage....
|
|
|
+ */
|
|
|
+ if(!priv->rx_skb_complete){
|
|
|
+
|
|
|
+ tmp_skb= dev_alloc_skb(priv->rx_skb->len +len+2);
|
|
|
+
|
|
|
+ if(!tmp_skb) goto drop;
|
|
|
+
|
|
|
+ tmp_skb->dev=dev;
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("Realloc skb %x",len+2);
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("going copy prev frag %x",priv->rx_skb->len);
|
|
|
+#endif
|
|
|
+ memcpy(skb_put(tmp_skb,priv->rx_skb->len),
|
|
|
+ priv->rx_skb->data,
|
|
|
+ priv->rx_skb->len);
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("skb copy prev frag complete");
|
|
|
+#endif
|
|
|
+
|
|
|
+ dev_kfree_skb_any(priv->rx_skb);
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("prev skb free ok");
|
|
|
+#endif
|
|
|
+
|
|
|
+ priv->rx_skb=tmp_skb;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("going to copy current payload %x",len);
|
|
|
+#endif
|
|
|
+ if(!priv->rx_skb_complete) {
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ if(padding) {
|
|
|
+ memcpy(skb_put(priv->rx_skb,len),
|
|
|
+ (((unsigned char *)priv->rxbuffer->buf) + 2),len);
|
|
|
+ } else {
|
|
|
+#endif
|
|
|
+ memcpy(skb_put(priv->rx_skb,len),
|
|
|
+ priv->rxbuffer->buf,len);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("current fragment skb copy complete");
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(last && !priv->rx_skb_complete){
|
|
|
+
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("Got last fragment");
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(priv->rx_skb->len > 4)
|
|
|
+ skb_trim(priv->rx_skb,priv->rx_skb->len-4);
|
|
|
+#ifdef DEBUG_RX_SKB
|
|
|
+ DMESG("yanked out crc, passing to the upper layer");
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef RX_DONT_PASS_UL
|
|
|
+ if(!ieee80211_rx(priv->ieee80211,
|
|
|
+ priv->rx_skb, &stats)){
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESGW("Packet not consumed");
|
|
|
+#endif
|
|
|
+#endif // RX_DONT_PASS_UL
|
|
|
+
|
|
|
+ dev_kfree_skb_any(priv->rx_skb);
|
|
|
+#ifndef RX_DONT_PASS_UL
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ else{
|
|
|
+ DMESG("Rcv frag");
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ priv->rx_skb_complete=1;
|
|
|
+ }
|
|
|
+
|
|
|
+#endif //DUMMY_RX
|
|
|
+
|
|
|
+ pci_dma_sync_single_for_device(priv->pdev,
|
|
|
+ priv->rxbuffer->dma,
|
|
|
+ priv->rxbuffersize * \
|
|
|
+ sizeof(u8),
|
|
|
+ PCI_DMA_FROMDEVICE);
|
|
|
+
|
|
|
+
|
|
|
+drop: // this is used when we have not enought mem
|
|
|
+
|
|
|
+ /* restore the descriptor */
|
|
|
+ *(priv->rxringtail+2)=priv->rxbuffer->dma;
|
|
|
+ *(priv->rxringtail)=*(priv->rxringtail) &~ 0xfff;
|
|
|
+ *(priv->rxringtail)=
|
|
|
+ *(priv->rxringtail) | priv->rxbuffersize;
|
|
|
+
|
|
|
+ *(priv->rxringtail)=
|
|
|
+ *(priv->rxringtail) | (1<<31);
|
|
|
+ //^empty descriptor
|
|
|
+
|
|
|
+ //wmb();
|
|
|
+
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESG("Current descriptor: %x",(u32)priv->rxringtail);
|
|
|
+#endif
|
|
|
+ //unsigned long flags;
|
|
|
+ //spin_lock_irqsave(&priv->irq_lock,flags);
|
|
|
+
|
|
|
+ priv->rxringtail+=rx_desc_size;
|
|
|
+ if(priv->rxringtail >=
|
|
|
+ (priv->rxring)+(priv->rxringcount )*rx_desc_size)
|
|
|
+ priv->rxringtail=priv->rxring;
|
|
|
+
|
|
|
+ //spin_unlock_irqrestore(&priv->irq_lock,flags);
|
|
|
+
|
|
|
+
|
|
|
+ priv->rxbuffer=(priv->rxbuffer->next);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// if(get_curr_tx_free_desc(dev,priority))
|
|
|
+// ieee80211_sta_ps_sleep(priv->ieee80211, &tmp, &tmp2);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_dma_kick(struct net_device *dev, int priority)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+/*
|
|
|
+
|
|
|
+ switch(priority){
|
|
|
+
|
|
|
+ case LOW_PRIORITY:
|
|
|
+
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,
|
|
|
+ (1<< TX_DMA_POLLING_LOWPRIORITY_SHIFT) |
|
|
|
+ priv->dma_poll_mask);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NORM_PRIORITY:
|
|
|
+
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,
|
|
|
+ (1<< TX_DMA_POLLING_NORMPRIORITY_SHIFT) |
|
|
|
+ priv->dma_poll_mask);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HI_PRIORITY:
|
|
|
+
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,
|
|
|
+ (1<< TX_DMA_POLLING_HIPRIORITY_SHIFT) |
|
|
|
+ priv->dma_poll_mask);
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+*/
|
|
|
+ write_nic_byte(dev, TX_DMA_POLLING,
|
|
|
+ (1 << (priority + 1)) | priv->dma_poll_mask);
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+ force_pci_posting(dev);
|
|
|
+}
|
|
|
+
|
|
|
+#if 0
|
|
|
+void rtl8180_tx_queues_stop(struct net_device *dev)
|
|
|
+{
|
|
|
+ //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u8 dma_poll_mask = (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT);
|
|
|
+ dma_poll_mask |= (1<<TX_DMA_STOP_HIPRIORITY_SHIFT);
|
|
|
+ dma_poll_mask |= (1<<TX_DMA_STOP_NORMPRIORITY_SHIFT);
|
|
|
+ dma_poll_mask |= (1<<TX_DMA_STOP_BEACON_SHIFT);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,dma_poll_mask);
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+void rtl8180_data_hard_stop(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ;
|
|
|
+ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask);
|
|
|
+#else
|
|
|
+ priv->dma_poll_mask |= (1<<TX_DMA_STOP_LOWPRIORITY_SHIFT);
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask);
|
|
|
+#endif
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_data_hard_resume(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ);
|
|
|
+ write_nic_byte(dev,TPPollStop, priv->dma_poll_stop_mask);
|
|
|
+#else
|
|
|
+ priv->dma_poll_mask &= ~(1<<TX_DMA_STOP_LOWPRIORITY_SHIFT);
|
|
|
+ write_nic_byte(dev,TX_DMA_POLLING,priv->dma_poll_mask);
|
|
|
+#endif
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* this function TX data frames when the ieee80211 stack requires this.
|
|
|
+ * It checks also if we need to stop the ieee tx queue, eventually do it
|
|
|
+ */
|
|
|
+void rtl8180_hard_data_xmit(struct sk_buff *skb,struct net_device *dev, int
|
|
|
+rate)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ int mode;
|
|
|
+ struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data;
|
|
|
+ short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS;
|
|
|
+ unsigned long flags;
|
|
|
+ int priority;
|
|
|
+ //static int count = 0;
|
|
|
+
|
|
|
+ mode = priv->ieee80211->iw_mode;
|
|
|
+
|
|
|
+ rate = ieeerate2rtlrate(rate);
|
|
|
+ /*
|
|
|
+ * This function doesn't require lock because we make
|
|
|
+ * sure it's called with the tx_lock already acquired.
|
|
|
+ * this come from the kernel's hard_xmit callback (trought
|
|
|
+ * the ieee stack, or from the try_wake_queue (again trought
|
|
|
+ * the ieee stack.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priority = AC2Q(skb->priority);
|
|
|
+#else
|
|
|
+ priority = LOW_PRIORITY;
|
|
|
+#endif
|
|
|
+ spin_lock_irqsave(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ if(priv->ieee80211->bHwRadioOff)
|
|
|
+ {
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //printk(KERN_WARNING "priority = %d@%d\n", priority, count++);
|
|
|
+ if (!check_nic_enought_desc(dev, priority)){
|
|
|
+ //DMESG("Error: no descriptor left by previous TX (avail %d) ",
|
|
|
+ // get_curr_tx_free_desc(dev, priority));
|
|
|
+ DMESGW("Error: no descriptor left by previous TX (avail %d) ",
|
|
|
+ get_curr_tx_free_desc(dev, priority));
|
|
|
+ //printk(KERN_WARNING "==============================================================> \n");
|
|
|
+ ieee80211_stop_queue(priv->ieee80211);
|
|
|
+ }
|
|
|
+ rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate);
|
|
|
+ if (!check_nic_enought_desc(dev, priority))
|
|
|
+ ieee80211_stop_queue(priv->ieee80211);
|
|
|
+
|
|
|
+ //dev_kfree_skb_any(skb);
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/* This is a rough attempt to TX a frame
|
|
|
+ * This is called by the ieee 80211 stack to TX management frames.
|
|
|
+ * If the ring is full packet are dropped (for data frame the queue
|
|
|
+ * is stopped before this can happen). For this reason it is better
|
|
|
+ * if the descriptors are larger than the largest management frame
|
|
|
+ * we intend to TX: i'm unsure what the HW does if it will not found
|
|
|
+ * the last fragment of a frame because it has been dropped...
|
|
|
+ * Since queues for Management and Data frames are different we
|
|
|
+ * might use a different lock than tx_lock (for example mgmt_tx_lock)
|
|
|
+ */
|
|
|
+/* these function may loops if invoked with 0 descriptors or 0 len buffer*/
|
|
|
+int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ int priority;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priority = MANAGE_PRIORITY;
|
|
|
+#else
|
|
|
+ priority = NORM_PRIORITY;
|
|
|
+#endif
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ if(priv->ieee80211->bHwRadioOff)
|
|
|
+ {
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ rtl8180_tx(dev, skb->data, skb->len, priority,
|
|
|
+ 0, 0,ieeerate2rtlrate(priv->ieee80211->basic_rate));
|
|
|
+
|
|
|
+ priv->ieee80211->stats.tx_bytes+=skb->len;
|
|
|
+ priv->ieee80211->stats.tx_packets++;
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// longpre 144+48 shortpre 72+24
|
|
|
+u16 rtl8180_len2duration(u32 len, short rate,short* ext)
|
|
|
+{
|
|
|
+ u16 duration;
|
|
|
+ u16 drift;
|
|
|
+ *ext=0;
|
|
|
+
|
|
|
+ switch(rate){
|
|
|
+ case 0://1mbps
|
|
|
+ *ext=0;
|
|
|
+ duration = ((len+4)<<4) /0x2;
|
|
|
+ drift = ((len+4)<<4) % 0x2;
|
|
|
+ if(drift ==0 ) break;
|
|
|
+ duration++;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1://2mbps
|
|
|
+ *ext=0;
|
|
|
+ duration = ((len+4)<<4) /0x4;
|
|
|
+ drift = ((len+4)<<4) % 0x4;
|
|
|
+ if(drift ==0 ) break;
|
|
|
+ duration++;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: //5.5mbps
|
|
|
+ *ext=0;
|
|
|
+ duration = ((len+4)<<4) /0xb;
|
|
|
+ drift = ((len+4)<<4) % 0xb;
|
|
|
+ if(drift ==0 )
|
|
|
+ break;
|
|
|
+ duration++;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ case 3://11mbps
|
|
|
+ *ext=0;
|
|
|
+ duration = ((len+4)<<4) /0x16;
|
|
|
+ drift = ((len+4)<<4) % 0x16;
|
|
|
+ if(drift ==0 )
|
|
|
+ break;
|
|
|
+ duration++;
|
|
|
+ if(drift > 6)
|
|
|
+ break;
|
|
|
+ *ext=1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return duration;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_prepare_beacon(struct net_device *dev)
|
|
|
+{
|
|
|
+
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ u16 word = read_nic_word(dev, BcnItv);
|
|
|
+ word &= ~BcnItv_BcnItv; // clear Bcn_Itv
|
|
|
+ word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval);//0x64;
|
|
|
+ write_nic_word(dev, BcnItv, word);
|
|
|
+
|
|
|
+
|
|
|
+ skb = ieee80211_get_beacon(priv->ieee80211);
|
|
|
+ if(skb){
|
|
|
+ rtl8180_tx(dev,skb->data,skb->len,BEACON_PRIORITY,
|
|
|
+ 0,0,ieeerate2rtlrate(priv->ieee80211->basic_rate));
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ }
|
|
|
+ #if 0
|
|
|
+ //DMESG("size %x",len);
|
|
|
+ if(*tail & (1<<31)){
|
|
|
+
|
|
|
+ //DMESG("No more beacon TX desc");
|
|
|
+ return ;
|
|
|
+
|
|
|
+ }
|
|
|
+ //while(! *tail & (1<<31)){
|
|
|
+ *tail= 0; // zeroes header
|
|
|
+
|
|
|
+ *tail = *tail| (1<<29) ; //fist segment of the packet
|
|
|
+ *tail = (*tail) | (1<<28); // last segment
|
|
|
+ // *tail = *tail | (1<<18); // this is a beacon frame
|
|
|
+ *(tail+3)=*(tail+3) &~ 0xfff;
|
|
|
+ *(tail+3)=*(tail+3) | len; // buffer lenght
|
|
|
+ *tail = *tail |len;
|
|
|
+ // zeroes the second 32-bits dword of the descriptor
|
|
|
+ *(tail+1)= 0;
|
|
|
+ *tail = *tail | (rate << 24);
|
|
|
+
|
|
|
+ duration = rtl8180_len2duration(len,rate,&ext);
|
|
|
+
|
|
|
+ *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16);
|
|
|
+
|
|
|
+ *tail = *tail | (1<<31);
|
|
|
+ //^ descriptor ready to be txed
|
|
|
+ if((tail - begin)/8 == priv->txbeaconcount-1)
|
|
|
+ tail=begin;
|
|
|
+ else
|
|
|
+ tail=tail+8;
|
|
|
+ //}
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/* This function do the real dirty work: it enqueues a TX command
|
|
|
+ * descriptor in the ring buffer, copyes the frame in a TX buffer
|
|
|
+ * and kicks the NIC to ensure it does the DMA transfer.
|
|
|
+ */
|
|
|
+short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
|
|
|
+ short morefrag, short descfrag, int rate)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u32 *tail,*temp_tail;
|
|
|
+ u32 *begin;
|
|
|
+ u32 *buf;
|
|
|
+ int i;
|
|
|
+ int remain;
|
|
|
+ int buflen;
|
|
|
+ int count;
|
|
|
+ //u16 AckCtsTime;
|
|
|
+ //u16 FrameTime;
|
|
|
+ u16 duration;
|
|
|
+ short ext;
|
|
|
+ struct buffer* buflist;
|
|
|
+ //unsigned long flags;
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf;
|
|
|
+ u8 dest[ETH_ALEN];
|
|
|
+ u8 bUseShortPreamble = 0;
|
|
|
+ u8 bCTSEnable = 0;
|
|
|
+ u8 bRTSEnable = 0;
|
|
|
+ //u16 RTSRate = 22;
|
|
|
+ //u8 RetryLimit = 0;
|
|
|
+ u16 Duration = 0;
|
|
|
+ u16 RtsDur = 0;
|
|
|
+ u16 ThisFrameTime = 0;
|
|
|
+ u16 TxDescDuration = 0;
|
|
|
+ u8 ownbit_flag = false; //added by david woo for sync Tx, 2007.12.14
|
|
|
+#endif
|
|
|
+
|
|
|
+ switch(priority) {
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ tail=priv->txmapringtail;
|
|
|
+ begin=priv->txmapring;
|
|
|
+ buflist = priv->txmapbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BK_PRIORITY:
|
|
|
+ tail=priv->txbkpringtail;
|
|
|
+ begin=priv->txbkpring;
|
|
|
+ buflist = priv->txbkpbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BE_PRIORITY:
|
|
|
+ tail=priv->txbepringtail;
|
|
|
+ begin=priv->txbepring;
|
|
|
+ buflist = priv->txbepbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VI_PRIORITY:
|
|
|
+ tail=priv->txvipringtail;
|
|
|
+ begin=priv->txvipring;
|
|
|
+ buflist = priv->txvipbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VO_PRIORITY:
|
|
|
+ tail=priv->txvopringtail;
|
|
|
+ begin=priv->txvopring;
|
|
|
+ buflist = priv->txvopbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HI_PRIORITY:
|
|
|
+ tail=priv->txhpringtail;
|
|
|
+ begin=priv->txhpring;
|
|
|
+ buflist = priv->txhpbufstail;
|
|
|
+ count = priv->txringcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BEACON_PRIORITY:
|
|
|
+ tail=priv->txbeaconringtail;
|
|
|
+ begin=priv->txbeaconring;
|
|
|
+ buflist = priv->txbeaconbufstail;
|
|
|
+ count = priv->txbeaconcount;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //printk("in rtl8180_tx(): rate is %d\n",priv->ieee80211->rate);
|
|
|
+#if 1
|
|
|
+ memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
|
|
|
+ if (is_multicast_ether_addr(dest) ||
|
|
|
+ is_broadcast_ether_addr(dest))
|
|
|
+ {
|
|
|
+ Duration = 0;
|
|
|
+ RtsDur = 0;
|
|
|
+ bRTSEnable = 0;
|
|
|
+ bCTSEnable = 0;
|
|
|
+
|
|
|
+ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
|
|
|
+ TxDescDuration = ThisFrameTime;
|
|
|
+ } else {// Unicast packet
|
|
|
+ //u8 AckRate;
|
|
|
+ u16 AckTime;
|
|
|
+
|
|
|
+ //YJ,add,080828,for Keep alive
|
|
|
+ priv->NumTxUnicast++;
|
|
|
+
|
|
|
+ // Figure out ACK rate according to BSS basic rate and Tx rate, 2006.03.08 by rcnjko.
|
|
|
+ //AckRate = ComputeAckRate( pMgntInfo->mBrates, (u1Byte)(pTcb->DataRate) );
|
|
|
+ // Figure out ACK time according to the AckRate and assume long preamble is used on receiver, 2006.03.08, by rcnjko.
|
|
|
+ //AckTime = ComputeTxTime( sAckCtsLng/8, AckRate, FALSE, FALSE);
|
|
|
+ //For simplicity, just use the 1M basic rate
|
|
|
+ //AckTime = ComputeTxTime(14, 540,0, 0); // AckCTSLng = 14 use 1M bps send
|
|
|
+ AckTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send
|
|
|
+ //AckTime = ComputeTxTime(14, 2,false, false); // AckCTSLng = 14 use 1M bps send
|
|
|
+
|
|
|
+ if ( ((len + sCrcLng) > priv->rts) && priv->rts )
|
|
|
+ { // RTS/CTS.
|
|
|
+ u16 RtsTime, CtsTime;
|
|
|
+ //u16 CtsRate;
|
|
|
+ bRTSEnable = 1;
|
|
|
+ bCTSEnable = 0;
|
|
|
+
|
|
|
+ // Rate and time required for RTS.
|
|
|
+ RtsTime = ComputeTxTime( sAckCtsLng/8,priv->ieee80211->basic_rate, 0, 0);
|
|
|
+ // Rate and time required for CTS.
|
|
|
+ CtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send
|
|
|
+
|
|
|
+ // Figure out time required to transmit this frame.
|
|
|
+ ThisFrameTime = ComputeTxTime(len + sCrcLng,
|
|
|
+ rtl8180_rate2rate(rate),
|
|
|
+ 0,
|
|
|
+ bUseShortPreamble);
|
|
|
+
|
|
|
+ // RTS-CTS-ThisFrame-ACK.
|
|
|
+ RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime;
|
|
|
+
|
|
|
+ TxDescDuration = RtsTime + RtsDur;
|
|
|
+ }
|
|
|
+ else {// Normal case.
|
|
|
+ bCTSEnable = 0;
|
|
|
+ bRTSEnable = 0;
|
|
|
+ RtsDur = 0;
|
|
|
+
|
|
|
+ ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), 0, bUseShortPreamble);
|
|
|
+ TxDescDuration = ThisFrameTime + aSifsTime + AckTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment
|
|
|
+ // ThisFrame-ACK.
|
|
|
+ Duration = aSifsTime + AckTime;
|
|
|
+ } else { // One or more fragments remained.
|
|
|
+ u16 NextFragTime;
|
|
|
+ NextFragTime = ComputeTxTime( len + sCrcLng, //pretend following packet length equal current packet
|
|
|
+ rtl8180_rate2rate(rate),
|
|
|
+ 0,
|
|
|
+ bUseShortPreamble );
|
|
|
+
|
|
|
+ //ThisFrag-ACk-NextFrag-ACK.
|
|
|
+ Duration = NextFragTime + 3*aSifsTime + 2*AckTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ } // End of Unicast packet
|
|
|
+
|
|
|
+ frag_hdr->duration_id = Duration;
|
|
|
+#endif
|
|
|
+
|
|
|
+ buflen=priv->txbuffsize;
|
|
|
+ remain=len;
|
|
|
+ temp_tail = tail;
|
|
|
+//printk("================================>buflen = %d, remain = %d!\n", buflen,remain);
|
|
|
+ while(remain!=0){
|
|
|
+#ifdef DEBUG_TX_FRAG
|
|
|
+ DMESG("TX iteration");
|
|
|
+#endif
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG("TX: filling descriptor %x",(u32)tail);
|
|
|
+#endif
|
|
|
+ mb();
|
|
|
+ if(!buflist){
|
|
|
+ DMESGE("TX buffer error, cannot TX frames. pri %d.", priority);
|
|
|
+ //spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ buf=buflist->buf;
|
|
|
+
|
|
|
+ if( (*tail & (1<<31)) && (priority != BEACON_PRIORITY)){
|
|
|
+
|
|
|
+ DMESGW("No more TX desc, returning %x of %x",
|
|
|
+ remain,len);
|
|
|
+ priv->stats.txrdu++;
|
|
|
+#ifdef DEBUG_TX_DESC
|
|
|
+ check_tx_ring(dev,priority);
|
|
|
+ // netif_stop_queue(dev);
|
|
|
+ // netif_carrier_off(dev);
|
|
|
+#endif
|
|
|
+ // spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ return remain;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ *tail= 0; // zeroes header
|
|
|
+ *(tail+1) = 0;
|
|
|
+ *(tail+3) = 0;
|
|
|
+ *(tail+5) = 0;
|
|
|
+ *(tail+6) = 0;
|
|
|
+ *(tail+7) = 0;
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ //FIXME: this should be triggered by HW encryption parameters.
|
|
|
+ *tail |= (1<<15); //no encrypt
|
|
|
+// *tail |= (1<<30); //raise int when completed
|
|
|
+ }
|
|
|
+ // *tail = *tail | (1<<16);
|
|
|
+ if(remain==len && !descfrag) {
|
|
|
+ ownbit_flag = false; //added by david woo,2007.12.14
|
|
|
+#ifdef DEBUG_TX_FRAG
|
|
|
+ DMESG("First descriptor");
|
|
|
+#endif
|
|
|
+ *tail = *tail| (1<<29) ; //fist segment of the packet
|
|
|
+ *tail = *tail |(len);
|
|
|
+ } else {
|
|
|
+ ownbit_flag = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ for(i=0;i<buflen&& remain >0;i++,remain--){
|
|
|
+ ((u8*)buf)[i]=txbuf[i]; //copy data into descriptor pointed DMAble buffer
|
|
|
+ if(remain == 4 && i+4 >= buflen) break;
|
|
|
+ /* ensure the last desc has at least 4 bytes payload */
|
|
|
+
|
|
|
+ }
|
|
|
+ txbuf = txbuf + i;
|
|
|
+ *(tail+3)=*(tail+3) &~ 0xfff;
|
|
|
+ *(tail+3)=*(tail+3) | i; // buffer lenght
|
|
|
+ // Use short preamble or not
|
|
|
+ if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE)
|
|
|
+ if (priv->plcp_preamble_mode==1 && rate!=0) // short mode now, not long!
|
|
|
+ // *tail |= (1<<16); // enable short preamble mode.
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ if(bCTSEnable) {
|
|
|
+ *tail |= (1<<18);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bRTSEnable) //rts enable
|
|
|
+ {
|
|
|
+ *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19);//RTS RATE
|
|
|
+ *tail |= (1<<23);//rts enable
|
|
|
+ *(tail+1) |=(RtsDur&0xffff);//RTS Duration
|
|
|
+ }
|
|
|
+ *(tail+3) |= ((TxDescDuration&0xffff)<<16); //DURATION
|
|
|
+// *(tail+3) |= (0xe6<<16);
|
|
|
+ *(tail+5) |= (11<<8);//(priv->retry_data<<8); //retry lim ;
|
|
|
+#else
|
|
|
+ //Use RTS or not
|
|
|
+#ifdef CONFIG_RTL8187B
|
|
|
+ if ( (len>priv->rts) && priv->rts && priority!=MANAGE_PRIORITY){
|
|
|
+#else
|
|
|
+ if ( (len>priv->rts) && priv->rts && priority==LOW_PRIORITY){
|
|
|
+#endif
|
|
|
+ *tail |= (1<<23); //enalbe RTS function
|
|
|
+ *tail |= (0<<19); //use 1M bps send RTS packet
|
|
|
+ AckCtsTime = ComputeTxTime(14, 10,0, 0); // AckCTSLng = 14 use 1M bps send
|
|
|
+ FrameTime = ComputeTxTime(len + 4, rtl8180_rate2rate(rate), 0, *tail&(1<<16));
|
|
|
+ // RTS/CTS time is calculate as follow
|
|
|
+ duration = FrameTime + 3*10 + 2*AckCtsTime; //10us is the SifsTime;
|
|
|
+ *(tail+1) |= duration; //Need to edit here! ----hikaru
|
|
|
+ }else{
|
|
|
+ *(tail+1)= 0; // zeroes the second 32-bits dword of the descriptor
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ *tail = *tail | ((rate&0xf) << 24);
|
|
|
+ //DMESG("rate %d",rate);
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+
|
|
|
+ #if 0
|
|
|
+ *(tail+5)&= ~(1<<24); /* tx ant 0 */
|
|
|
+
|
|
|
+ *(tail+5) &= ~(1<<23); /* random tx agc 23-16 */
|
|
|
+ *(tail+5) |= (1<<22)|(1<<21)|(1<<20)|(1<<19)|(1<<18)|(1<<17)|(1<<16);
|
|
|
+
|
|
|
+ *(tail+5) &=
|
|
|
+~((1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8));
|
|
|
+ *(tail+5) |= (7<<8); // Max retry limit
|
|
|
+
|
|
|
+ *(tail+5) &= ~((1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0));
|
|
|
+ *(tail+5) |= (8<<4); // Max contention window
|
|
|
+ *(tail+6) |= 4; // Min contention window
|
|
|
+ #endif
|
|
|
+ // *(tail+5) = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* hw_plcp_len is not used for rtl8180 chip */
|
|
|
+ /* FIXME */
|
|
|
+ if(priv->card_8185 == 0 || !priv->hw_plcp_len){
|
|
|
+
|
|
|
+ duration = rtl8180_len2duration(len,
|
|
|
+ rate,&ext);
|
|
|
+
|
|
|
+
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG("PLCP duration %d",duration );
|
|
|
+ //DMESG("drift %d",drift);
|
|
|
+ DMESG("extension %s", (ext==1) ? "on":"off");
|
|
|
+#endif
|
|
|
+ *(tail+1) = *(tail+1) | ((duration & 0x7fff)<<16);
|
|
|
+ if(ext) *(tail+1) = *(tail+1) |(1<<31); //plcp length extension
|
|
|
+ }
|
|
|
+
|
|
|
+ if(morefrag) *tail = (*tail) | (1<<17); // more fragment
|
|
|
+ if(!remain) *tail = (*tail) | (1<<28); // last segment of frame
|
|
|
+
|
|
|
+#ifdef DEBUG_TX_FRAG
|
|
|
+ if(!remain)DMESG("Last descriptor");
|
|
|
+ if(morefrag)DMESG("More frag");
|
|
|
+#endif
|
|
|
+ *(tail+5) = *(tail+5)|(2<<27);
|
|
|
+ *(tail+7) = *(tail+7)|(1<<4);
|
|
|
+
|
|
|
+ wmb();
|
|
|
+ if(ownbit_flag)
|
|
|
+ {
|
|
|
+ *tail = *tail | (1<<31); // descriptor ready to be txed
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_TX_DESC2
|
|
|
+ printk("tx desc is:\n");
|
|
|
+ DMESG("%8x %8x %8x %8x %8x %8x %8x %8x", tail[0], tail[1], tail[2], tail[3],
|
|
|
+ tail[4], tail[5], tail[6], tail[7]);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if((tail - begin)/8 == count-1)
|
|
|
+ tail=begin;
|
|
|
+
|
|
|
+ else
|
|
|
+ tail=tail+8;
|
|
|
+
|
|
|
+ buflist=buflist->next;
|
|
|
+
|
|
|
+ mb();
|
|
|
+
|
|
|
+ switch(priority) {
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ priv->txmapringtail=tail;
|
|
|
+ priv->txmapbufstail=buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BK_PRIORITY:
|
|
|
+ priv->txbkpringtail=tail;
|
|
|
+ priv->txbkpbufstail=buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BE_PRIORITY:
|
|
|
+ priv->txbepringtail=tail;
|
|
|
+ priv->txbepbufstail=buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VI_PRIORITY:
|
|
|
+ priv->txvipringtail=tail;
|
|
|
+ priv->txvipbufstail=buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VO_PRIORITY:
|
|
|
+ priv->txvopringtail=tail;
|
|
|
+ priv->txvopbufstail=buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HI_PRIORITY:
|
|
|
+ priv->txhpringtail=tail;
|
|
|
+ priv->txhpbufstail = buflist;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BEACON_PRIORITY:
|
|
|
+ /* the HW seems to be happy with the 1st
|
|
|
+ * descriptor filled and the 2nd empty...
|
|
|
+ * So always update descriptor 1 and never
|
|
|
+ * touch 2nd
|
|
|
+ */
|
|
|
+ // priv->txbeaconringtail=tail;
|
|
|
+ // priv->txbeaconbufstail=buflist;
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //rtl8180_dma_kick(dev,priority);
|
|
|
+ }
|
|
|
+ *temp_tail = *temp_tail | (1<<31); // descriptor ready to be txed
|
|
|
+ rtl8180_dma_kick(dev,priority);
|
|
|
+ //spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_irq_rx_tasklet(struct r8180_priv * priv);
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_link_change(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u16 beacon_interval;
|
|
|
+
|
|
|
+ struct ieee80211_network *net = &priv->ieee80211->current_network;
|
|
|
+// rtl8180_adapter_start(dev);
|
|
|
+ rtl8180_update_msr(dev);
|
|
|
+
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+
|
|
|
+ write_nic_dword(dev,BSSID,((u32*)net->bssid)[0]);
|
|
|
+ write_nic_word(dev,BSSID+4,((u16*)net->bssid)[2]);
|
|
|
+
|
|
|
+
|
|
|
+ beacon_interval = read_nic_dword(dev,BEACON_INTERVAL);
|
|
|
+ beacon_interval &= ~ BEACON_INTERVAL_MASK;
|
|
|
+ beacon_interval |= net->beacon_interval;
|
|
|
+ write_nic_dword(dev, BEACON_INTERVAL, beacon_interval);
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ u16 atim = read_nic_dword(dev,ATIM);
|
|
|
+ u16 = u16 &~ ATIM_MASK;
|
|
|
+ u16 = u16 | beacon->atim;
|
|
|
+ */
|
|
|
+#if 0
|
|
|
+ if (net->capability & WLAN_CAPABILITY_PRIVACY) {
|
|
|
+ if (priv->hw_wep) {
|
|
|
+ DMESG("Enabling hardware WEP support");
|
|
|
+ rtl8180_set_hw_wep(dev);
|
|
|
+ priv->ieee80211->host_encrypt=0;
|
|
|
+ priv->ieee80211->host_decrypt=0;
|
|
|
+ }
|
|
|
+#ifndef CONFIG_IEEE80211_NOWEP
|
|
|
+ else {
|
|
|
+ priv->ieee80211->host_encrypt=1;
|
|
|
+ priv->ieee80211->host_decrypt=1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#ifndef CONFIG_IEEE80211_NOWEP
|
|
|
+ else{
|
|
|
+ priv->ieee80211->host_encrypt=0;
|
|
|
+ priv->ieee80211->host_decrypt=0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+ if(priv->card_8185)
|
|
|
+ rtl8180_set_chan(dev, priv->chan);
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void rtl8180_rq_tx_ack(struct net_device *dev){
|
|
|
+
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+// printk("====================>%s\n",__FUNCTION__);
|
|
|
+ write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)|CONFIG4_PWRMGT);
|
|
|
+ priv->ack_tx_to_ieee = 1;
|
|
|
+}
|
|
|
+
|
|
|
+short rtl8180_is_tx_queue_empty(struct net_device *dev){
|
|
|
+
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u32* d;
|
|
|
+
|
|
|
+ for (d = priv->txmapring;
|
|
|
+ d < priv->txmapring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+
|
|
|
+ for (d = priv->txbkpring;
|
|
|
+ d < priv->txbkpring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+
|
|
|
+ for (d = priv->txbepring;
|
|
|
+ d < priv->txbepring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+
|
|
|
+ for (d = priv->txvipring;
|
|
|
+ d < priv->txvipring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+
|
|
|
+ for (d = priv->txvopring;
|
|
|
+ d < priv->txvopring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+
|
|
|
+ for (d = priv->txhpring;
|
|
|
+ d < priv->txhpring + priv->txringcount;d+=8)
|
|
|
+ if(*d & (1<<31)) return 0;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+/* FIXME FIXME 5msecs is random */
|
|
|
+#define HW_WAKE_DELAY 5
|
|
|
+
|
|
|
+void rtl8180_hw_wakeup(struct net_device *dev)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->ps_lock,flags);
|
|
|
+ //DMESG("Waken up!");
|
|
|
+ write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)&~CONFIG4_PWRMGT);
|
|
|
+
|
|
|
+ if(priv->rf_wakeup)
|
|
|
+ priv->rf_wakeup(dev);
|
|
|
+// mdelay(HW_WAKE_DELAY);
|
|
|
+ spin_unlock_irqrestore(&priv->ps_lock,flags);
|
|
|
+}
|
|
|
+
|
|
|
+void rtl8180_hw_sleep_down(struct net_device *dev)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->ps_lock,flags);
|
|
|
+ //DMESG("Sleep!");
|
|
|
+
|
|
|
+ if(priv->rf_sleep)
|
|
|
+ priv->rf_sleep(dev);
|
|
|
+ spin_unlock_irqrestore(&priv->ps_lock,flags);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl)
|
|
|
+{
|
|
|
+
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ u32 rb = jiffies;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->ps_lock,flags);
|
|
|
+
|
|
|
+ /* Writing HW register with 0 equals to disable
|
|
|
+ * the timer, that is not really what we want
|
|
|
+ */
|
|
|
+ tl -= MSECS(4+16+7);
|
|
|
+
|
|
|
+ //if(tl == 0) tl = 1;
|
|
|
+
|
|
|
+ /* FIXME HACK FIXME HACK */
|
|
|
+// force_pci_posting(dev);
|
|
|
+ //mdelay(1);
|
|
|
+
|
|
|
+// rb = read_nic_dword(dev, TSFTR);
|
|
|
+
|
|
|
+ /* If the interval in witch we are requested to sleep is too
|
|
|
+ * short then give up and remain awake
|
|
|
+ */
|
|
|
+ if(((tl>=rb)&& (tl-rb) <= MSECS(MIN_SLEEP_TIME))
|
|
|
+ ||((rb>tl)&& (rb-tl) < MSECS(MIN_SLEEP_TIME))) {
|
|
|
+ spin_unlock_irqrestore(&priv->ps_lock,flags);
|
|
|
+ printk("too short to sleep\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+// write_nic_dword(dev, TimerInt, tl);
|
|
|
+// rb = read_nic_dword(dev, TSFTR);
|
|
|
+ {
|
|
|
+ u32 tmp = (tl>rb)?(tl-rb):(rb-tl);
|
|
|
+ // if (tl<rb)
|
|
|
+
|
|
|
+ //lzm,add,080828
|
|
|
+ priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp);
|
|
|
+
|
|
|
+ queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); //as tl may be less than rb
|
|
|
+ }
|
|
|
+ /* if we suspect the TimerInt is gone beyond tl
|
|
|
+ * while setting it, then give up
|
|
|
+ */
|
|
|
+#if 1
|
|
|
+ if(((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME)))||
|
|
|
+ ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) {
|
|
|
+ spin_unlock_irqrestore(&priv->ps_lock,flags);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+// if(priv->rf_sleep)
|
|
|
+// priv->rf_sleep(dev);
|
|
|
+
|
|
|
+ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq);
|
|
|
+ spin_unlock_irqrestore(&priv->ps_lock,flags);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//void rtl8180_wmm_param_update(struct net_device *dev,u8 *ac_param)
|
|
|
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,6,20)
|
|
|
+void rtl8180_wmm_param_update(struct work_struct * work)
|
|
|
+{
|
|
|
+ struct ieee80211_device * ieee = container_of(work, struct ieee80211_device,wmm_param_update_wq);
|
|
|
+ //struct r8180_priv *priv = (struct r8180_priv*)(ieee->priv);
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+#else
|
|
|
+void rtl8180_wmm_param_update(struct ieee80211_device *ieee)
|
|
|
+{
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+ 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;
|
|
|
+
|
|
|
+#ifndef CONFIG_RTL8185B
|
|
|
+ //for legacy 8185 keep the PARAM unchange.
|
|
|
+ return;
|
|
|
+#else
|
|
|
+ if(!ieee->current_network.QoS_Enable){
|
|
|
+ //legacy ac_xx_param update
|
|
|
+ AcParam.longData = 0;
|
|
|
+ AcParam.f.AciAifsn.f.AIFSN = 2; // Follow 802.11 DIFS.
|
|
|
+ AcParam.f.AciAifsn.f.ACM = 0;
|
|
|
+ AcParam.f.Ecw.f.ECWmin = 3; // Follow 802.11 CWmin.
|
|
|
+ AcParam.f.Ecw.f.ECWmax = 7; // Follow 802.11 CWmax.
|
|
|
+ AcParam.f.TXOPLimit = 0;
|
|
|
+ for(eACI = 0; eACI < AC_MAX; eACI++){
|
|
|
+ AcParam.f.AciAifsn.f.ACI = (u8)eACI;
|
|
|
+ {
|
|
|
+ u8 u1bAIFS;
|
|
|
+ u32 u4bAcParam;
|
|
|
+ pAcParam = (PAC_PARAM)(&AcParam);
|
|
|
+ // Retrive paramters to udpate.
|
|
|
+ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN *(((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime;
|
|
|
+ u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
|
|
|
+ (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
|
|
|
+ (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)|
|
|
|
+ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
|
|
|
+ switch(eACI){
|
|
|
+ case AC1_BK:
|
|
|
+ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC0_BE:
|
|
|
+ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC2_VI:
|
|
|
+ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC3_VO:
|
|
|
+ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "SetHwReg8185():invalid ACI: %d!\n", eACI);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for(i = 0; i < AC_MAX; i++){
|
|
|
+ //AcParam.longData = 0;
|
|
|
+ pAcParam = (AC_PARAM * )ac_param;
|
|
|
+ {
|
|
|
+ AC_CODING eACI;
|
|
|
+ u8 u1bAIFS;
|
|
|
+ u32 u4bAcParam;
|
|
|
+
|
|
|
+ // Retrive paramters to udpate.
|
|
|
+ eACI = pAcParam->f.AciAifsn.f.ACI;
|
|
|
+ //Mode G/A: slotTimeTimer = 9; Mode B: 20
|
|
|
+ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G)?9:20) + aSifsTime;
|
|
|
+ u4bAcParam = ( (((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
|
|
|
+ (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) |
|
|
|
+ (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
|
|
|
+ (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
|
|
|
+
|
|
|
+ switch(eACI){
|
|
|
+ case AC1_BK:
|
|
|
+ write_nic_dword(dev, AC_BK_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC0_BE:
|
|
|
+ write_nic_dword(dev, AC_BE_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC2_VI:
|
|
|
+ write_nic_dword(dev, AC_VI_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AC3_VO:
|
|
|
+ write_nic_dword(dev, AC_VO_PARAM, u4bAcParam);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ printk(KERN_WARNING "SetHwReg8185(): invalid ACI: %d !\n", eACI);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ac_param += (sizeof(AC_PARAM));
|
|
|
+ }
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_tx_irq_wq(struct work_struct *work);
|
|
|
+#else
|
|
|
+void rtl8180_tx_irq_wq(struct net_device *dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_restart_wq(struct work_struct *work);
|
|
|
+//void rtl8180_rq_tx_ack(struct work_struct *work);
|
|
|
+#else
|
|
|
+ void rtl8180_restart_wq(struct net_device *dev);
|
|
|
+//void rtl8180_rq_tx_ack(struct net_device *dev);
|
|
|
+#endif
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_watch_dog_wq(struct work_struct *work);
|
|
|
+#else
|
|
|
+void rtl8180_watch_dog_wq(struct net_device *dev);
|
|
|
+#endif
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_hw_wakeup_wq(struct work_struct *work);
|
|
|
+#else
|
|
|
+void rtl8180_hw_wakeup_wq(struct net_device *dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_hw_sleep_wq(struct work_struct *work);
|
|
|
+#else
|
|
|
+void rtl8180_hw_sleep_wq(struct net_device *dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_sw_antenna_wq(struct work_struct *work);
|
|
|
+#else
|
|
|
+void rtl8180_sw_antenna_wq(struct net_device *dev);
|
|
|
+#endif
|
|
|
+ void rtl8180_watch_dog(struct net_device *dev);
|
|
|
+void watch_dog_adaptive(unsigned long data)
|
|
|
+{
|
|
|
+ struct r8180_priv* priv = ieee80211_priv((struct net_device *)data);
|
|
|
+// DMESG("---->watch_dog_adaptive()\n");
|
|
|
+ if(!priv->up)
|
|
|
+ {
|
|
|
+ DMESG("<----watch_dog_adaptive():driver is not up!\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // queue_work(priv->ieee80211->wq,&priv->ieee80211->watch_dog_wq);
|
|
|
+//{by amy 080312
|
|
|
+#if 1
|
|
|
+ // Tx High Power Mechanism.
|
|
|
+#ifdef HIGH_POWER
|
|
|
+ if(CheckHighPower((struct net_device *)data))
|
|
|
+ {
|
|
|
+ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ // Tx Power Tracking on 87SE.
|
|
|
+#ifdef TX_TRACK
|
|
|
+ //if( priv->bTxPowerTrack ) //lzm mod 080826
|
|
|
+ if( CheckTxPwrTracking((struct net_device *)data));
|
|
|
+ TxPwrTracking87SE((struct net_device *)data);
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+ // Perform DIG immediately.
|
|
|
+#ifdef SW_DIG
|
|
|
+ if(CheckDig((struct net_device *)data) == true)
|
|
|
+ {
|
|
|
+ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+//by amy 080312}
|
|
|
+ rtl8180_watch_dog((struct net_device *)data);
|
|
|
+
|
|
|
+
|
|
|
+ queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem);
|
|
|
+
|
|
|
+ priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME);
|
|
|
+ add_timer(&priv->watch_dog_timer);
|
|
|
+// DMESG("<----watch_dog_adaptive()\n");
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef ENABLE_DOT11D
|
|
|
+
|
|
|
+static CHANNEL_LIST ChannelPlan[] = {
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, //FCC
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11},11}, //IC
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //ETSI
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Spain. Change to ETSI.
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //France. Change to ETSI.
|
|
|
+ {{14,36,40,44,48,52,56,60,64},9}, //MKK
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},//MKK1
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, //Israel.
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, // For 11a , TELEC
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, //For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626
|
|
|
+ {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} //world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826
|
|
|
+};
|
|
|
+
|
|
|
+static void rtl8180_set_channel_map(u8 channel_plan, struct ieee80211_device *ieee)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ //lzm add 080826
|
|
|
+ ieee->MinPassiveChnlNum=MAX_CHANNEL_NUMBER+1;
|
|
|
+ ieee->IbssStartChnl=0;
|
|
|
+
|
|
|
+ switch (channel_plan)
|
|
|
+ {
|
|
|
+ case COUNTRY_CODE_FCC:
|
|
|
+ case COUNTRY_CODE_IC:
|
|
|
+ case COUNTRY_CODE_ETSI:
|
|
|
+ case COUNTRY_CODE_SPAIN:
|
|
|
+ case COUNTRY_CODE_FRANCE:
|
|
|
+ case COUNTRY_CODE_MKK:
|
|
|
+ case COUNTRY_CODE_MKK1:
|
|
|
+ case COUNTRY_CODE_ISRAEL:
|
|
|
+ case COUNTRY_CODE_TELEC:
|
|
|
+ {
|
|
|
+ Dot11d_Init(ieee);
|
|
|
+ ieee->bGlobalDomain = false;
|
|
|
+ if (ChannelPlan[channel_plan].Len != 0){
|
|
|
+ // Clear old channel map
|
|
|
+ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
|
|
|
+ // Set new channel map
|
|
|
+ for (i=0;i<ChannelPlan[channel_plan].Len;i++)
|
|
|
+ {
|
|
|
+ if(ChannelPlan[channel_plan].Channel[i] <= 14)
|
|
|
+ GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case COUNTRY_CODE_GLOBAL_DOMAIN:
|
|
|
+ {
|
|
|
+ GET_DOT11D_INFO(ieee)->bEnabled = 0;
|
|
|
+ Dot11d_Reset(ieee);
|
|
|
+ ieee->bGlobalDomain = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case COUNTRY_CODE_WORLD_WIDE_13_INDEX://lzm add 080826
|
|
|
+ {
|
|
|
+ ieee->MinPassiveChnlNum=12;
|
|
|
+ ieee->IbssStartChnl= 10;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ Dot11d_Init(ieee);
|
|
|
+ ieee->bGlobalDomain = false;
|
|
|
+ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map));
|
|
|
+ for (i=1;i<=14;i++)
|
|
|
+ {
|
|
|
+ GET_DOT11D_INFO(ieee)->channel_map[i] = 1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+//Add for RF power on power off by lizhaoming 080512
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void GPIOChangeRFWorkItemCallBack(struct work_struct *work);
|
|
|
+#else
|
|
|
+void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee);
|
|
|
+#endif
|
|
|
+
|
|
|
+//YJ,add,080828
|
|
|
+static void rtl8180_statistics_init(struct Stats *pstats)
|
|
|
+{
|
|
|
+ memset(pstats, 0, sizeof(struct Stats));
|
|
|
+}
|
|
|
+static void rtl8180_link_detect_init(plink_detect_t plink_detect)
|
|
|
+{
|
|
|
+ memset(plink_detect, 0, sizeof(link_detect_t));
|
|
|
+ plink_detect->SlotNum = DEFAULT_SLOT_NUM;
|
|
|
+}
|
|
|
+//YJ,add,080828,end
|
|
|
+
|
|
|
+short rtl8180_init(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u16 word;
|
|
|
+ u16 version;
|
|
|
+ u8 hw_version;
|
|
|
+ //u8 config3;
|
|
|
+ u32 usValue;
|
|
|
+ u16 tmpu16;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+#ifdef ENABLE_DOT11D
|
|
|
+#if 0
|
|
|
+ for(i=0;i<0xFF;i++) {
|
|
|
+ if(i%16 == 0)
|
|
|
+ printk("\n[%x]: ", i/16);
|
|
|
+ printk("\t%4.4x", eprom_read(dev,i));
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ priv->channel_plan = eprom_read(dev, EEPROM_COUNTRY_CODE>>1) & 0xFF;
|
|
|
+ if(priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN){
|
|
|
+ printk("rtl8180_init:Error channel plan! Set to default.\n");
|
|
|
+ priv->channel_plan = 0;
|
|
|
+ }
|
|
|
+ //priv->channel_plan = 9; //Global Domain
|
|
|
+
|
|
|
+ DMESG("Channel plan is %d\n",priv->channel_plan);
|
|
|
+ rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211);
|
|
|
+#else
|
|
|
+ int ch;
|
|
|
+ //Set Default Channel Plan
|
|
|
+ if(!channels){
|
|
|
+ DMESG("No channels, aborting");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ch=channels;
|
|
|
+ priv->channel_plan = 0;//hikaru
|
|
|
+ // set channels 1..14 allowed in given locale
|
|
|
+ for (i=1; i<=14; i++) {
|
|
|
+ (priv->ieee80211->channel_map)[i] = (u8)(ch & 0x01);
|
|
|
+ ch >>= 1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ //memcpy(priv->stats,0,sizeof(struct Stats));
|
|
|
+
|
|
|
+ //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;
|
|
|
+ priv->txbeaconcount = 2;
|
|
|
+ priv->rx_skb_complete = 1;
|
|
|
+ //priv->txnp_pending.ispending=0;
|
|
|
+ /* ^^ the SKB does not containt a partial RXed
|
|
|
+ * packet (is empty)
|
|
|
+ */
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ priv->RegThreeWireMode = HW_THREE_WIRE_SI;
|
|
|
+#else
|
|
|
+ priv->RegThreeWireMode = SW_THREE_WIRE;
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+//Add for RF power on power off by lizhaoming 080512
|
|
|
+ priv->RFChangeInProgress = false;
|
|
|
+ priv->SetRFPowerStateInProgress = false;
|
|
|
+ priv->RFProgType = 0;
|
|
|
+ priv->bInHctTest = false;
|
|
|
+
|
|
|
+ priv->irq_enabled=0;
|
|
|
+
|
|
|
+//YJ,modified,080828
|
|
|
+#if 0
|
|
|
+ priv->stats.rxdmafail=0;
|
|
|
+ priv->stats.txrdu=0;
|
|
|
+ priv->stats.rxrdu=0;
|
|
|
+ priv->stats.rxnolast=0;
|
|
|
+ priv->stats.rxnodata=0;
|
|
|
+ //priv->stats.rxreset=0;
|
|
|
+ //priv->stats.rxwrkaround=0;
|
|
|
+ priv->stats.rxnopointer=0;
|
|
|
+ priv->stats.txnperr=0;
|
|
|
+ priv->stats.txresumed=0;
|
|
|
+ priv->stats.rxerr=0;
|
|
|
+ priv->stats.rxoverflow=0;
|
|
|
+ priv->stats.rxint=0;
|
|
|
+ priv->stats.txnpokint=0;
|
|
|
+ priv->stats.txhpokint=0;
|
|
|
+ priv->stats.txhperr=0;
|
|
|
+ priv->stats.ints=0;
|
|
|
+ priv->stats.shints=0;
|
|
|
+ priv->stats.txoverflow=0;
|
|
|
+ priv->stats.txbeacon=0;
|
|
|
+ priv->stats.txbeaconerr=0;
|
|
|
+ priv->stats.txlperr=0;
|
|
|
+ priv->stats.txlpokint=0;
|
|
|
+ priv->stats.txretry=0;//tony 20060601
|
|
|
+ priv->stats.rxcrcerrmin=0;
|
|
|
+ priv->stats.rxcrcerrmid=0;
|
|
|
+ priv->stats.rxcrcerrmax=0;
|
|
|
+ priv->stats.rxicverr=0;
|
|
|
+#else
|
|
|
+ rtl8180_statistics_init(&priv->stats);
|
|
|
+ rtl8180_link_detect_init(&priv->link_detect);
|
|
|
+#endif
|
|
|
+//YJ,modified,080828,end
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+ priv->ieee80211->rate = 110; //11 mbps
|
|
|
+ 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;
|
|
|
+ priv->prism_hdr=0;
|
|
|
+ priv->dev=dev;
|
|
|
+ priv->retry_rts = DEFAULT_RETRY_RTS;
|
|
|
+ priv->retry_data = DEFAULT_RETRY_DATA;
|
|
|
+ priv->RFChangeInProgress = false;
|
|
|
+ priv->SetRFPowerStateInProgress = false;
|
|
|
+ priv->RFProgType = 0;
|
|
|
+ priv->bInHctTest = false;
|
|
|
+ priv->bInactivePs = true;//false;
|
|
|
+ priv->ieee80211->bInactivePs = priv->bInactivePs;
|
|
|
+ priv->bSwRfProcessing = false;
|
|
|
+ priv->eRFPowerState = eRfOff;
|
|
|
+ priv->RfOffReason = 0;
|
|
|
+ priv->LedStrategy = SW_LED_MODE0;
|
|
|
+ //priv->NumRxOkInPeriod = 0; //YJ,del,080828
|
|
|
+ //priv->NumTxOkInPeriod = 0; //YJ,del,080828
|
|
|
+ priv->TxPollingTimes = 0;//lzm add 080826
|
|
|
+ priv->bLeisurePs = true;
|
|
|
+ priv->dot11PowerSaveMode = eActive;
|
|
|
+//by amy for antenna
|
|
|
+ priv->AdMinCheckPeriod = 5;
|
|
|
+ priv->AdMaxCheckPeriod = 10;
|
|
|
+// Lower signal strength threshold to fit the HW participation in antenna diversity. +by amy 080312
|
|
|
+ priv->AdMaxRxSsThreshold = 30;//60->30
|
|
|
+ priv->AdRxSsThreshold = 20;//50->20
|
|
|
+ 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;
|
|
|
+//by amy for antenna
|
|
|
+//{by amy 080312
|
|
|
+ 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;
|
|
|
+ priv->RegDigOfdmFaUpTh = 0xc; // Upper threhold of OFDM false alarm, which is used in DIG.
|
|
|
+ priv->DIG_NumberFallbackVote = 0;
|
|
|
+ priv->DIG_NumberUpgradeVote = 0;
|
|
|
+ priv->LastSignalStrengthInPercent = 0;
|
|
|
+ priv->Stats_SignalStrength = 0;
|
|
|
+ priv->LastRxPktAntenna = 0;
|
|
|
+ priv->SignalQuality = 0; // in 0-100 index.
|
|
|
+ priv->Stats_SignalQuality = 0;
|
|
|
+ priv->RecvSignalPower = 0; // in dBm.
|
|
|
+ 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;
|
|
|
+ //YJ,add,080828
|
|
|
+ priv->NumTxOkTotal = 0;
|
|
|
+ priv->NumTxUnicast = 0;
|
|
|
+ priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL;
|
|
|
+ priv->PowerProfile = POWER_PROFILE_AC;
|
|
|
+ //YJ,add,080828,end
|
|
|
+//by amy for rate adaptive
|
|
|
+ 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;
|
|
|
+ priv->ForcedDataRate = 0;
|
|
|
+ priv->RegBModeGainStage = 1;
|
|
|
+
|
|
|
+//by amy for rate adaptive
|
|
|
+//by amy 080312}
|
|
|
+ priv->promisc = (dev->flags & IFF_PROMISC) ? 1:0;
|
|
|
+ spin_lock_init(&priv->irq_lock);
|
|
|
+ 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);
|
|
|
+ sema_init(&priv->wx_sem,1);
|
|
|
+ sema_init(&priv->rf_state,1);
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+ INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq);
|
|
|
+ INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_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_DELAYED_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq);
|
|
|
+ //INIT_DELAYED_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_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);//+by amy 080312
|
|
|
+ INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq);//+by amy 080312
|
|
|
+ INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq);//+by amy 080312
|
|
|
+
|
|
|
+ //add for RF power on power off by lizhaoming 080512
|
|
|
+ INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack);
|
|
|
+#else
|
|
|
+ INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev);
|
|
|
+ INIT_WORK(&priv->tx_irq_wq,(void*) rtl8180_tx_irq_wq,dev);
|
|
|
+ //INIT_WORK(&priv->ieee80211->watch_dog_wq,(void*) rtl8180_watch_dog_wq,dev);
|
|
|
+ INIT_WORK(&priv->ieee80211->hw_wakeup_wq,(void*) rtl8180_hw_wakeup_wq,dev);
|
|
|
+ INIT_WORK(&priv->ieee80211->hw_sleep_wq,(void*) rtl8180_hw_sleep_wq,dev);
|
|
|
+ //INIT_WORK(&priv->ieee80211->sw_antenna_wq,(void*) rtl8180_sw_antenna_wq,dev);
|
|
|
+ INIT_WORK(&priv->ieee80211->wmm_param_update_wq,(void*) rtl8180_wmm_param_update,priv->ieee80211);
|
|
|
+ INIT_WORK(&priv->ieee80211->rate_adapter_wq,(void*)rtl8180_rate_adapter,dev);//+by amy 080312
|
|
|
+ INIT_WORK(&priv->ieee80211->hw_dig_wq,(void*)rtl8180_hw_dig_wq,dev);//+by amy 080312
|
|
|
+ INIT_WORK(&priv->ieee80211->tx_pw_wq,(void*)rtl8180_tx_pw_wq,dev);//+by amy 080312
|
|
|
+
|
|
|
+ //add for RF power on power off by lizhaoming 080512
|
|
|
+ INIT_WORK(&priv->ieee80211->GPIOChangeRFWorkItem,(void*) GPIOChangeRFWorkItemCallBack, priv->ieee80211);
|
|
|
+#endif
|
|
|
+ //INIT_WORK(&priv->reset_wq,(void*) rtl8180_restart_wq,dev);
|
|
|
+
|
|
|
+ tasklet_init(&priv->irq_rx_tasklet,
|
|
|
+ (void(*)(unsigned long)) rtl8180_irq_rx_tasklet,
|
|
|
+ (unsigned long)priv);
|
|
|
+//by amy
|
|
|
+ init_timer(&priv->watch_dog_timer);
|
|
|
+ priv->watch_dog_timer.data = (unsigned long)dev;
|
|
|
+ priv->watch_dog_timer.function = watch_dog_adaptive;
|
|
|
+//by amy
|
|
|
+
|
|
|
+//{by amy 080312
|
|
|
+//by amy for rate adaptive
|
|
|
+ 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;
|
|
|
+//by amy for rate adaptive
|
|
|
+//by amy 080312}
|
|
|
+ //priv->ieee80211->func =
|
|
|
+ // kmalloc(sizeof(struct ieee80211_helper_functions),GFP_KERNEL);
|
|
|
+ //memset(priv->ieee80211->func, 0,
|
|
|
+ // sizeof(struct ieee80211_helper_functions));
|
|
|
+
|
|
|
+ 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;
|
|
|
+
|
|
|
+ priv->ieee80211->init_wmmparam_flag = 0;
|
|
|
+
|
|
|
+ priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon;
|
|
|
+ priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable;
|
|
|
+ priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ priv->MWIEnable = 0;
|
|
|
+
|
|
|
+ priv->ShortRetryLimit = 7;
|
|
|
+ priv->LongRetryLimit = 7;
|
|
|
+ priv->EarlyRxThreshold = 7;
|
|
|
+
|
|
|
+ priv->CSMethod = (0x01 << 29);
|
|
|
+
|
|
|
+ priv->TransmitConfig =
|
|
|
+ 1<<TCR_DurProcMode_OFFSET | //for RTL8185B, duration setting by HW
|
|
|
+ (7<<TCR_MXDMA_OFFSET) | // Max DMA Burst Size per Tx DMA Burst, 7: reservied.
|
|
|
+ (priv->ShortRetryLimit<<TCR_SRL_OFFSET) | // Short retry limit
|
|
|
+ (priv->LongRetryLimit<<TCR_LRL_OFFSET) | // Long retry limit
|
|
|
+ (0 ? TCR_SAT : 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them
|
|
|
+
|
|
|
+ priv->ReceiveConfig =
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+#else
|
|
|
+ priv->CSMethod |
|
|
|
+#endif
|
|
|
+// RCR_ENMARP |
|
|
|
+ RCR_AMF | RCR_ADF | //accept management/data
|
|
|
+ RCR_ACF | //accept control frame for SW AP needs PS-poll, 2005.07.07, by rcnjko.
|
|
|
+ RCR_AB | RCR_AM | RCR_APM | //accept BC/MC/UC
|
|
|
+ //RCR_AICV | RCR_ACRC32 | //accept ICV/CRC error packet
|
|
|
+ (7<<RCR_MXDMA_OFFSET) | // Max DMA Burst Size per Rx DMA Burst, 7: unlimited.
|
|
|
+ (priv->EarlyRxThreshold<<RCR_FIFO_OFFSET) | // Rx FIFO Threshold, 7: No Rx threshold.
|
|
|
+ (priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0);
|
|
|
+
|
|
|
+ priv->IntrMask = IMR_TMGDOK | IMR_TBDER | IMR_THPDER |
|
|
|
+ IMR_THPDER | IMR_THPDOK |
|
|
|
+ IMR_TVODER | IMR_TVODOK |
|
|
|
+ IMR_TVIDER | IMR_TVIDOK |
|
|
|
+ IMR_TBEDER | IMR_TBEDOK |
|
|
|
+ IMR_TBKDER | IMR_TBKDOK |
|
|
|
+ IMR_RDU | // To handle the defragmentation not enough Rx descriptors case. Annie, 2006-03-27.
|
|
|
+ IMR_RER | IMR_ROK |
|
|
|
+ IMR_RQoSOK; // <NOTE> ROK and RQoSOK are mutually exclusive, so, we must handle RQoSOK interrupt to receive QoS frames, 2005.12.09, by rcnjko.
|
|
|
+
|
|
|
+ priv->InitialGain = 6;
|
|
|
+#endif
|
|
|
+
|
|
|
+ hw_version =( read_nic_dword(dev, TCR) & TCR_HWVERID_MASK)>>TCR_HWVERID_SHIFT;
|
|
|
+
|
|
|
+ switch (hw_version){
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ case HW_VERID_R8185B_B:
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ priv->card_8185 = VERSION_8187S_C;
|
|
|
+ DMESG("MAC controller is a RTL8187SE b/g");
|
|
|
+ priv->phy_ver = 2;
|
|
|
+ break;
|
|
|
+#else
|
|
|
+ DMESG("MAC controller is a RTL8185B b/g");
|
|
|
+ priv->card_8185 = 3;
|
|
|
+ priv->phy_ver = 2;
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+ case HW_VERID_R8185_ABC:
|
|
|
+ DMESG("MAC controller is a RTL8185 b/g");
|
|
|
+ priv->card_8185 = 1;
|
|
|
+ /* you should not find a card with 8225 PHY ver < C*/
|
|
|
+ priv->phy_ver = 2;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HW_VERID_R8185_D:
|
|
|
+ DMESG("MAC controller is a RTL8185 b/g (V. D)");
|
|
|
+ priv->card_8185 = 2;
|
|
|
+ /* you should not find a card with 8225 PHY ver < C*/
|
|
|
+ priv->phy_ver = 2;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HW_VERID_R8180_ABCD:
|
|
|
+ DMESG("MAC controller is a RTL8180");
|
|
|
+ priv->card_8185 = 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HW_VERID_R8180_F:
|
|
|
+ DMESG("MAC controller is a RTL8180 (v. F)");
|
|
|
+ priv->card_8185 = 0;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ DMESGW("MAC chip not recognized: version %x. Assuming RTL8180",hw_version);
|
|
|
+ priv->card_8185 = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION;
|
|
|
+ priv->ieee80211->short_slot = 1;
|
|
|
+ }
|
|
|
+ /* you should not found any 8185 Ver B Card */
|
|
|
+ priv->card_8185_Bversion = 0;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ // just for sync 85
|
|
|
+ priv->card_type = PCI;
|
|
|
+ DMESG("This is a PCI NIC");
|
|
|
+#else
|
|
|
+ config3 = read_nic_byte(dev, CONFIG3);
|
|
|
+ if(config3 & 0x8){
|
|
|
+ priv->card_type = CARDBUS;
|
|
|
+ DMESG("This is a CARDBUS NIC");
|
|
|
+ }
|
|
|
+ else if( config3 & 0x4){
|
|
|
+ priv->card_type = MINIPCI;
|
|
|
+ DMESG("This is a MINI-PCI NIC");
|
|
|
+ }else{
|
|
|
+ priv->card_type = PCI;
|
|
|
+ DMESG("This is a PCI NIC");
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+ priv->enable_gpio0 = 0;
|
|
|
+
|
|
|
+//by amy for antenna
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ usValue = eprom_read(dev, EEPROM_SW_REVD_OFFSET);
|
|
|
+ DMESG("usValue is 0x%x\n",usValue);
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ //3Read AntennaDiversity
|
|
|
+ // SW Antenna Diversity.
|
|
|
+ if( (usValue & EEPROM_SW_AD_MASK) != EEPROM_SW_AD_ENABLE )
|
|
|
+ {
|
|
|
+ priv->EEPROMSwAntennaDiversity = false;
|
|
|
+ //printk("EEPROM Disable SW Antenna Diversity\n");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->EEPROMSwAntennaDiversity = true;
|
|
|
+ //printk("EEPROM Enable SW Antenna Diversity\n");
|
|
|
+ }
|
|
|
+ // Default Antenna to use.
|
|
|
+ if( (usValue & EEPROM_DEF_ANT_MASK) != EEPROM_DEF_ANT_1 )
|
|
|
+ {
|
|
|
+ priv->EEPROMDefaultAntenna1 = false;
|
|
|
+ //printk("EEPROM Default Antenna 0\n");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->EEPROMDefaultAntenna1 = true;
|
|
|
+ //printk("EEPROM Default Antenna 1\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // Antenna diversity mechanism. Added by Roger, 2007.11.05.
|
|
|
+ //
|
|
|
+ if( priv->RegSwAntennaDiversityMechanism == 0 ) // Auto
|
|
|
+ {// 0: default from EEPROM.
|
|
|
+ priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {// 1:disable antenna diversity, 2: enable antenna diversity.
|
|
|
+ priv->bSwAntennaDiverity = ((priv->RegSwAntennaDiversityMechanism == 1)? false : true);
|
|
|
+ }
|
|
|
+ //printk("bSwAntennaDiverity = %d\n", priv->bSwAntennaDiverity);
|
|
|
+
|
|
|
+
|
|
|
+ //
|
|
|
+ // Default antenna settings. Added by Roger, 2007.11.05.
|
|
|
+ //
|
|
|
+ if( priv->RegDefaultAntenna == 0)
|
|
|
+ {// 0: default from EEPROM.
|
|
|
+ priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {// 1: main, 2: aux.
|
|
|
+ priv->bDefaultAntenna1 = ((priv->RegDefaultAntenna== 2) ? true : false);
|
|
|
+ }
|
|
|
+ //printk("bDefaultAntenna1 = %d\n", priv->bDefaultAntenna1);
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+//by amy for antenna
|
|
|
+ /* rtl8185 can calc plcp len in HW.*/
|
|
|
+ priv->hw_plcp_len = 1;
|
|
|
+
|
|
|
+ priv->plcp_preamble_mode = 2;
|
|
|
+ /*the eeprom type is stored in RCR register bit #6 */
|
|
|
+ if (RCR_9356SEL & read_nic_dword(dev, RCR)){
|
|
|
+ priv->epromtype=EPROM_93c56;
|
|
|
+ //DMESG("Reported EEPROM chip is a 93c56 (2Kbit)");
|
|
|
+ }else{
|
|
|
+ priv->epromtype=EPROM_93c46;
|
|
|
+ //DMESG("Reported EEPROM chip is a 93c46 (1Kbit)");
|
|
|
+ }
|
|
|
+
|
|
|
+ dev->get_stats = rtl8180_stats;
|
|
|
+
|
|
|
+ dev->dev_addr[0]=eprom_read(dev,MAC_ADR) & 0xff;
|
|
|
+ dev->dev_addr[1]=(eprom_read(dev,MAC_ADR) & 0xff00)>>8;
|
|
|
+ dev->dev_addr[2]=eprom_read(dev,MAC_ADR+1) & 0xff;
|
|
|
+ dev->dev_addr[3]=(eprom_read(dev,MAC_ADR+1) & 0xff00)>>8;
|
|
|
+ dev->dev_addr[4]=eprom_read(dev,MAC_ADR+2) & 0xff;
|
|
|
+ dev->dev_addr[5]=(eprom_read(dev,MAC_ADR+2) & 0xff00)>>8;
|
|
|
+ //DMESG("Card MAC address is "MAC_FMT, MAC_ARG(dev->dev_addr));
|
|
|
+
|
|
|
+
|
|
|
+ for(i=1,j=0; i<14; i+=2,j++){
|
|
|
+
|
|
|
+ word = eprom_read(dev,EPROM_TXPW_CH1_2 + j);
|
|
|
+ priv->chtxpwr[i]=word & 0xff;
|
|
|
+ priv->chtxpwr[i+1]=(word & 0xff00)>>8;
|
|
|
+#ifdef DEBUG_EPROM
|
|
|
+ DMESG("tx word %x:%x",j,word);
|
|
|
+ DMESG("ch %d pwr %x",i,priv->chtxpwr[i]);
|
|
|
+ DMESG("ch %d pwr %x",i+1,priv->chtxpwr[i+1]);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ if(priv->card_8185){
|
|
|
+ for(i=1,j=0; i<14; i+=2,j++){
|
|
|
+
|
|
|
+ word = eprom_read(dev,EPROM_TXPW_OFDM_CH1_2 + j);
|
|
|
+ priv->chtxpwr_ofdm[i]=word & 0xff;
|
|
|
+ priv->chtxpwr_ofdm[i+1]=(word & 0xff00)>>8;
|
|
|
+#ifdef DEBUG_EPROM
|
|
|
+ DMESG("ofdm tx word %x:%x",j,word);
|
|
|
+ DMESG("ofdm ch %d pwr %x",i,priv->chtxpwr_ofdm[i]);
|
|
|
+ DMESG("ofdm ch %d pwr %x",i+1,priv->chtxpwr_ofdm[i+1]);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ }
|
|
|
+//{by amy 080312
|
|
|
+ //3Read crystal calibtration and thermal meter indication on 87SE.
|
|
|
+
|
|
|
+ // By SD3 SY's request. Added by Roger, 2007.12.11.
|
|
|
+
|
|
|
+ tmpu16 = eprom_read(dev, EEPROM_RSV>>1);
|
|
|
+
|
|
|
+ //printk("ReadAdapterInfo8185(): EEPROM_RSV(%04x)\n", tmpu16);
|
|
|
+
|
|
|
+ // Crystal calibration for Xin and Xout resp.
|
|
|
+ priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; // 0~7.5pF
|
|
|
+ priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK)>>4; // 0~7.5pF
|
|
|
+ if((tmpu16 & EEPROM_XTAL_CAL_ENABLE)>>12)
|
|
|
+ priv->bXtalCalibration = true;
|
|
|
+
|
|
|
+ // Thermal meter reference indication.
|
|
|
+ priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK)>>8);
|
|
|
+ if((tmpu16 & EEPROM_THERMAL_METER_ENABLE)>>13)
|
|
|
+ priv->bTxPowerTrack = true;
|
|
|
+
|
|
|
+//by amy 080312}
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ word = eprom_read(dev,EPROM_TXPW_BASE);
|
|
|
+ priv->cck_txpwr_base = word & 0xf;
|
|
|
+ priv->ofdm_txpwr_base = (word>>4) & 0xf;
|
|
|
+#endif
|
|
|
+
|
|
|
+ version = eprom_read(dev,EPROM_VERSION);
|
|
|
+ DMESG("EEPROM version %x",version);
|
|
|
+ if( (!priv->card_8185) && version < 0x0101){
|
|
|
+ DMESG ("EEPROM version too old, assuming defaults");
|
|
|
+ DMESG ("If you see this message *plase* send your \
|
|
|
+DMESG output to andreamrl@tiscali.it THANKS");
|
|
|
+ priv->digphy=1;
|
|
|
+ priv->antb=0;
|
|
|
+ priv->diversity=1;
|
|
|
+ priv->cs_treshold=0xc;
|
|
|
+ priv->rcr_csense=1;
|
|
|
+ priv->rf_chip=RFCHIPID_PHILIPS;
|
|
|
+ }else{
|
|
|
+ if(!priv->card_8185){
|
|
|
+ u8 rfparam = eprom_read(dev,RF_PARAM);
|
|
|
+ DMESG("RfParam: %x",rfparam);
|
|
|
+
|
|
|
+ priv->digphy = rfparam & (1<<RF_PARAM_DIGPHY_SHIFT) ? 0:1;
|
|
|
+ priv->antb = rfparam & (1<<RF_PARAM_ANTBDEFAULT_SHIFT) ? 1:0;
|
|
|
+
|
|
|
+ priv->rcr_csense = (rfparam & RF_PARAM_CARRIERSENSE_MASK) >>
|
|
|
+ RF_PARAM_CARRIERSENSE_SHIFT;
|
|
|
+
|
|
|
+ priv->diversity =
|
|
|
+ (read_nic_byte(dev,CONFIG2)&(1<<CONFIG2_ANTENNA_SHIFT)) ? 1:0;
|
|
|
+ }else{
|
|
|
+ priv->rcr_csense = 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->cs_treshold = (eprom_read(dev,ENERGY_TRESHOLD)&0xff00) >>8;
|
|
|
+
|
|
|
+ priv->rf_chip = 0xff & eprom_read(dev,RFCHIPID);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+#ifdef CONFIG_RTL818X_S
|
|
|
+ priv->rf_chip = RF_ZEBRA4;
|
|
|
+ priv->rf_sleep = rtl8225z4_rf_sleep;
|
|
|
+ priv->rf_wakeup = rtl8225z4_rf_wakeup;
|
|
|
+#else
|
|
|
+ priv->rf_chip = RF_ZEBRA2;
|
|
|
+#endif
|
|
|
+ //DMESG("Card reports RF frontend Realtek 8225z2");
|
|
|
+ //DMESGW("This driver has EXPERIMENTAL support for this chipset.");
|
|
|
+ //DMESGW("use it with care and at your own risk and");
|
|
|
+ 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;
|
|
|
+ //priv->rf_sleep = rtl8225_rf_sleep;
|
|
|
+ //priv->rf_wakeup = rtl8225_rf_wakeup;
|
|
|
+
|
|
|
+#else
|
|
|
+ /* check RF frontend chipset */
|
|
|
+ switch (priv->rf_chip) {
|
|
|
+
|
|
|
+ case RFCHIPID_RTL8225:
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ DMESG("Card reports RF frontend Realtek 8225");
|
|
|
+ DMESGW("This driver has EXPERIMENTAL support for this chipset.");
|
|
|
+ DMESGW("use it with care and at your own risk and");
|
|
|
+ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it");
|
|
|
+
|
|
|
+ priv->rf_close = rtl8225_rf_close;
|
|
|
+ priv->rf_init = rtl8225_rf_init;
|
|
|
+ priv->rf_set_chan = rtl8225_rf_set_chan;
|
|
|
+ priv->rf_set_sens = NULL;
|
|
|
+ priv->rf_sleep = rtl8225_rf_sleep;
|
|
|
+ priv->rf_wakeup = rtl8225_rf_wakeup;
|
|
|
+
|
|
|
+ }else{
|
|
|
+ DMESGW("Detected RTL8225 radio on a card recognized as RTL8180");
|
|
|
+ DMESGW("This could not be... something went wrong....");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RFCHIPID_RTL8255:
|
|
|
+ if(priv->card_8185){
|
|
|
+ DMESG("Card reports RF frontend Realtek 8255");
|
|
|
+ DMESGW("This driver has EXPERIMENTAL support for this chipset.");
|
|
|
+ DMESGW("use it with care and at your own risk and");
|
|
|
+ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it");
|
|
|
+
|
|
|
+ priv->rf_close = rtl8255_rf_close;
|
|
|
+ priv->rf_init = rtl8255_rf_init;
|
|
|
+ priv->rf_set_chan = rtl8255_rf_set_chan;
|
|
|
+ priv->rf_set_sens = NULL;
|
|
|
+ priv->rf_sleep = NULL;
|
|
|
+ priv->rf_wakeup = NULL;
|
|
|
+
|
|
|
+ }else{
|
|
|
+ DMESGW("Detected RTL8255 radio on a card recognized as RTL8180");
|
|
|
+ DMESGW("This could not be... something went wrong....");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case RFCHIPID_INTERSIL:
|
|
|
+ DMESGW("Card reports RF frontend by Intersil.");
|
|
|
+ DMESGW("This driver has NO support for this chipset.");
|
|
|
+ return -ENODEV;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RFCHIPID_RFMD:
|
|
|
+ DMESGW("Card reports RF frontend by RFMD.");
|
|
|
+ DMESGW("This driver has NO support for this chipset.");
|
|
|
+ return -ENODEV;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RFCHIPID_GCT:
|
|
|
+ DMESGW("Card reports RF frontend by GCT.");
|
|
|
+ DMESGW("This driver has EXPERIMENTAL support for this chipset.");
|
|
|
+ DMESGW("use it with care and at your own risk and");
|
|
|
+ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it");
|
|
|
+ priv->rf_close = gct_rf_close;
|
|
|
+ priv->rf_init = gct_rf_init;
|
|
|
+ priv->rf_set_chan = gct_rf_set_chan;
|
|
|
+ priv->rf_set_sens = NULL;
|
|
|
+ priv->rf_sleep = NULL;
|
|
|
+ priv->rf_wakeup = NULL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RFCHIPID_MAXIM:
|
|
|
+ DMESGW("Card reports RF frontend by MAXIM.");
|
|
|
+ DMESGW("This driver has EXPERIMENTAL support for this chipset.");
|
|
|
+ DMESGW("use it with care and at your own risk and");
|
|
|
+ DMESGW("**PLEASE** REPORT SUCCESS/INSUCCESS TO andreamrl@tiscali.it");
|
|
|
+ priv->rf_close = maxim_rf_close;
|
|
|
+ priv->rf_init = maxim_rf_init;
|
|
|
+ priv->rf_set_chan = maxim_rf_set_chan;
|
|
|
+ priv->rf_set_sens = NULL;
|
|
|
+ priv->rf_sleep = NULL;
|
|
|
+ priv->rf_wakeup = NULL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case RFCHIPID_PHILIPS:
|
|
|
+ DMESG("Card reports RF frontend by Philips.");
|
|
|
+ DMESG("OK! Philips SA2400 radio chipset is supported.");
|
|
|
+ priv->rf_close = sa2400_rf_close;
|
|
|
+ priv->rf_init = sa2400_rf_init;
|
|
|
+ priv->rf_set_chan = sa2400_rf_set_chan;
|
|
|
+ priv->rf_set_sens = sa2400_rf_set_sens;
|
|
|
+ priv->sens = SA2400_RF_DEF_SENS; /* default sensitivity */
|
|
|
+ priv->max_sens = SA2400_RF_MAX_SENS; /* maximum sensitivity */
|
|
|
+ priv->rf_sleep = NULL;
|
|
|
+ priv->rf_wakeup = NULL;
|
|
|
+
|
|
|
+ if(priv->digphy){
|
|
|
+ DMESGW("Digital PHY found");
|
|
|
+ DMESGW("Philips DIGITAL PHY is untested! *Please*\
|
|
|
+ report success/failure to <andreamrl@tiscali.it>");
|
|
|
+ }else{
|
|
|
+ DMESG ("Analog PHY found");
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ DMESGW("Unknown RF module %x",priv->rf_chip);
|
|
|
+ DMESGW("Exiting...");
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+ if(!priv->card_8185){
|
|
|
+ if(priv->antb)
|
|
|
+ DMESG ("Antenna B is default antenna");
|
|
|
+ else
|
|
|
+ DMESG ("Antenna A is default antenna");
|
|
|
+
|
|
|
+ if(priv->diversity)
|
|
|
+ DMESG ("Antenna diversity is enabled");
|
|
|
+ else
|
|
|
+ DMESG("Antenna diversity is disabled");
|
|
|
+
|
|
|
+ DMESG("Carrier sense %d",priv->rcr_csense);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0!=alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_MANAGEPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_BKPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_BEPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_VIPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_VOPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount,
|
|
|
+ TX_HIGHPRIORITY_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ if (0!=alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount,
|
|
|
+ TX_BEACON_RING_ADDR))
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+
|
|
|
+ //priv->beacon_buf=NULL;
|
|
|
+
|
|
|
+ if(!priv->card_8185){
|
|
|
+
|
|
|
+ if(read_nic_byte(dev, CONFIG0) & (1<<CONFIG0_WEP40_SHIFT))
|
|
|
+ DMESG ("40-bit WEP is supported in hardware");
|
|
|
+ else
|
|
|
+ DMESG ("40-bit WEP is NOT supported in hardware");
|
|
|
+
|
|
|
+ if(read_nic_byte(dev,CONFIG0) & (1<<CONFIG0_WEP104_SHIFT))
|
|
|
+ DMESG ("104-bit WEP is supported in hardware");
|
|
|
+ else
|
|
|
+ DMESG ("104-bit WEP is NOT supported in hardware");
|
|
|
+ }
|
|
|
+#if !defined(SA_SHIRQ)
|
|
|
+ if(request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)){
|
|
|
+#else
|
|
|
+ if(request_irq(dev->irq, (void *)rtl8180_interrupt, SA_SHIRQ, dev->name, dev)){
|
|
|
+#endif
|
|
|
+ DMESGE("Error allocating IRQ %d",dev->irq);
|
|
|
+ return -1;
|
|
|
+ }else{
|
|
|
+ priv->irq=dev->irq;
|
|
|
+ DMESG("IRQ %d",dev->irq);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef DEBUG_EPROM
|
|
|
+ dump_eprom(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_no_hw_wep(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ if(!priv->card_8185)
|
|
|
+ {
|
|
|
+ u8 security;
|
|
|
+
|
|
|
+ security = read_nic_byte(dev, SECURITY);
|
|
|
+ security &=~(1<<SECURITY_WEP_TX_ENABLE_SHIFT);
|
|
|
+ security &=~(1<<SECURITY_WEP_RX_ENABLE_SHIFT);
|
|
|
+
|
|
|
+ write_nic_byte(dev, SECURITY, security);
|
|
|
+
|
|
|
+ }else{
|
|
|
+
|
|
|
+ //FIXME!!!
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ write_nic_dword(dev,TX_CONF,read_nic_dword(dev,TX_CONF) |
|
|
|
+ (1<<TX_NOICV_SHIFT) );
|
|
|
+ */
|
|
|
+// priv->ieee80211->hw_wep=0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_set_hw_wep(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u8 pgreg;
|
|
|
+ u8 security;
|
|
|
+ u32 key0_word4;
|
|
|
+
|
|
|
+ pgreg=read_nic_byte(dev, PGSELECT);
|
|
|
+ write_nic_byte(dev, PGSELECT, pgreg &~ (1<<PGSELECT_PG_SHIFT));
|
|
|
+
|
|
|
+ key0_word4 = read_nic_dword(dev, KEY0+4+4+4);
|
|
|
+ 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));
|
|
|
+
|
|
|
+ /*
|
|
|
+ TX_CONF,read_nic_dword(dev,TX_CONF) &~(1<<TX_NOICV_SHIFT));
|
|
|
+ */
|
|
|
+
|
|
|
+ security = read_nic_byte(dev,SECURITY);
|
|
|
+ security |= (1<<SECURITY_WEP_TX_ENABLE_SHIFT);
|
|
|
+ security |= (1<<SECURITY_WEP_RX_ENABLE_SHIFT);
|
|
|
+ security &= ~ SECURITY_ENCRYP_MASK;
|
|
|
+ security |= (SECURITY_ENCRYP_104<<SECURITY_ENCRYP_SHIFT);
|
|
|
+
|
|
|
+ write_nic_byte(dev, SECURITY, security);
|
|
|
+
|
|
|
+ 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));
|
|
|
+
|
|
|
+ //priv->ieee80211->hw_wep=1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8185_rf_pins_enable(struct net_device *dev)
|
|
|
+{
|
|
|
+// u16 tmp;
|
|
|
+// tmp = read_nic_word(dev, RFPinsEnable);
|
|
|
+ write_nic_word(dev, RFPinsEnable, 0x1fff);// | tmp);
|
|
|
+// write_nic_word(dev, RFPinsEnable,7 | tmp);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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);
|
|
|
+ write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT));
|
|
|
+ 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);
|
|
|
+ write_nic_byte(dev, CONFIG3, conf3 &~(1<<CONFIG3_ANAPARAM_W_SHIFT));
|
|
|
+ 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)
|
|
|
+{
|
|
|
+ //u8 phyr;
|
|
|
+ u32 phyw;
|
|
|
+ //int i;
|
|
|
+
|
|
|
+ adr |= 0x80;
|
|
|
+
|
|
|
+ phyw= ((data<<8) | adr);
|
|
|
+#if 0
|
|
|
+
|
|
|
+ write_nic_dword(dev, PHY_ADR, phyw);
|
|
|
+
|
|
|
+ //read_nic_dword(dev, PHY_ADR);
|
|
|
+ for(i=0;i<10;i++){
|
|
|
+ write_nic_dword(dev, PHY_ADR, 0xffffff7f & phyw);
|
|
|
+ phyr = read_nic_byte(dev, PHY_READ);
|
|
|
+ if(phyr == (data&0xff)) break;
|
|
|
+
|
|
|
+ }
|
|
|
+#else
|
|
|
+ // Note that, we must write 0xff7c after 0x7d-0x7f to write BB register.
|
|
|
+ write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24));
|
|
|
+ write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16));
|
|
|
+ write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8));
|
|
|
+ write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff) ));
|
|
|
+#endif
|
|
|
+ /* this is ok to fail when we write AGC table. check for AGC table might be
|
|
|
+ * done by masking with 0x7f instead of 0xff
|
|
|
+ */
|
|
|
+ //if(phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data,adr);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+inline void write_phy_ofdm (struct net_device *dev, u8 adr, u32 data)
|
|
|
+{
|
|
|
+ data = data & 0xff;
|
|
|
+ rtl8185_write_phy(dev, adr, data);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void write_phy_cck (struct net_device *dev, u8 adr, u32 data)
|
|
|
+{
|
|
|
+ data = data & 0xff;
|
|
|
+ rtl8185_write_phy(dev, adr, data | 0x10000);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* 70*3 = 210 ms
|
|
|
+ * I hope this is enougth
|
|
|
+ */
|
|
|
+#define MAX_PHY 70
|
|
|
+void write_phy(struct net_device *dev, u8 adr, u8 data)
|
|
|
+{
|
|
|
+ u32 phy;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ phy = 0xff0000;
|
|
|
+ phy |= adr;
|
|
|
+ phy |= 0x80; /* this should enable writing */
|
|
|
+ phy |= (data<<8);
|
|
|
+
|
|
|
+ //PHY_ADR, PHY_R and PHY_W are contig and treated as one dword
|
|
|
+ write_nic_dword(dev,PHY_ADR, phy);
|
|
|
+
|
|
|
+ phy= 0xffff00;
|
|
|
+ phy |= adr;
|
|
|
+
|
|
|
+ write_nic_dword(dev,PHY_ADR, phy);
|
|
|
+ for(i=0;i<MAX_PHY;i++){
|
|
|
+ phy=read_nic_dword(dev,PHY_ADR);
|
|
|
+ phy= phy & 0xff0000;
|
|
|
+ phy= phy >> 16;
|
|
|
+ if(phy == data){ //SUCCESS!
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(3); //random value
|
|
|
+#ifdef DEBUG_BB
|
|
|
+ DMESG("Phy wr %x,%x",adr,data);
|
|
|
+#endif
|
|
|
+ return;
|
|
|
+ }else{
|
|
|
+ force_pci_posting(dev);
|
|
|
+ mdelay(3); //random value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ DMESGW ("Phy writing %x %x failed!", adr,data);
|
|
|
+}
|
|
|
+
|
|
|
+void rtl8185_set_rate(struct net_device *dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ u16 word;
|
|
|
+ int basic_rate,min_rr_rate,max_rr_rate;
|
|
|
+
|
|
|
+// struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ //if (ieee80211_is_54g(priv->ieee80211->current_network) &&
|
|
|
+// priv->ieee80211->state == IEEE80211_LINKED){
|
|
|
+ basic_rate = ieeerate2rtlrate(240);
|
|
|
+ min_rr_rate = ieeerate2rtlrate(60);
|
|
|
+ max_rr_rate = ieeerate2rtlrate(240);
|
|
|
+
|
|
|
+//
|
|
|
+// }else{
|
|
|
+// basic_rate = ieeerate2rtlrate(20);
|
|
|
+// min_rr_rate = ieeerate2rtlrate(10);
|
|
|
+// max_rr_rate = ieeerate2rtlrate(110);
|
|
|
+// }
|
|
|
+
|
|
|
+ write_nic_byte(dev, RESP_RATE,
|
|
|
+ max_rr_rate<<MAX_RESP_RATE_SHIFT| min_rr_rate<<MIN_RESP_RATE_SHIFT);
|
|
|
+
|
|
|
+ word = read_nic_word(dev, BRSR);
|
|
|
+ word &= ~BRSR_MBR_8185;
|
|
|
+
|
|
|
+
|
|
|
+ for(i=0;i<=basic_rate;i++)
|
|
|
+ word |= (1<<i);
|
|
|
+
|
|
|
+ write_nic_word(dev, BRSR, word);
|
|
|
+ //DMESG("RR:%x BRSR: %x", read_nic_byte(dev,RESP_RATE),read_nic_word(dev,BRSR));
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_adapter_start(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ u32 anaparam;
|
|
|
+ u16 word;
|
|
|
+ u8 config3;
|
|
|
+// int i;
|
|
|
+
|
|
|
+ rtl8180_rtx_disable(dev);
|
|
|
+ rtl8180_reset(dev);
|
|
|
+
|
|
|
+ /* seems that 0xffff or 0xafff will cause
|
|
|
+ * HW interrupt line crash
|
|
|
+ */
|
|
|
+
|
|
|
+ //priv->irq_mask = 0xafff;
|
|
|
+// priv->irq_mask = 0x4fcf;
|
|
|
+
|
|
|
+ /* enable beacon timeout, beacon TX ok and err
|
|
|
+ * LP tx ok and err, HP TX ok and err, NP TX ok and err,
|
|
|
+ * RX ok and ERR, and GP timer */
|
|
|
+ priv->irq_mask = 0x6fcf;
|
|
|
+
|
|
|
+ priv->dma_poll_mask = 0;
|
|
|
+
|
|
|
+ rtl8180_beacon_tx_disable(dev);
|
|
|
+
|
|
|
+ if(priv->card_type == CARDBUS ){
|
|
|
+ config3=read_nic_byte(dev, CONFIG3);
|
|
|
+ write_nic_byte(dev,CONFIG3,config3 | CONFIG3_FuncRegEn);
|
|
|
+ write_nic_word(dev,FEMR, FEMR_INTR | FEMR_WKUP | FEMR_GWAKE |
|
|
|
+ read_nic_word(dev, FEMR));
|
|
|
+ }
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
+ write_nic_dword(dev, MAC0, ((u32*)dev->dev_addr)[0]);
|
|
|
+ write_nic_word(dev, MAC4, ((u32*)dev->dev_addr)[1] & 0xffff );
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+ rtl8180_update_msr(dev);
|
|
|
+
|
|
|
+ if(!priv->card_8185){
|
|
|
+ anaparam = eprom_read(dev,EPROM_ANAPARAM_ADDRLWORD);
|
|
|
+ anaparam |= eprom_read(dev,EPROM_ANAPARAM_ADDRHWORD)<<16;
|
|
|
+
|
|
|
+ rtl8180_set_anaparam(dev,anaparam);
|
|
|
+ }
|
|
|
+ /* These might be unnecessary since we do in rx_enable / tx_enable */
|
|
|
+ fix_rx_fifo(dev);
|
|
|
+ fix_tx_fifo(dev);
|
|
|
+ /*set_nic_rxring(dev);
|
|
|
+ set_nic_txring(dev);*/
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
+
|
|
|
+ /*
|
|
|
+ The following is very strange. seems to be that 1 means test mode,
|
|
|
+ but we need to acknolwledges the nic when a packet is ready
|
|
|
+ altought we set it to 0
|
|
|
+ */
|
|
|
+
|
|
|
+ write_nic_byte(dev,
|
|
|
+ CONFIG2, read_nic_byte(dev,CONFIG2) &~\
|
|
|
+ (1<<CONFIG2_DMA_POLLING_MODE_SHIFT));
|
|
|
+ //^the nic isn't in test mode
|
|
|
+ if(priv->card_8185)
|
|
|
+ write_nic_byte(dev,
|
|
|
+ CONFIG2, read_nic_byte(dev,CONFIG2)|(1<<4));
|
|
|
+
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+ write_nic_dword(dev,INT_TIMEOUT,0);
|
|
|
+#ifdef DEBUG_REGISTERS
|
|
|
+ rtl8180_dump_reg(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if(!priv->card_8185)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ experimental - this might be needed to calibrate AGC,
|
|
|
+ anyway it shouldn't hurt
|
|
|
+ */
|
|
|
+ write_nic_byte(dev, CONFIG5,
|
|
|
+ read_nic_byte(dev, CONFIG5) | (1<<AGCRESET_SHIFT));
|
|
|
+ read_nic_byte(dev, CONFIG5);
|
|
|
+ udelay(15);
|
|
|
+ write_nic_byte(dev, CONFIG5,
|
|
|
+ read_nic_byte(dev, CONFIG5) &~ (1<<AGCRESET_SHIFT));
|
|
|
+ }else{
|
|
|
+
|
|
|
+ write_nic_byte(dev, WPA_CONFIG, 0);
|
|
|
+ //write_nic_byte(dev, TESTR, 0xd);
|
|
|
+ }
|
|
|
+
|
|
|
+ rtl8180_no_hw_wep(dev);
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ rtl8185_set_rate(dev);
|
|
|
+ write_nic_byte(dev, RATE_FALLBACK, 0x81);
|
|
|
+ // write_nic_byte(dev, 0xdf, 0x15);
|
|
|
+ }else{
|
|
|
+ word = read_nic_word(dev, BRSR);
|
|
|
+ word &= ~BRSR_MBR;
|
|
|
+ word &= ~BRSR_BPLCP;
|
|
|
+ word |= ieeerate2rtlrate(priv->ieee80211->basic_rate);
|
|
|
+//by amy
|
|
|
+ word |= 0x0f;
|
|
|
+//by amy
|
|
|
+ write_nic_word(dev, BRSR, word);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(priv->card_8185){
|
|
|
+ write_nic_byte(dev, GP_ENABLE,read_nic_byte(dev, GP_ENABLE) & ~(1<<6));
|
|
|
+
|
|
|
+ //FIXME cfg 3 ClkRun enable - isn't it ReadOnly ?
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_CONFIG);
|
|
|
+ write_nic_byte(dev,CONFIG3, read_nic_byte(dev, CONFIG3)
|
|
|
+|(1<<CONFIG3_CLKRUN_SHIFT));
|
|
|
+ rtl8180_set_mode(dev, EPROM_CMD_NORMAL);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->rf_init(dev);
|
|
|
+
|
|
|
+ if(priv->rf_set_sens != NULL)
|
|
|
+ priv->rf_set_sens(dev,priv->sens);
|
|
|
+ rtl8180_irq_enable(dev);
|
|
|
+
|
|
|
+ netif_start_queue(dev);
|
|
|
+ /*DMESG ("lfree %d",get_curr_tx_free_desc(dev,LOW_PRIORITY));
|
|
|
+
|
|
|
+ DMESG ("nfree %d",get_curr_tx_free_desc(dev,NORM_PRIORITY));
|
|
|
+
|
|
|
+ DMESG ("hfree %d",get_curr_tx_free_desc(dev,HI_PRIORITY));
|
|
|
+ if(check_nic_enought_desc(dev,NORM_PRIORITY)) DMESG("NORM OK");
|
|
|
+ if(check_nic_enought_desc(dev,HI_PRIORITY)) DMESG("HI OK");
|
|
|
+ if(check_nic_enought_desc(dev,LOW_PRIORITY)) DMESG("LOW OK");*/
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/* this configures registers for beacon tx and enables it via
|
|
|
+ * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might
|
|
|
+ * be used to stop beacon transmission
|
|
|
+ */
|
|
|
+void rtl8180_start_tx_beacon(struct net_device *dev)
|
|
|
+{
|
|
|
+// struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+ u16 word;
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+
|
|
|
+ DMESG("Enabling beacon TX");
|
|
|
+ //write_nic_byte(dev, 0x42,0xe6);// TCR
|
|
|
+// set_nic_txring(dev);
|
|
|
+// fix_tx_fifo(dev);
|
|
|
+ rtl8180_prepare_beacon(dev);
|
|
|
+ rtl8180_irq_disable(dev);
|
|
|
+ rtl8180_beacon_tx_enable(dev);
|
|
|
+#if 0
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+ //write_nic_byte(dev,0x9d,0x20); //DMA Poll
|
|
|
+ //write_nic_word(dev,0x7a,0);
|
|
|
+ //write_nic_word(dev,0x7a,0x8000);
|
|
|
+
|
|
|
+#if 0
|
|
|
+ word = read_nic_word(dev, BcnItv);
|
|
|
+ word &= ~BcnItv_BcnItv; // clear Bcn_Itv
|
|
|
+ word |= priv->ieee80211->current_network.beacon_interval;//0x64;
|
|
|
+ write_nic_word(dev, BcnItv, word);
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+ word = read_nic_word(dev, AtimWnd) &~ AtimWnd_AtimWnd;
|
|
|
+ write_nic_word(dev, AtimWnd,word);// word |=
|
|
|
+//priv->ieee80211->current_network.atim_window);
|
|
|
+
|
|
|
+ word = read_nic_word(dev, BintrItv);
|
|
|
+ word &= ~BintrItv_BintrItv;
|
|
|
+ word |= 1000;/*priv->ieee80211->current_network.beacon_interval *
|
|
|
+ ((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);
|
|
|
+
|
|
|
+// rtl8180_beacon_tx_enable(dev);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rtl8185b_irq_enable(dev);
|
|
|
+#else
|
|
|
+ rtl8180_irq_enable(dev);
|
|
|
+#endif
|
|
|
+ /* VV !!!!!!!!!! VV*/
|
|
|
+ /*
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_CONFIG);
|
|
|
+ write_nic_byte(dev,0x9d,0x00);
|
|
|
+ rtl8180_set_mode(dev,EPROM_CMD_NORMAL);
|
|
|
+*/
|
|
|
+// DMESG("ring %x %x", priv->txlpringdma,read_nic_dword(dev,TLPDA));
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/***************************************************************************
|
|
|
+ -------------------------------NET STUFF---------------------------
|
|
|
+***************************************************************************/
|
|
|
+static struct net_device_stats *rtl8180_stats(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ return &priv->ieee80211->stats;
|
|
|
+}
|
|
|
+//
|
|
|
+// Change current and default preamble mode.
|
|
|
+// 2005.01.06, by rcnjko.
|
|
|
+//
|
|
|
+bool
|
|
|
+MgntActSet_802_11_PowerSaveMode(
|
|
|
+ struct r8180_priv *priv,
|
|
|
+ RT_PS_MODE rtPsMode
|
|
|
+)
|
|
|
+{
|
|
|
+
|
|
|
+ // Currently, we do not change power save mode on IBSS mode.
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ //
|
|
|
+ // <RJ_NOTE> If we make HW to fill up the PwrMgt bit for us,
|
|
|
+ // some AP will not response to our mgnt frames with PwrMgt bit set,
|
|
|
+ // e.g. cannot associate the AP.
|
|
|
+ // So I commented out it. 2005.02.16, by rcnjko.
|
|
|
+ //
|
|
|
+// // Change device's power save mode.
|
|
|
+// Adapter->HalFunc.SetPSModeHandler( Adapter, rtPsMode );
|
|
|
+
|
|
|
+ // Update power save mode configured.
|
|
|
+// priv->dot11PowerSaveMode = rtPsMode;
|
|
|
+ priv->ieee80211->ps = rtPsMode;
|
|
|
+ // Determine ListenInterval.
|
|
|
+#if 0
|
|
|
+ if(priv->dot11PowerSaveMode == eMaxPs)
|
|
|
+ {
|
|
|
+ priv->ieee80211->ListenInterval = 10;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->ieee80211->ListenInterval = 2;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//================================================================================
|
|
|
+// Leisure Power Save in linked state.
|
|
|
+//================================================================================
|
|
|
+
|
|
|
+//
|
|
|
+// Description:
|
|
|
+// Enter the leisure power save mode.
|
|
|
+//
|
|
|
+void
|
|
|
+LeisurePSEnter(
|
|
|
+ struct r8180_priv *priv
|
|
|
+ )
|
|
|
+{
|
|
|
+ if (priv->bLeisurePs)
|
|
|
+ {
|
|
|
+ if (priv->ieee80211->ps == IEEE80211_PS_DISABLED)
|
|
|
+ {
|
|
|
+ //printk("----Enter PS\n");
|
|
|
+ MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST);//IEEE80211_PS_ENABLE
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//
|
|
|
+// Description:
|
|
|
+// Leave the leisure power save mode.
|
|
|
+//
|
|
|
+void
|
|
|
+LeisurePSLeave(
|
|
|
+ struct r8180_priv *priv
|
|
|
+ )
|
|
|
+{
|
|
|
+ if (priv->bLeisurePs)
|
|
|
+ {
|
|
|
+ if (priv->ieee80211->ps != IEEE80211_PS_DISABLED)
|
|
|
+ {
|
|
|
+ //printk("----Leave PS\n");
|
|
|
+ MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_hw_wakeup_wq (struct work_struct *work)
|
|
|
+{
|
|
|
+// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
|
|
|
+// struct ieee80211_device * ieee = (struct ieee80211_device*)
|
|
|
+// container_of(work, struct ieee80211_device, watch_dog_wq);
|
|
|
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
|
|
|
+ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq);
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+#else
|
|
|
+void rtl8180_hw_wakeup_wq(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+// printk("dev is %d\n",dev);
|
|
|
+// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__);
|
|
|
+ rtl8180_hw_wakeup(dev);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_hw_sleep_wq (struct work_struct *work)
|
|
|
+{
|
|
|
+// struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq);
|
|
|
+// struct ieee80211_device * ieee = (struct ieee80211_device*)
|
|
|
+// container_of(work, struct ieee80211_device, watch_dog_wq);
|
|
|
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
|
|
|
+ struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq);
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+#else
|
|
|
+void rtl8180_hw_sleep_wq(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ rtl8180_hw_sleep_down(dev);
|
|
|
+}
|
|
|
+
|
|
|
+//YJ,add,080828,for KeepAlive
|
|
|
+static void MgntLinkKeepAlive(struct r8180_priv *priv )
|
|
|
+{
|
|
|
+ if (priv->keepAliveLevel == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if(priv->ieee80211->state == IEEE80211_LINKED)
|
|
|
+ {
|
|
|
+ //
|
|
|
+ // Keep-Alive.
|
|
|
+ //
|
|
|
+ //printk("LastTx:%d Tx:%d LastRx:%d Rx:%ld Idle:%d\n",priv->link_detect.LastNumTxUnicast,priv->NumTxUnicast, priv->link_detect.LastNumRxUnicast, priv->ieee80211->NumRxUnicast, priv->link_detect.IdleCount);
|
|
|
+
|
|
|
+ if ( (priv->keepAliveLevel== 2) ||
|
|
|
+ (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast &&
|
|
|
+ priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast )
|
|
|
+ )
|
|
|
+ {
|
|
|
+ priv->link_detect.IdleCount++;
|
|
|
+
|
|
|
+ //
|
|
|
+ // Send a Keep-Alive packet packet to AP if we had been idle for a while.
|
|
|
+ //
|
|
|
+ if(priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1) )
|
|
|
+ {
|
|
|
+ priv->link_detect.IdleCount = 0;
|
|
|
+ ieee80211_sta_ps_send_null_frame(priv->ieee80211, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ priv->link_detect.IdleCount = 0;
|
|
|
+ }
|
|
|
+ priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast;
|
|
|
+ priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast;
|
|
|
+ }
|
|
|
+}
|
|
|
+//YJ,add,080828,for KeepAlive,end
|
|
|
+
|
|
|
+static u8 read_acadapter_file(char *filename);
|
|
|
+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;
|
|
|
+#ifdef ENABLE_IPS
|
|
|
+ if(priv->ieee80211->actscanning == false){
|
|
|
+ if((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && (priv->ieee80211->state == IEEE80211_NOLINK) && (priv->ieee80211->beinretry == false) && (priv->eRFPowerState == eRfOn)){
|
|
|
+ IPSEnter(dev);
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ //YJ,add,080828,for link state check
|
|
|
+ if((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)){
|
|
|
+ SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum;
|
|
|
+ priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod;
|
|
|
+ for( i=0; i<priv->link_detect.SlotNum; i++ )
|
|
|
+ TotalRxNum+= priv->link_detect.RxFrameNum[i];
|
|
|
+ //printk("&&&&&=== TotalRxNum = %d\n", TotalRxNum);
|
|
|
+ if(TotalRxNum == 0){
|
|
|
+ priv->ieee80211->state = IEEE80211_ASSOCIATING;
|
|
|
+ queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //YJ,add,080828,for KeepAlive
|
|
|
+ MgntLinkKeepAlive(priv);
|
|
|
+
|
|
|
+ //YJ,add,080828,for LPS
|
|
|
+#ifdef ENABLE_LPS
|
|
|
+ if(priv->PowerProfile == POWER_PROFILE_BATTERY )
|
|
|
+ {
|
|
|
+ //Turn on LeisurePS on battery power
|
|
|
+ //printk("!!!!!On battery power\n");
|
|
|
+ priv->bLeisurePs = true;
|
|
|
+ }
|
|
|
+ else if(priv->PowerProfile == POWER_PROFILE_AC )
|
|
|
+ {
|
|
|
+ // Turn off LeisurePS on AC power
|
|
|
+ //printk("----On AC power\n");
|
|
|
+ LeisurePSLeave(priv);
|
|
|
+ priv->bLeisurePs= false;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+#if 0
|
|
|
+#ifndef ENABLE_LPS
|
|
|
+ if(priv->ieee80211->state == IEEE80211_LINKED){
|
|
|
+ if( priv->NumRxOkInPeriod> 666 ||
|
|
|
+ priv->NumTxOkInPeriod > 666 ) {
|
|
|
+ bBusyTraffic = true;
|
|
|
+ }
|
|
|
+ if((priv->ieee80211->NumRxData + priv->NumTxOkInPeriod)<8) {
|
|
|
+ bEnterPS= true;
|
|
|
+ }
|
|
|
+ if(bEnterPS) {
|
|
|
+ LeisurePSEnter(priv);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ LeisurePSLeave(priv);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ LeisurePSLeave(priv);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ priv->NumRxOkInPeriod = 0;
|
|
|
+ priv->NumTxOkInPeriod = 0;
|
|
|
+ priv->ieee80211->NumRxData = 0;
|
|
|
+#else
|
|
|
+#ifdef ENABLE_LPS
|
|
|
+ if(priv->ieee80211->state == IEEE80211_LINKED){
|
|
|
+ priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod;
|
|
|
+ //printk("TxOk=%d RxOk=%d\n", priv->link_detect.NumTxOkInPeriod, priv->link_detect.NumRxOkInPeriod);
|
|
|
+ if( priv->link_detect.NumRxOkInPeriod> 666 ||
|
|
|
+ priv->link_detect.NumTxOkInPeriod> 666 ) {
|
|
|
+ bBusyTraffic = true;
|
|
|
+ }
|
|
|
+ if(((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8)
|
|
|
+ || (priv->link_detect.NumRxOkInPeriod > 2)) {
|
|
|
+ bEnterPS= false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ bEnterPS= true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bEnterPS) {
|
|
|
+ LeisurePSEnter(priv);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ LeisurePSLeave(priv);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ LeisurePSLeave(priv);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ priv->link_detect.bBusyTraffic = bBusyTraffic;
|
|
|
+ priv->link_detect.NumRxOkInPeriod = 0;
|
|
|
+ priv->link_detect.NumTxOkInPeriod = 0;
|
|
|
+ priv->ieee80211->NumRxDataInPeriod = 0;
|
|
|
+ priv->ieee80211->NumRxBcnInPeriod = 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+int _rtl8180_up(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ //int i;
|
|
|
+
|
|
|
+ priv->up=1;
|
|
|
+
|
|
|
+ DMESG("Bringing up iface");
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rtl8185b_adapter_start(dev);
|
|
|
+ rtl8185b_rx_enable(dev);
|
|
|
+ rtl8185b_tx_enable(dev);
|
|
|
+#else
|
|
|
+ rtl8180_adapter_start(dev);
|
|
|
+ rtl8180_rx_enable(dev);
|
|
|
+ rtl8180_tx_enable(dev);
|
|
|
+#endif
|
|
|
+#ifdef ENABLE_IPS
|
|
|
+ if(priv->bInactivePs){
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
|
|
|
+ IPSLeave(dev);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+//by amy 080312
|
|
|
+#ifdef RATE_ADAPT
|
|
|
+ timer_rate_adaptive((unsigned long)dev);
|
|
|
+#endif
|
|
|
+//by amy 080312
|
|
|
+ watch_dog_adaptive((unsigned long)dev);
|
|
|
+#ifdef SW_ANTE
|
|
|
+ if(priv->bSwAntennaDiverity)
|
|
|
+ SwAntennaDiversityTimerCallback(dev);
|
|
|
+#endif
|
|
|
+// IPSEnter(dev);
|
|
|
+ ieee80211_softmac_start_protocol(priv->ieee80211);
|
|
|
+
|
|
|
+//Add for RF power on power off by lizhaoming 080512
|
|
|
+// priv->eRFPowerState = eRfOn;
|
|
|
+// printk("\n--------Start queue_work:GPIOChangeRFWorkItem");
|
|
|
+// queue_delayed_work(priv->ieee80211->wq,&priv->ieee80211->GPIOChangeRFWorkItem,1000);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (priv->up == 1) return -1;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ if (priv->up == 0) return -1;
|
|
|
+
|
|
|
+ priv->up=0;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ //cancel_delayed_work(&priv->ieee80211->watch_dog_wq);
|
|
|
+//{by amy 080312
|
|
|
+ del_timer_sync(&priv->rateadapter_timer);
|
|
|
+ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
|
|
|
+//by amy 080312}
|
|
|
+ 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);
|
|
|
+ SetZebraRFPowerState8185(dev,eRfOff);
|
|
|
+ //ieee80211_softmac_stop_protocol(priv->ieee80211);
|
|
|
+ memset(&(priv->ieee80211->current_network),0,sizeof(struct ieee80211_network));
|
|
|
+ priv->ieee80211->state = IEEE80211_NOLINK;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+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;
|
|
|
+#else
|
|
|
+void rtl8180_restart_wq(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+ 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);
|
|
|
+ //rtl8180_commit(dev);
|
|
|
+ schedule_work(&priv->reset_wq);
|
|
|
+ //DMESG("TXTIMEOUT");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_commit(struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+
|
|
|
+ if (priv->up == 0) return ;
|
|
|
+//+by amy 080312
|
|
|
+ del_timer_sync(&priv->watch_dog_timer);
|
|
|
+ //cancel_delayed_work(&priv->ieee80211->watch_dog_wq);
|
|
|
+//{by amy 080312
|
|
|
+//by amy for rate adaptive
|
|
|
+ del_timer_sync(&priv->rateadapter_timer);
|
|
|
+ cancel_delayed_work(&priv->ieee80211->rate_adapter_wq);
|
|
|
+//by amy for rate adaptive
|
|
|
+//by amy 080312}
|
|
|
+ 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;
|
|
|
+
|
|
|
+ //down(&priv->wx_sem);
|
|
|
+
|
|
|
+ promisc = (dev->flags & IFF_PROMISC) ? 1:0;
|
|
|
+
|
|
|
+ if (promisc != priv->promisc)
|
|
|
+ rtl8180_restart(dev);
|
|
|
+
|
|
|
+ priv->promisc = promisc;
|
|
|
+
|
|
|
+ //up(&priv->wx_sem);
|
|
|
+}
|
|
|
+
|
|
|
+#if 0
|
|
|
+/* this is called by the kernel when it needs to TX a 802.3 encapsulated frame*/
|
|
|
+int rtl8180_8023_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+ int ret;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->tx_lock,flags);
|
|
|
+ ret = ieee80211_r8180_8023_hardstartxmit(skb,priv->ieee80211);
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+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);
|
|
|
+
|
|
|
+ if(priv->ieee80211->iw_mode == IW_MODE_MASTER)
|
|
|
+ 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;
|
|
|
+ int ret=-1;
|
|
|
+ switch (cmd) {
|
|
|
+ case RTL_IOCTL_WPA_SUPPLICANT:
|
|
|
+ ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data);
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/****************************************************************************
|
|
|
+ -----------------------------PCI STUFF---------------------------
|
|
|
+*****************************************************************************/
|
|
|
+
|
|
|
+
|
|
|
+static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
|
|
|
+ const struct pci_device_id *id)
|
|
|
+{
|
|
|
+ unsigned long ioaddr = 0;
|
|
|
+ struct net_device *dev = NULL;
|
|
|
+ struct r8180_priv *priv= NULL;
|
|
|
+ //u8 *ptr;
|
|
|
+ u8 unit = 0;
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_IO_MAP
|
|
|
+ unsigned long pio_start, pio_len, pio_flags;
|
|
|
+#else
|
|
|
+ unsigned long pmem_start, pmem_len, pmem_flags;
|
|
|
+#endif //end #ifdef RTL_IO_MAP
|
|
|
+
|
|
|
+ DMESG("Configuring chip resources");
|
|
|
+
|
|
|
+ if( pci_enable_device (pdev) ){
|
|
|
+ DMESG("Failed to enable PCI device");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_set_master(pdev);
|
|
|
+ //pci_set_wmi(pdev);
|
|
|
+ pci_set_dma_mask(pdev, 0xffffff00ULL);
|
|
|
+ pci_set_consistent_dma_mask(pdev,0xffffff00ULL);
|
|
|
+ dev = alloc_ieee80211(sizeof(struct r8180_priv));
|
|
|
+ if (!dev)
|
|
|
+ return -ENOMEM;
|
|
|
+ priv = ieee80211_priv(dev);
|
|
|
+ priv->ieee80211 = netdev_priv(dev);
|
|
|
+
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
|
|
+ SET_MODULE_OWNER(dev);
|
|
|
+#endif
|
|
|
+ pci_set_drvdata(pdev, dev);
|
|
|
+ SET_NETDEV_DEV(dev, &pdev->dev);
|
|
|
+
|
|
|
+ priv = ieee80211_priv(dev);
|
|
|
+// memset(priv,0,sizeof(struct r8180_priv));
|
|
|
+ priv->pdev=pdev;
|
|
|
+
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_IO_MAP
|
|
|
+
|
|
|
+ pio_start = (unsigned long)pci_resource_start (pdev, 0);
|
|
|
+ pio_len = (unsigned long)pci_resource_len (pdev, 0);
|
|
|
+ pio_flags = (unsigned long)pci_resource_flags (pdev, 0);
|
|
|
+
|
|
|
+ if (!(pio_flags & IORESOURCE_IO)) {
|
|
|
+ DMESG("region #0 not a PIO resource, aborting");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ //DMESG("IO space @ 0x%08lx", pio_start );
|
|
|
+ if( ! request_region( pio_start, pio_len, RTL8180_MODULE_NAME ) ){
|
|
|
+ DMESG("request_region failed!");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ ioaddr = pio_start;
|
|
|
+ dev->base_addr = ioaddr; // device I/O address
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ pmem_start = pci_resource_start(pdev, 1);
|
|
|
+ pmem_len = pci_resource_len(pdev, 1);
|
|
|
+ pmem_flags = pci_resource_flags (pdev, 1);
|
|
|
+
|
|
|
+ if (!(pmem_flags & IORESOURCE_MEM)) {
|
|
|
+ DMESG("region #1 not a MMIO resource, aborting");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ //DMESG("Memory mapped space @ 0x%08lx ", pmem_start);
|
|
|
+ if( ! request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) {
|
|
|
+ DMESG("request_mem_region failed!");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ ioaddr = (unsigned long)ioremap_nocache( pmem_start, pmem_len);
|
|
|
+ if( ioaddr == (unsigned long)NULL ){
|
|
|
+ DMESG("ioremap failed!");
|
|
|
+ // release_mem_region( pmem_start, pmem_len );
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev->mem_start = ioaddr; // shared mem start
|
|
|
+ dev->mem_end = ioaddr + pci_resource_len(pdev, 0); // shared mem end
|
|
|
+
|
|
|
+#endif //end #ifdef RTL_IO_MAP
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ //pci_read_config_byte(pdev, 0x05, ptr);
|
|
|
+ //pci_write_config_byte(pdev, 0x05, (*ptr) & (~0x04));
|
|
|
+ pci_read_config_byte(pdev, 0x05, &unit);
|
|
|
+ pci_write_config_byte(pdev, 0x05, unit & (~0x04));
|
|
|
+#endif
|
|
|
+
|
|
|
+ dev->irq = pdev->irq;
|
|
|
+ priv->irq = 0;
|
|
|
+
|
|
|
+ dev->open = rtl8180_open;
|
|
|
+ dev->stop = rtl8180_close;
|
|
|
+ //dev->hard_start_xmit = ieee80211_xmit;
|
|
|
+ dev->tx_timeout = rtl8180_restart;
|
|
|
+ dev->wireless_handlers = &r8180_wx_handlers_def;
|
|
|
+ dev->do_ioctl = rtl8180_ioctl;
|
|
|
+ dev->set_multicast_list = r8180_set_multicast;
|
|
|
+ dev->set_mac_address = r8180_set_mac_adr;
|
|
|
+
|
|
|
+#if WIRELESS_EXT >= 12
|
|
|
+#if WIRELESS_EXT < 17
|
|
|
+ dev->get_wireless_stats = r8180_get_wireless_stats;
|
|
|
+#endif
|
|
|
+ dev->wireless_handlers = (struct iw_handler_def *) &r8180_wx_handlers_def;
|
|
|
+#endif
|
|
|
+
|
|
|
+ dev->type=ARPHRD_ETHER;
|
|
|
+ dev->watchdog_timeo = HZ*3; //added by david woo, 2007.12.13
|
|
|
+
|
|
|
+ if (dev_alloc_name(dev, ifname) < 0){
|
|
|
+ DMESG("Oops: devname already taken! Trying wlan%%d...\n");
|
|
|
+ ifname = "wlan%d";
|
|
|
+ // ifname = "ath%d";
|
|
|
+ dev_alloc_name(dev, ifname);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(rtl8180_init(dev)!=0){
|
|
|
+ DMESG("Initialization failed");
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+
|
|
|
+ netif_carrier_off(dev);
|
|
|
+
|
|
|
+ register_netdev(dev);
|
|
|
+
|
|
|
+ rtl8180_proc_init_one(dev);
|
|
|
+
|
|
|
+ DMESG("Driver probe completed\n");
|
|
|
+ return 0;
|
|
|
+
|
|
|
+fail1:
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_IO_MAP
|
|
|
+
|
|
|
+ if( dev->base_addr != 0 ){
|
|
|
+
|
|
|
+ release_region(dev->base_addr,
|
|
|
+ pci_resource_len(pdev, 0) );
|
|
|
+ }
|
|
|
+#else
|
|
|
+ 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) );
|
|
|
+ }
|
|
|
+#endif //end #ifdef RTL_IO_MAP
|
|
|
+
|
|
|
+
|
|
|
+fail:
|
|
|
+ if(dev){
|
|
|
+
|
|
|
+ if (priv->irq) {
|
|
|
+ free_irq(dev->irq, dev);
|
|
|
+ dev->irq=0;
|
|
|
+ }
|
|
|
+ free_ieee80211(dev);
|
|
|
+ }
|
|
|
+
|
|
|
+ pci_disable_device(pdev);
|
|
|
+
|
|
|
+ DMESG("wlan driver load failed\n");
|
|
|
+ pci_set_drvdata(pdev, NULL);
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void __devexit rtl8180_pci_remove(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv;
|
|
|
+ struct net_device *dev = pci_get_drvdata(pdev);
|
|
|
+ if(dev){
|
|
|
+
|
|
|
+ unregister_netdev(dev);
|
|
|
+
|
|
|
+ priv=ieee80211_priv(dev);
|
|
|
+
|
|
|
+ rtl8180_proc_remove_one(dev);
|
|
|
+ rtl8180_down(dev);
|
|
|
+ priv->rf_close(dev);
|
|
|
+ rtl8180_reset(dev);
|
|
|
+ //rtl8180_rtx_disable(dev);
|
|
|
+ //rtl8180_irq_disable(dev);
|
|
|
+ mdelay(10);
|
|
|
+ //write_nic_word(dev,INTA,read_nic_word(dev,INTA));
|
|
|
+ //force_pci_posting(dev);
|
|
|
+ //mdelay(10);
|
|
|
+
|
|
|
+ if(priv->irq){
|
|
|
+
|
|
|
+ DMESG("Freeing irq %d",dev->irq);
|
|
|
+ free_irq(dev->irq, dev);
|
|
|
+ priv->irq=0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ free_rx_desc_ring(dev);
|
|
|
+ free_tx_desc_rings(dev);
|
|
|
+ // free_beacon_desc_ring(dev,priv->txbeaconcount);
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8180_IO_MAP
|
|
|
+
|
|
|
+ if( dev->base_addr != 0 ){
|
|
|
+
|
|
|
+ release_region(dev->base_addr,
|
|
|
+ pci_resource_len(pdev, 0) );
|
|
|
+ }
|
|
|
+#else
|
|
|
+ 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) );
|
|
|
+ }
|
|
|
+#endif /*end #ifdef RTL_IO_MAP*/
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ printk(KERN_ERR "ieee80211_crypto_init() failed %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ret = ieee80211_crypto_tkip_init();
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_ERR "ieee80211_crypto_tkip_init() failed %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ret = ieee80211_crypto_ccmp_init();
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_ERR "ieee80211_crypto_ccmp_init() failed %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ ret = ieee80211_crypto_wep_init();
|
|
|
+ if (ret) {
|
|
|
+ printk(KERN_ERR "ieee80211_crypto_wep_init() failed %d\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "\nLinux kernel driver for RTL8180 \
|
|
|
+/ RTL8185 based WLAN cards\n");
|
|
|
+ printk(KERN_INFO "Copyright (c) 2004-2005, Andrea Merello\n");
|
|
|
+ DMESG("Initializing module");
|
|
|
+ DMESG("Wireless extensions version %d", WIRELESS_EXT);
|
|
|
+ rtl8180_proc_module_init();
|
|
|
+
|
|
|
+#if(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
|
|
|
+ if(0!=pci_module_init(&rtl8180_pci_driver))
|
|
|
+#else
|
|
|
+ if(0!=pci_register_driver(&rtl8180_pci_driver))
|
|
|
+#endif
|
|
|
+ //if(0!=pci_module_init(&rtl8180_pci_driver))
|
|
|
+ {
|
|
|
+ DMESG("No device found");
|
|
|
+ /*pci_unregister_driver (&rtl8180_pci_driver);*/
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void __exit rtl8180_pci_module_exit(void)
|
|
|
+{
|
|
|
+ pci_unregister_driver (&rtl8180_pci_driver);
|
|
|
+ rtl8180_proc_module_remove();
|
|
|
+ ieee80211_crypto_deinit();
|
|
|
+ ieee80211_crypto_tkip_exit();
|
|
|
+ ieee80211_crypto_ccmp_exit();
|
|
|
+ ieee80211_crypto_wep_exit();
|
|
|
+ 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);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->tx_lock,flags);
|
|
|
+ enough_desc = check_nic_enought_desc(dev,pri);
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flags);
|
|
|
+
|
|
|
+ if(enough_desc)
|
|
|
+ ieee80211_wake_queue(priv->ieee80211);
|
|
|
+}
|
|
|
+
|
|
|
+/*****************************************************************************
|
|
|
+ -----------------------------IRQ STUFF---------------------------
|
|
|
+******************************************************************************/
|
|
|
+
|
|
|
+void rtl8180_tx_isr(struct net_device *dev, int pri,short error)
|
|
|
+{
|
|
|
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
|
|
|
+
|
|
|
+ u32 *tail; //tail virtual addr
|
|
|
+ u32 *head; //head virtual addr
|
|
|
+ u32 *begin;//start of ring virtual addr
|
|
|
+ u32 *nicv; //nic pointer virtual addr
|
|
|
+// u32 *txdv; //packet just TXed
|
|
|
+ u32 nic; //nic pointer physical addr
|
|
|
+ u32 nicbegin;// start of ring physical addr
|
|
|
+// short txed;
|
|
|
+ unsigned long flag;
|
|
|
+ /* physical addr are ok on 32 bits since we set DMA mask*/
|
|
|
+
|
|
|
+ int offs;
|
|
|
+ int j,i;
|
|
|
+ int hd;
|
|
|
+ if (error) priv->stats.txretry++; //tony 20060601
|
|
|
+ spin_lock_irqsave(&priv->tx_lock,flag);
|
|
|
+ switch(pri) {
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ tail = priv->txmapringtail;
|
|
|
+ begin = priv->txmapring;
|
|
|
+ head = priv->txmapringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_MANAGEPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txmapringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BK_PRIORITY:
|
|
|
+ tail = priv->txbkpringtail;
|
|
|
+ begin = priv->txbkpring;
|
|
|
+ head = priv->txbkpringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_BKPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txbkpringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case BE_PRIORITY:
|
|
|
+ tail = priv->txbepringtail;
|
|
|
+ begin = priv->txbepring;
|
|
|
+ head = priv->txbepringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_BEPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txbepringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VI_PRIORITY:
|
|
|
+ tail = priv->txvipringtail;
|
|
|
+ begin = priv->txvipring;
|
|
|
+ head = priv->txvipringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_VIPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txvipringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case VO_PRIORITY:
|
|
|
+ tail = priv->txvopringtail;
|
|
|
+ begin = priv->txvopring;
|
|
|
+ head = priv->txvopringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_VOPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txvopringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case HI_PRIORITY:
|
|
|
+ tail = priv->txhpringtail;
|
|
|
+ begin = priv->txhpring;
|
|
|
+ head = priv->txhpringhead;
|
|
|
+ nic = read_nic_dword(dev,TX_HIGHPRIORITY_RING_ADDR);
|
|
|
+ nicbegin = priv->txhpringdma;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flag);
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+/* DMESG("%x %s %x %x",((int)nic & 0xfff)/8/4,
|
|
|
+ *(priv->txnpring + ((int)nic&0xfff)/4/8) & (1<<31) ? "filled" : "empty",
|
|
|
+ (priv->txnpringtail - priv->txnpring)/8,(priv->txnpringhead -
|
|
|
+priv->txnpring)/8);
|
|
|
+*/
|
|
|
+ //nicv = (u32*) ((nic - nicbegin) + (int)begin);
|
|
|
+ nicv = (u32*) ((nic - nicbegin) + (u8*)begin);
|
|
|
+ if((head <= tail && (nicv > tail || nicv < head)) ||
|
|
|
+ (head > tail && (nicv > tail && nicv < head))){
|
|
|
+
|
|
|
+ DMESGW("nic has lost pointer");
|
|
|
+#ifdef DEBUG_TX_DESC
|
|
|
+ //check_tx_ring(dev,NORM_PRIORITY);
|
|
|
+ check_tx_ring(dev,pri);
|
|
|
+#endif
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flag);
|
|
|
+ rtl8180_restart(dev);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* we check all the descriptors between the head and the nic,
|
|
|
+ * but not the currenly pointed by the nic (the next to be txed)
|
|
|
+ * and the previous of the pointed (might be in process ??)
|
|
|
+ */
|
|
|
+ //if (head == nic) return;
|
|
|
+ //DMESG("%x %x",head,nic);
|
|
|
+ offs = (nic - nicbegin);
|
|
|
+ //DMESG("%x %x %x",nic ,(u32)nicbegin, (int)nic -nicbegin);
|
|
|
+
|
|
|
+ offs = offs / 8 /4;
|
|
|
+
|
|
|
+ hd = (head - begin) /8;
|
|
|
+
|
|
|
+ if(offs >= hd)
|
|
|
+ j = offs - hd;
|
|
|
+ else
|
|
|
+ j = offs + (priv->txringcount -1 -hd);
|
|
|
+ // j= priv->txringcount -1- (hd - offs);
|
|
|
+
|
|
|
+ j-=2;
|
|
|
+ if(j<0) j=0;
|
|
|
+
|
|
|
+
|
|
|
+ for(i=0;i<j;i++)
|
|
|
+ {
|
|
|
+// printk("+++++++++++++check status desc\n");
|
|
|
+ if((*head) & (1<<31))
|
|
|
+ break;
|
|
|
+ if(((*head)&(0x10000000)) != 0){
|
|
|
+// printk("++++++++++++++last desc,retry count is %d\n",((*head) & (0x000000ff)));
|
|
|
+ priv->CurrRetryCnt += (u16)((*head) & (0x000000ff));
|
|
|
+#if 1
|
|
|
+ if(!error)
|
|
|
+ {
|
|
|
+ priv->NumTxOkTotal++;
|
|
|
+// printk("NumTxOkTotal is %d\n",priv->NumTxOkTotal++);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ // printk("in function %s:curr_retry_count is %d\n",__FUNCTION__,((*head) & (0x000000ff)));
|
|
|
+ }
|
|
|
+ if(!error){
|
|
|
+ priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff);
|
|
|
+ }
|
|
|
+// printk("in function %s:curr_txokbyte_count is %d\n",__FUNCTION__,(*(head+3)) & (0x00000fff));
|
|
|
+ *head = *head &~ (1<<31);
|
|
|
+
|
|
|
+ if((head - begin)/8 == priv->txringcount-1)
|
|
|
+ head=begin;
|
|
|
+
|
|
|
+ else
|
|
|
+ head+=8;
|
|
|
+ }
|
|
|
+#if 0
|
|
|
+ if(nicv == begin)
|
|
|
+ txdv = begin + (priv->txringcount -1)*8;
|
|
|
+ else
|
|
|
+ txdv = nicv - 8;
|
|
|
+
|
|
|
+ txed = !(txdv[0] &(1<<31));
|
|
|
+
|
|
|
+ if(txed){
|
|
|
+ if(!(txdv[0] & (1<<15))) error = 1;
|
|
|
+ //if(!(txdv[0] & (1<<30))) error = 1;
|
|
|
+ if(error)DMESG("%x",txdv[0]);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ //DMESG("%x",txdv[0]);
|
|
|
+ /* the head has been moved to the last certainly TXed
|
|
|
+ * (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
|
|
|
+ * TXed no memory leak occour at all.
|
|
|
+ */
|
|
|
+
|
|
|
+ switch(pri) {
|
|
|
+ case MANAGE_PRIORITY:
|
|
|
+ priv->txmapringhead = head;
|
|
|
+ //printk("1==========================================> priority check!\n");
|
|
|
+ if(priv->ack_tx_to_ieee){
|
|
|
+ // try to implement power-save mode 2008.1.22
|
|
|
+ // printk("2==========================================> priority check!\n");
|
|
|
+#if 1
|
|
|
+ if(rtl8180_is_tx_queue_empty(dev)){
|
|
|
+ // printk("tx queue empty, after send null sleep packet, try to sleep !\n");
|
|
|
+ priv->ack_tx_to_ieee = 0;
|
|
|
+ ieee80211_ps_tx_ack(priv->ieee80211,!error);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*DMESG("%x %x %x", (priv->txnpringhead - priv->txnpring) /8 ,
|
|
|
+ (priv->txnpringtail - priv->txnpring) /8,
|
|
|
+ offs );
|
|
|
+ */
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&priv->tx_lock,flag);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void rtl8180_tx_irq_wq(struct work_struct *work)
|
|
|
+{
|
|
|
+ //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq);
|
|
|
+ struct delayed_work *dwork = container_of(work,struct delayed_work,work);
|
|
|
+ struct ieee80211_device * ieee = (struct ieee80211_device*)
|
|
|
+ container_of(dwork, struct ieee80211_device, watch_dog_wq);
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+#else
|
|
|
+void rtl8180_tx_irq_wq(struct net_device *dev)
|
|
|
+{
|
|
|
+ //struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+ rtl8180_tx_isr(dev,MANAGE_PRIORITY,0);
|
|
|
+}
|
|
|
+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 */
|
|
|
+ if(priv->irq_enabled == 0) return IRQ_HANDLED;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->irq_th_lock,flags);
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ //ISR: 4bytes
|
|
|
+ inta = read_nic_dword(dev, ISR);// & priv->IntrMask;
|
|
|
+ write_nic_dword(dev,ISR,inta); // reset int situation
|
|
|
+#else
|
|
|
+ inta = read_nic_word(dev,INTA) & priv->irq_mask;
|
|
|
+ write_nic_word(dev,INTA,inta); // reset int situation
|
|
|
+#endif
|
|
|
+
|
|
|
+ priv->stats.shints++;
|
|
|
+
|
|
|
+ //DMESG("Enter interrupt, ISR value = 0x%08x", inta);
|
|
|
+
|
|
|
+ if(!inta){
|
|
|
+ spin_unlock_irqrestore(&priv->irq_th_lock,flags);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ /*
|
|
|
+ most probably we can safely return IRQ_NONE,
|
|
|
+ but for now is better to avoid problems
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta == 0xffff){
|
|
|
+ /* HW disappared */
|
|
|
+ spin_unlock_irqrestore(&priv->irq_th_lock,flags);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ priv->stats.ints++;
|
|
|
+#ifdef DEBUG_IRQ
|
|
|
+ DMESG("NIC irq %x",inta);
|
|
|
+#endif
|
|
|
+ //priv->irqpending = inta;
|
|
|
+
|
|
|
+
|
|
|
+ if(!netif_running(dev)) {
|
|
|
+ spin_unlock_irqrestore(&priv->irq_th_lock,flags);
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TimeOut){
|
|
|
+ write_nic_dword(dev, TimerInt, 0);
|
|
|
+ //DMESG("=================>waking up");
|
|
|
+// rtl8180_hw_wakeup(dev);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TBDOK){
|
|
|
+ priv->stats.txbeacon++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TBDER){
|
|
|
+ priv->stats.txbeaconerr++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & IMR_TMGDOK ) {
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ rtl8180_tx_isr(dev,MANAGE_PRIORITY,0);
|
|
|
+// schedule_work(&priv->tx_irq_wq);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_THPDER){
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG ("TX high priority ERR");
|
|
|
+#endif
|
|
|
+ priv->stats.txhperr++;
|
|
|
+ rtl8180_tx_isr(dev,HI_PRIORITY,1);
|
|
|
+ priv->ieee80211->stats.tx_errors++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_THPDOK){ //High priority tx ok
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG ("TX high priority OK");
|
|
|
+#endif
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ //priv->NumTxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828
|
|
|
+ priv->stats.txhpokint++;
|
|
|
+ rtl8180_tx_isr(dev,HI_PRIORITY,0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_RER) {
|
|
|
+ priv->stats.rxerr++;
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESGW("RX error int");
|
|
|
+#endif
|
|
|
+ }
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ if(inta & ISR_TBKDER){ //corresponding to BK_PRIORITY
|
|
|
+ priv->stats.txbkperr++;
|
|
|
+ priv->ieee80211->stats.tx_errors++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX bkp error int");
|
|
|
+#endif
|
|
|
+ //tasklet_schedule(&priv->irq_tx_tasklet);
|
|
|
+ rtl8180_tx_isr(dev,BK_PRIORITY,1);
|
|
|
+ rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TBEDER){ //corresponding to BE_PRIORITY
|
|
|
+ priv->stats.txbeperr++;
|
|
|
+ priv->ieee80211->stats.tx_errors++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX bep error int");
|
|
|
+#endif
|
|
|
+ rtl8180_tx_isr(dev,BE_PRIORITY,1);
|
|
|
+ //tasklet_schedule(&priv->irq_tx_tasklet);
|
|
|
+ rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ if(inta & ISR_TNPDER){ //corresponding to VO_PRIORITY
|
|
|
+ priv->stats.txnperr++;
|
|
|
+ priv->ieee80211->stats.tx_errors++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX np error int");
|
|
|
+#endif
|
|
|
+ //tasklet_schedule(&priv->irq_tx_tasklet);
|
|
|
+ rtl8180_tx_isr(dev,NORM_PRIORITY,1);
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ rtl8180_try_wake_queue(dev, NORM_PRIORITY);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TLPDER){ //corresponding to VI_PRIORITY
|
|
|
+ priv->stats.txlperr++;
|
|
|
+ priv->ieee80211->stats.tx_errors++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX lp error int");
|
|
|
+#endif
|
|
|
+ rtl8180_tx_isr(dev,LOW_PRIORITY,1);
|
|
|
+ //tasklet_schedule(&priv->irq_tx_tasklet);
|
|
|
+ rtl8180_try_wake_queue(dev, LOW_PRIORITY);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_ROK){
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESG("Frame arrived !");
|
|
|
+#endif
|
|
|
+ //priv->NumRxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->stats.rxint++;
|
|
|
+ tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_RQoSOK ){
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESG("QoS Frame arrived !");
|
|
|
+#endif
|
|
|
+ //priv->NumRxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->stats.rxint++;
|
|
|
+ tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
+ }
|
|
|
+ if(inta & ISR_BcnInt) {
|
|
|
+ //DMESG("Preparing Beacons");
|
|
|
+ rtl8180_prepare_beacon(dev);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_RDU){
|
|
|
+//#ifdef DEBUG_RX
|
|
|
+ DMESGW("No RX descriptor available");
|
|
|
+ priv->stats.rxrdu++;
|
|
|
+//#endif
|
|
|
+ tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
+ /*queue_work(priv->workqueue ,&priv->restart_work);*/
|
|
|
+
|
|
|
+ }
|
|
|
+ if(inta & ISR_RXFOVW){
|
|
|
+#ifdef DEBUG_RX
|
|
|
+ DMESGW("RX fifo overflow");
|
|
|
+#endif
|
|
|
+ priv->stats.rxoverflow++;
|
|
|
+ tasklet_schedule(&priv->irq_rx_tasklet);
|
|
|
+ //queue_work(priv->workqueue ,&priv->restart_work);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TXFOVW) priv->stats.txoverflow++;
|
|
|
+
|
|
|
+ if(inta & ISR_TNPDOK){ //Normal priority tx ok
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG ("TX normal priority OK");
|
|
|
+#endif
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ //priv->NumTxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828
|
|
|
+ // priv->ieee80211->stats.tx_packets++;
|
|
|
+ priv->stats.txnpokint++;
|
|
|
+ rtl8180_tx_isr(dev,NORM_PRIORITY,0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TLPDOK){ //Low priority tx ok
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESG ("TX low priority OK");
|
|
|
+#endif
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ //priv->NumTxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828
|
|
|
+ // priv->ieee80211->stats.tx_packets++;
|
|
|
+ priv->stats.txlpokint++;
|
|
|
+ rtl8180_tx_isr(dev,LOW_PRIORITY,0);
|
|
|
+ rtl8180_try_wake_queue(dev, LOW_PRIORITY);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef CONFIG_RTL8185B
|
|
|
+ if(inta & ISR_TBKDOK){ //corresponding to BK_PRIORITY
|
|
|
+ priv->stats.txbkpokint++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX bk priority ok");
|
|
|
+#endif
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ //priv->NumTxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828
|
|
|
+ rtl8180_tx_isr(dev,BK_PRIORITY,0);
|
|
|
+ rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(inta & ISR_TBEDOK){ //corresponding to BE_PRIORITY
|
|
|
+ priv->stats.txbeperr++;
|
|
|
+#ifdef DEBUG_TX
|
|
|
+ DMESGW("TX be priority ok");
|
|
|
+#endif
|
|
|
+// priv->NumTxOkTotal++;
|
|
|
+ //priv->NumTxOkInPeriod++; //YJ,del,080828
|
|
|
+ priv->link_detect.NumTxOkInPeriod++; //YJ,add,080828
|
|
|
+ rtl8180_tx_isr(dev,BE_PRIORITY,0);
|
|
|
+ rtl8180_try_wake_queue(dev, BE_PRIORITY);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ force_pci_posting(dev);
|
|
|
+ spin_unlock_irqrestore(&priv->irq_th_lock,flags);
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void rtl8180_irq_rx_tasklet(struct r8180_priv* priv)
|
|
|
+{
|
|
|
+// unsigned long flags;
|
|
|
+
|
|
|
+/* spin_lock_irqsave(&priv->irq_lock, flags);
|
|
|
+ priv->irq_mask &=~IMR_ROK;
|
|
|
+ priv->irq_mask &=~IMR_RDU;
|
|
|
+
|
|
|
+ rtl8180_irq_enable(priv->dev);
|
|
|
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
|
|
|
+*/
|
|
|
+ rtl8180_rx(priv->dev);
|
|
|
+
|
|
|
+/* spin_lock_irqsave(&priv->irq_lock, flags);
|
|
|
+ priv->irq_mask |= IMR_ROK;
|
|
|
+ priv->irq_mask |= IMR_RDU;
|
|
|
+ rtl8180_irq_enable(priv->dev);
|
|
|
+ spin_unlock_irqrestore(&priv->irq_lock, flags);
|
|
|
+*/
|
|
|
+}
|
|
|
+
|
|
|
+/****************************************************************************
|
|
|
+lizhaoming--------------------------- RF power on/power off -----------------
|
|
|
+*****************************************************************************/
|
|
|
+
|
|
|
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
|
+void GPIOChangeRFWorkItemCallBack(struct work_struct *work)
|
|
|
+{
|
|
|
+ //struct delayed_work *dwork = container_of(work, struct delayed_work, 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);
|
|
|
+#else
|
|
|
+void GPIOChangeRFWorkItemCallBack(struct ieee80211_device *ieee)
|
|
|
+{
|
|
|
+ struct net_device *dev = ieee->dev;
|
|
|
+ struct r8180_priv *priv = ieee80211_priv(dev);
|
|
|
+#endif
|
|
|
+
|
|
|
+ //u16 tmp2byte;
|
|
|
+ u8 btPSR;
|
|
|
+ u8 btConfig0;
|
|
|
+ RT_RF_POWER_STATE eRfPowerStateToSet;
|
|
|
+ bool bActuallySet=false;
|
|
|
+
|
|
|
+ char *argv[3];
|
|
|
+ static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh";
|
|
|
+ static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL};
|
|
|
+ static int readf_count = 0;
|
|
|
+ //printk("============>%s in \n", __func__);
|
|
|
+
|
|
|
+#ifdef ENABLE_LPS
|
|
|
+ if(readf_count % 10 == 0)
|
|
|
+ priv->PowerProfile = read_acadapter_file("/proc/acpi/ac_adapter/AC0/state");
|
|
|
+
|
|
|
+ readf_count = (readf_count+1)%0xffff;
|
|
|
+#endif
|
|
|
+#if 0
|
|
|
+ if(priv->up == 0)//driver stopped
|
|
|
+ {
|
|
|
+ printk("\nDo nothing...");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ // We should turn off LED before polling FF51[4].
|
|
|
+
|
|
|
+ //Turn off LED.
|
|
|
+ btPSR = read_nic_byte(dev, PSR);
|
|
|
+ write_nic_byte(dev, PSR, (btPSR & ~BIT3));
|
|
|
+
|
|
|
+ //It need to delay 4us suggested by Jong, 2008-01-16
|
|
|
+ udelay(4);
|
|
|
+
|
|
|
+ //HW radio On/Off according to the value of FF51[4](config0)
|
|
|
+ btConfig0 = btPSR = read_nic_byte(dev, CONFIG0);
|
|
|
+
|
|
|
+ //Turn on LED.
|
|
|
+ write_nic_byte(dev, PSR, btPSR| BIT3);
|
|
|
+
|
|
|
+ eRfPowerStateToSet = (btConfig0 & BIT4) ? eRfOn : eRfOff;
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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{
|
|
|
+ //if(!priv->RfOffReason)
|
|
|
+ argv[1] = "RFON";
|
|
|
+ //else
|
|
|
+ // argv[1] = "RFOFF";
|
|
|
+ }
|
|
|
+ argv[0] = RadioPowerPath;
|
|
|
+ argv[2] = NULL;
|
|
|
+
|
|
|
+ call_usermodehelper(RadioPowerPath,argv,envp,1);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static u8 read_acadapter_file(char *filename)
|
|
|
+{
|
|
|
+//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
|
|
|
+#if 0
|
|
|
+ int fd;
|
|
|
+ char buf[1];
|
|
|
+ char ret[50];
|
|
|
+ int i = 0;
|
|
|
+ int n = 0;
|
|
|
+ mm_segment_t old_fs = get_fs();
|
|
|
+ set_fs(KERNEL_DS);
|
|
|
+
|
|
|
+ fd = sys_open(filename, O_RDONLY, 0);
|
|
|
+ if (fd >= 0) {
|
|
|
+ while (sys_read(fd, buf, 1) == 1)
|
|
|
+ {
|
|
|
+ i++;
|
|
|
+ if(i>10)
|
|
|
+ {
|
|
|
+ if(buf[0]!=' ')
|
|
|
+ {
|
|
|
+ ret[n]=buf[0];
|
|
|
+ n++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sys_close(fd);
|
|
|
+ }
|
|
|
+ ret[n]='\0';
|
|
|
+// printk("%s \n", ret);
|
|
|
+ set_fs(old_fs);
|
|
|
+
|
|
|
+ if(strncmp(ret, "off-line",8) == 0)
|
|
|
+ {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/***************************************************************************
|
|
|
+ ------------------- module init / exit stubs ----------------
|
|
|
+****************************************************************************/
|
|
|
+module_init(rtl8180_pci_module_init);
|
|
|
+module_exit(rtl8180_pci_module_exit);
|
|
|
+
|