Kernel  |  4.1

下载     查看原文件
C++程序  |  1911行  |  49.29 KB
/*
 * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * File: device_main.c
 *
 * Purpose: driver entry for initial, open, close, tx and rx.
 *
 * Author: Lyndon Chen
 *
 * Date: Jan 8, 2003
 *
 * Functions:
 *
 *   vt6655_probe - module initial (insmod) driver entry
 *   vt6655_remove - module remove entry
 *   vt6655_init_info - device structure resource allocation function
 *   device_free_info - device structure resource free function
 *   device_get_pci_info - get allocated pci io/mem resource
 *   device_print_info - print out resource
 *   device_intr - interrupt handle function
 *   device_rx_srv - rx service function
 *   device_alloc_rx_buf - rx buffer pre-allocated function
 *   device_free_tx_buf - free tx buffer function
 *   device_init_rd0_ring- initial rd dma0 ring
 *   device_init_rd1_ring- initial rd dma1 ring
 *   device_init_td0_ring- initial tx dma0 ring buffer
 *   device_init_td1_ring- initial tx dma1 ring buffer
 *   device_init_registers- initial MAC & BBP & RF internal registers.
 *   device_init_rings- initial tx/rx ring buffer
 *   device_free_rings- free all allocated ring buffer
 *   device_tx_srv- tx interrupt service function
 *
 * Revision History:
 */
#undef __NO_VERSION__

#include <linux/file.h>
#include "device.h"
#include "card.h"
#include "channel.h"
#include "baseband.h"
#include "mac.h"
#include "power.h"
#include "rxtx.h"
#include "dpc.h"
#include "rf.h"
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/slab.h>

/*---------------------  Static Definitions -------------------------*/
/*
 * Define module options
 */
MODULE_AUTHOR("VIA Networking Technologies, Inc., <lyndonchen@vntek.com.tw>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver");

#define DEVICE_PARAM(N, D)

#define RX_DESC_MIN0     16
#define RX_DESC_MAX0     128
#define RX_DESC_DEF0     32
DEVICE_PARAM(RxDescriptors0, "Number of receive descriptors0");

#define RX_DESC_MIN1     16
#define RX_DESC_MAX1     128
#define RX_DESC_DEF1     32
DEVICE_PARAM(RxDescriptors1, "Number of receive descriptors1");

#define TX_DESC_MIN0     16
#define TX_DESC_MAX0     128
#define TX_DESC_DEF0     32
DEVICE_PARAM(TxDescriptors0, "Number of transmit descriptors0");

#define TX_DESC_MIN1     16
#define TX_DESC_MAX1     128
#define TX_DESC_DEF1     64
DEVICE_PARAM(TxDescriptors1, "Number of transmit descriptors1");

#define INT_WORKS_DEF   20
#define INT_WORKS_MIN   10
#define INT_WORKS_MAX   64

DEVICE_PARAM(int_works, "Number of packets per interrupt services");

#define RTS_THRESH_DEF     2347

#define FRAG_THRESH_DEF     2346

#define SHORT_RETRY_MIN     0
#define SHORT_RETRY_MAX     31
#define SHORT_RETRY_DEF     8

DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits");

#define LONG_RETRY_MIN     0
#define LONG_RETRY_MAX     15
#define LONG_RETRY_DEF     4

DEVICE_PARAM(LongRetryLimit, "long frame retry limits");

/* BasebandType[] baseband type selected
   0: indicate 802.11a type
   1: indicate 802.11b type
   2: indicate 802.11g type
*/
#define BBP_TYPE_MIN     0
#define BBP_TYPE_MAX     2
#define BBP_TYPE_DEF     2

DEVICE_PARAM(BasebandType, "baseband type");

/*
 * Static vars definitions
 */
static CHIP_INFO chip_info_table[] = {
	{ VT3253,       "VIA Networking Solomon-A/B/G Wireless LAN Adapter ",
	  256, 1,     DEVICE_FLAGS_IP_ALIGN|DEVICE_FLAGS_TX_ALIGN },
	{0, NULL}
};

static const struct pci_device_id vt6655_pci_id_table[] = {
	{ PCI_VDEVICE(VIA, 0x3253), (kernel_ulong_t)chip_info_table},
	{ 0, }
};

/*---------------------  Static Functions  --------------------------*/

static int  vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent);
static void vt6655_init_info(struct pci_dev *pcid,
			     struct vnt_private **ppDevice, PCHIP_INFO);
static void device_free_info(struct vnt_private *pDevice);
static bool device_get_pci_info(struct vnt_private *, struct pci_dev *pcid);
static void device_print_info(struct vnt_private *pDevice);
static  irqreturn_t  device_intr(int irq,  void *dev_instance);

#ifdef CONFIG_PM
static int device_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
static struct notifier_block device_notifier = {
	.notifier_call = device_notify_reboot,
	.next = NULL,
	.priority = 0,
};
#endif

static void device_init_rd0_ring(struct vnt_private *pDevice);
static void device_init_rd1_ring(struct vnt_private *pDevice);
static void device_init_td0_ring(struct vnt_private *pDevice);
static void device_init_td1_ring(struct vnt_private *pDevice);

static int  device_rx_srv(struct vnt_private *pDevice, unsigned int uIdx);
static int  device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx);
static bool device_alloc_rx_buf(struct vnt_private *pDevice, PSRxDesc pDesc);
static void device_init_registers(struct vnt_private *pDevice);
static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc);
static void device_free_td0_ring(struct vnt_private *pDevice);
static void device_free_td1_ring(struct vnt_private *pDevice);
static void device_free_rd0_ring(struct vnt_private *pDevice);
static void device_free_rd1_ring(struct vnt_private *pDevice);
static void device_free_rings(struct vnt_private *pDevice);

/*---------------------  Export Variables  --------------------------*/

/*---------------------  Export Functions  --------------------------*/

static char *get_chip_name(int chip_id)
{
	int i;

	for (i = 0; chip_info_table[i].name != NULL; i++)
		if (chip_info_table[i].chip_id == chip_id)
			break;
	return chip_info_table[i].name;
}

static void vt6655_remove(struct pci_dev *pcid)
{
	struct vnt_private *pDevice = pci_get_drvdata(pcid);

	if (pDevice == NULL)
		return;
	device_free_info(pDevice);
}

static void device_get_options(struct vnt_private *pDevice)
{
	POPTIONS pOpts = &(pDevice->sOpts);

	pOpts->nRxDescs0 = RX_DESC_DEF0;
	pOpts->nRxDescs1 = RX_DESC_DEF1;
	pOpts->nTxDescs[0] = TX_DESC_DEF0;
	pOpts->nTxDescs[1] = TX_DESC_DEF1;
	pOpts->int_works = INT_WORKS_DEF;

	pOpts->short_retry = SHORT_RETRY_DEF;
	pOpts->long_retry = LONG_RETRY_DEF;
	pOpts->bbp_type = BBP_TYPE_DEF;
}

