Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

r8180_core.c

/*
   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,
        },
#if 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,
      },
#endif
        {
                .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);
      if (dev->netdev_ops->ndo_stop)
            dev->netdev_ops->ndo_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 = rtl8180_proc;
      if (!priv->dir_dev) {
            DMESGE("Unable to initialize /proc/net/r8180/%s\n",
                  dev->name);
            return;
      }

      e = create_proc_read_entry("stats-hw", S_IFREG | S_IRUGO,
                           priv->dir_dev, proc_get_stats_hw, dev);

      if (!e) {
            DMESGE("Unable to initialize "
                  "/proc/net/r8180/%s/stats-hw\n",
                  dev->name);
      }

      e = create_proc_read_entry("stats-rx", S_IFREG | S_IRUGO,
                           priv->dir_dev, proc_get_stats_rx, dev);

      if (!e) {
            DMESGE("Unable to initialize "
                  "/proc/net/r8180/%s/stats-rx\n",
                  dev->name);
      }


      e = create_proc_read_entry("stats-tx", S_IFREG | S_IRUGO,
                           priv->dir_dev, proc_get_stats_tx, dev);

      if (!e) {
            DMESGE("Unable to initialize "
                  "/proc/net/r8180/%s/stats-tx\n",
                  dev->name);
      }
      #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/r8180/%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));
      }

      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", __func__, ch);
            return;
      }

      priv->chan=ch;
      //printk("in %s:channel is %d\n",__func__,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 !
             */
            WARN(1, "DMA buffer is not aligned\n");
      }
      tmp=desc;
      for (i=0;i<count;i++)
      {
            buf = (void*)pci_alloc_consistent(pdev,bufsize,&dma_tmp);
            if (buf == NULL) return -ENOMEM;

            switch(addr) {
#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
             */
            WARN(1, "DMA buffer is not aligned\n");
      }

      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",__func__);
      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->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 = to_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", __func__);
      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 = to_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 const struct net_device_ops rtl8180_netdev_ops = {
      .ndo_open         = rtl8180_open,
      .ndo_stop         = rtl8180_close,
      .ndo_get_stats          = rtl8180_stats,
      .ndo_tx_timeout         = rtl8180_restart,
      .ndo_do_ioctl           = rtl8180_ioctl,
      .ndo_set_multicast_list = r8180_set_multicast,
      .ndo_set_mac_address    = r8180_set_mac_adr,
      .ndo_validate_addr      = eth_validate_addr,
      .ndo_change_mtu         = eth_change_mtu,
      .ndo_start_xmit         = ieee80211_xmit,
};

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->netdev_ops = &rtl8180_netdev_ops;
      dev->wireless_handlers = &r8180_wx_handlers_def;

#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_tkip_exit();
      ieee80211_crypto_ccmp_exit();
      ieee80211_crypto_wep_exit();
      ieee80211_crypto_deinit();
      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",__func__,((*head) & (0x000000ff)));
            }
            if(!error){
                  priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff);
            }
//          printk("in function %s:curr_txokbyte_count is %d\n",__func__,(*(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 = to_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 = to_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);


Generated by  Doxygen 1.6.0   Back to index