/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 */

//
// Embedded 802.11a/g wireless network interface
// MAC layer hardware interface for ConnectCore Wi-9C
// Copyright 2006 Digi International
//
#include "mac.h"
#include <mcsys_reg.h>
#include "processorgpio.h"
#include "reg_def.h"

#ifdef NET_OS_SPECIFIC
#include "bsp_net.h"
#if (BSP_WPS_ENABLED == TRUE)
#include "mac_wps.h"
#endif
#endif

extern char *textStaState[];
extern char *macStatusState[];

//
// Hardware register defines
//
#define MAC_BASE		0x60000000		// Register base address
#define MAC_PROG		0x70000000		// FPGA program address
#define MAC_MASK		0xffffc001		// Size mask and enable bit

#define	REG32(offset)	(* (volatile uint32 *) (MAC_BASE + (offset)))

// Baseband control registers
#define	HW_VERSION		REG32(0x00)		// Version
#define	HW_GEN_CONTROL	REG32(0x04)		// General control
#define	HW_GEN_STATUS	REG32(0x08)		// General status
#define	HW_RSSI_AES		REG32(0x0c)		// RSSI and AES status
#define	HW_INTR_MASK	REG32(0x10)		// Interrupt mask
#define	HW_INTR_STATUS	REG32(0x14)		// Interrupt status
#define	HW_SPI			REG32(0x18)		// RF SPI interface
#define	HW_DATA_FIFO	REG32(0x20)		// Data FIFO
#define	HW_AES_FIFO		REG32(0x30)		// AES FIFO
#define	HW_AES_MODE		REG32(0x38)		// ARS mode

// MAC control registers.
#define	HW_STAID0		REG32(0x40)		// Station ID (6 bytes)
#define	HW_STAID1		REG32(0x44)
#define	HW_BSSID0		REG32(0x48)		// BSS ID (6 bytes)
#define	HW_BSSID1		REG32(0x4c)
#define	HW_SSID_LEN		REG32(0x50)		// Basic rates (high 16 bits), SSID length (low 8 bits)
#define	HW_BACKOFF		REG32(0x54)		// Backoff period (16 bits)
#define	HW_LISTEN		REG32(0x58)		// Listen interval (16 bits), CFP (8 bits), DTIM (8 bits)
#define	HW_CFP_ATIM		REG32(0x5c)		// CFP max duration/ATIM period (16 bits), beacon interval (16 bits)
#define	HW_MAC_STATUS	REG32(0x60)		// MAC status (8 bits)
#define	HW_MAC_CONTROL	REG32(0x64)		// MAC control (8 bits)
#define	HW_REMAIN_BO	REG32(0x68)		// Remaining backoff (16 bits)
#define	HW_BEACON_BO	REG32(0x6c)		// Beacon backoff (16 bits), beacon mask (8 bits)
#define	HW_SSID			REG32(0x80)		// Service set ID (32 bytes)
#define	HW_STA2ID0		REG32(0xb0)		// Second Station ID (6 bytes)
#define	HW_STA2ID1		REG32(0xb4)
#define	HW_STA3ID0		REG32(0xb8)		// Third Station ID (6 bytes)
#define	HW_STA3ID1		REG32(0xbc)

// FIFO sizes in bytes
#define	HW_TX_FIFO_SIZE	1792
#define	HW_RX_FIFO_SIZE	2048

#if (MAX_FRAME_SIZE > HW_TX_FIFO_SIZE)
#error	MAX_FRAME_SIZE too big
#endif

// Min fragment size to allow interrupt latency between frames
#define	MIN_FRAG_SIZE	400

// Size of CTS frame in FIFO
#define	CTS_OVERHEAD	20
// Max overhead per fragment (CCMP is worst case)
#define	FRAG_OVERHEAD	(8+DATA_SIZE+CCMP_SIZE-FCS_SIZE)
// Max fragment size to fit CTS and 2 fragments in transmit FIFO
#define	MAX_FRAG_SIZE	(DATA_SIZE + (HW_TX_FIFO_SIZE-CTS_OVERHEAD-2*FRAG_OVERHEAD)/2)

// General control register bits
#define	GEN_RXEN		0x00000001		// Receive enable
#define	GEN_ANTDIV		0x00000002		// Antenna diversity
#define	GEN_ANTSEL		0x00000004		// Antenna select
#define	GEN_5GEN		0x00000008		// 5 GHz band enable
#define	GEN_SHPRE		0x00000010		// Transmit short preamble
#define	GEN_RXFIFORST	0x00000020		// Receive FIFO reset
#define	GEN_TXFIFORST	0x00000040		// Transmit FIFO reset
#define	GEN_TXHOLD		0x00000080		// Transmit FIFO hold
#define	GEN_BEACEN		0x00000100		// Beacon enable
#define	GEN_TXFIFOEMPTY	0x00004000		// Transmit FIFO empty
#define	GEN_TXFIFOFULL	0x00008000		// Transmit FIFO full

#define	GEN_RESET		0x527f0000		// Reset state
#define	GEN_INIT		0x377a0000		// Initial state

// General status register bits
#define	STAT_RXFE		0x00000010		// Receive FIFO empty
#define STAT_DLLLOCK    0x00000020      // DLL lock

// AES status register bits
#define	AES_EMPTY		0x00010000		// AES receive FIFO empty
#define	AES_FULL		0x00020000		// AES transmit FIFO full
#define	AES_BUSY		0x00040000		// AES engine busy
#define	AES_MIC			0x00080000		// AES MIC correct

// Interrupt mask and status register bits
#define	INTR_RXFIFO		0x00000001		// Receive FIFO not empty
#define	INTR_TXEND		0x00000002		// Transmit complete
#define	INTR_TIMEOUT	0x00000004		// CTS/ACK receive timeout
#define	INTR_ABORT		0x00000008		// CTS transmit abort
#define	INTR_TBTT		0x00000010		// Beacon transmission time
#define	INTR_ATIM		0x00000020		// ATIM interval end
#define	INTR_RXOVERRUN	0x00000040		// Receive FIFO overrun

// MAC control register bits
#define	CTRL_TXREQ		0x00000001		// Transmit request
#define	CTRL_AUTOTXDIS	0x00000002		// Auto-transmit disable
#define	CTRL_BEACONTX	0x00000004		// Beacon transmit enable
#define	CTRL_PROMISC	0x00000008		// Promiscuous mode
#define	CTRL_IBSS		0x00000010		// IBBS mode
#define	CTRL_MAC_FLTR	0x00000040		// Extra address filter mode

#if BSP_RF_TESTING
#define	GEN_TESTMODE	0x80000000		// Test mode of operation
#define	REG16(offset)	(* (volatile uint16 *) (MAC_BASE + (offset)))
#endif

//
// PIO pins
//
#define PIN_INIT		58				// FPGA program init
#define PIN_DONE		65				// FPGA program done
#define PIN_INTR		65				// Interrupt (same as done)
#define PIN_LED			67				// Link status LED
#define PIN_ACTIVITY_LED  66            // Link activity LED


#define INTR_ID			ETH_PHY_INTERRUPT	// Interrupt ID for PIN_INTR

#define	gpio_args(pin)	(pin)/32, (pin)%32

// Get/set/clear a PIO pin
#define PIO_GET(pin)	ProcessorGpioGetValue (gpio_args (pin))
#define PIO_SET(pin)	ProcessorGpioSetOutputValue (gpio_args (pin), 1)
#define PIO_CLR(pin)	ProcessorGpioSetOutputValue (gpio_args (pin), 0)

// Set PIO pin mode
#define PIO_OUTPUT(pin)	ProcessorGpioSetOutput (gpio_args (pin), 1)
#define PIO_INPUT(pin)	ProcessorGpioSetInput (gpio_args (pin))
#define PIO_INTR(pin)	ProcessorGpioSetInterrupt (gpio_args (pin), 0, 0)

#define	LOAD_TIMEOUT	1000			// FPGA load timeout (ms)


// RF transceiver transmitter gain for each power level.
// This is the 0-15 power level, bit reversed.
static uint8 powerTable[] = {
	0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
	0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
};