static void
device_set_options(struct vnt_private *pDevice)
{
	pDevice->byShortRetryLimit = pDevice->sOpts.short_retry;
	pDevice->byLongRetryLimit = pDevice->sOpts.long_retry;
	pDevice->byBBType = pDevice->sOpts.bbp_type;
	pDevice->byPacketType = pDevice->byBBType;
	pDevice->byAutoFBCtrl = AUTO_FB_0;
	pDevice->bUpdateBBVGA = true;
	pDevice->byPreambleType = 0;

	pr_debug(" byShortRetryLimit= %d\n", (int)pDevice->byShortRetryLimit);
	pr_debug(" byLongRetryLimit= %d\n", (int)pDevice->byLongRetryLimit);
	pr_debug(" byPreambleType= %d\n", (int)pDevice->byPreambleType);
	pr_debug(" byShortPreamble= %d\n", (int)pDevice->byShortPreamble);
	pr_debug(" byBBType= %d\n", (int)pDevice->byBBType);
}

/*
 * Initialisation of MAC & BBP registers
 */

static void device_init_registers(struct vnt_private *pDevice)
{
	unsigned long flags;
	unsigned int ii;
	unsigned char byValue;
	unsigned char byCCKPwrdBm = 0;
	unsigned char byOFDMPwrdBm = 0;

	MACbShutdown(pDevice->PortOffset);
	BBvSoftwareReset(pDevice);

	/* Do MACbSoftwareReset in MACvInitialize */
	MACbSoftwareReset(pDevice->PortOffset);

	pDevice->bAES = false;

	/* Only used in 11g type, sync with ERP IE */
	pDevice->bProtectMode = false;

	pDevice->bNonERPPresent = false;
	pDevice->bBarkerPreambleMd = false;
	pDevice->wCurrentRate = RATE_1M;
	pDevice->byTopOFDMBasicRate = RATE_24M;
	pDevice->byTopCCKBasicRate = RATE_1M;

	/* Target to IF pin while programming to RF chip. */
	pDevice->byRevId = 0;

	/* init MAC */
	MACvInitialize(pDevice->PortOffset);

	/* Get Local ID */
	VNSvInPortB(pDevice->PortOffset + MAC_REG_LOCALID, &pDevice->byLocalID);

	spin_lock_irqsave(&pDevice->lock, flags);

	SROMvReadAllContents(pDevice->PortOffset, pDevice->abyEEPROM);

	spin_unlock_irqrestore(&pDevice->lock, flags);

	/* Get Channel range */
	pDevice->byMinChannel = 1;
	pDevice->byMaxChannel = CB_MAX_CHANNEL;

	/* Get Antena */
	byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
	if (byValue & EEP_ANTINV)
		pDevice->bTxRxAntInv = true;
	else
		pDevice->bTxRxAntInv = false;

	byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
	/* if not set default is All */
	if (byValue == 0)
		byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);

	if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
		pDevice->byAntennaCount = 2;
		pDevice->byTxAntennaMode = ANT_B;
		pDevice->dwTxAntennaSel = 1;
		pDevice->dwRxAntennaSel = 1;

		if (pDevice->bTxRxAntInv)
			pDevice->byRxAntennaMode = ANT_A;
		else
			pDevice->byRxAntennaMode = ANT_B;
	} else  {
		pDevice->byAntennaCount = 1;
		pDevice->dwTxAntennaSel = 0;
		pDevice->dwRxAntennaSel = 0;

		if (byValue & EEP_ANTENNA_AUX) {
			pDevice->byTxAntennaMode = ANT_A;

			if (pDevice->bTxRxAntInv)
				pDevice->byRxAntennaMode = ANT_B;
			else
				pDevice->byRxAntennaMode = ANT_A;
		} else {
			pDevice->byTxAntennaMode = ANT_B;

			if (pDevice->bTxRxAntInv)
				pDevice->byRxAntennaMode = ANT_A;
			else
				pDevice->byRxAntennaMode = ANT_B;
		}
	}

	/* Set initial antenna mode */
	BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode);
	BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode);

	/* zonetype initial */
	pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];

	if (!pDevice->bZoneRegExist)
		pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];

	pr_debug("pDevice->byZoneType = %x\n", pDevice->byZoneType);

	/* Init RF module */
	RFbInit(pDevice);

	/* Get Desire Power Value */
	pDevice->byCurPwr = 0xFF;
	pDevice->byCCKPwr = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_CCK);
	pDevice->byOFDMPwrG = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_OFDMG);

	/* Load power Table */
	for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) {
		pDevice->abyCCKPwrTbl[ii + 1] =
			SROMbyReadEmbedded(pDevice->PortOffset,
					   (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL));
		if (pDevice->abyCCKPwrTbl[ii + 1] == 0)
			pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr;

		pDevice->abyOFDMPwrTbl[ii + 1] =
			SROMbyReadEmbedded(pDevice->PortOffset,
					   (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL));
		if (pDevice->abyOFDMPwrTbl[ii + 1] == 0)
			pDevice->abyOFDMPwrTbl[ii + 1] = pDevice->byOFDMPwrG;

		pDevice->abyCCKDefaultPwr[ii + 1] = byCCKPwrdBm;
		pDevice->abyOFDMDefaultPwr[ii + 1] = byOFDMPwrdBm;
	}

	/* recover 12,13 ,14channel for EUROPE by 11 channel */
	for (ii = 11; ii < 14; ii++) {
		pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10];
		pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10];
	}

	/* Load OFDM A Power Table */
	for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) {
		pDevice->abyOFDMPwrTbl[ii + CB_MAX_CHANNEL_24G + 1] =
			SROMbyReadEmbedded(pDevice->PortOffset,
					   (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL));

		pDevice->abyOFDMDefaultPwr[ii + CB_MAX_CHANNEL_24G + 1] =
			SROMbyReadEmbedded(pDevice->PortOffset,
					   (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm));
	}

	if (pDevice->byLocalID > REV_ID_VT3253_B1) {
		MACvSelectPage1(pDevice->PortOffset);

		VNSvOutPortB(pDevice->PortOffset + MAC_REG_MSRCTL + 1,
			     (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN));

		MACvSelectPage0(pDevice->PortOffset);
	}

	/* use relative tx timeout and 802.11i D4 */
	MACvWordRegBitsOn(pDevice->PortOffset,
			  MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT));

	/* set performance parameter by registry */
	MACvSetShortRetryLimit(pDevice->PortOffset, pDevice->byShortRetryLimit);
	MACvSetLongRetryLimit(pDevice->PortOffset, pDevice->byLongRetryLimit);

	/* reset TSF counter */
	VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
	/* enable TSF counter */
	VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);

	/* initialize BBP registers */
	BBbVT3253Init(pDevice);

	if (pDevice->bUpdateBBVGA) {
		pDevice->byBBVGACurrent = pDevice->abyBBVGA[0];
		pDevice->byBBVGANew = pDevice->byBBVGACurrent;
		BBvSetVGAGainOffset(pDevice, pDevice->abyBBVGA[0]);
	}

	BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode);
	BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode);

	/* Set BB and packet type at the same time. */
	/* Set Short Slot Time, xIFS, and RSPINF. */
	pDevice->wCurrentRate = RATE_54M;

	pDevice->bRadioOff = false;

	pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset,
						 EEP_OFS_RADIOCTL);
	pDevice->bHWRadioOff = false;

	if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) {
		/* Get GPIO */
		MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);

		if (((pDevice->byGPIO & GPIO0_DATA) &&
		     !(pDevice->byRadioCtl & EEP_RADIOCTL_INV)) ||
		     (!(pDevice->byGPIO & GPIO0_DATA) &&
		     (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
			pDevice->bHWRadioOff = true;
	}

	if (pDevice->bHWRadioOff || pDevice->bRadioControlOff)
		CARDbRadioPowerOff(pDevice);

	/* get Permanent network address */
	SROMvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr);
	pr_debug("Network address = %pM\n", pDevice->abyCurrentNetAddr);

	/* reset Tx pointer */
	CARDvSafeResetRx(pDevice);
	/* reset Rx pointer */
	CARDvSafeResetTx(pDevice);

	if (pDevice->byLocalID <= REV_ID_VT3253_A1)
		MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_WPAERR);

	/* Turn On Rx DMA */
	MACvReceive0(pDevice->PortOffset);
	MACvReceive1(pDevice->PortOffset);

	/* start the adapter */
	MACvStart(pDevice->PortOffset);
}