// RF transceiver frequency divider for each channel
static const struct {
	uint16 integer;
	uint16 fraction;
} freqTable[] = {
	{ 0, 0 },
	{ 0x6847, 0x0999 }, // 1 (2412 MHz)
	{ 0x6847, 0x099b }, // 2 (2417 MHz)
	{ 0x6867, 0x0998 }, // 3
	{ 0x6867, 0x099a }, // 4
	{ 0x6867, 0x0999 }, // 5
	{ 0x6867, 0x099b }, // 6
	{ 0x6857, 0x0998 }, // 7
	{ 0x6857, 0x099a }, // 8
	{ 0x6857, 0x0999 }, // 9
	{ 0x6857, 0x099b }, // 10
	{ 0x6877, 0x0998 }, // 11
	{ 0x6877, 0x099a }, // 12
	{ 0x6877, 0x0999 }, // 13 (2472 MHz)
	{ 0x684f, 0x0ccc }, // 14 (2484 MHz)
};

// Map LNA value to gain value
static const uint8 lnaTable[] =
{
    0, 0, 23, 39
};

// Map high gain values to dbm
static const signed char gainTable[] =
{
    -82, -84, -85, -86, -87, -89, -90, -92, -94, -98
};

static MacBuffer rxFrame;	// Frame being received
static uint32 intrMask;		// Interrupt mask register
static uint32 timerLoops;	// Loops for 10 usec delay

static int HandleIR (void *ignore);


/* set the MAX AGC field in control register */
/*
 * For UBEC   :     Before association, BG band, use 0x78;  for A band,  use 0x77.
 *                  After association, , BG band, use no less than 0x72;  for A band,  use no less than 0x72.
 *
 */
void adjustMaxAgc_wi9c(epStatus *pSta, MacBuffer *buf)
{
#define LOWEST_MAXAGC        (0x72)
#define HIGHEST_MAXAGC       (0x7A)
#define RSSI_AVG_COUNT  8

    unsigned char maxgain = 0;
    unsigned char lowest = 0, highest = 0;
    static int k=0, j=0, i =0, tempRssi=0;

    if (pSta == NULL || buf == NULL)
        return;


    lowest = LOWEST_MAXAGC;
    highest = HIGHEST_MAXAGC;

    if (pSta->staState == SS_ASSOC)
    {

        if ( pSta->macStatus.bss_caps & CAP_IBSS)
        {
            //Monitor the receive signal strength from Ad-hoc network
            if (EQUAL_ADDR (pSta->macStatus.bss_addr, buf->macHdr.addr3))
            {
                /* we don't do avareging on all the signals here because it may come from different
                 * unit in that Ad-hoc network. Instead, we do avareging on the signals with higher rssi
                 */

                if ((buf->rssi + 4) > lowest)
                {
                    k++;
                    tempRssi += buf->rssi;

                    if (k >= RSSI_AVG_COUNT)
                    {
                        maxgain = (((tempRssi/k) + 4) > highest)? highest : ((tempRssi/k) + 4) ;
                        k = 0;
                        tempRssi = 0;
                        i =0;
                    }
                }
                else
                {
                    i++;
                    if (i >= (RSSI_AVG_COUNT*4))
                    {
                        maxgain = lowest;
                        i = 0;
                    }

                }
            }
        }
        else
        {
            //Monitor the receive signal strength from the frames we received from the associated AP
            if (EQUAL_ADDR (pSta->macStatus.bss_addr, buf->macHdr.addr2))
            {
                //avareging all the signals because it come from the same AP
                k++;
                tempRssi += buf->rssi;

                if (k >= RSSI_AVG_COUNT*2)
                {
                    if (((tempRssi/k) + 4) > lowest)
                        maxgain = (((tempRssi/k) + 4) > highest)? highest : ((tempRssi/k) + 4) ;
                    else
                        maxgain = lowest;

                    k = 0;
                    tempRssi = 0;
                }
            }
        }
        j = 0;
    }
    else
    {
        if (pSta->macStatus.state == WLN_ST_STOPPED)
            maxgain = highest;
        else
        {
            j++;
            if (j >= (RSSI_AVG_COUNT*4))
            {
                maxgain = highest;
                j = 0;
            }
            k = 0;
            tempRssi = 0;
        }
    }

    if (maxgain && (maxgain != (HW_GEN_CONTROL & 0x007F0000) >> 16))
    {
        uint32 mg = HW_GEN_CONTROL & 0xFF80FFFF;
        HW_GEN_CONTROL = mg | ((maxgain & 0x7F) << 16);
    }
}



uint8 naWifiStartHWGetBasicMeasureMap(void)
{
    return 0;           /* only implemented on Piper */
}


void naWifiStartHWBasicMeasure(void)
{
    /* This function is only implemented on Piper based platforms.*/
}

//
// Delay for usec microseconds
//
void naWifiWaitUS (uint32 usec)
{
	volatile int n = usec*timerLoops/10;

	while (n-- > 0)
		;
}

//
// Calibrate the spin loop in naWifiWaitUS()
//
// We need 10us resolution, but the threadx timer is only accurate to 10ms.
// Use it to calibrate a large number of iterations of the spin loop in naWifiWaitUS().
//
static void InitTimer (void)
{
	uint32 t; // time

	// Initial guess
	timerLoops = 500;

	// Time 100ms delay using hardware timer
	t = getTimeMS();
	naWifiWaitUS (100000);
	t = getTimeMS() - t;

	// Calculate loops for 100ms delay:
	// (initial guess)*(expected time)/(actual time)
	if (t != 0)
		timerLoops = 500*100/t;

#ifdef DEBUG
	DPRINTF ("time=%lu ms, loops=%lu\n", (long unsigned) t, (long unsigned) timerLoops);

	t = getTimeMS();
	naWifiWaitUS (100000);
	t = getTimeMS() - t;

	DPRINTF ("time=%lu ms (should be 100)\n", (long unsigned) t);
#endif
}

//
// Write data to an RF tranceiver register
// @param addr Register address (4 bits)
// @param data Data to write (20 bits, bit reversed)
//
static void WriteRF (uint8 addr, uint32 data)
{
	HW_SPI = (addr << 20) | data;
	naWifiWaitUS (10);
}

//
// Copy memory to/from hardware using 32-bit operations
//
static void HWMemcpy (volatile void *dst_, volatile void *src_, int len)
{
    if (((((unsigned) dst_) & 3) == 0) && ((((unsigned) src_) & 3) == 0))
    {
    	volatile uint32 *dst = (uint32 *) dst_;
    	volatile uint32 *src = (uint32 *) src_;

    	for (; len >= 16; len -= 16)
    	{
    		*dst++ = *src++;
    		*dst++ = *src++;
    		*dst++ = *src++;
    		*dst++ = *src++;
    	}
    	for (; len > 0; len -= 4)
    		*dst++ = *src++;
    }
    else if (len != 0)
    {
        memcpy((void *) dst_, (void *) src_, len);
    }
}

//
// Copy from receive FIFO
//
static void HWReadFifo (void *dst_, int len)
{
	uint32 *dst = (uint32 *) dst_;

	for (; len >= 16; len -= 16)
	{
		*dst++ = HW_DATA_FIFO;
		*dst++ = HW_DATA_FIFO;
		*dst++ = HW_DATA_FIFO;
		*dst++ = HW_DATA_FIFO;
	}
	for (; len > 0; len -= 4)
		*dst++ = HW_DATA_FIFO;
}

//
// Copy to transmit FIFO
//
static void HWWriteFifo (void *src_, int len)
{
	uint32 *src = (uint32 *) src_;

	for (; len >= 16; len -= 16)
	{
		HW_DATA_FIFO = *src++;
		HW_DATA_FIFO = *src++;
		HW_DATA_FIFO = *src++;
		HW_DATA_FIFO = *src++;
	}
	for (; len > 0; len -= 4)
		HW_DATA_FIFO = *src++;
}

//
// Copy from AES read FIFO
//
static void HWReadAES (void *dst_, int len)
{
	uint32 *dst = (uint32 *) dst_;

	while (len > 0)
		if (!(HW_RSSI_AES & AES_EMPTY))
		{
			*dst++ = HW_AES_FIFO;
			len -= 4;
		}
}

//
// Copy to AES write FIFO
//
static void HWWriteAES (void *src_, int len)
{
	uint32 *src = (uint32 *) src_;

	while (len > 0)
		if (!(HW_RSSI_AES & AES_FULL))
		{
			HW_AES_FIFO = *src++;
			len -= 4;
		}
}