static void device_print_info(struct vnt_private *pDevice)
{
	dev_info(&pDevice->pcid->dev, "%s\n", get_chip_name(pDevice->chip_id));

	dev_info(&pDevice->pcid->dev, "MAC=%pM IO=0x%lx Mem=0x%lx IRQ=%d\n",
		 pDevice->abyCurrentNetAddr, (unsigned long)pDevice->ioaddr,
		 (unsigned long)pDevice->PortOffset, pDevice->pcid->irq);
}

static void vt6655_init_info(struct pci_dev *pcid,
			     struct vnt_private **ppDevice,
			     PCHIP_INFO pChip_info)
{
	memset(*ppDevice, 0, sizeof(**ppDevice));

	(*ppDevice)->pcid = pcid;
	(*ppDevice)->chip_id = pChip_info->chip_id;
	(*ppDevice)->io_size = pChip_info->io_size;
	(*ppDevice)->nTxQueues = pChip_info->nTxQueue;
	(*ppDevice)->multicast_limit = 32;

	spin_lock_init(&((*ppDevice)->lock));
}

static bool device_get_pci_info(struct vnt_private *pDevice,
				struct pci_dev *pcid)
{
	u16 pci_cmd;
	u8  b;
	unsigned int cis_addr;

	pci_read_config_byte(pcid, PCI_REVISION_ID, &pDevice->byRevId);
	pci_read_config_word(pcid, PCI_SUBSYSTEM_ID, &pDevice->SubSystemID);
	pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, &pDevice->SubVendorID);
	pci_read_config_word(pcid, PCI_COMMAND, (u16 *)&(pci_cmd));

	pci_set_master(pcid);

	pDevice->memaddr = pci_resource_start(pcid, 0);
	pDevice->ioaddr = pci_resource_start(pcid, 1);

	cis_addr = pci_resource_start(pcid, 2);

	pDevice->pcid = pcid;

	pci_read_config_byte(pcid, PCI_COMMAND, &b);
	pci_write_config_byte(pcid, PCI_COMMAND, (b|PCI_COMMAND_MASTER));

	return true;
}

static void device_free_info(struct vnt_private *pDevice)
{
	if (!pDevice)
		return;

	if (pDevice->mac_hw)
		ieee80211_unregister_hw(pDevice->hw);

	if (pDevice->PortOffset)
		iounmap(pDevice->PortOffset);

	if (pDevice->pcid)
		pci_release_regions(pDevice->pcid);

	if (pDevice->hw)
		ieee80211_free_hw(pDevice->hw);
}

static bool device_init_rings(struct vnt_private *pDevice)
{
	void *vir_pool;

	/*allocate all RD/TD rings a single pool*/
	vir_pool = dma_zalloc_coherent(&pDevice->pcid->dev,
					 pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
					 pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
					 pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
					 pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
					 &pDevice->pool_dma, GFP_ATOMIC);
	if (vir_pool == NULL) {
		dev_err(&pDevice->pcid->dev, "allocate desc dma memory failed\n");
		return false;
	}

	pDevice->aRD0Ring = vir_pool;
	pDevice->aRD1Ring = vir_pool +
		pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);

	pDevice->rd0_pool_dma = pDevice->pool_dma;
	pDevice->rd1_pool_dma = pDevice->rd0_pool_dma +
		pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);

	pDevice->tx0_bufs = dma_zalloc_coherent(&pDevice->pcid->dev,
						  pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
						  pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
						  CB_BEACON_BUF_SIZE +
						  CB_MAX_BUF_SIZE,
						  &pDevice->tx_bufs_dma0,
						  GFP_ATOMIC);
	if (pDevice->tx0_bufs == NULL) {
		dev_err(&pDevice->pcid->dev, "allocate buf dma memory failed\n");

		dma_free_coherent(&pDevice->pcid->dev,
				    pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
				    pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
				    pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
				    pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
				    vir_pool, pDevice->pool_dma
			);
		return false;
	}

	pDevice->td0_pool_dma = pDevice->rd1_pool_dma +
		pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);

	pDevice->td1_pool_dma = pDevice->td0_pool_dma +
		pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);

	/* vir_pool: pvoid type */
	pDevice->apTD0Rings = vir_pool
		+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
		+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);

	pDevice->apTD1Rings = vir_pool
		+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
		+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc)
		+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);

	pDevice->tx1_bufs = pDevice->tx0_bufs +
		pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;

	pDevice->tx_beacon_bufs = pDevice->tx1_bufs +
		pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;

	pDevice->pbyTmpBuff = pDevice->tx_beacon_bufs +
		CB_BEACON_BUF_SIZE;

	pDevice->tx_bufs_dma1 = pDevice->tx_bufs_dma0 +
		pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;

	pDevice->tx_beacon_dma = pDevice->tx_bufs_dma1 +
		pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;

	return true;
}

static void device_free_rings(struct vnt_private *pDevice)
{
	dma_free_coherent(&pDevice->pcid->dev,
			    pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
			    pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
			    pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
			    pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc)
			    ,
			    pDevice->aRD0Ring, pDevice->pool_dma
		);

	if (pDevice->tx0_bufs)
		dma_free_coherent(&pDevice->pcid->dev,
				    pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
				    pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
				    CB_BEACON_BUF_SIZE +
				    CB_MAX_BUF_SIZE,
				    pDevice->tx0_bufs, pDevice->tx_bufs_dma0
			);
}

static void device_init_rd0_ring(struct vnt_private *pDevice)
{
	int i;
	dma_addr_t      curr = pDevice->rd0_pool_dma;
	PSRxDesc        pDesc;

	/* Init the RD0 ring entries */
	for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) {
		pDesc = &(pDevice->aRD0Ring[i]);
		pDesc->pRDInfo = alloc_rd_info();
		ASSERT(pDesc->pRDInfo);
		if (!device_alloc_rx_buf(pDevice, pDesc))
			dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n");

		pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]);
		pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
		pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
	}

	if (i > 0)
		pDevice->aRD0Ring[i-1].next_desc = cpu_to_le32(pDevice->rd0_pool_dma);
	pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]);
}