//
// Wait for a PIO pin to be set
//
static BOOL WaitForPIO (int pin)
{
	uint32 t = getTimeMS();

	while (PIO_GET (pin) == 0)
	{
		if (getTimeMS() - t > LOAD_TIMEOUT)
			return FALSE;

        if (PIN_DONE == pin)
            *(volatile uint32 *)MAC_BASE = 0;
  }
	return TRUE;
}

//
// Load the baseband controller firmware
//
static MacReturn LoadHW (void)
{
	// Baseband firmware image
	extern const char bbfw_bin_data[];
	extern const int bbfw_bin_data_len;

	static BOOL loaded = FALSE;
	int i;

	// Load only once after reset
	if (loaded)
		return ERR_OK;

	//DPRINTF ("HW load\n");

	// Set up PIO pins for programming
	PIO_INPUT (PIN_INIT);
	PIO_INPUT (PIN_DONE);

    // CS3 is used to put the FPGA into program mode.
    // Map to MAC_PROG address, 32 bit width, 24 wait states.
	*NA_MPMCStaticConfig3_ADDRESS   = 0x82;
	*NA_MPMCStaticWaitWen3_ADDRESS  = 0;
	*NA_MPMCStaticWaitOen3_ADDRESS  = 0;
	*NA_MPMCStaticWaitRd3_ADDRESS   = 24;
	*NA_MPMCStaticWaitPage3_ADDRESS = 0;
	*NA_MPMCStaticWaitWr3_ADDRESS   = 24;
	*NA_MPMCStaticWaitTurn3_ADDRESS = 0;

	*NA_SCM_SMCS_STATIC_MEM_BASE(3) = MAC_PROG;
	*NA_SCM_SMCS_STATIC_MEM_MASK(3) = MAC_MASK;

	// Put FPGA into program mode
	*(volatile uint32 *)MAC_PROG = 0;

	// Disable CS3
	*NA_SCM_SMCS_STATIC_MEM_MASK(3) = 0;


	// Wait for FPGA to enter program mode
	if (!WaitForPIO (PIN_INIT))
		return ERR_LOAD;

    // CS2 is used for FPGA code download.
    // Map to MAC_BASE address, 32 bit width, 0 wait states.
	*NA_MPMCStaticConfig2_ADDRESS   = 0x82;
	*NA_MPMCStaticWaitWen2_ADDRESS  = 0;
	*NA_MPMCStaticWaitOen2_ADDRESS  = 0;
	*NA_MPMCStaticWaitRd2_ADDRESS   = 0;
	*NA_MPMCStaticWaitPage2_ADDRESS = 0;
	*NA_MPMCStaticWaitWr2_ADDRESS   = 0;
	*NA_MPMCStaticWaitTurn2_ADDRESS = 0;

	*NA_SCM_SMCS_STATIC_MEM_BASE(2) = MAC_BASE;
	*NA_SCM_SMCS_STATIC_MEM_MASK(2) = MAC_MASK;

	// Write each byte to LSB
	for (i = 0; i < bbfw_bin_data_len; i++)
		*(volatile uint32 *)MAC_BASE = bbfw_bin_data[i];

	// Wait for FPGA program complete
	if (!WaitForPIO (PIN_DONE))
		return ERR_LOAD;

	loaded = TRUE;
	return ERR_OK;
}

//
// Initialize the wireless hardware
//
MacReturn InitHW (void)
{
	int ret;
	epStatus *pSta = rootEndPoint[0];

	DPRINTF ("HW init\n");

	// Hardware supports 802.11b/g, channels 1-14, AES acceleration
	hwAES = TRUE;
	macParams.chan_mask[0] &= 0x3fff;
	macParams.chan_mask[1] = 0;
	if (macParams.band == WLN_BAND_B)
		macParams.options |= WLN_OPT_BONLY;

	// Minimum fragment size
	if (macParams.frag_thresh < MIN_FRAG_SIZE)
		macParams.frag_thresh = MIN_FRAG_SIZE;
	//if configured with an odd fragmentation threashhold, the device should
	//round down to the nearest even mumber Vantive #19867
	if (macParams.frag_thresh % 2)
		macParams.frag_thresh = macParams.frag_thresh - 1;

	// Max fragment size applies when more than one fragment.
	// Leave threshold possibly higher for single fragment.
	maxFragSize = macParams.frag_thresh;
	if (maxFragSize > MAX_FRAG_SIZE)
		maxFragSize = MAX_FRAG_SIZE;

    // Set RSSI average to a middle value so it
    // converges to its initial value faster
    pSta->macStatus.rx_signal = -50*RSSI_SCALE;

#if (BSP_WPS_ENABLED == TRUE)
    naWpsParamsInit(&macParams);
#endif

	InitTimer();

	// Load the baseband controller firmware
	ret = LoadHW();
	if (ret != ERR_OK)
		return (MacReturn)ret;

	// Configure PIO pins
	PIO_OUTPUT (PIN_LED);
	PIO_INTR (PIN_INTR);

    // CS2 is used for wireless baseband registers.
    // Map to MAC_BASE address, 32 bit width, 8 wait states.
	*NA_MPMCStaticConfig2_ADDRESS   = 0x82;
	*NA_MPMCStaticWaitWen2_ADDRESS  = 0;
	*NA_MPMCStaticWaitOen2_ADDRESS  = 2;
	*NA_MPMCStaticWaitRd2_ADDRESS   = 8;
	*NA_MPMCStaticWaitPage2_ADDRESS = 0;
	*NA_MPMCStaticWaitWr2_ADDRESS   = 4;
	*NA_MPMCStaticWaitTurn2_ADDRESS = 2;

	*NA_SCM_SMCS_STATIC_MEM_BASE(2) = MAC_BASE;
	*NA_SCM_SMCS_STATIC_MEM_MASK(2) = MAC_MASK;

	// Init baseband processor and MAC assist
	HW_GEN_CONTROL = GEN_INIT;
	intrMask = INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_RXOVERRUN;
	HW_INTR_MASK = intrMask;

	if (((HW_MAC_STATUS >> 16) & 0xff) >= 7)
	{
	    /*
	     * Make sure secondary MAC addresses are disabled and set to
	     * zero by default.
	     */
	    HW_MAC_CONTROL &= ~CTRL_MAC_FLTR;
		/* make sure addresses are zero to start with
		 * to insure we don't start with extraneous bits */
		HW_STA2ID0 = 0;
		HW_STA2ID1 = 0;
		HW_STA3ID0 = 0;
		HW_STA3ID1 = 0;
    }


	HWMemcpy (&HW_STAID0, macParams.sta_addr, WLN_ADDR_SIZE);

    // Transmit on primary antenna
    HW_RSSI_AES = 0x88000000;

	// Set anternna diversity if enabled
	if (macParams.options & WLN_OPT_ANTDIV)
		HW_GEN_CONTROL |= GEN_ANTDIV;

	// Initialize RF tranceiver
    WriteRF (7, 0x27ffe); // TEST register
    WriteRF (6, 0xf81ac); // Filter Register
    WriteRF (5, 0x19e4f); // Transmitter Gain -- Low power setting
    WriteRF (4, 0x0002b); // Receiver Gain
    WriteRF (3, 0x46662); // VCO Control -- Low power setting
	WriteRF (0, 0x27fdc /*0x25f9c*/); // Mode Control - Calibrate Filter
	naWifiWaitUS (10);

	MacSetTxPower (macParams.tx_power);

	// Install interrupt handler
	NAInstallIsr (INTR_ID, HandleIR, NULL);

    // Added so that calling wln_start() to restart the driver will re-enable the interrupt.
    NAEnableIsr (INTR_ID);

	return ERR_OK;
}

//
// Shutdown the wireless hardware
//
void ShutdownHW (void)
{
	DPRINTF ("HW shutdown\n");

	//HW_GEN_CONTROL = GEN_RESET; //this is causing the ccwi9c hang
	HW_GEN_CONTROL &= ~GEN_RXEN; //disable receiving
	HW_MAC_CONTROL = 0;
	HW_INTR_MASK = 0;

	NADisableIsr (INTR_ID);
}

//
// Select a channel
// @param channel Channel number: 1-14
//
void SetChannel (int channel)
{
    HW_GEN_CONTROL &= ~GEN_RXEN;

	// Set frequency divider for channel
    WriteRF (1, freqTable[channel].integer);
    WriteRF (2, freqTable[channel].fraction);

    // Filter Calibration
	WriteRF (0, 0x27fdc /*0x25f9c*/);
	naWifiWaitUS (10);

    // VCO Calibration
	WriteRF (0, 0x27fda /*0x25f9a*/);
	naWifiWaitUS (80);

	// Mode Control - RX/TX mode
	WriteRF (0, 0x27fd4 /*0x25f94*/);
	//allow the transceiver to settle in the new mode of operation
	naWifiWaitUS (10);

    HW_GEN_CONTROL |= GEN_RXEN;
	global_chan = channel;
}

/* jhl register an additional address for extra address filtering */

int HWSetFilterAddress(MacAddr staAddr)
{
	int rc = 0;
	unsigned int copyStaAddr[2] = {0, 0};

	// if ((HW_VERSION & 0xff) >= 7)
	/* Mike Shaffner says to use the revision at 0x60 */
	if (((HW_MAC_STATUS >> 16) & 0xff) >= 7)
	{
		/* see if extra address is set up yet */
		if (( HW_MAC_CONTROL &= CTRL_MAC_FLTR ) == 0)
		{
			/* make sure addresses are zero to start with
			 * to insure we don't start with extraneous bits */
			HW_STA2ID0 = 0;
			HW_STA2ID1 = 0;
			HW_STA3ID0 = 0;
			HW_STA3ID1 = 0;
		}
		/* copy to buffer to allow trailing bytes to be zeroed */
		memcpy((char *) copyStaAddr, staAddr, WLN_ADDR_SIZE);
		if (HW_STA2ID0 == 0)
		{
			HWMemcpy (&HW_STA2ID0, copyStaAddr, WLN_ADDR_SIZE);
		}
		else if (HW_STA3ID0 == 0)
		{
			unsigned int mac2[2];
			mac2[0] = HW_STA2ID0;
			mac2[1] = HW_STA2ID1;
			/* don't add the same address twice */
			if (memcmp((char *) &mac2, (char *) copyStaAddr, WLN_ADDR_SIZE))
				HWMemcpy (&HW_STA3ID0, copyStaAddr, WLN_ADDR_SIZE);
		}
		else
		{
			/* sorry -- no room at the inn */
			rc = -1;
		}
		if (rc == 0)
			HW_MAC_CONTROL |= CTRL_MAC_FLTR;
	}
	else
	{
		/* firmware doesn't support multiple address filters */
		/* Panic(); */
		rc = -2;
	}
	return rc;
}

//
// Set BSS mode and IDs
// @param bssCaps BSS capabilities, OR of CAP_xxx
// @param bssid ID of BSS to join or start
// @param ssid Service set ID
// @param ssid_len Service set ID length
// @param basic Basic rates, OR of WLN_RATE_xxx
// @param atim IBSS ATIM window size in TU
//
void SetBSS (int bssCaps, MacAddr bssid, uint8 *ssid, int ssid_len, uint16 basic, int atim)
{
	//__FIX_NULL_SSID_MEMORY_ACCESS == TRUE)
	unsigned char ssid_tmp[WLN_SSID_SIZE];
	int nr_ssid_bytes_to_output;

	if (ssid && ssid_len)
	{
		nr_ssid_bytes_to_output = ssid_len;
	}
	else
	{
		nr_ssid_bytes_to_output = 32;
		ssid_len = 0;
 		memset( ssid_tmp, 0, sizeof(ssid_tmp) );
 		ssid = &ssid_tmp[0];
 	}

	// Set BSSID in hardware
	HWMemcpy (&HW_BSSID0, bssid, WLN_ADDR_SIZE);

	// Set SSID and basic rates in hardware
	//HWMemcpy (&HW_SSID, ssid, ssid_len);
	//__FIX_NULL_SSID_MEMORY_ACCESS
	HWMemcpy (&HW_SSID, ssid, nr_ssid_bytes_to_output);

	HW_SSID_LEN = ssid_len |
		((basic & RATE_MASK_OFDM) << 20) |
		((basic & (RATE_MASK_PSK|RATE_MASK_CCK)) << 16);

	// IBSS mode
	if (bssCaps & CAP_IBSS)
	{
		// If starting IBSS, set beacon and ATIM intervals
		HW_CFP_ATIM = atim | (BEACON_INT << 16);

		// Write beacon frame to beacon buffer
		if (bcnFrame)
		{
			HW_GEN_CONTROL |= GEN_BEACEN;
			HWWriteFifo (&bcnFrame->frameHdr,
				sizeof(FrameHeader) + sizeof(PlcpHeader) + bcnFrame->length - FCS_SIZE);
			HW_GEN_CONTROL &= ~GEN_BEACEN;
		}

		// Set interrupt mask to enable TBTT and ATIM interrupts
		HW_INTR_STATUS = INTR_TBTT|INTR_ATIM; // clear
		intrMask |= INTR_TBTT|INTR_ATIM;      // enable
		HW_INTR_MASK = intrMask;

		// Enable IBSS mode
		HW_MAC_CONTROL |= CTRL_IBSS|CTRL_BEACONTX;
	}

	// ESS mode
	else
	{
		// Set interrupt mask to disable TBTT and ATIM interrupts
		intrMask &= ~(INTR_TBTT|INTR_ATIM); // disable
		HW_INTR_MASK = intrMask;

		// Disable IBSS mode
		HW_MAC_CONTROL &= ~(CTRL_IBSS|CTRL_BEACONTX);
	}
}

void SetPromiscuousMode(BOOLEAN enable)
{
    if (enable == TRUE)    // Enable PROMISC mode
    {
		HW_MAC_CONTROL |= CTRL_PROMISC;
	}

    else    //disable
    {
		HW_MAC_CONTROL &= ~CTRL_PROMISC;
	}
}

//
// Set the link status LED
// @param on TRUE to turn LED on
//
void SetLED (BOOL on)
{
	if (on)
		PIO_CLR (PIN_LED);
	else
		PIO_SET (PIN_LED);
}

//
// Set the link activity LED
// @param on TRUE to turn LED on
//
void SetActivityLED (BOOL on)
{
	if (on)
		PIO_CLR (PIN_ACTIVITY_LED);
	else
		PIO_SET (PIN_ACTIVITY_LED);
}

//
// Transmit a frame
// @param buf Frame to transmit
// @param cw Contention window size, 0 if no backoff
// @param next Next expected event, one of SF_xxx
//
void MacSendFrame (MacBuffer *buf, int cw, int next)
{
	CcmpData data;

	// Set backoff timer
	if (cw)
	{
		// Pick a random time up to cw, convert to usecs
		cw = 10*((int)wln_rand() & cw);
		if (buf->macHdr.fc.type == TYPE_BEACON)
		{
			// Beacon frame is already in beacon buffer.
			// Only set backoff timer here.
			HW_BEACON_BO = cw;

			// Simulate TxEnd
			HandleTxEnd();
			return;
		}
		else
			HW_BACKOFF = cw;
	}

	// Use short preamble?
	if (USE_SHORTPRE (buf->tx_rate))
		HW_GEN_CONTROL |= GEN_SHPRE;
	else
		HW_GEN_CONTROL &= ~GEN_SHPRE;

	// If expecting TxEnd, enable interrupt
	if (next == SF_TXEND)
		HW_INTR_MASK |= INTR_TXEND; // enable
	else
		HW_INTR_MASK &= ~INTR_TXEND; // disable

	// Use hardware AES if encrypted with AES
	if (hwAES && buf->macHdr.fc.protected && CcmpGetData (buf->macHdr.addr2, buf, &data))
	{
		while (HW_RSSI_AES & AES_BUSY)
			;

		// Prevent transmit until encrypted data is ready
		HW_GEN_CONTROL |= GEN_TXHOLD;

		// Write frame headers to transmit FIFO
		HWWriteFifo (&buf->frameHdr, 4*10);

		// Set transmit mode
		HW_AES_MODE = 0;

		// Write key, init block, headers to AES FIFO
		HWWriteAES (data.key->rd_key, 4*44);
		HWWriteAES (data.init, 4*12);

		// Write plaintext data to AES FIFO
		HWWriteAES (buf->body+EXTIV_SIZE, buf->length-DATA_SIZE-CCMP_SIZE);
		
		// Start transmit
		HW_GEN_CONTROL &= ~GEN_TXHOLD;

		XPRINTF(TRACE_CRITICAL, "WriteAES data frm %x plcp %x fc %x"
						    " addr2 " WLN_MACSTR "\n\r",
				buf->frameHdr.hdr32, buf->plcpHdr.plcp32,
		   		*(short *) &buf->macHdr.fc,
				WLN_MAC2STR(buf->macHdr.addr2));
	}

	else
	{
	    // Prevent transmit FIFO underrun
		HW_GEN_CONTROL |= GEN_TXHOLD;
		
		// Write frame to transmit FIFO, excluding FCS
		HWWriteFifo (&buf->frameHdr,
			sizeof(FrameHeader) + sizeof(PlcpHeader) + buf->length - FCS_SIZE);
			
		// Start transmit
		HW_GEN_CONTROL &= ~GEN_TXHOLD;
	}
}