static void device_init_rd1_ring(struct vnt_private *pDevice)
{
	int i;
	dma_addr_t      curr = pDevice->rd1_pool_dma;
	PSRxDesc        pDesc;

	/* Init the RD1 ring entries */
	for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) {
		pDesc = &(pDevice->aRD1Ring[i]);
		pDesc->pRDInfo = alloc_rd_info();
		ASSERT(pDesc->pRDInfo);
		if (!device_alloc_rx_buf(pDevice, pDesc))
			dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n");

		pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]);
		pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
		pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
	}

	if (i > 0)
		pDevice->aRD1Ring[i-1].next_desc = cpu_to_le32(pDevice->rd1_pool_dma);
	pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]);
}

static void device_free_rd0_ring(struct vnt_private *pDevice)
{
	int i;

	for (i = 0; i < pDevice->sOpts.nRxDescs0; i++) {
		PSRxDesc        pDesc = &(pDevice->aRD0Ring[i]);
		PDEVICE_RD_INFO  pRDInfo = pDesc->pRDInfo;

		dma_unmap_single(&pDevice->pcid->dev, pRDInfo->skb_dma,
				 pDevice->rx_buf_sz, DMA_FROM_DEVICE);

		dev_kfree_skb(pRDInfo->skb);

		kfree(pDesc->pRDInfo);
	}
}

static void device_free_rd1_ring(struct vnt_private *pDevice)
{
	int i;

	for (i = 0; i < pDevice->sOpts.nRxDescs1; i++) {
		PSRxDesc        pDesc = &(pDevice->aRD1Ring[i]);
		PDEVICE_RD_INFO  pRDInfo = pDesc->pRDInfo;

		dma_unmap_single(&pDevice->pcid->dev, pRDInfo->skb_dma,
				 pDevice->rx_buf_sz, DMA_FROM_DEVICE);

		dev_kfree_skb(pRDInfo->skb);

		kfree(pDesc->pRDInfo);
	}
}

static void device_init_td0_ring(struct vnt_private *pDevice)
{
	int i;
	dma_addr_t  curr;
	PSTxDesc        pDesc;

	curr = pDevice->td0_pool_dma;
	for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) {
		pDesc = &(pDevice->apTD0Rings[i]);
		pDesc->pTDInfo = alloc_td_info();
		ASSERT(pDesc->pTDInfo);
		if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
			pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ;
			pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ;
		}
		pDesc->next = &(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]);
		pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
		pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
	}

	if (i > 0)
		pDevice->apTD0Rings[i-1].next_desc = cpu_to_le32(pDevice->td0_pool_dma);
	pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]);
}

static void device_init_td1_ring(struct vnt_private *pDevice)
{
	int i;
	dma_addr_t  curr;
	PSTxDesc    pDesc;

	/* Init the TD ring entries */
	curr = pDevice->td1_pool_dma;
	for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr += sizeof(STxDesc)) {
		pDesc = &(pDevice->apTD1Rings[i]);
		pDesc->pTDInfo = alloc_td_info();
		ASSERT(pDesc->pTDInfo);
		if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
			pDesc->pTDInfo->buf = pDevice->tx1_bufs + (i) * PKT_BUF_SZ;
			pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma1 + (i) * PKT_BUF_SZ;
		}
		pDesc->next = &(pDevice->apTD1Rings[(i + 1) % pDevice->sOpts.nTxDescs[1]]);
		pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
		pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
	}

	if (i > 0)
		pDevice->apTD1Rings[i-1].next_desc = cpu_to_le32(pDevice->td1_pool_dma);
	pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]);
}

static void device_free_td0_ring(struct vnt_private *pDevice)
{
	int i;

	for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++) {
		PSTxDesc        pDesc = &(pDevice->apTD0Rings[i]);
		PDEVICE_TD_INFO  pTDInfo = pDesc->pTDInfo;

		if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
			dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma,
					 pTDInfo->skb->len, DMA_TO_DEVICE);

		if (pTDInfo->skb)
			dev_kfree_skb(pTDInfo->skb);

		kfree(pDesc->pTDInfo);
	}
}

static void device_free_td1_ring(struct vnt_private *pDevice)
{
	int i;

	for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++) {
		PSTxDesc        pDesc = &(pDevice->apTD1Rings[i]);
		PDEVICE_TD_INFO  pTDInfo = pDesc->pTDInfo;

		if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
			dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma,
					 pTDInfo->skb->len, DMA_TO_DEVICE);

		if (pTDInfo->skb)
			dev_kfree_skb(pTDInfo->skb);

		kfree(pDesc->pTDInfo);
	}
}

/*-----------------------------------------------------------------*/

static int device_rx_srv(struct vnt_private *pDevice, unsigned int uIdx)
{
	PSRxDesc    pRD;
	int works = 0;

	for (pRD = pDevice->pCurrRD[uIdx];
	     pRD->m_rd0RD0.f1Owner == OWNED_BY_HOST;
	     pRD = pRD->next) {
		if (works++ > 15)
			break;
		if (vnt_receive_frame(pDevice, pRD)) {
			if (!device_alloc_rx_buf(pDevice, pRD)) {
				dev_err(&pDevice->pcid->dev,
					"can not allocate rx buf\n");
				break;
			}
		}
		pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
	}

	pDevice->pCurrRD[uIdx] = pRD;

	return works;
}

static bool device_alloc_rx_buf(struct vnt_private *pDevice, PSRxDesc pRD)
{
	PDEVICE_RD_INFO pRDInfo = pRD->pRDInfo;

	pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
	if (pRDInfo->skb == NULL)
		return false;
	ASSERT(pRDInfo->skb);

	pRDInfo->skb_dma =
		dma_map_single(&pDevice->pcid->dev,
			       skb_put(pRDInfo->skb, skb_tailroom(pRDInfo->skb)),
			       pDevice->rx_buf_sz, DMA_FROM_DEVICE);

	*((unsigned int *)&(pRD->m_rd0RD0)) = 0; /* FIX cast */

	pRD->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz);
	pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
	pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz);
	pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma);

	return true;
}

static const u8 fallback_rate0[5][5] = {
	{RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
	{RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
	{RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
	{RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
	{RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
};

static const u8 fallback_rate1[5][5] = {
	{RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
	{RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
	{RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
	{RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M},
	{RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
};

static int vnt_int_report_rate(struct vnt_private *priv,
			       PDEVICE_TD_INFO context, u8 tsr0, u8 tsr1)
{
	struct vnt_tx_fifo_head *fifo_head;
	struct ieee80211_tx_info *info;
	struct ieee80211_rate *rate;
	u16 fb_option;
	u8 tx_retry = (tsr0 & TSR0_NCR);
	s8 idx;

	if (!context)
		return -ENOMEM;

	if (!context->skb)
		return -EINVAL;

	fifo_head = (struct vnt_tx_fifo_head *)context->buf;
	fb_option = (le16_to_cpu(fifo_head->fifo_ctl) &
			(FIFOCTL_AUTO_FB_0 | FIFOCTL_AUTO_FB_1));

	info = IEEE80211_SKB_CB(context->skb);
	idx = info->control.rates[0].idx;

	if (fb_option && !(tsr1 & TSR1_TERR)) {
		u8 tx_rate;
		u8 retry = tx_retry;

		rate = ieee80211_get_tx_rate(priv->hw, info);
		tx_rate = rate->hw_value - RATE_18M;

		if (retry > 4)
			retry = 4;

		if (fb_option & FIFOCTL_AUTO_FB_0)
			tx_rate = fallback_rate0[tx_rate][retry];
		else if (fb_option & FIFOCTL_AUTO_FB_1)
			tx_rate = fallback_rate1[tx_rate][retry];

		if (info->band == IEEE80211_BAND_5GHZ)
			idx = tx_rate - RATE_6M;
		else
			idx = tx_rate;
	}

	ieee80211_tx_info_clear_status(info);

	info->status.rates[0].count = tx_retry;

	if (!(tsr1 & TSR1_TERR)) {
		info->status.rates[0].idx = idx;

		if (info->flags & IEEE80211_TX_CTL_NO_ACK)
			info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
		else
			info->flags |= IEEE80211_TX_STAT_ACK;
	}

	return 0;
}

static int device_tx_srv(struct vnt_private *pDevice, unsigned int uIdx)
{
	PSTxDesc                 pTD;
	int                      works = 0;
	unsigned char byTsr0;
	unsigned char byTsr1;

	for (pTD = pDevice->apTailTD[uIdx]; pDevice->iTDUsed[uIdx] > 0; pTD = pTD->next) {
		if (pTD->m_td0TD0.f1Owner == OWNED_BY_NIC)
			break;
		if (works++ > 15)
			break;

		byTsr0 = pTD->m_td0TD0.byTSR0;
		byTsr1 = pTD->m_td0TD0.byTSR1;

		/* Only the status of first TD in the chain is correct */
		if (pTD->m_td1TD1.byTCR & TCR_STP) {
			if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) {
				if (!(byTsr1 & TSR1_TERR)) {
					if (byTsr0 != 0) {
						pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n",
							 (int)uIdx, byTsr1,
							 byTsr0);
					}
				} else {
					pr_debug(" Tx[%d] dropped & tsr1[%02X] tsr0[%02X]\n",
						 (int)uIdx, byTsr1, byTsr0);
				}
			}

			if (byTsr1 & TSR1_TERR) {
				if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
					pr_debug(" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X]\n",
						 (int)uIdx, byTsr1, byTsr0);
				}
			}

			vnt_int_report_rate(pDevice, pTD->pTDInfo, byTsr0, byTsr1);

			device_free_tx_buf(pDevice, pTD);
			pDevice->iTDUsed[uIdx]--;
		}
	}

	pDevice->apTailTD[uIdx] = pTD;

	return works;
}

static void device_error(struct vnt_private *pDevice, unsigned short status)
{
	if (status & ISR_FETALERR) {
		dev_err(&pDevice->pcid->dev, "Hardware fatal error\n");

		MACbShutdown(pDevice->PortOffset);
		return;
	}
}

static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc)
{
	PDEVICE_TD_INFO  pTDInfo = pDesc->pTDInfo;
	struct sk_buff *skb = pTDInfo->skb;

	/* pre-allocated buf_dma can't be unmapped. */
	if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) {
		dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma,
				 skb->len, DMA_TO_DEVICE);
	}

	if (skb)
		ieee80211_tx_status_irqsafe(pDevice->hw, skb);

	pTDInfo->skb_dma = 0;
	pTDInfo->skb = NULL;
	pTDInfo->byFlags = 0;
}

static void vnt_check_bb_vga(struct vnt_private *priv)
{
	long dbm;
	int i;

	if (!priv->bUpdateBBVGA)
		return;

	if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
		return;

	if (!(priv->vif->bss_conf.assoc && priv->uCurrRSSI))
		return;

	RFvRSSITodBm(priv, (u8)priv->uCurrRSSI, &dbm);

	for (i = 0; i < BB_VGA_LEVEL; i++) {
		if (dbm < priv->ldBmThreshold[i]) {
			priv->byBBVGANew = priv->abyBBVGA[i];
			break;
		}
	}

	if (priv->byBBVGANew == priv->byBBVGACurrent) {
		priv->uBBVGADiffCount = 1;
		return;
	}

	priv->uBBVGADiffCount++;

	if (priv->uBBVGADiffCount == 1) {
		/* first VGA diff gain */
		BBvSetVGAGainOffset(priv, priv->byBBVGANew);

		dev_dbg(&priv->pcid->dev,
			"First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
			(int)dbm, priv->byBBVGANew,
			priv->byBBVGACurrent,
			(int)priv->uBBVGADiffCount);
	}

	if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
		dev_dbg(&priv->pcid->dev,
			"RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
			(int)dbm, priv->byBBVGANew,
			priv->byBBVGACurrent,
			(int)priv->uBBVGADiffCount);

		BBvSetVGAGainOffset(priv, priv->byBBVGANew);
	}
}

static  irqreturn_t  device_intr(int irq,  void *dev_instance)
{
	struct vnt_private *pDevice = dev_instance;
	int             max_count = 0;
	unsigned long dwMIBCounter = 0;
	unsigned char byOrgPageSel = 0;
	int             handled = 0;
	unsigned long flags;

	MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);

	if (pDevice->dwIsr == 0)
		return IRQ_RETVAL(handled);

	if (pDevice->dwIsr == 0xffffffff) {
		pr_debug("dwIsr = 0xffff\n");
		return IRQ_RETVAL(handled);
	}

	handled = 1;
	MACvIntDisable(pDevice->PortOffset);

	spin_lock_irqsave(&pDevice->lock, flags);

	/* Make sure current page is 0 */
	VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel);
	if (byOrgPageSel == 1)
		MACvSelectPage0(pDevice->PortOffset);
	else
		byOrgPageSel = 0;

	MACvReadMIBCounter(pDevice->PortOffset, &dwMIBCounter);
	/*
	 * TBD....
	 * Must do this after doing rx/tx, cause ISR bit is slow
	 * than RD/TD write back
	 * update ISR counter
	 */
	STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic, dwMIBCounter);
	while (pDevice->dwIsr != 0) {
		STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr);
		MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr);

		if (pDevice->dwIsr & ISR_FETALERR) {
			pr_debug(" ISR_FETALERR\n");
			VNSvOutPortB(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, 0);
			VNSvOutPortW(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI);
			device_error(pDevice, pDevice->dwIsr);
		}

		if (pDevice->dwIsr & ISR_TBTT) {
			if (pDevice->vif &&
			    pDevice->op_mode != NL80211_IFTYPE_ADHOC)
				vnt_check_bb_vga(pDevice);

			pDevice->bBeaconSent = false;
			if (pDevice->bEnablePSMode)
				PSbIsNextTBTTWakeUp((void *)pDevice);

			if ((pDevice->op_mode == NL80211_IFTYPE_AP ||
			    pDevice->op_mode == NL80211_IFTYPE_ADHOC) &&
			    pDevice->vif->bss_conf.enable_beacon) {
				MACvOneShotTimer1MicroSec(pDevice->PortOffset,
							  (pDevice->vif->bss_conf.beacon_int - MAKE_BEACON_RESERVED) << 10);
			}

			/* TODO: adhoc PS mode */

		}

		if (pDevice->dwIsr & ISR_BNTX) {
			if (pDevice->op_mode == NL80211_IFTYPE_ADHOC) {
				pDevice->bIsBeaconBufReadySet = false;
				pDevice->cbBeaconBufReadySetCnt = 0;
			}

			pDevice->bBeaconSent = true;
		}

		if (pDevice->dwIsr & ISR_RXDMA0)
			max_count += device_rx_srv(pDevice, TYPE_RXDMA0);

		if (pDevice->dwIsr & ISR_RXDMA1)
			max_count += device_rx_srv(pDevice, TYPE_RXDMA1);

		if (pDevice->dwIsr & ISR_TXDMA0)
			max_count += device_tx_srv(pDevice, TYPE_TXDMA0);

		if (pDevice->dwIsr & ISR_AC0DMA)
			max_count += device_tx_srv(pDevice, TYPE_AC0DMA);

		if (pDevice->dwIsr & ISR_SOFTTIMER1) {
			if (pDevice->vif) {
				if (pDevice->vif->bss_conf.enable_beacon)
					vnt_beacon_make(pDevice, pDevice->vif);
			}
		}

		/* If both buffers available wake the queue */
		if (pDevice->vif) {
			if (AVAIL_TD(pDevice, TYPE_TXDMA0) &&
			    AVAIL_TD(pDevice, TYPE_AC0DMA) &&
			    ieee80211_queue_stopped(pDevice->hw, 0))
				ieee80211_wake_queues(pDevice->hw);
		}

		MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);

		MACvReceive0(pDevice->PortOffset);
		MACvReceive1(pDevice->PortOffset);

		if (max_count > pDevice->sOpts.int_works)
			break;
	}

	if (byOrgPageSel == 1)
		MACvSelectPage1(pDevice->PortOffset);

	spin_unlock_irqrestore(&pDevice->lock, flags);

	MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);

	return IRQ_RETVAL(handled);
}