//
// Handle an interrupt request
//
static int HandleIR (void *ignore)
{
    int gain;
	epStatus *pSta = rootEndPoint[0];

    (void)ignore;

	while (1)
	{
		// Get interrupt status
		uint32 intrStatus = HW_INTR_STATUS & intrMask;
		if (intrStatus == 0)
			break;

		// Handle errors
		if (intrStatus & (INTR_TIMEOUT|INTR_ABORT))
		{
			HandleMacError (intrStatus);

			// Clear txEnd after timeout
			HW_INTR_STATUS = INTR_TXEND;
			intrStatus &= ~INTR_TXEND;
		}
		if (intrStatus & INTR_RXOVERRUN)
			macStats.rxDropOverrun++;

		// Handle beacon/ATIM timer
		if (intrStatus & (INTR_TBTT|INTR_ATIM))
			HandleBeacon (intrStatus & INTR_TBTT);

		// Transmit complete
		if (intrStatus & INTR_TXEND)
			HandleTxEnd();

		// Received a frame
		if (intrStatus & INTR_RXFIFO)
		{
			// Read frames until FIFO empty
			while (!(HW_GEN_STATUS & STAT_RXFE))
			{
				// Get only the headers (up to MAC addr2 field).
				// This is enough to hold the smallest frame (ACK).
				// The rest is gotten by GetFrame() if needed.
				HWReadFifo (&rxFrame.frameHdr, 24);
#ifdef	WIFI_VERBOSE
				XPRINTF(TRACE_RECV, "from rx fifo frm %x plcp %x fc %x"
						" addr2 %02x:%02x:%02x:%02x:%02x:%02x\n\r",
					rxFrame.frameHdr.hdr32, rxFrame.plcpHdr.plcp32,
					*(unsigned short *) &rxFrame.macHdr.fc,
					rxFrame.macHdr.addr2[0], rxFrame.macHdr.addr2[1],
		   			rxFrame.macHdr.addr2[2], rxFrame.macHdr.addr2[3],
		   			rxFrame.macHdr.addr2[4], rxFrame.macHdr.addr2[5]);
#endif
                // Convert received signal strength to dbm
                rxFrame.rssi = (rxFrame.frameHdr.rx.rssiLNA << 5) | rxFrame.frameHdr.rx.rssiVGA;
                gain = lnaTable[rxFrame.frameHdr.rx.rssiLNA] + 2*rxFrame.frameHdr.rx.rssiVGA;
                if (gain > 96)
                    rxFrame.rx_signal = -98;
                else if (gain > 86)
                    rxFrame.rx_signal = gainTable[gain-87];
                else
                    rxFrame.rx_signal = 5-gain;

				// Add into average RSSI
				pSta->macStatus.rx_signal += rxFrame.rx_signal - pSta->macStatus.rx_signal/RSSI_SCALE;

				// Process the frame
				HandleRxEnd (&rxFrame);
			}
		}

		// Clear interrupts
		HW_INTR_STATUS = intrStatus;
	}

	return 0;
}

//
// Get the complete frame that is being received
// @param buf Buffer to copy frame into, length field contains frame size.
// length covers the MAC frame after the plcp header. The fifo contains
// the 8 additional bytes of the frame header and the plcp header.
//
BOOL GetFrame (MacBuffer *buf)
{
	CcmpData data;
	volatile uint32 tmp;

	// Copy data already read from rxFrame
	buf->rx_signal = rxFrame.rx_signal;
    buf->rssi = rxFrame.rssi;
	memcpy (&buf->frameHdr, &rxFrame.frameHdr, 24);

	// Use hardware AES if encrypted with AES
	if (hwAES && buf->macHdr.fc.protected && buf->length >= DATA_SIZE+CCMP_SIZE)
	{
		// Get rest of frame headers and init vector from receive FIFO
		HWReadFifo (buf->macHdr.addr3, 16);

		// Get AES key, init block, headers
		if (CcmpGetData (buf->macHdr.addr1, buf, &data))
		{
			while (HW_RSSI_AES & AES_BUSY)
				;
			// Set receive mode
			tmp = HW_AES_MODE;

			// Write key, init vector, headers to AES FIFO
			HWWriteAES (data.key->rd_key, 4*44);
			HWWriteAES (data.init, 4*12);

			// Get plaintext data from AES FIFO
			HWReadAES (buf->body+EXTIV_SIZE, buf->length-DATA_SIZE-CCMP_SIZE);

			while (HW_RSSI_AES & AES_BUSY)
				;

			// Check if MIC is correct
			if (!(HW_RSSI_AES & AES_MIC))
			{
				macStats.rxDropDecrypt++;
				macStats.rxDropMICFail++;
				return FALSE;
			}
		}

		// Not AES, get remaining data from receive FIFO
		else
			/* This 32 is hdr 24 + ext iv 8. The 24 becomes
			 * 30 if wds additional addr4 field len 6 is present. */
			HWReadFifo (buf->body+EXTIV_SIZE, buf->length-32);
	}

	// Get remaining data from receive FIFO
	else
		/* jhl this is "- 16" and not "- 24" because the 24 byte HWReadFifo
		 * includes the frame hdr and plcp hdr, while the length does not.
		 * If there is a WDS addr4 field, length will simply be longer.
		 */
		HWReadFifo (buf->macHdr.addr3, buf->length-16);

	return TRUE;
}

//
// Received frame is not needed, remove from FIFO
// @param length MAC frame size
//
void DropFrame (int length)
{
	volatile uint32 tmp;

	if (length <= HW_RX_FIFO_SIZE)
	{
		// First 16 bytes already read
		length -= 16;
		for (; length > 0; length -= 4)
			tmp = HW_DATA_FIFO;
	}
	else
	{
		// Length is unreasonable.
		// We might not be looking at the start of a frame.
		// Reset the receive FIFO.
		HW_GEN_CONTROL |=  GEN_RXFIFORST;
		HW_GEN_CONTROL &= ~GEN_RXFIFORST;
	}
}

#ifdef NET_OS_SPECIFIC
//
// Public function to load the FPGA image
//
int InitWirelessHw(void)
{
	if (LoadHW() != ERR_OK)
		return 1;
	else
		return 0;
}
#endif

//
// Convert a received signal strength value in dbm
// to a percentage value (0-100).
//
int MacGetSignalQuality (int dbm)
{
    int n;

    if (dbm == 0)
        return 0;

// Useful RSSI range in dbm
#define RSSI_LOW    (-90)
#define RSSI_HIGH   (-30)

    n = 100*(dbm-RSSI_LOW)/(RSSI_HIGH-RSSI_LOW);
    if (n < 0)
        n = 0;
    else if (n > 100)
        n = 100;

    return n;
}

//
// This is used to set the transmit power.
// Value is in dbm and will be limited to 0-15 dbm.
//
void MacSetTxPower(int value)
{
    epStatus *pSta = rootEndPoint[0];

    if (value < 0)
        value = 0;
    else if ((value > 10) && (macParams.band == WLN_BAND_B))
    	value = 10;
    else if (value > 15)
        value = 15;

    WriteRF (5, 0x19e40 | powerTable[value]);
    naDot11.currentTxPower = value;

    //update the status
    pSta->macStatus.tx_power = value;
}

//
// This is used to set the transmit power for tst_wifi.
// Value is in dbm and will be limited to 0-15 dbm.
//
void MacSetDirectTxPower(int value)
{
    if (value < 0)
        value = 0;
    else if (value > 15)
        value = 15;

    WriteRF (5, 0x19e40 | powerTable[value]);
    naDot11.currentTxPower = value;
}

#if BSP_RF_TESTING


/**
 * bss_save is a static scoped variable that contains the original BSS type.
 *
 * It is used to remember the BSS type when switching to a new test type.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 */
static wln_bss bss_save = WLN_BSS_NONE;