static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
	PSTxDesc head_td;
	u32 dma_idx;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	if (ieee80211_is_data(hdr->frame_control))
		dma_idx = TYPE_AC0DMA;
	else
		dma_idx = TYPE_TXDMA0;

	if (AVAIL_TD(priv, dma_idx) < 1) {
		spin_unlock_irqrestore(&priv->lock, flags);
		return -ENOMEM;
	}

	head_td = priv->apCurrTD[dma_idx];

	head_td->m_td1TD1.byTCR = 0;

	head_td->pTDInfo->skb = skb;

	if (dma_idx == TYPE_AC0DMA)
		head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;

	priv->apCurrTD[dma_idx] = head_td->next;

	spin_unlock_irqrestore(&priv->lock, flags);

	vnt_generate_fifo_header(priv, dma_idx, head_td, skb);

	if (MACbIsRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
		MACbPSWakeup(priv->PortOffset);

	spin_lock_irqsave(&priv->lock, flags);

	priv->bPWBitOn = false;

	/* Set TSR1 & ReqCount in TxDescHead */
	head_td->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
	head_td->m_td1TD1.wReqCount =
			cpu_to_le16((u16)head_td->pTDInfo->dwReqCount);

	head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);

	/* Poll Transmit the adapter */
	wmb();
	head_td->m_td0TD0.f1Owner = OWNED_BY_NIC;
	wmb(); /* second memory barrier */

	if (head_td->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)
		MACvTransmitAC0(priv->PortOffset);
	else
		MACvTransmit0(priv->PortOffset);

	priv->iTDUsed[dma_idx]++;

	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

static void vnt_tx_80211(struct ieee80211_hw *hw,
			 struct ieee80211_tx_control *control,
			 struct sk_buff *skb)
{
	struct vnt_private *priv = hw->priv;

	ieee80211_stop_queues(hw);

	if (vnt_tx_packet(priv, skb)) {
		ieee80211_free_txskb(hw, skb);

		ieee80211_wake_queues(hw);
	}
}

static int vnt_start(struct ieee80211_hw *hw)
{
	struct vnt_private *priv = hw->priv;
	int ret;

	priv->rx_buf_sz = PKT_BUF_SZ;
	if (!device_init_rings(priv))
		return -ENOMEM;

	ret = request_irq(priv->pcid->irq, &device_intr,
			  IRQF_SHARED, "vt6655", priv);
	if (ret) {
		dev_dbg(&priv->pcid->dev, "failed to start irq\n");
		return ret;
	}

	dev_dbg(&priv->pcid->dev, "call device init rd0 ring\n");
	device_init_rd0_ring(priv);
	device_init_rd1_ring(priv);
	device_init_td0_ring(priv);
	device_init_td1_ring(priv);

	device_init_registers(priv);

	dev_dbg(&priv->pcid->dev, "call MACvIntEnable\n");
	MACvIntEnable(priv->PortOffset, IMR_MASK_VALUE);

	ieee80211_wake_queues(hw);

	return 0;
}

static void vnt_stop(struct ieee80211_hw *hw)
{
	struct vnt_private *priv = hw->priv;

	ieee80211_stop_queues(hw);

	MACbShutdown(priv->PortOffset);
	MACbSoftwareReset(priv->PortOffset);
	CARDbRadioPowerOff(priv);

	device_free_td0_ring(priv);
	device_free_td1_ring(priv);
	device_free_rd0_ring(priv);
	device_free_rd1_ring(priv);
	device_free_rings(priv);

	free_irq(priv->pcid->irq, priv);
}

static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct vnt_private *priv = hw->priv;

	priv->vif = vif;

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		break;
	case NL80211_IFTYPE_ADHOC:
		MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST);

		MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);

		break;
	case NL80211_IFTYPE_AP:
		MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST);

		MACvRegBitsOn(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);

		break;
	default:
		return -EOPNOTSUPP;
	}

	priv->op_mode = vif->type;

	return 0;
}

static void vnt_remove_interface(struct ieee80211_hw *hw,
				 struct ieee80211_vif *vif)
{
	struct vnt_private *priv = hw->priv;

	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
		break;
	case NL80211_IFTYPE_ADHOC:
		MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
		MACvRegBitsOff(priv->PortOffset,
			       MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
		MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);
		break;
	case NL80211_IFTYPE_AP:
		MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
		MACvRegBitsOff(priv->PortOffset,
			       MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
		MACvRegBitsOff(priv->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);
		break;
	default:
		break;
	}

	priv->op_mode = NL80211_IFTYPE_UNSPECIFIED;
}


static int vnt_config(struct ieee80211_hw *hw, u32 changed)
{
	struct vnt_private *priv = hw->priv;
	struct ieee80211_conf *conf = &hw->conf;
	u8 bb_type;

	if (changed & IEEE80211_CONF_CHANGE_PS) {
		if (conf->flags & IEEE80211_CONF_PS)
			PSvEnablePowerSaving(priv, conf->listen_interval);
		else
			PSvDisablePowerSaving(priv);
	}

	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
	    (conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
		set_channel(priv, conf->chandef.chan);

		if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
			bb_type = BB_TYPE_11A;
		else
			bb_type = BB_TYPE_11G;

		if (priv->byBBType != bb_type) {
			priv->byBBType = bb_type;

			CARDbSetPhyParameter(priv, priv->byBBType);
		}
	}

	if (changed & IEEE80211_CONF_CHANGE_POWER) {
		if (priv->byBBType == BB_TYPE_11B)
			priv->wCurrentRate = RATE_1M;
		else
			priv->wCurrentRate = RATE_54M;

		RFbSetPower(priv, priv->wCurrentRate,
			    conf->chandef.chan->hw_value);
	}

	return 0;
}

static void vnt_bss_info_changed(struct ieee80211_hw *hw,
		struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf,
		u32 changed)
{
	struct vnt_private *priv = hw->priv;

	priv->current_aid = conf->aid;

	if (changed & BSS_CHANGED_BSSID) {
		unsigned long flags;

		spin_lock_irqsave(&priv->lock, flags);

		MACvWriteBSSIDAddress(priv->PortOffset, (u8 *)conf->bssid);

		spin_unlock_irqrestore(&priv->lock, flags);
	}

	if (changed & BSS_CHANGED_BASIC_RATES) {
		priv->basic_rates = conf->basic_rates;

		CARDvUpdateBasicTopRate(priv);

		dev_dbg(&priv->pcid->dev,
			"basic rates %x\n", conf->basic_rates);
	}

	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
		if (conf->use_short_preamble) {
			MACvEnableBarkerPreambleMd(priv->PortOffset);
			priv->byPreambleType = true;
		} else {
			MACvDisableBarkerPreambleMd(priv->PortOffset);
			priv->byPreambleType = false;
		}
	}

	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
		if (conf->use_cts_prot)
			MACvEnableProtectMD(priv->PortOffset);
		else
			MACvDisableProtectMD(priv->PortOffset);
	}

	if (changed & BSS_CHANGED_ERP_SLOT) {
		if (conf->use_short_slot)
			priv->bShortSlotTime = true;
		else
			priv->bShortSlotTime = false;

		CARDbSetPhyParameter(priv, priv->byBBType);
		BBvSetVGAGainOffset(priv, priv->abyBBVGA[0]);
	}

	if (changed & BSS_CHANGED_TXPOWER)
		RFbSetPower(priv, priv->wCurrentRate,
			    conf->chandef.chan->hw_value);

	if (changed & BSS_CHANGED_BEACON_ENABLED) {
		dev_dbg(&priv->pcid->dev,
			"Beacon enable %d\n", conf->enable_beacon);

		if (conf->enable_beacon) {
			vnt_beacon_enable(priv, vif, conf);

			MACvRegBitsOn(priv->PortOffset, MAC_REG_TCR,
				      TCR_AUTOBCNTX);
		} else {
			MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR,
				       TCR_AUTOBCNTX);
		}
	}

	if (changed & BSS_CHANGED_ASSOC && priv->op_mode != NL80211_IFTYPE_AP) {
		if (conf->assoc) {
			CARDbUpdateTSF(priv, conf->beacon_rate->hw_value,
				       conf->sync_tsf);

			CARDbSetBeaconPeriod(priv, conf->beacon_int);

			CARDvSetFirstNextTBTT(priv, conf->beacon_int);
		} else {
			VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL,
				     TFTCTL_TSFCNTRST);
			VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL,
				     TFTCTL_TSFCNTREN);
		}
	}
}

static u64 vnt_prepare_multicast(struct ieee80211_hw *hw,
	struct netdev_hw_addr_list *mc_list)
{
	struct vnt_private *priv = hw->priv;
	struct netdev_hw_addr *ha;
	u64 mc_filter = 0;
	u32 bit_nr = 0;

	netdev_hw_addr_list_for_each(ha, mc_list) {
		bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;

		mc_filter |= 1ULL << (bit_nr & 0x3f);
	}

	priv->mc_list_count = mc_list->count;

	return mc_filter;
}

static void vnt_configure(struct ieee80211_hw *hw,
	unsigned int changed_flags, unsigned int *total_flags, u64 multicast)
{
	struct vnt_private *priv = hw->priv;
	u8 rx_mode = 0;

	*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_PROMISC_IN_BSS |
		FIF_BCN_PRBRESP_PROMISC;

	VNSvInPortB(priv->PortOffset + MAC_REG_RCR, &rx_mode);

	dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode);

	if (changed_flags & FIF_PROMISC_IN_BSS) {
		/* unconditionally log net taps */
		if (*total_flags & FIF_PROMISC_IN_BSS)
			rx_mode |= RCR_UNICAST;
		else
			rx_mode &= ~RCR_UNICAST;
	}

	if (changed_flags & FIF_ALLMULTI) {
		if (*total_flags & FIF_ALLMULTI) {
			unsigned long flags;

			spin_lock_irqsave(&priv->lock, flags);

			if (priv->mc_list_count > 2) {
				MACvSelectPage1(priv->PortOffset);

				VNSvOutPortD(priv->PortOffset +
					     MAC_REG_MAR0, 0xffffffff);
				VNSvOutPortD(priv->PortOffset +
					    MAC_REG_MAR0 + 4, 0xffffffff);

				MACvSelectPage0(priv->PortOffset);
			} else {
				MACvSelectPage1(priv->PortOffset);

				VNSvOutPortD(priv->PortOffset +
					     MAC_REG_MAR0, (u32)multicast);
				VNSvOutPortD(priv->PortOffset +
					     MAC_REG_MAR0 + 4,
					     (u32)(multicast >> 32));

				MACvSelectPage0(priv->PortOffset);
			}

			spin_unlock_irqrestore(&priv->lock, flags);

			rx_mode |= RCR_MULTICAST | RCR_BROADCAST;
		} else {
			rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST);
		}
	}

	if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) {
		rx_mode |= RCR_MULTICAST | RCR_BROADCAST;

		if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC))
			rx_mode &= ~RCR_BSSID;
		else
			rx_mode |= RCR_BSSID;
	}

	VNSvOutPortB(priv->PortOffset + MAC_REG_RCR, rx_mode);

	dev_dbg(&priv->pcid->dev, "rx mode out= %x\n", rx_mode);
}

static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
	struct ieee80211_vif *vif, struct ieee80211_sta *sta,
		struct ieee80211_key_conf *key)
{
	struct vnt_private *priv = hw->priv;

	switch (cmd) {
	case SET_KEY:
		if (vnt_set_keys(hw, sta, vif, key))
			return -EOPNOTSUPP;
		break;
	case DISABLE_KEY:
		if (test_bit(key->hw_key_idx, &priv->key_entry_inuse))
			clear_bit(key->hw_key_idx, &priv->key_entry_inuse);
	default:
		break;
	}

	return 0;
}

static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct vnt_private *priv = hw->priv;
	u64 tsf;

	CARDbGetCurrentTSF(priv, &tsf);

	return tsf;
}

static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
			u64 tsf)
{
	struct vnt_private *priv = hw->priv;

	CARDvUpdateNextTBTT(priv, tsf, vif->bss_conf.beacon_int);
}

static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
	struct vnt_private *priv = hw->priv;

	/* reset TSF counter */
	VNSvOutPortB(priv->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
}

static const struct ieee80211_ops vnt_mac_ops = {
	.tx			= vnt_tx_80211,
	.start			= vnt_start,
	.stop			= vnt_stop,
	.add_interface		= vnt_add_interface,
	.remove_interface	= vnt_remove_interface,
	.config			= vnt_config,
	.bss_info_changed	= vnt_bss_info_changed,
	.prepare_multicast	= vnt_prepare_multicast,
	.configure_filter	= vnt_configure,
	.set_key		= vnt_set_key,
	.get_tsf		= vnt_get_tsf,
	.set_tsf		= vnt_set_tsf,
	.reset_tsf		= vnt_reset_tsf,
};