/**
 * fcc_txbuffer[] is a static scoped array that is used as the transmit buffer for testing the
 * continuous transmit FCC test.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 */
static unsigned char fcc_txbuffer[64];

#if 0 // unused
static unsigned char fcc_txbuffer2[36]={0x00,0x09,0x00,0x00,0x0a,0x04,0x00,0x01, \
	                                      0x08,0x00,0x00,0x00,0x00,0x22,0x33,0x44, \
	                                      0x55,0x66,0x10,0x20,0x30,0x40,0x50,0x60, \
	                                      0x10,0x20,0x30,0x40,0x50,0x60,0x00,0x00, \
	                                      0x05,0x55,0x55,0x00};
#endif

/**
 * radio_txbuffer[] is a static scoped array that is used as the transmit buffer for testing the
 * continuous transmit test.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 */
static unsigned char radio_txbuffer[1024];


/**
 * MacSetQuiet() is a function that is used to put the mac driver in a quiet mode where
 * no transmitting is done, but the FPGA is still running.  By disabling interrupts
 * the FPGA will not do any automatic acking of received data.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  enable_quiet
 *
 * @return none
 */

void MacSetQuiet(int enable_quiet)
{
     int level;
     epStatus *pSta = rootEndPoint[0];

    /* disable interrupts */
    level = DISABLE();

    if (enable_quiet)
    {
        /* disable the mac driver */
        pSta->macStatus.state = WLN_ST_STOPPED;

        /* disable continuous transmit */
        HW_GEN_STATUS = 0x30000000;

        /* disable mac interrupts except for rx */
        HW_INTR_MASK = INTR_RXFIFO;
    }
    else
    {
        /* enable common mac interrupts */
        HW_INTR_MASK |= INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

        /* re-enable the mac driver */
        pSta->macStatus.state = WLN_ST_SCANNING;
        pSta->staState = SS_WAIT;
    }

    /* enable interrupts */
    ENABLE(level);
}

/**
 * MacUpdateFccBuffer() is a function that is used to fill the fcc_txbuffer with random data
 * for the transmit test.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  transmit_mode
 * @param  transmit_rate
 *
 * @return none
 */

void MacUpdateFccBuffer(unsigned int transmit_mode, unsigned int transmit_rate)
{
    int i;

    switch (transmit_rate)
    {
    case 0:
        /* 1mpbs */
        fcc_txbuffer[0] = 0x00;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0a;
        break;

    case 1:
        /* 2mpbs */
        fcc_txbuffer[0] = 0x00;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x14;
        break;

    case 2:
        /* 5.5mpbs */
        fcc_txbuffer[0] = 0x00;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x37;
        break;

    case 3:
        /* 11mpbs */
        fcc_txbuffer[0] = 0x00;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x6e;
        break;

    /*OFDM */

    case 4:
        /* 6mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0B;
        break;

    case 5:
        /* 9mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0F;
        break;

    case 6:
        /* 12mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0A;
        break;

    case 7:
        /* 18mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0E;
        break;

    case 8:
        /* 24mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x09;
        break;

    case 9:
        /* 36mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0D;
        break;

    case 10:
        /* 48mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x08;
        break;

    case 11:
        /* 54mpbs */
        fcc_txbuffer[0] = 0xEE;
        fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0C;
        break;

    default:
    	fcc_txbuffer[0] = 0x00;
    	fcc_txbuffer[1] = 0x10;
        fcc_txbuffer[4] = 0x0a;
        break;
    }

    if (transmit_mode == 4)
    {
        /* for fcc transmit 01 pattern */
        for (i=5; i < 64; i++)
        {
            fcc_txbuffer[i] = 0xaa;
        }
    }
    else
    {
        for (i=5; i < 64; i++)
        {
            fcc_txbuffer[i] = (unsigned char )rand();
        }
    }

    /* copy to transmit buffer */
    //HWMemcpy (HW_TX_BUFFER, fcc_txbuffer, 64);
    HWWriteFifo (&fcc_txbuffer, 16);
}

/**
 * MacContinuousTransmit() is a function that puts the driver into continuous transfer mode.
 *
 * When doing so it attempts to shutdown normal driver functionality so the driver
 * will not interfere with the continuous transfer.
 *
 * @note I do not think
 * the process of shutting down the driver while enabling continous transfer
 * mode is completely void of interference, but I think it will work well
 * enough for FCC testing.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  enable
 * @param  transmit_mode
 * @param  transmit_rate
 *
 * @return none
 */

void MacContinuousTransmit(int enable, unsigned int transmit_mode, unsigned int transmit_rate)
{
    int level;
    uint32 data;
    epStatus *pSta = rootEndPoint[0];

    switch (transmit_mode)
    {
        case 0:
           /* random */
           data = 0x30100000;
           break;

        case 1:
            /* zeros */
            data = 0x30300000;
            //data = 0x30330000;  /*with scrambling and spreading disabled */
            break;

        case 2:
            /* ones */
            data = 0x30500000;
            break;

        case 3:
            /* Unmodulated signal, carrier only, continuous
            transmit.  Used for Japan emmissions testing. */
            data = 0x30700000;
            //data = 0x30730000; /*with scrambling and spreading disabled */
            break;

        case 4:
            /* FCC - continuous transmit, scramble disable, 010101...*/
            data = 0x30100000;
            break;

        default:
            data = 0x30100000;
            break;
    }


    /* disable interrupts */
    level = DISABLE();

    if (enable)
    {
        /* disable the mac driver */
        pSta->macStatus.state = WLN_ST_STOPPED;

        pSta->staState = SS_WAIT;
        bss_save = macParams.bss_type;
        macParams.bss_type = WLN_BSS_NONE;

        MacUpdateFccBuffer(transmit_mode, transmit_rate);

        /* disable mac interrupts */
        HW_INTR_MASK = 0;

        // Disable IBSS mode
		HW_MAC_CONTROL &= ~(CTRL_IBSS|CTRL_BEACONTX);

        if(3 == transmit_mode)
          //enable test mode of operation
          //HW_GEN_CONTROL = 0x93780001;
          HW_GEN_CONTROL |= GEN_TESTMODE;

        /* set to continuous transmit; test bit too */
        HW_GEN_STATUS = data;

        /* start transmiting */
        HW_MAC_CONTROL = CTRL_TXREQ;
    }
    else
    {
        /* disable continuous transmit */
        switch(transmit_mode)
        {
        	case 0:
        		HW_GEN_STATUS = 0x30000000;
        		break;

        	case 1:
        		HW_GEN_STATUS = 0x30200000;
        		break;

        	case 2:
        		HW_GEN_STATUS = 0x30400000;
        		break;

        	case 3:
                //restore normal mode of operation
                //CC HW_GEN_CONTROL = 0x13780001;
                HW_GEN_STATUS = 0x30000000;
                HW_GEN_CONTROL &= ~GEN_TESTMODE;
         		break;

        	case 4:
        	    HW_GEN_STATUS = 0x30000000;
        		break;

        	default:
                HW_GEN_STATUS = 0x30000000;
        		break;
        }

        macParams.bss_type = bss_save;
        pSta->macStatus.state = WLN_ST_SCANNING;


        /* enable common mac interrupts */
        HW_INTR_MASK |= INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;
    }

    /* enable interrupts */
    ENABLE (level);
}

/**
 * MacRadioPrepareTXBeacon() is a function that transmits a beacon test frame
 * with a period specified by the caller.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  tx_frame_period
 *
 * @return none
 */

void MacRadioPrepareTXBeacon(unsigned int tx_frame_period)
{
    /* set frame interval to tx_frame_period */
    HW_CFP_ATIM = (tx_frame_period << 16);

    /* enable beacon transmission */
    HW_GEN_CONTROL |= GEN_BEACEN;
}

/**
 * MacRadioTXRandomBuffer() is a function that builds a test frame of
 * 128 or 1024 bytes in length.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  transmit_rate
 * @param  tx_frame_length
 *
 * @return none
 */