static int vnt_init(struct vnt_private *priv)
{
	SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr);

	vnt_init_bands(priv);

	if (ieee80211_register_hw(priv->hw))
		return -ENODEV;

	priv->mac_hw = true;

	CARDbRadioPowerOff(priv);

	return 0;
}

static int
vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
{
	PCHIP_INFO  pChip_info = (PCHIP_INFO)ent->driver_data;
	struct vnt_private *priv;
	struct ieee80211_hw *hw;
	struct wiphy *wiphy;
	int         rc;

	dev_notice(&pcid->dev,
		   "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION);

	dev_notice(&pcid->dev,
		   "Copyright (c) 2003 VIA Networking Technologies, Inc.\n");

	hw = ieee80211_alloc_hw(sizeof(*priv), &vnt_mac_ops);
	if (!hw) {
		dev_err(&pcid->dev, "could not register ieee80211_hw\n");
		return -ENOMEM;
	}

	priv = hw->priv;

	vt6655_init_info(pcid, &priv, pChip_info);

	priv->hw = hw;

	SET_IEEE80211_DEV(priv->hw, &pcid->dev);

	if (pci_enable_device(pcid)) {
		device_free_info(priv);
		return -ENODEV;
	}

	dev_dbg(&pcid->dev,
		"Before get pci_info memaddr is %x\n", priv->memaddr);

	if (!device_get_pci_info(priv, pcid)) {
		dev_err(&pcid->dev, ": Failed to find PCI device.\n");
		device_free_info(priv);
		return -ENODEV;
	}

#ifdef	DEBUG
	dev_dbg(&pcid->dev,
		"after get pci_info memaddr is %x, io addr is %x,io_size is %d\n",
		priv->memaddr, priv->ioaddr, priv->io_size);
	{
		int i;
		u32 bar, len;
		u32 address[] = {
			PCI_BASE_ADDRESS_0,
			PCI_BASE_ADDRESS_1,
			PCI_BASE_ADDRESS_2,
			PCI_BASE_ADDRESS_3,
			PCI_BASE_ADDRESS_4,
			PCI_BASE_ADDRESS_5,
			0};
		for (i = 0; address[i]; i++) {
			pci_read_config_dword(pcid, address[i], &bar);

			dev_dbg(&pcid->dev, "bar %d is %x\n", i, bar);

			if (!bar) {
				dev_dbg(&pcid->dev,
					"bar %d not implemented\n", i);
				continue;
			}

			if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
				/* This is IO */

				len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xffff);
				len = len & ~(len - 1);

				dev_dbg(&pcid->dev,
					"IO space:  len in IO %x, BAR %d\n",
					len, i);
			} else {
				len = bar & 0xfffffff0;
				len = ~len + 1;

				dev_dbg(&pcid->dev,
					"len in MEM %x, BAR %d\n", len, i);
			}
		}
	}
#endif

	priv->PortOffset = ioremap(priv->memaddr & PCI_BASE_ADDRESS_MEM_MASK,
				   priv->io_size);
	if (!priv->PortOffset) {
		dev_err(&pcid->dev, ": Failed to IO remapping ..\n");
		device_free_info(priv);
		return -ENODEV;
	}

	rc = pci_request_regions(pcid, DEVICE_NAME);
	if (rc) {
		dev_err(&pcid->dev, ": Failed to find PCI device\n");
		device_free_info(priv);
		return -ENODEV;
	}

	/* do reset */
	if (!MACbSoftwareReset(priv->PortOffset)) {
		dev_err(&pcid->dev, ": Failed to access MAC hardware..\n");
		device_free_info(priv);
		return -ENODEV;
	}
	/* initial to reload eeprom */
	MACvInitialize(priv->PortOffset);
	MACvReadEtherAddress(priv->PortOffset, priv->abyCurrentNetAddr);

	/* Get RFType */
	priv->byRFType = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_RFTYPE);
	priv->byRFType &= RF_MASK;

	dev_dbg(&pcid->dev, "RF Type = %x\n", priv->byRFType);

	device_get_options(priv);
	device_set_options(priv);
	/* Mask out the options cannot be set to the chip */
	priv->sOpts.flags &= pChip_info->flags;

	/* Enable the chip specified capabilities */
	priv->flags = priv->sOpts.flags | (pChip_info->flags & 0xff000000UL);

	wiphy = priv->hw->wiphy;

	wiphy->frag_threshold = FRAG_THRESH_DEF;
	wiphy->rts_threshold = RTS_THRESH_DEF;
	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
		BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);

	priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
		IEEE80211_HW_SIGNAL_DBM |
		IEEE80211_HW_TIMING_BEACON_ONLY;

	priv->hw->max_signal = 100;

	if (vnt_init(priv))
		return -ENODEV;

	device_print_info(priv);
	pci_set_drvdata(pcid, priv);

	return 0;
}

/*------------------------------------------------------------------*/

#ifdef CONFIG_PM
static int vt6655_suspend(struct pci_dev *pcid, pm_message_t state)
{
	struct vnt_private *priv = pci_get_drvdata(pcid);
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	pci_save_state(pcid);

	MACbShutdown(priv->PortOffset);

	pci_disable_device(pcid);
	pci_set_power_state(pcid, pci_choose_state(pcid, state));

	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
}

static int vt6655_resume(struct pci_dev *pcid)
{

	pci_set_power_state(pcid, PCI_D0);
	pci_enable_wake(pcid, PCI_D0, 0);
	pci_restore_state(pcid);

	return 0;
}
#endif

MODULE_DEVICE_TABLE(pci, vt6655_pci_id_table);

static struct pci_driver device_driver = {
	.name = DEVICE_NAME,
	.id_table = vt6655_pci_id_table,
	.probe = vt6655_probe,
	.remove = vt6655_remove,
#ifdef CONFIG_PM
	.suspend = vt6655_suspend,
	.resume = vt6655_resume,
#endif
};

static int __init vt6655_init_module(void)
{
	int ret;

	ret = pci_register_driver(&device_driver);
#ifdef CONFIG_PM
	if (ret >= 0)
		register_reboot_notifier(&device_notifier);
#endif

	return ret;
}

static void __exit vt6655_cleanup_module(void)
{
#ifdef CONFIG_PM
	unregister_reboot_notifier(&device_notifier);
#endif
	pci_unregister_driver(&device_driver);
}

module_init(vt6655_init_module);
module_exit(vt6655_cleanup_module);

#ifdef CONFIG_PM
static int
device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
	struct pci_dev *pdev = NULL;

	switch (event) {
	case SYS_DOWN:
	case SYS_HALT:
	case SYS_POWER_OFF:
		for_each_pci_dev(pdev) {
			if (pci_dev_driver(pdev) == &device_driver) {
				if (pci_get_drvdata(pdev))
					vt6655_suspend(pdev, PMSG_HIBERNATE);
			}
		}
	}
	return NOTIFY_DONE;
}
#endif