void MacRadioTXRandomBuffer( unsigned int transmit_rate, unsigned int tx_frame_length)
{
    int i;

    switch (transmit_rate)
    {
    case 0:
        /* 1mpbs */

        /* modulation type = 0x00; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0x00;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0a; length of 1,024 bytes frame in usecs = 0x2000 */
        radio_txbuffer[4] = 0x0a;
        radio_txbuffer[5] = 0x04;

        if(!tx_frame_length)
	      {
           radio_txbuffer[6] = 0x00;
           radio_txbuffer[7] = 0x20;
        }
        else
	      {
           radio_txbuffer[6] = 0xe8;
           radio_txbuffer[7] = 0x03;
        }

        break;

     case 1:
        /* 2mpbs */

        /* modulation type = 0x00; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0x00;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x14; length of 1,024 bytes frame in usecs = 0x1000 */
        radio_txbuffer[4] = 0x14;
        radio_txbuffer[5] = 0x04;

        if(!tx_frame_length)
	      {
          radio_txbuffer[6] = 0x00;
          radio_txbuffer[7] = 0x10;
	      }
	      else
	      {
          radio_txbuffer[6] = 0xF4;
          radio_txbuffer[7] = 0x01;
        }
        break;

    case 2:
        /* 5.5mpbs */

        /* modulation type = 0x00; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0x00;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x37; length of 1,024 bytes frame in usecs = 0x0661 */
        radio_txbuffer[4] = 0x37;
        radio_txbuffer[5] = 0x04;

        if(!tx_frame_length)
	      {
          radio_txbuffer[6] = 0x61;
          radio_txbuffer[7] = 0x06;
        }
	      else
	      {
          radio_txbuffer[6] = 0xB5;
          radio_txbuffer[7] = 0x00;
        }

        break;

    case 3:
        /* 11mpbs */

        /* modulation type = 0x00; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0x00;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x6e; length of 1,024 bytes frame in usecs = 0x02e8 */
        radio_txbuffer[4] = 0x6e;
        radio_txbuffer[5] = 0x04;

        if(!tx_frame_length)
	      {
          radio_txbuffer[6] = 0xe8;
          radio_txbuffer[7] = 0x02;
	      }
	      else
	      {
          radio_txbuffer[6] = 0x5A;
          radio_txbuffer[7] = 0x00;
	      }
        break;

    /*OFDM */

    case 4:
        /* 6mpbs */

        /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0B;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 5:
        /* 9mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0F;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 6:
        /* 12mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0A;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 7:
        /* 18mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0E;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 8:
        /* 24mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x09;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 9:
        /* 36mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0d;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 10:
        /* 48mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x08;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;

    case 11:
        /* 54mpbs */

       /* modulation type = 0xEE; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0xEE;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

        /*data rate identifier = 0x0B; length of 1,024 bytes frame in bytes = 0x80 */
        radio_txbuffer[4] = 0x0c;

        if(!tx_frame_length)
          radio_txbuffer[5] = 0x80;
        else
          radio_txbuffer[5] = 0x10;

        radio_txbuffer[6] = 0x00;
        radio_txbuffer[7] = 0x00;
        break;


    default:

    	  /* modulation type = 0x00; no of ensuing 32bits words = 0x01 */
        radio_txbuffer[0] = 0x00;
        radio_txbuffer[1] = 0x01;
        radio_txbuffer[2] = 0x00;
        radio_txbuffer[3] = 0x00;

       /*data rate identifier = 0x0a; length of 1,024 bytes frame in usecs = 0x2000 */
        radio_txbuffer[4] = 0x0a;
        radio_txbuffer[5] = 0x04;

        if(!tx_frame_length)
	      {
          radio_txbuffer[6] = 0x00;
          radio_txbuffer[7] = 0x20;
	      }
	      else
	      {
          radio_txbuffer[6] = 0xe8;
          radio_txbuffer[7] = 0x03;
	      }
       break;
    }
/* Added Mike's beacon_data */
    radio_txbuffer[8] = 0x08;
    radio_txbuffer[9] = 0x0;
    radio_txbuffer[10] = 0x0;
    radio_txbuffer[11] = 0x0;
    radio_txbuffer[12] = 0x0;
    radio_txbuffer[13] = 0x22;
    radio_txbuffer[14] = 0x33;
    radio_txbuffer[15] = 0x44;
    radio_txbuffer[16] = 0x55;
    radio_txbuffer[17] = 0x66;
    radio_txbuffer[18] = 0x10;
    radio_txbuffer[19] = 0x20;
    radio_txbuffer[20] = 0x30;
    radio_txbuffer[21] = 0x40;
    radio_txbuffer[22] = 0x50;
    radio_txbuffer[23] = 0x60;
    radio_txbuffer[24] = 0x10;
    radio_txbuffer[25] = 0x20;
    radio_txbuffer[26] = 0x30;
    radio_txbuffer[27] = 0x40;


   for (i=28; i < 128; i++)
    {
        radio_txbuffer[i] = 0x0;
    }

    /* fill the rest of the frame with random data */
    for (i=128; i < 1023; i++)
    {
        radio_txbuffer[i] = (unsigned char )wln_rand();
    }

    /* copy 2 words of data to the transmit buffer, length in bytes! */
    HWWriteFifo (&radio_txbuffer, 128);

#if OLD_RF_TEST_CODE
    /* fill the rest of the frame with random data */
    for (i=8; i < 1023; i++)
    {
        radio_txbuffer[i] = (unsigned char )wln_rand();
    }

    /* copy 2 words of data to the transmit buffer, length in bytes! */
    HWWriteFifo (&radio_txbuffer, 8);
#endif  //if 0
}

/**
 * MacRadioTXBeacon() is a function that starts a beacon test, or terminates an existing test.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  enable           0 = terminate existing test, non-zero = start new beacon test
 * @param  transmit_rate
 * @param  tx_frame_period
 * @param  tx_frame_length
 *
 * @return none
 */

void MacRadioTXBeacon(int enable, unsigned int transmit_rate, unsigned int tx_frame_period, unsigned int tx_frame_length)
{
    int level;
    epStatus *pSta = rootEndPoint[0];

    /* disable interrupts */
    level = DISABLE();

    if (enable)
    {
        /* disable the mac driver */
        bss_save = macParams.bss_type;
        macParams.bss_type = WLN_BSS_NONE;
        pSta->staState = SS_WAIT;

	    MacRadioPrepareTXBeacon(tx_frame_period);

        MacRadioTXRandomBuffer(transmit_rate, tx_frame_length);

         /* disable mac interrupts */
        HW_INTR_MASK = 0;

		/* set ad-hoc mode of operation */
		HW_MAC_CONTROL |= (CTRL_IBSS|CTRL_BEACONTX);

    }
    else
    {
		HW_MAC_CONTROL &= ~(CTRL_IBSS|CTRL_BEACONTX);
		HW_GEN_CONTROL &= ~GEN_BEACEN;

        /* enable common mac interrupts */
        HW_INTR_MASK |= INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

        macParams.bss_type = bss_save;
        pSta->staState = SS_WAIT;
    }

    /* enable interrupts */
    ENABLE (level);
}

/**
 * MacRadioRXTest() is a function that is used to put the mac driver in a
 * quiet mode where no transmitting is done, but the FPGA is still running.
 *
 * @note It is my hope that by disabling interrupts the FPGA will not do any automatic
 * acking of received data.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  enable           0 = terminate existing test, non-zero = start new beacon test
 * @param  rx_frames
 *
 * @return none
 */

void MacRadioRXTest(int enable, uint32* rx_frames)
{
    int level;
    epStatus *pSta = rootEndPoint[0];

    /* disable interrupts */
    level = DISABLE();

    if (enable)
    {

         /* disable the mac driver */
         bss_save = macParams.bss_type;
         macParams.bss_type = WLN_BSS_NONE;
             pSta->staState = SS_WAIT;

         memset (&macStats, 0, sizeof macStats);

         SetPromiscuousMode(TRUE);
         MacSetQuiet(1);
     }
    else
    {
         SetPromiscuousMode(FALSE);
         *rx_frames = (uint32) macStats.rxFrames;

         MacSetQuiet(0);

        macParams.bss_type = bss_save;
        pSta->staState = SS_WAIT;
    }

    /* enable interrupts */
    ENABLE(level);
}

/**
 * MacWriteRF() is a function that writes a RF register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  addr       register address in RX transceiver (4-bits)
 * @param  data       data to be written
 *
 * @return none
 */

void MacWriteRF(uint8 addr, uint32 data)
{
    WriteRF(addr, data);
}

/**
 * MacReadRF() is a function that reads a RF register (Not used)
 *
 * RF registers cannot be read. This function is unused.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param  addr       register address in RX transceiver (4-bits)
 * @param  data       pointer to unsigned long data variable to receive data from register
 *
 * @return none
 */

void MacReadRF(uint8 addr, uint32 *data)
{
   /* RF registers cannot be read */
   addr = addr;
  *data = *data;
}

/**
 * MacWriteReg8() is a function that writes an unsigned char value to a hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to write (unsigned int)
 * @param   data      unsigned char value to be written to hardware register
 */

void MacWriteReg8(unsigned int offset, uint8 data)
{
    /* Not supported */
    //    REG8(offset) = data;

   (void) offset;
   (void) data;
}

/**
 * MacReadReg8() is a function that reads and returns an unsigned char
 * hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to read (unsigned int)
 *
 * @retval  value     unsigned char value of hardware register
 */

uint8 MacReadReg8(unsigned int offset)
{
   /* Not supported */
   (void) offset;

#if 0
    uint8 data;

    data = REG8(offset);
    return data;
#endif

    return 0xFF;
}

/**
 * MacWriteReg16() is a function that writes an unsigned short value to a hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to write (unsigned int)
 * @param   data      unsigned short value to be written to hardware register
 */

void MacWriteReg16(unsigned int offset, uint16 data)
{
    REG16(offset) = data;
}

/**
 * MacReadReg16() is a function that reads and returns an unsigned short
 * hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to read (unsigned int)
 *
 * @retval  value     unsigned short value of hardware register
 */

uint16 MacReadReg16(unsigned int offset)
{
    uint16 data;

    data = REG16(offset);
    return data;
}

/**
 * MacWriteReg32() is a function that writes an unsigned long value to a hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to write (unsigned int)
 * @param   data      unsigned long value to be written to hardware register
 */

void MacWriteReg32(unsigned int offset, uint32 data)
{
  REG32(offset) = data;
}

/**
 * MacReadReg32() is a function that reads and returns an unsigned long
 * hardware register.
 *
 * @ingroup digitest
 * @version 1.0
 * @since 1.0
 *
 * @param   offset    offset from controller base (MAC_BASE) of register to read (unsigned int)
 *
 * @retval  value     unsigned long value of hardware register
 */

uint32 MacReadReg32(unsigned int offset)
{

   uint32 data = 0;
   data = REG32(offset);

   return data;
}

#endif /* End RF testing */

#ifdef FCC_ENABLED // TODO

//
// This function is used to put the mac driver in a quiet mode where
// no transmitting is done, but the FPGA is still running.  It is my
// hope that by disabling interrupts the FPGA will not do any automatic
// acking of received data.
//
void MacSetQuiet(int enable_quiet)
{
    int level;

    /* disable interrupts */
    level = DISABLE();

    if (enable_quiet)
    {
        /* disable the mac driver */
        macStatus.state = WLN_ST_STOPPED;
	XPRINTF(TRACE_INFO, "macStatus.state -> %s\n\r", macStatusState[macStatus.state]);

        //fcc_transmit_disabled = 1;

        /* disable mac interrupts */
        HW_INTR_MASK = 0;
    }
    else
    {
        //fcc_transmit_disabled = 0;

        /* enable common mac interrupts */
        HW_INTR_MASK |= INTR_RXEND|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

        /* enable the mac driver */
        macStatus.state = WLN_ST_SCANNING;
	XPRINTF(TRACE_INFO, "macStatus.state -> %s\n\r", macStatusState[macStatus.state]);
        staState = SS_WAIT;
	XPRINTF(TRACE_INFO, "staState -> %s\n\r", textStaState[staState]);
    }

    /* enable interrupts */
    ENABLE(level);
}

// This buffer is used as the transmit buffer for testing the
// continuous transmit FCC test.
static unsigned char fcc_txbuffer[64];

//
// This function is used to fill the fcc_txbuffer with random data
// for the transmit test.
//
void MacUpdateFccBuffer(unsigned int transmit_mode, unsigned int transmit_rate)
{
    int i;

    switch (transmit_rate)
    {
    case 0:
        /* 1mpbs */
        fcc_txbuffer[0] = 0x0a;
        break;

    case 1:
        /* 2mpbs */
        fcc_txbuffer[0] = 0x14;
        break;

    case 2:
        /* 5.5mpbs */
        fcc_txbuffer[0] = 0x37;
        break;

    case 3:
        /* 11mpbs */
        fcc_txbuffer[0] = 0x6e;
        break;

    default:
        fcc_txbuffer[0] = 0x0a;
        break;
    }

    if (transmit_mode == 4)
    {
        /* for fcc transmit 01 pattern */
        for (i=1; i < 64; i++)
        {
            fcc_txbuffer[i] = 0xaa;
        }
    }
    else
    {
        for (i=1; i < 64; i++)
        {
            fcc_txbuffer[i] = (unsigned char )wln_rand();
        }
    }

    /* copy to transmit buffer */
    HWMemcpy (HW_TX_BUFFER, fcc_txbuffer, 64);
}

//
// This function puts the driver into continuous transfer mode.  When doing
// so it attempts to shutdown normal driver functionality so the driver
// will not interfere with the continuous transfer.  However I do not think
// the process of shutting down the driver while enabling continous transfer
// mode is completely void of interference, but I think it will work well
// enough for FCC testing.
//
void MacContinuousTransmit(int enable, unsigned int transmit_mode, unsigned int transmit_rate)
{
    int level;
    uint8 data;

    switch (transmit_mode)
    {
    case 0:
        /* random */
        data = 0x4;
        break;

    case 1:
        /* zeros */
        data = 0x14;
        break;

    case 2:
        /* ones */
        data = 0x24;
        break;

    case 3:
        /* Unmodulated signal, carrier only, continuous
           transmit.  Used for Japan emmissions testing. */
        data = 0x17;
        break;

    case 4:
        /* FCC - continuous transmit, scramble disable, 010101...*/
        data = 0x06;
        break;

    default:
        data = 0x4;
        break;
    }


    /* disable interrupts */
    level = DISABLE();

    if (enable)
    {
        /* disable the mac driver */
        macStatus.state = WLN_ST_STOPPED;
	XPRINTF(TRACE_INFO, "macStatus.state -> %s\n\r", macStatusState[macStatus.state]);

        MacUpdateFccBuffer(transmit_mode, transmit_rate);

        /* disable mac interrupts */
        HW_INTR_MASK = 0;

        /* set to continuous transmit */
        HW_TEST_MODE = data;

        /* start transmiting */
        HW_MAC_CONTROL = CTRL_TXREQ;
    }
    else
    {
        /* clear test mode */
        HW_TEST_MODE = 0x0;

        /* enable common mac interrupts */
        HW_INTR_MASK |= INTR_RXEND|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

        macStatus.state = WLN_ST_SCANNING;
	XPRINTF(TRACE_INFO, "macStatus.state -> %s\n\r", macStatusState[macStatus.state]);
        staState = SS_WAIT;
	XPRINTF(TRACE_INFO, "staState -> %s\n\r", textStaState[staState]);
    }

    /* enable interrupts */
    ENABLE (level);
}

void MacWriteRF(uint8 addr, uint32 data)
{
    uint8 data0;
    uint8 data1;
    uint8 data2;

    data0 = data & 0xff;
    data1 = (data >> 8) & 0xff;
    data2 = (data >> 16) & 0xff;

    HW_SSI_ADDR  = addr | SSI_ADDR_WR;

    HW_SSI_DATA0 = data0;
    HW_SSI_DATA1 = data1;
    HW_SSI_DATA2 = data2;
    naWifiWaitUS (50);
}

void MacReadRF(uint8 addr, uint32 *data)
{
    uint8 data0;
    uint8 data1;
    uint8 data2;

    addr &= ~SSI_ADDR_WR;

    HW_SSI_ADDR  = addr;
    naWifiWaitUS(50);
    data0 = HW_SSI_DATA0;
    data1 = HW_SSI_DATA1;
    data2 = HW_SSI_DATA2;

    *data = ((uint32)data0) | (((uint32)data1) << 8) | (((uint32)data2) << 16);
}

void MacWriteReg8(unsigned int offset, uint8 data)
{
    REG8(offset) = data;
}

uint8 MacReadReg8(unsigned int offset)
{
    uint8 data;

    data = REG8(offset);
    return data;
}

void MacWriteReg16(unsigned int offset, uint16 data)
{
    REG16(offset) = data;
}


uint16 MacReadReg16(unsigned int offset)
{
    uint16 data;

    data = REG16(offset);
    return data;
}

#endif /* FCC_ENABLED */

