/*
 *  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 ConnectCorewi9p9215 and Connectwiem9210
// Copyright 2008 Digi International
//

#include "mac.h"
#include "reg_def.h"
#ifdef NDS_SPECIFIC
#include "pll.h"
#endif 
#include "country_codes.h"

#ifdef NET_OS_SPECIFIC
#include "npttypes.h"
#include "nagpio.h"
#if (PLATFORM == connectcorewi9c_b) || (defined MAC_PS_ENABLED)
#include "processorgpio.h"
#endif
#include "bsp_net.h"
#if (BSP_WPS_ENABLED == TRUE)
#include "mac_wps.h"
#endif

#else
#include "bcomm.h"
#endif

#if AIROHA_PWR_CALIBRATION
#include "airoha_pwr_cal.h"
#endif

#define RF_AIROHA_7230 0
#define RF_AIROHA_2236 1
#define RF_MAXIM_2829  2
#define RF_UBEC_2453   3

#define RF_24GHZ 0
#define RF_50GHZ 1

// in cconnectcorewi9p9215_a the power control pin is tied to GPIO 92
#if (PROCESSOR == ns9215)
#define WLN_PS_CNTRL_PIN    92
#elif (PROCESSOR == ns9210)
#define WLN_PS_CNTRL_PIN    106         // A26
#endif

#if (PLATFORM == connectcorewi9c_b) || (defined MAC_PS_ENABLED)
#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)
#endif

#if AIROHA_TRANSCEIVER
#if (PROCESSOR == ns9210)
#if AIROHA_PWR_CALIBRATION
int AIROHA_PWR_SETTING = AIROHA_PWR_SETTING_AL2236;
#endif
int rf_chip = RF_AIROHA_2236;
BOOLEAN isRF_AIROHA_7230(void);
#define CLOCK_ENABLE_GPIO       (43)
#define PIPER_RESET_GPIO        (106)
#include "gpiomux_def.h" 
#else
int rf_chip = RF_AIROHA_7230; 
#if AIROHA_PWR_CALIBRATION
int AIROHA_PWR_SETTING = AIROHA_PWR_SETTING_AL7230;
#endif
#endif
void InitializeRF(int chip_selection, int band_selection);
static int rf_band = RF_24GHZ;
static BOOLEAN isOFDM = FALSE;  //this is used for tst_wifi power control
#endif


//
// Hardware register defines
//
#if (PROCESSOR == ns9210)

#define MAC_BASE		0x40000000		// Register base address
#define MAC_CTRL_BASE   (volatile uint32 *) (MAC_BASE + (0x40))
#define	REG32(offset)	(* (volatile uint32 *) (MAC_BASE + (offset)))

#else

#if (PLATFORM == connectcorewi9c_b)
#define MAC_BASE		0x60000000		// Register base address (SCS2)
#define MAC_CTRL_BASE   (volatile uint32 *) (MAC_BASE + (0x40*4))
#define	REG32(offset)	(* (volatile uint32 *) (MAC_BASE + (offset)*4))
#else
#define MAC_BASE		0x70000000		// Register base address
#define MAC_CTRL_BASE   (volatile uint32 *) (MAC_BASE + (0x40))
#define	REG32(offset)	(* (volatile uint32 *) (MAC_BASE + (offset)))
#endif

#endif

#define MAC_MASK		0xffffc001		// Size mask and enable bit

// 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_SPI_CTRL     REG32(0x1C)		// RF SPI control
#define	HW_DATA_FIFO	REG32(0x20)		// Data FIFO
//CC CAT rev2
#define	HW_TRACK_CONTROL REG32(0x28)		// frequency-band specific tracking constant
//CC CAT rev2
#define HW_CONF1        REG32(0x28)		// Configuration 1
#define HW_CONF2        REG32(0x2C)		// Configuration 2
#define	HW_AES_FIFO		REG32(0x30)		// AES FIFO
#define	HW_AES_MODE		REG32(0x38)		// ARS mode
#define HW_OUT_CTRL     REG32(0x3C)     //Output control


// 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_MEASURE      REG32(0x60)     // Measure register is in bits 4-6
#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

// Measurement bits
#define HW_MEASUREMENT_BSS              (1 << 4)
#define HW_MEASUREMENT_PREAMBLE         (1 << 5)
#define HW_MEASUREMENT_UNIDENTIFIED     (1 << 6)
#define HW_MEASUREMENT_MASK             (0x00000030)


#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)

#define DSP_LOAD_ENABLE             0x00000400          //1 << 10
#define MACASSIST_LOAD_ENABLE       0x00000200          //1 << 9
#define DSP_MACASSIST_ENABLE        0x00000800          //1 << 11

// 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

#if AIROHA_TRANSCEIVER
#define	GEN_TESTMODE	0x80000000		// Test mode of operation 
#define	GEN_PA_ON	    0x02000000		// 0 = 5.0Ghz PA; 1 = 2.4Ghz PA (Airoha AL7230)

#define CONT_TX 0x00100000                     //Piper continuous transmit, in General status Register
#define TX_CTL  0x00006000			//Piper, tansmit control value, 11 DAC data is positive DC

/*
 * STAT_B_EN is a constant that defines a bit in the Wireless Controller FPGA Baseband Control Register
 * for General Status, which enables the PSK/CCK receiver baseband circuitry (802.11b receiver).
 * STAT_A_EN is a constant that defines a bit in the Wireless Controller FPGA Baseband Control Register
 * for General Status, which enables the OFDM receive baseband circuitry (802.11a receiver).
 */

#define STAT_B_EN		0x10000000      // B EN (PSK/CCK)
#define STAT_A_EN		0x20000000      // A EN (OFDM)

//CC CAT rev2
#define TRACK_BG_BAND           0x00430000     // Tracking constant for 802.11 b/g frequency band
#define TRACK_4920_4980_A_BAND  0x00210000     // Tracking constant for 802.11 a sub-frequency band
#define TRACK_5150_5350_A_BAND  0x001F0000     // Tracking constant for 802.11 a sub-frequency band
#define TRACK_5470_5725_A_BAND  0x001D0000     // Tracking constant for 802.11 a sub-frequency band
#define TRACK_5725_5825_A_BAND  0x001C0000     // Tracking constant for 802.11 a sub-frequency band
//CC CAT rev2
#endif

#define	GEN_RESET		0x527f0000		// Reset state

#if AIROHA_TRANSCEIVER
#define	GEN_INIT		0x37720005		    // Initial state; this was used for ubec chip
#define	GEN_INIT_MAXIM	0x37780005		    //  Initial state; PA_ON= active low; bit 25
/* 
 * For AL7230 :     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.
 *
 * For AL2236 :     Before association, BG band, use 0x7B
 *                  After association, , BG band, use no less than 0x76 
 */
#define	GEN_INIT_AIROHA_24GHZ_AL2236	0x317B0005	//  Initial state; 2.4GHZ_PA_ON= active low; bit 25
#define	GEN_INIT_AIROHA_24GHZ_AL7230	0x31780005	//  Initial state; 2.4GHZ_PA_ON= active low; bit 25
#define	GEN_INIT_AIROHA_50GHZ_AL7230	0x33770008	// Initial state; 5.0GHZ_PA_ON= active high; bit 25
#define	SPI_INIT_MAXIM	0x00000012          //  MAXIM-specific SPI length
#define	SPI_INIT_AIROHA	0x00000018          //  AIROHA-specific SPI length  
#define	SPI_INIT_AIROHA2236	0x00000014          //  AIROHA 2236-specific SPI length  
#define HW_SPI_CONTROL  REG32(0x1c)         //  SPI control baseband register
#else
#define	GEN_INIT		0x37780005		// Initial state
#endif

// 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

// Powersave register index
#define	INDX_GEN_CONTROL    0		// General control
#define	INDX_GEN_STATUS	    1		// General status
#define	INDX_RSSI_AES		2		// RSSI and AES status
#define	INDX_INTR_MASK	    3		// Interrupt mask
#define INDX_SPI_CTRL       4		// RF SPI control
#define INDX_CONF1          5		// Configuration 1
#define INDX_CONF2          6		// Configuration 2
#define	INDX_AES_MODE		7		// ARS mode
#define INDX_OUT_CTRL       8       // Output control
#define INDX_MAC_CONTROL    9       // MAC control
#define INDX_TOTAL          10

#ifdef FCC_ENABLED
#define	INTR_RXEND		0x00000001		//  Receive FIFO not empty
int HW_TEST_MODE = 0;
int HW_TX_BUFFER[2000];
#define HW_SSI_ADDR   REG32(0x10)
#define SSI_ADDR_WR   REG32(0x14)
#define HW_SSI_DATA0   REG32(0x18)
#define HW_SSI_DATA1   REG32(0x18)
#define HW_SSI_DATA2   REG32(0x18)
#define	REG16(offset)	(* (volatile uint16 *) (MAC_BASE + (offset)))  
#define REG8(offset)	(* (volatile uint8  *) (MAC_BASE + (offset) + 1)) 
#endif

#if BSP_RF_TESTING
#define	REG16(offset)	(* (volatile uint16 *) (MAC_BASE + (offset)))  
#endif
//
// PIO pins
//

#if AIROHA_TRANSCEIVER
#define PIN_LED			PIN_INIT     		// Link status LED
#else
#define PIN_LED			PIN_INIT
#endif

#if (PROCESSOR == ns9210)

#define INTR_ID			EXTERNAL1_INTERRUPT	//external interupt 1, active high

#else

#if (PLATFORM == connectcorewi9c_b)
#define INTR_ID			ETH_PHY_INTERRUPT	// Piper Interrupt ID
#define PIN_PIPER_RST 58              // 0 = reset state; 1 = operational state
#define PIN_PIPER_INTERRUPT 65        // GPIO 65 is used to interrupt the host processor 
#else
#define INTR_ID			EXTERNAL0_INTERRUPT	//external interupt 0, active high
#endif

#endif

#if AIROHA_TRANSCEIVER
#if  (AIROHA_PWR_CALIBRATION != 1)
// 1dBm-16dBm power levels. Configurable levels: 6,8,10,12,14,16 dBm  
//this is constructed by Claudio's UNIT16 54mbps data
static uint8 powerTable_2236[] = {
    4, 10, 10, 18, 22, 22, 28, 28,
    33, 33, 36, 38, 40, 43, 45, 47, 47
};  /* AL2236 */


// 1dBm-16dBm power levels. Configurable levels: 6,8,10,12,14,16 dBm
// CC CAT rel2
static uint8 powerTable_7230[] = {
    0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x1c, 0x29,
    0x20, 0x29, 0x24, 0x29, 0x29, 0x29, 0x2c, 0x30, 0x30
};  /* AL7230 */

#if 0
// 1dBm-16dBm power levels. Configurable levels: 6,8,10,12,14,16 dBm
static uint8 powerTable_7230[] = {
    3, 7, 11, 15, 19, 23, 27, 31,
    35, 39, 43, 47, 51, 55, 59, 63
};  /* AL7230 */
#endif

// MAXIM RF transceiver transmitter gain values for each power level.
// 0dBm-15dBm power levels. Configurable levels: 6,8,10,12,15 dBm
// All other levels are set to 12dBm (0x29) for the time being. 
static uint8 powerTable[] = {
    0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x1c, 0x29,
    0x20, 0x29, 0x24, 0x29, 0x29, 0x29, 0x2c, 0x30
};
#endif //#ifndef AIROHA_PWR_CALIBRATION


// AIROHA specific RF transceiver frequency divider for each channel
static const struct {
    uint32 integer;
    uint32 fraction;
} freqTableAiroha_2236[] = {
    { 0, 0 },
    // 2.4 GHz band (802.11b/g), 20MHz XO, 2.8V +/- 0.1V
    { 0x01F79, 0x03333 }, // 1  (2412 MHz)
    { 0x01F79, 0x0B333 }, // 2  (2417 MHz)
    { 0x01E79, 0x03333 }, // 3  (2422 MHz)
    { 0x01E79, 0x0B333 }, // 4  (2427 MHz)
    { 0x01F7A, 0x03333 }, // 5  (2432 MHz)
    { 0x01F7A, 0x0B333 }, // 6  (2437 MHz)
    { 0x01E7A, 0x03333 }, // 7  (2442 MHz)
    { 0x01E7A, 0x0B333 }, // 8  (2447 MHz)
    { 0x01F7B, 0x03333 }, // 9  (2452 MHz)
    { 0x01F7B, 0x0B333 }, // 10 (2457 MHz)
    { 0x01E7B, 0x03333 }, // 11 (2462 MHz)
    { 0x01E7B, 0x0B333 }, // 12 (2467 MHz)
    { 0x01F7C, 0x03333 }, // 13 (2472 MHz)
    { 0x01E7C, 0x06666 }, // 14 (2484 MHz)
};

static const struct
{
    uint32 integer;
    uint32 fraction;
    uint32 address4;
    uint32 tracking;
} freqTableAiroha_7230[] =
{
    { 0, 0, 0, 0 },             //                    0
    
    // 2.4 GHz band (802.11b/g)
    { 0x00379, 0x13333, 0x7FD78, TRACK_BG_BAND }, // B-1   (2412 MHz)   1
    { 0x00379, 0x1B333, 0x7FD78, TRACK_BG_BAND }, // B-2   (2417 MHz)   2
    { 0x00379, 0x03333, 0x7FD78, TRACK_BG_BAND }, // B-3   (2422 MHz)   3
    { 0x00379, 0x0B333, 0x7FD78, TRACK_BG_BAND }, // B-4   (2427 MHz)   4
    { 0x0037A, 0x13333, 0x7FD78, TRACK_BG_BAND }, // B-5   (2432 MHz)   5
    { 0x0037A, 0x1B333, 0x7FD78, TRACK_BG_BAND }, // B-6   (2437 MHz)   6
    { 0x0037A, 0x03333, 0x7FD78, TRACK_BG_BAND }, // B-7   (2442 MHz)   7
    { 0x0037A, 0x0B333, 0x7FD78, TRACK_BG_BAND }, // B-8   (2447 MHz)   8
    { 0x0037B, 0x13333, 0x7FD78, TRACK_BG_BAND }, // B-9   (2452 MHz)   9
    { 0x0037B, 0x1B333, 0x7FD78, TRACK_BG_BAND }, // B-10  (2457 MHz)  10
    { 0x0037B, 0x03333, 0x7FD78, TRACK_BG_BAND }, // B-11  (2462 MHz)  11
    { 0x0037B, 0x0B333, 0x7FD78, TRACK_BG_BAND }, // B-12  (2467 MHz)  12
    { 0x0037C, 0x13333, 0x7FD78, TRACK_BG_BAND }, // B-13  (2472 MHz)  13
    { 0x0037C, 0x06666, 0x7FD78, TRACK_BG_BAND }, // B-14  (2484 MHz)  14

    { 0, 0, 0, 0 },             // reserved for future b/g expansion   15
    { 0, 0, 0, 0 },             // reserved for future b/g expansion   16

    // Extended 4 GHz bands (802.11a) - Lower Band
    { 0x0FF52, 0x00000, 0x67F78, TRACK_4920_4980_A_BAND }, // L-184 (4920 MHz)  17
    { 0x0FF52, 0x0AAAA, 0x77F78, TRACK_4920_4980_A_BAND }, // L-188 (4940 MHz)  18
    { 0x0FF53, 0x15555, 0x77F78, TRACK_4920_4980_A_BAND }, // L-192 (4960 MHz)  19
    { 0x0FF53, 0x00000, 0x67F78, TRACK_4920_4980_A_BAND }, // L-196 (4980 MHz)  20

    // Extended 5 GHz bands (802.11a)
    { 0x0FF54, 0x00000, 0x67F78, TRACK_5150_5350_A_BAND }, // A-8   (5040 MHz)  21 tracking?
    { 0x0FF54, 0x0AAAA, 0x77F78, TRACK_5150_5350_A_BAND }, // A-12  (5060 MHz)  22 tracking?
    { 0x0FF55, 0x15555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-16  (5080 MHz)  23 tracking?
    { 0x0FF56, 0x05555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-34  (5170 MHz)  24
    { 0x0FF56, 0x0AAAA, 0x77F78, TRACK_5150_5350_A_BAND }, // A-36  (5180 MHz)  25
    { 0x0FF57, 0x10000, 0x77F78, TRACK_5150_5350_A_BAND }, // A-38  (5190 MHz)  26
    { 0x0FF57, 0x15555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-40  (5200 MHz)  27
    { 0x0FF57, 0x1AAAA, 0x77F78, TRACK_5150_5350_A_BAND }, // A-42  (5210 MHz)  28
    { 0x0FF57, 0x00000, 0x67F78, TRACK_5150_5350_A_BAND }, // A-44  (5220 MHz)  29
    { 0x0FF57, 0x05555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-46  (5230 MHz)  30
    { 0x0FF57, 0x0AAAA, 0x77F78, TRACK_5150_5350_A_BAND }, // A-48  (5240 MHz)  31
    
    { 0x0FF58, 0x15555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-52  (5260 MHz)  32
    { 0x0FF58, 0x00000, 0x67F78, TRACK_5150_5350_A_BAND }, // A-56  (5280 MHz)  33
    { 0x0FF58, 0x0AAAA, 0x77F78, TRACK_5150_5350_A_BAND }, // A-60  (5300 MHz)  34
    { 0x0FF59, 0x15555, 0x77F78, TRACK_5150_5350_A_BAND }, // A-64  (5320 MHz)  35
    
    { 0x0FF5C, 0x15555, 0x77F78, TRACK_5470_5725_A_BAND }, // A-100 (5500 MHz)  36
    { 0x0FF5C, 0x00000, 0x67F78, TRACK_5470_5725_A_BAND }, // A-104 (5520 MHz)  37
    { 0x0FF5C, 0x0AAAA, 0x77F78, TRACK_5470_5725_A_BAND }, // A-108 (5540 MHz)  38
    { 0x0FF5D, 0x15555, 0x77F78, TRACK_5470_5725_A_BAND }, // A-112 (5560 MHz)  39
    { 0x0FF5D, 0x00000, 0x67F78, TRACK_5470_5725_A_BAND }, // A-116 (5580 MHz)  40
    { 0x0FF5D, 0x0AAAA, 0x77F78, TRACK_5470_5725_A_BAND }, // A-120 (5600 MHz)  41
    { 0x0FF5E, 0x15555, 0x77F78, TRACK_5470_5725_A_BAND }, // A-124 (5620 MHz)  42
    { 0x0FF5E, 0x00000, 0x67F78, TRACK_5470_5725_A_BAND }, // A-128 (5640 MHz)  43
    { 0x0FF5E, 0x0AAAA, 0x77F78, TRACK_5470_5725_A_BAND }, // A-132 (5660 MHz)  44
    { 0x0FF5F, 0x15555, 0x77F78, TRACK_5470_5725_A_BAND }, // A-136 (5680 MHz)  45
    { 0x0FF5F, 0x00000, 0x67F78, TRACK_5470_5725_A_BAND }, // A-140 (5700 MHz)  46
    
    { 0x0FF60, 0x18000, 0x77F78, TRACK_5725_5825_A_BAND }, // A-149 (5745 MHz)  47
    { 0x0FF60, 0x02AAA, 0x77F78, TRACK_5725_5825_A_BAND }, // A-153 (5765 MHz)  48
    { 0x0FF60, 0x0D555, 0x77F78, TRACK_5725_5825_A_BAND }, // A-157 (5785 MHz)  49
    { 0x0FF61, 0x18000, 0x77F78, TRACK_5725_5825_A_BAND }, // A-161 (5805 MHz)  50
    { 0x0FF61, 0x02AAA, 0x77F78, TRACK_5725_5825_A_BAND }, // A-165 (5825 MHz)  51
};

// Map LNA value to gain value
/*  For AL2236
    0x7c    -96 dBm
    0x7c    -92 dBm
    0x7b    -88 dBm
    0x7a    -85 dBm
    0x79    -82 dBm
    0x78    -80 dBm
    0x77    -78 dBm
    … etc.

    The gain with LNA == 3 is 20+16 = 36 dB
    The gain with LNA == 2 is 20
    The gain with LNA <2 is 0
    */

static const uint8 lnaTable_al2236[] = 
{
    0, 0, 20, 36
};

// Map high gain values to dbm
static const signed char gainTable_al2236[] = 
{
   -85, -85, -88, -88, -92
};


// Map LNA value to gain value
/* Here is AL7230 in the 2.4Ghz band.  I did these on a CAT board, other AL7230 designs *should* be the same -

    0x79    -96 dBm
    0x79       -93 dBm
    0x78       -90 dBm
    0x77       -87 dBm
    0x76       -84 dBm
    0x75       -82 dBm
    0x74       -80 dBm
    
    … etc.

    The gain with LNA == 3 is 18+24 = 42 dB
    The gain with LNA == 2 is 18
    The gain with LNA <2 is 0
    
    RX_PWR = 2 - RX_GAIN
 */
static const uint8 lnaTable_al7230_24ghz[] = 
{
    0, 0, 18, 42
};
/*Here is AL7230 in the 5 Ghz band that I measured about a year ago on a CAT board -

    0x78    -96 dBm
    0x78       -92 dBm
    0x77       -89 dBm
    0x76       -86 dBm
    0x75       -84 dBm
    0x74       -82 dBm
    
    … etc.
    
    The gain with LNA == 3 is 17+20 = 37 dB
    The gain with LNA == 2 is 17
    The gain with LNA <2 is 0
    
    RX_PWR = -5 - RX_GAIN
 */
static const uint8 lnaTable_al7230_50ghz[] = 
{
    0, 0, 17, 37
};

#else
// 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)
};

#define UBEC_PWR_SETTING 0x39ee0

struct wifi_rf_power {
    uint8 			index;
    unsigned long   reg;
};

const struct wifi_rf_power  ubec_pwr[] = {
    { 0 , 0x0fffe},   // 0
    { 1 , 0x0fffe },  // 1
    { 3 , 0x0fffe },  // 2
    { 5 , 0x0fffe },  // 3
    { 7 , 0x0fffe },  // 4
    { 4 , 0x1fffe },  // 5
    { 5 , 0x1fffe },  // 6
    { 7 , 0x1fffe },  // 7
    { 8 , 0x17ffe },  // 8
    { 9 , 0x17ffe },  // 9
    { 11 , 0x17ffe },  // 10
    { 13 , 0x17ffe },  // 11
    { 15 , 0x17ffe },  // 12
    { 13 , 0x1fffe },  // 13
    { 14 , 0x1fffe },  // 14
   { 15 , 0x1fffe },  // 15
};

// 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
};
#endif

static MacBuffer rxFrame;	// Frame being received
static uint32 intrMask;		// Interrupt mask register
static uint32 timerLoops;	// Loops for 10 usec delay
#ifdef MAC_PS_ENABLED
static uint32 savedRegs[INDX_TOTAL]; // Used to save registers for sleep mode
#endif

static int HandleIR (void *ignore);

/* keep a backup of the station2/3 addresses in case the station2/3 address are changed somehow */
static unsigned int sta2BackupAddr[2] = {0, 0};
static unsigned int sta3BackupAddr[2] = {0, 0};

/* for wiem9210, read the HW strapping; wip9 only has AL7230*/
BOOLEAN isRF_AIROHA_7230(void)
{
    #if (PROCESSOR == ns9210)
#define GENID_REG            	((unsigned long volatile *)0xA0900210)
#define RF_CHIP_BIT       	(9)     	// bit 9 at register 0xA0900210
    if (*GENID_REG & (1 << RF_CHIP_BIT))
    {
    	#if AIROHA_PWR_CALIBRATION
    	AIROHA_PWR_SETTING = AIROHA_PWR_SETTING_AL7230;
    	#endif 
        return TRUE;
    }
    else
    {
    	#if AIROHA_PWR_CALIBRATION
    	AIROHA_PWR_SETTING = AIROHA_PWR_SETTING_AL2236;
    	#endif
        return FALSE;
    }
    
    #else
    	#if AIROHA_PWR_CALIBRATION
    	AIROHA_PWR_SETTING = AIROHA_PWR_SETTING_AL7230;
    	#endif
        return TRUE;
    #endif
}

/* set the B_TX_GAIN field in configuration 1 register */
void setAttenuation( unsigned char value)
{
    HW_CONF1 &= 0x00FFFFFF;
    HW_CONF1 |= value << 24;
}

/* set the MAX AGC field in control register */
/* 
 * For AL7230 :     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.
 *
 * For AL2236 :     Before association, BG band, use 0x7B
 *                  After association, , BG band, use no less than 0x76 
 */
void adjustMaxAgc(epStatus *pSta, MacBuffer *buf)
{
#define LOWEST_MAXAGC_AL2236        0x76
#define HIGHEST_MAXAGC_AL2236       0x7B
#define LOWEST_MAXAGC_AL7230        0x72
#define HIGHEST_MAXAGC_AL7230_24GHZ       0x78
#define HIGHEST_MAXAGC_AL7230_50GHZ       0x77
#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;
    
    
    if (rf_chip == RF_AIROHA_2236)
    {
        lowest = LOWEST_MAXAGC_AL2236;
        highest = HIGHEST_MAXAGC_AL2236;
    }
    else
    {
        lowest = LOWEST_MAXAGC_AL7230;  
        if (rf_band == RF_50GHZ)
            highest = HIGHEST_MAXAGC_AL7230_50GHZ;	
        else
            highest = HIGHEST_MAXAGC_AL7230_24GHZ;	 
    }       
         
    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))
    {
        HW_GEN_CONTROL &= 0xFF80FFFF;
        HW_GEN_CONTROL |= (maxgain & 0x7F) << 16;
    }
}

int subBand(int channel)
{
	if (channel >= 17 && channel <= 20 )
		return A_SUBBAND1;
	if (channel >= 21 && channel <= 31)
		return A_SUBBAND2;
	if (channel >= 32 && channel <= 35)
		return A_SUBBAND3;
	if (channel >= 36 && channel <= 46)
		return A_SUBBAND4;
	if (channel >= 47 && channel <= 51 )
		return A_SUBBAND5;	
	
	return A_SUBBAND_NO_EXIST;
}

uint8 naWifiStartHWGetBasicMeasureMap(void)
{
#define MEASURE_MAP_BSS             (1)
#define MEASURE_MAP_PREAMBLE        (2)
#define MEASURE_MAP_UNIDENTIFIED    (4)
    uint32 measure = HW_MEASURE;
    uint8 result = 0;
    
    if (measure & HW_MEASUREMENT_BSS)
    {
        result |= MEASURE_MAP_BSS;
    }
    
    if (measure & HW_MEASUREMENT_PREAMBLE)
    {
        result |= MEASURE_MAP_PREAMBLE;
    }

    if (measure & HW_MEASUREMENT_UNIDENTIFIED)
    {
        result |= MEASURE_MAP_UNIDENTIFIED;
    }
    
    return result;
}
    
    


/*
 * This routine starts the process of taking a basic measurement.  A basic
 * measurement checks for RF activity on the current channel during a quiet
 * period.
 */
void naWifiStartHWBasicMeasure(void)
{
#define MAX_START_HW_BASIC_MEASURE_SPIN_TIME        (1000)
    unsigned i;
    
/*
 * Wait for current transmit to finish, but don't wait forever.
 */
    for (i = 0; i < MAX_START_HW_BASIC_MEASURE_SPIN_TIME; i++)
    {
        if ((HW_GEN_CONTROL & GEN_TXFIFOEMPTY) != 0)
        {
            break;
        }
        
        naWifiWaitUS(1);
    }

/*
 * Clear measurement status bits in preparation for taking the measure.
 */    
    HW_MEASURE &= ~HW_MEASUREMENT_MASK;
}


    
//
// 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)
//
void WriteRF (uint8 addr, uint32 data)
{
#if AIROHA_TRANSCEIVER
    HW_SPI = (data << 4) | addr;
#else	
    HW_SPI = (addr << 20) | data;
#endif

    if (rf_band == RF_50GHZ)
        naWifiWaitUS (100);
    else
        naWifiWaitUS (10);
}

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

#if (PLATFORM == connectcorewi9c_b)
    for (; len >= 16; len -= 16)
    {
        *dst++ = *src++;
        dst++;
        dst++;
        dst++;
        *dst++ = *src++;
        dst++;
        dst++;
        dst++;
        *dst++ = *src++;
        dst++;
        dst++;
        dst++;
        *dst++ = *src++;
        dst++;
        dst++;
        dst++;
    }
    for (; len > 0; len -= 4)
    {
        *dst++ = *src++;
        dst++;
        dst++;
        dst++;
    }
#else
    if (((((unsigned) dst_) & 3) == 0) && ((((unsigned) src_) & 3) == 0))
    {
        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);
    }
#endif    
}

//
// 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;
        }
}


//
// Load the baseband controller firmware
//
static MacReturn LoadHW (void)
{
    // Baseband firmware image
    extern const unsigned long wifi_macassist_ucode[];
    extern const int macassist_data_len;
    extern const unsigned long wifi_dsp_ucode[];
    extern const int dsp_data_len;

    static BOOL loaded = FALSE;
    int i;
    volatile u32 *addr;
    int timeout1 = 300, timeout2 = 300;

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

#if (PROCESSOR == ns9210)
    /* 20MHz oscillator for Piper and RF has an enable line connected to pin A13 of Camry.  
       This needs to be high all the time.*/
    NAconfigureGPIOpin(CLOCK_ENABLE_GPIO, NA_GPIO_OUTPUT_STATE, 0);
    naWifiWaitUS(500);
    NAconfigureGPIOpin(CLOCK_ENABLE_GPIO, NA_GPIO_OUTPUT_STATE, 1);
    naWifiWaitUS(500);	
    NAconfigureGPIOpin(PIPER_RESET_GPIO, NA_GPIO_OUTPUT_STATE, 0);
    naWifiWaitUS(500);
    NAconfigureGPIOpin(PIPER_RESET_GPIO, NA_GPIO_OUTPUT_STATE, 1);
    naWifiWaitUS(500);	
 
#endif


#if (PLATFORM == connectcorewi9c_b)
    /* enable PIPER device */  
    PIO_OUTPUT (PIN_PIPER_RST);
    PIO_SET(PIN_PIPER_RST);
  
    /* configure ns9360 GPIO pin for interrupt funcationality */
    PIO_INTR (PIN_PIPER_INTERRUPT);
#endif

    DPRINTF ("HW load\n");
    
#if (PROCESSOR == ns9210)
    /* CS0 is used for wireless baseband registers. The registers start at address 0x00 - 
        the base address is defined by the configuration of the chip select. */
    *NA_MPMCStaticConfig0_ADDRESS   = 0x82;
    *NA_MPMCStaticWaitWen0_ADDRESS  = 0;
    *NA_MPMCStaticWaitOen0_ADDRESS  = 2;
    *NA_MPMCStaticWaitRd0_ADDRESS   = 8;
    *NA_MPMCStaticWaitPage0_ADDRESS = 0;
    *NA_MPMCStaticWaitWr0_ADDRESS   = 4;
    *NA_MPMCStaticWaitTurn0_ADDRESS = 2;

    *NA_SCM_SMCS_STATIC_MEM_BASE(0) = MAC_BASE;
    *NA_SCM_SMCS_STATIC_MEM_MASK(0) = MAC_MASK;
#endif

#if (PLATFORM == connectcorewi9c_b)
    /* Static Chip Select 2 (SCS2) is used to access wireless baseband 
       registers. The registers start at offset 0 relative to 
       the MAC_BASE address */
       
    *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;
#endif

#if (PROCESSOR == ns9215)
    /* CS3 is used for wireless baseband registers. The registers start at address 0x00 - 
        the base address is defined by the configuration of the chip select.  */
    *NA_MPMCStaticConfig3_ADDRESS   = 0x82;
    *NA_MPMCStaticWaitWen3_ADDRESS  = 0;
    *NA_MPMCStaticWaitOen3_ADDRESS  = 2;
    *NA_MPMCStaticWaitRd3_ADDRESS   = 8;
    *NA_MPMCStaticWaitPage3_ADDRESS = 0;
    *NA_MPMCStaticWaitWr3_ADDRESS   = 4;
    *NA_MPMCStaticWaitTurn3_ADDRESS = 2;

    /*
    *((volatile unsigned long *)0xA090025C) = 0x1818181D;
    *((volatile unsigned long *)0xA0900274) = 0x12240000;
    *((volatile unsigned long *)0xA0700260) = 0x00000082;
    */

    //naWifiWaitUS (500);

    *NA_SCM_SMCS_STATIC_MEM_BASE(3) = MAC_BASE;
    *NA_SCM_SMCS_STATIC_MEM_MASK(3) = MAC_MASK;
#endif           	

    // Zero out MAC assist SRAM (put into known state before enabling MAC assist)
#if (PLATFORM == connectcorewi9c_b)
    for (addr=MAC_CTRL_BASE; addr<(MAC_CTRL_BASE+ (0x20 * 4)); addr += 4)
#else
    for (addr=MAC_CTRL_BASE; addr<(MAC_CTRL_BASE+ 0x20); addr++)
#endif
        *addr = 0;
        
    // Enable download the MAC Assist program RAM
    HW_GEN_CONTROL |= MACASSIST_LOAD_ENABLE;
    
    //load MAC Assist data
    for (i = 0; i < macassist_data_len; i++)
        HW_DATA_FIFO = wifi_macassist_ucode[i];
    
    // disable MAC Assist download
    HW_GEN_CONTROL &= ~MACASSIST_LOAD_ENABLE;
    
    // Enable download the DSP program RAM
    HW_GEN_CONTROL |= DSP_LOAD_ENABLE;
    
    //load DSP data
    for (i = 0; i < dsp_data_len; i++)
        HW_DATA_FIFO = wifi_dsp_ucode[i];
    
    // disable DSP download
    HW_GEN_CONTROL &= ~DSP_LOAD_ENABLE;

    // set bit-11 in the general control register to a 1 to start the processors
    HW_GEN_CONTROL |= DSP_MACASSIST_ENABLE;
     
    // Initial timing measurement to avoid spike
     /* The new "magic" value is 0x63 at address 0xA62.  Bit-0 indicates the
      timing measurement is complete.  Bit-1 indicates that a second timing 
      measurment was performed.  The upper nibble is the timing measurement 
      value. This code should eliminate the possibility of spikes at the 
      beginning of all PSK/CCK frames and eliminate the spikes at the end of 
      all PSK (1M, 2M) frames.
      */
                
    // reset the timing value WrPortI(0xA62, NULL, 0x00); 
    HW_MAC_STATUS &= 0xffff00ff;
                    
    while ( (HW_MAC_STATUS & 0x0000ff00) != 0x00006300) //while (RdPortI(0xA62) != 0x63)
    {          
        // reset the timing value 
        HW_MAC_STATUS &= 0xffff00ff;   //WrPortI(0xA62, NULL, 0x00);    

        // issue WiFi soft reset     
        HW_GEN_STATUS = 0x40000000;    //_wc_write32(0xA08, 0x40000000);                        

                // Set TX_ON Low WrPortI(0xA3C, NULL, ((RdPortI(0xA3C) & ~0xC0) | 0x80));
        HW_OUT_CTRL &= 0xffffff3f;
        HW_OUT_CTRL |= 0x00000080;
    
        // Set PA_2G Low WrPortI(0xA3D, NULL, ((RdPortI(0xA3D) & ~0x0C) | 0x08)); 
        HW_OUT_CTRL &= 0xfffff0ff;
        HW_OUT_CTRL |= 0x00000a00;  //both PA_2G and PA_5G low
           
        // Set RX_ON low  WrPortI(0xA3F, NULL, ((RdPortI(0xA3F) & ~0x30) | 0x20)); 
        HW_OUT_CTRL &= 0xcfffffff;
        HW_OUT_CTRL |= 0x20000000;
           
        // start the WiFi mac & dsp
        HW_GEN_CONTROL = 0x37720820;                 

        timeout1= 500;

        // Wait for timing measurement to finish
        while ( (HW_MAC_STATUS & 0x0000ff00) != 0x00000100) //((RdPortI(0xA62) & 0x01) != 0x01)
        {
           naWifiWaitUS(2);
           timeout1--;
           if (!timeout1)
               break;
        }

        timeout2--;
        if(!timeout2)
            return ERR_LOAD;
    }   

    // Set TX_ON/RXHP_ON and RX to normal wifi, restore the reset value to HW_OUT_CTRL
    HW_OUT_CTRL = 0x1;
    // ---- end of spike detection

    // set the TX-hold bit
    HW_GEN_CONTROL = 0x37720080;    	
    
    // clear the TX-FIFO memory
    for (i=0; i<448; i++)
        HW_DATA_FIFO = 0;     

    // reset the TX-FIFO
    HW_GEN_CONTROL = 0x377200C0; 	 
    
    // release the TX-hold and reset 	
    HW_GEN_CONTROL = 0x37720000;  	  	
   
    loaded = TRUE;
    return ERR_OK;
}

#if AIROHA_TRANSCEIVER
void InitializeRF(int chip_selection, int band_selection)
{
    switch(chip_selection)
    {
        case RF_AIROHA_2236:
            
            /* Initial settings for 20 MHz reference frequency, 802.11b/g */	                   
            HW_OUT_CTRL &= 0xfffffcff ;
            HW_OUT_CTRL |= 0x00000200 ;
            naWifiWaitUS(150);
               
            /* CH_integer: Frequency register 0 */ 
            WriteRF(0, 0x01f79 );

            /* CH_fraction: Frequency register 1 */		
            WriteRF(1, 0x03333 );

            /*Config 1 = default value */
            WriteRF(2, 0x00B80 );

            /*Config 2 = default value */		
            WriteRF(3, 0x00E7F );

            /*Config 3 = default value */		
            WriteRF(4, 0x0905A );

            /*Config 4 = default value */
            WriteRF(5, 0x0F4DC );

            /*Config 5 = default value */
            WriteRF(6, 0x0805B );

            /*Config 6 = Crystal frequency /2 to pll reference divider */
            WriteRF(7, 0x0116C );

            /*Config 7 = RSSI = default value */
            WriteRF(8, 0x05B68 );   

            /* TX gain control for LA2236 */
            WriteRF(9, 0x05460 );   // sit at the middle

            /* RX Gain = digi specific value: AGC adjustment is done over the GC1-GC7 
            IC pins interface. AGC MAX GAIN value is configured in the FPGA BB register 
            instead of the RF register here below */
            WriteRF(10, 0x001BB );

            /* TX Gain = digi specific vaue: TX GAIN set using the register */
            WriteRF(11, 0x000f9 );   
               
            /* PA current = default value */
            WriteRF(12, 0x039D8 );

            /* Config 8 = default value  */
            WriteRF(13, 0x08000 );

            /* Config 9 = default value */
            WriteRF(14, 0x00000 );

            /* Config 10 = default value  */
            WriteRF(15, 0x00587 );

            //MacSetTxPower (macParams.tx_power);

            /* Calibration procedure */
            HW_OUT_CTRL |= 0x00000300 ;  		
            naWifiWaitUS(150);
    
            /* TXDCOC->active; RCK->disable */
            WriteRF(15, 0x00D87 );
            naWifiWaitUS(50);

            /* TXDCOC->disable; RCK->enable */		
            WriteRF(15, 0x00787 );	
            naWifiWaitUS(50);	

            /* TXDCOC->disable; RCK->disable */
            WriteRF(15, 0x00587 );	
            naWifiWaitUS(50);	
        
            break;
            
            
        case RF_AIROHA_7230:
            switch(band_selection)
            {	
                case RF_24GHZ:
                    
                    /* Initial settings for 20 MHz reference frequency, 802.11b/g */
                    HW_OUT_CTRL &= 0xfffffcff ;
                    HW_OUT_CTRL |= 0x00000200 ;
                    naWifiWaitUS(150);

                    /* Frequency register 0 */ 
                    WriteRF(0, 0x00379 );

                    /* Frequency register 1 */		
                    WriteRF(1, 0x13333 );
                    naWifiWaitUS(10);

                    /*Config 1 = default value */
                    WriteRF(2, 0x841FF );

                    /*Config 2 = default value */		
                    WriteRF(3, 0x3FDFA );

                    /*Config 3 = default value */		
                    WriteRF(4, 0x7FD78 );

                    /*Config 4 = default value */
                    WriteRF(5, 0x802BF );

                    /*Config 5 = default value */
                    WriteRF(6, 0x56AF3 );

                    /*Config 6 = Crystal frequency /2 to pll reference divider */
                    WriteRF(7, 0xCE000 );

                    /*Config 7 = RSSI = default value */
                    WriteRF(8, 0x6EBC0 );

                    /* Filter BW  = default value */
                    WriteRF(9, 0x221BB );

                    /* RX Gain = digi specific value: AGC adjustment is done over the GC1-GC7 
                    IC pins interface. AGC MAX GAIN value is configured in the FPGA BB register 
                    instead of the RF register here below */
                    WriteRF(10, 0xE0040 );   

                    /* TX Gain = digi specific vaue: TX GAIN set using the register */
                    // WriteRF(11, 0x08070);
                    MacSetTxPower (macParams.tx_power);  //Digi value                                        

                    /* PA current = default value */
                    WriteRF(12, 0x0002B ); //Changed from 0xA3 to 0x2B

                    /* Config 8 = default value  */
                    WriteRF(13, 0xFFFFF );

                    /* Config 9 = default value */
                    WriteRF(14, 0x00000 );

                    /* Config 10 = default value  */
                    WriteRF(15, 0x1ABA8 );

                    /* Calibration procedure */
                    HW_OUT_CTRL |= 0x00000300 ;  //for AL2236 is it 0x300 or 0xc00?

                    naWifiWaitUS(150);

                    /* Calibration procedure */

                    /* TXDCOC->active; RCK->disable */
                    WriteRF(15, 0x9ABA8 );
                    naWifiWaitUS(50);

                    /* TXDCOC->disable; RCK->enable */		
                    WriteRF(15, 0x3ABA8 );	
                    naWifiWaitUS(50);	

                    /* TXDCOC->disable; RCK->disable */
                    WriteRF(15, 0x1ABA8 );
                    naWifiWaitUS(50);				
                   
                    break;
                
                case RF_50GHZ:
                
                    /* Initial settings for 20 MHz reference frequency, 802.11a */
                    HW_OUT_CTRL &= 0xfffffcff ;
                    HW_OUT_CTRL |= 0x00000200 ;
                    naWifiWaitUS(150);


                    /* Frequency register 0 */ 
                    WriteRF(0, 0x0FF56 );

                    /* Frequency register 1 */		
                    WriteRF(1, 0x0AAAA );
                    
                    naWifiWaitUS(10); 

                    /*Config 1 = default value */
                    WriteRF(2, 0x451FE );

                    /*Config 2 = default value */		
                    WriteRF(3, 0x5FDFA );

                    /*Config 3 = default value */		
                    WriteRF(4, 0x67f78 );

                    /*Config 4 = default value */
                    WriteRF(5, 0x853FF );

                    /*Config 5 = default value */
                    WriteRF(6, 0x56AF3 );

                    /*Config 6 = Crystal frequency /2 to pll reference divider */
                    WriteRF(7, 0xCE000 );

                    /*Config 7 = RSSI = default value */
                    WriteRF(8, 0x6EBC0 );

                    /* Filter BW  = default value */
                    WriteRF(9, 0x221BB );

                    /* RX Gain = digi value */
                    WriteRF(10, 0xE0600 ); 

                    /* TX Gain = digi specific vaue: TX GAIN set using the register */
                    // WriteRF(11, 0x08070 );  
                    MacSetTxPower (macParams.tx_power);  //Digi value                    

                    /* PA current = default value */
                    WriteRF(12, 0x00143 );

                    /* Config 8 = default value  */
                    WriteRF(13, 0xFFFFF );

                    /* Config 9 = default value */
                    WriteRF(14, 0x00000 );

                    /* Config 10 = default value  */
                    WriteRF(15, 0x12BAC );

                    /* Calibration procedure */
                    HW_OUT_CTRL |= 0x00000300 ; 

                    naWifiWaitUS(150);

                    /* Calibration procedure */

                    /* TXDCOC->active; RCK->disable */
                    WriteRF(15, 0x9ABA8 );
                    naWifiWaitUS(50);

                    /* TXDCOC->disable; RCK->enable */		
                    WriteRF(15, 0x3ABA8 );
                    naWifiWaitUS(50);		

                    /* TXDCOC->disable; RCK->disable */
                    WriteRF(15, 0x12BAC );	
                    naWifiWaitUS(50);			
                                    
                    break;
                
                default:
                    break;	
            }
            
            break;
            
        case RF_MAXIM_2829:
            
            switch(band_selection)
            {	
                case RF_24GHZ:
                         
                    /* Initial settings for 40 MHz reference frequency, 802.11b/g */
                    WriteRF (0,  0x1140);  //register 0: default value 
                    WriteRF (1,  0x00ca);  //register 1: default value
                    WriteRF (2,  0x1007);  //standby register: default value
                    WriteRF (6,  0x1c00);  //calibration register: default value
                    WriteRF (7,  0x002a);  //low-pass filter register: default value 
                    WriteRF (8,  0x0021);  //Rx Control/RSSI register: Digi value
                    WriteRF (9,  0x0600);  //Tx Linearity/Baseband Gain Register: Digi value
                    //CC MacSetTxPower (0x30);  //Tx VGA Gain register: Digi value
                    MacSetTxPower (macParams.tx_power);  //Tx VGA Gain register: Digi value
                    WriteRF (10, 0x03c0);  //PA Bias DAC register: default value
                    WriteRF (11, 0x007f);  //Rx Gain register: default value

                    break;
                
                case RF_50GHZ:
                
                    /* Initial settings for 40 MHz reference frequency, 802.11a */		         	        	
                    break;
                
                default:
                    break;	
            }			
            
            break;
            
        case RF_UBEC_2453:
            break;		

        default:
            break; 		
    }
    
    return;
}
#endif

//
// 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;
    
    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 nearst 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;


    // Init baseband processor and MAC assist

#if AIROHA_TRANSCEIVER
    if(isRF_AIROHA_7230())
        rf_chip = RF_AIROHA_7230;
    else
        rf_chip = RF_AIROHA_2236;            
            
    switch(rf_chip)
    {
        case RF_AIROHA_7230:
        
            /* Initialize baseband general control register */
            if (macParams.band == WLN_BAND_B || macParams.band == WLN_BAND_BG)		
            {
                HW_GEN_CONTROL = GEN_INIT_AIROHA_24GHZ_AL7230;
                HW_TRACK_CONTROL &= 0xff00ffff;
                HW_TRACK_CONTROL |= TRACK_BG_BAND;
            }
            else
            {
                HW_GEN_CONTROL = GEN_INIT_AIROHA_50GHZ_AL7230;	      
                    
                /* All supported 802.11a channels are in this 802.11a frequency sub-band */ 
                HW_TRACK_CONTROL &= 0xff00ffff;	          		
                HW_TRACK_CONTROL |= TRACK_5150_5350_A_BAND; 
            }
            

            HW_GEN_STATUS = 0x30000000;
            HW_CONF2 = 0x08329AD4;    
     
#if (PLATFORM == connectcorewi9c_b)
            HW_GEN_CONTROL |= DSP_MACASSIST_ENABLE;
#endif              
            /* Initialize the SPI word length */	   
            HW_SPI_CONTROL = SPI_INIT_AIROHA;
        
        break;
    
        case RF_AIROHA_2236:
        
            /* Initialize baseband general control register */
           
            HW_GEN_CONTROL = GEN_INIT_AIROHA_24GHZ_AL2236;
          
            HW_GEN_STATUS = 0x30000000;
            
            HW_CONF2 = 0x08729AD4;        /* 2nd LNA == 22 dB*/
            
            HW_TRACK_CONTROL &= 0xff00ffff;
            HW_TRACK_CONTROL |= TRACK_BG_BAND;
          
            /* Initialize the SPI word length */	   
            HW_SPI_CONTROL = SPI_INIT_AIROHA2236;  
        
            break;
            
        case RF_MAXIM_2829:
        
            /* Initialize baseband general control register */
            HW_GEN_CONTROL = GEN_INIT_MAXIM;		
       
            /* Initialize the SPI word length */
            HW_SPI_CONTROL = SPI_INIT_MAXIM;
        
            break;
        
        case RF_UBEC_2453:
            break;
        
        default:
            break;			
    }
#else	
    HW_GEN_CONTROL = GEN_INIT;
#endif	
    // Clear the Interrupt Mask Register before enabling external interrupts.
    // Also clear out any status bits in the Interrupt Status Register.
    HW_INTR_MASK = 0;
    HW_INTR_STATUS = 0xff;
    
    /*
     * If this firmware supports additional MAC addresses.
     */
    if (((HW_MAC_STATUS >> 16) & 0xff) >= 8)
    {
        /* Disable additional addresses to start with */
        HW_MAC_CONTROL &= ~CTRL_MAC_FLTR;
        /*
         * Clear registers that hold extra addresses.
         */
        HW_STA2ID0 = 0;
        HW_STA2ID1 = 0;
        HW_STA3ID0 = 0;
        HW_STA3ID1 = 0;
    }
    
    intrMask = INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_RXOVERRUN;
    HW_INTR_MASK = intrMask;
    HWMemcpy (&HW_STAID0, macParams.sta_addr, WLN_ADDR_SIZE);


    // Set anternna diversity if enabled
    if (macParams.options & WLN_OPT_ANTDIV)
        HW_GEN_CONTROL |= GEN_ANTDIV;
    
#if (PROCESSOR == ns9210)
        // Transmit on primary antenna on wiem9210 platform
        HW_RSSI_AES |= 0x5A000000;   
#else
//on connectcorewi9p9215_a platform
        if (HW_GEN_CONTROL & GEN_ANTDIV)
            HW_RSSI_AES |= 0x96000000;  
        else
        {
            HW_RSSI_AES |= 0x1E000000; 
            HW_GEN_CONTROL &= 0xfffffffb;
        }
#endif


    // reset RX and TX FIFOs
    HW_GEN_CONTROL |= GEN_RXFIFORST | GEN_TXFIFORST;
    HW_GEN_CONTROL &= ~(GEN_RXFIFORST | GEN_TXFIFORST);

    HW_CONF1 = 0xE043002C; //OFDM power is ~4.86 dbm lower than CCK power
    
        
#if AIROHA_TRANSCEIVER
    /* Initialize RF transceiver */
    if (macParams.band == WLN_BAND_A)
    {
        rf_band = RF_50GHZ;
        InitializeRF(rf_chip, RF_50GHZ);
    }
    else
    {
        rf_band = RF_24GHZ;
        InitializeRF(rf_chip, RF_24GHZ);
    }
#else
    // Transmit on primary antenna
    HW_RSSI_AES |= 0xA5000000;

    // 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, 0x25f9c); // Mode Control - Calibrate Filter
    naWifiWaitUS (10);
     
    MacSetTxPower (macParams.tx_power);
#endif

#if AIROHA_PWR_CALIBRATION
    initPwrCal();
    
    if (getPowerCalibrationVersion() == CALIBRATION_VERSION_1)
    {
        HW_CONF1 = 0xC043002C; //OFDM power is ~3.5 dbm lower than CCK power
    }
        
#endif

#if (PLATFORM != connectcorewi9c_b)	
    HW_OUT_CTRL |= (1 << 26);
#endif
        
    // 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);
    
#ifdef MAC_PS_ENABLED
    PIO_OUTPUT(WLN_PS_CNTRL_PIN);
#endif

    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-22
//
void SetChannel (int channel)
{
#if AIROHA_TRANSCEIVER

    /* current frequency band */
    //static int rf_band = RF_24GHZ; 

    if (CHAN_5G (channel))
        rf_band = RF_50GHZ;
    else
        rf_band = RF_24GHZ;       	
    
    /* Disable the rx processing path */
    HW_GEN_CONTROL &= ~GEN_RXEN;
    global_chan = channel;
    
    DPRINTF("in SetChannel (), Channel=%d, rf_band= %d\n", channel, rf_band);
    switch(rf_chip)
    {
        case RF_AIROHA_2236:
                
            HW_GEN_STATUS |= (STAT_B_EN);
            if (macParams.band == WLN_BAND_B)
            {
                // turn off OFDM
                HW_GEN_STATUS &= (~STAT_A_EN);
            }
            else
            {
                // turn on OFDM
                HW_GEN_STATUS |= (STAT_A_EN);
            }
                
            /* set the 802.11b/g frequency band specific tracking constant */
            HW_TRACK_CONTROL &= 0xff00ffff;
            HW_TRACK_CONTROL |= TRACK_BG_BAND;  	
                                    
            /* perform chip and frequency-band specific RF initialization */
            InitializeRF(RF_AIROHA_2236, rf_band);    
            
            MacSetTxPower (macParams.tx_power);

            WriteRF (0, freqTableAiroha_2236[channel].integer); 
            WriteRF (1, freqTableAiroha_2236[channel].fraction); 

            /* critical delay for correct calibration */
            naWifiWaitUS (10);
    
            /* TXON, PAON and RXON should all be low before Calibration 
             * TXON and PAON will be low as long as no frames are written to the TX DATA fifo.  
             * RXON will be low as long as the receive path is not enabled (bit 0 of GEN CTL register is 0).  
             */   
     
                /* calibrate RF transceiver */
       
                /* TXDCOC->active; RCK->disable */
            WriteRF(15, 0x00D87 );
            naWifiWaitUS (50);	
            /* TXDCOC->disable; RCK->enable */		
            WriteRF(15, 0x00787 );		
            naWifiWaitUS (50);	
            /* TXDCOC->disable; RCK->disable */
            WriteRF(15, 0x00587 );
            naWifiWaitUS (50);
                
            /* configure the baseband processing engine */		    
            HW_GEN_CONTROL &= ~GEN_5GEN;		   
          
            break;
    
        case RF_AIROHA_7230:
            /* enable the frequency-band specific PA */
            if (rf_band == RF_24GHZ)
            {
                //HW_GEN_CONTROL &= ~GEN_PA_ON;
                HW_GEN_STATUS |= (STAT_B_EN);
                if (macParams.band == WLN_BAND_B)
                {
                    // turn off OFDM
                    HW_GEN_STATUS &= (~STAT_A_EN);
                }
                else
                {
                    // turn on OFDM
                    HW_GEN_STATUS |= (STAT_A_EN);
                }
                
                /* set the 802.11b/g frequency band specific tracking constant */
                HW_TRACK_CONTROL &= 0xff00ffff;
                HW_TRACK_CONTROL |= TRACK_BG_BAND;  	  	  
            }
            else
            {
                //HW_GEN_CONTROL |= GEN_PA_ON; 

                // turn on OFDM
                HW_GEN_STATUS |= (STAT_A_EN);
                
                // turn off PSK/CCK
                HW_GEN_STATUS &= (~STAT_B_EN);
                
                /* Set the 802.11a frequency sub-band specific tracking constant */	      
                /* All 8 supported 802.11a channels are in this 802.11a frequency sub-band */
                HW_TRACK_CONTROL &= 0xff00ffff;
                HW_TRACK_CONTROL |= freqTableAiroha_7230[channel].tracking;
            } 
        
            /* perform chip and frequency-band specific RF initialization */
            InitializeRF(RF_AIROHA_7230, rf_band);
            
            MacSetTxPower (macParams.tx_power);
    
            /* Set the channel frequency */
            WriteRF (0, freqTableAiroha_7230[channel].integer); 
            WriteRF (1, freqTableAiroha_7230[channel].fraction); 
            WriteRF (4, freqTableAiroha_7230[channel].address4); 
 
            /* critical delay for correct calibration */
            naWifiWaitUS (10);
       
            // Select the frequency band: 5Ghz or 2.4Ghz
            if (CHAN_5G (channel))
            {
                /* calibrate RF transceiver */

                /* TXDCOC->active; RCK->disable */
                WriteRF(15, 0x9ABA8 );
                naWifiWaitUS (50);	

                /* TXDCOC->disable; RCK->enable */		
                WriteRF(15, 0x3ABA8 );	
                naWifiWaitUS (50);		

                /* TXDCOC->disable; RCK->disable */
                WriteRF(15, 0x12BAC );
                naWifiWaitUS (50);	

                /* configure the baseband processing engine */
                //HW_GEN_CONTROL |= GEN_5GEN;  
                HW_GEN_CONTROL &= ~GEN_5GEN;  
            }
            else
            {
                /* calibrate RF transceiver */

                /* TXDCOC->active; RCK->disable */
                WriteRF(15, 0x9ABA8 );
                naWifiWaitUS (50);	

                /* TXDCOC->disable; RCK->enable */		
                WriteRF(15, 0x3ABA8 );	
                naWifiWaitUS (50);		

                /* TXDCOC->disable; RCK->disable */
                WriteRF(15, 0x1ABA8 );
                naWifiWaitUS (50);	

                /* configure the baseband processing engine */		    
                HW_GEN_CONTROL &= ~GEN_5GEN;
            }

            break;
            
        case RF_MAXIM_2829:
            break;
        
        case RF_UBEC_2453:
            break;
        
        default:
            break;		
    }

#else
    HW_GEN_CONTROL &= ~GEN_RXEN;

    // Set frequency divider for channel
    WriteRF (1, freqTable[channel].integer);
    WriteRF (2, freqTable[channel].fraction);
    
    // Filter Calibration
    WriteRF (0, 0x25f9c);
    naWifiWaitUS (10);
    
    // VCO Calibration
    WriteRF (0, 0x25f9a);
    naWifiWaitUS (80);

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

    HW_GEN_CONTROL |= GEN_RXEN;
#endif    
    
    /* reload mac address in case they are changed */
    HWMemcpy (&HW_STAID0, macParams.sta_addr, WLN_ADDR_SIZE);
     
    /* reload station2 mac address in case they are changed */
    if(sta2BackupAddr[0] != 0 || sta2BackupAddr[1] != 0)
        HWMemcpy (&HW_STA2ID0, sta2BackupAddr, WLN_ADDR_SIZE);
 
    /* reload station3 mac address in case they are changed */
    if(sta3BackupAddr[0] != 0 || sta3BackupAddr[1] != 0)
        HWMemcpy (&HW_STA3ID0, sta3BackupAddr, WLN_ADDR_SIZE);
        
    /*Re-enable the rx processing path */
    HW_GEN_CONTROL |= GEN_RXEN;
    
   //printf("in SetChannel (), Channel=%d, rf_band= %d, global_chan =%d\n", channel, rf_band, global_chan);	
               
}

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) >= 8)
    {
        /* 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);
            memcpy((char *) sta2BackupAddr, (char *) 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);
                memcpy((char *) sta3BackupAddr, (char *) 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);
    
    // don't walk on TXP, it's controlled by power control
    HW_SSID_LEN &= 0x0000FF00;
    
    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;
    }
}

void SetCoverageclass( uint coverageClass )
{
	HW_MAC_CONTROL &= 0xff00ffff;
	HW_MAC_CONTROL |= coverageClass << 16;
}

//
// Set the link activity LED (stubbed function, taken care in FPGA level)
// @param on TRUE to turn LED on
//
void SetActivityLED (BOOL on)
{
#if defined(WI9P_WIFI_LEDS)
    naGpioSetOutputValue(GPIO_WIFI_LINK_ACTIVITY, on ? 0 : 1);
#else
    NA_UNUSED_PARAM(on);
#endif
}

//
// Set the link status LED
// @param on TRUE to turn LED on
//
void SetLED (BOOL on)
{
#if defined(WI9P_WIFI_LEDS)
    naGpioSetOutputValue(GPIO_WIFI_LINK_GREEN, on ? 0 : 1);
#else
    NA_UNUSED_PARAM(on);
#endif
}

//
// 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;
extern int sendingCTSRTS;
#if AIROHA_PWR_CALIBRATION
  //  _wifi_pwrCntrl();
  tx_event_flags_set(&airoha_pwr_cal_group, MAC_SEND_FRAME_EVENT, TX_OR);   
#endif

    // 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 ;    //|0x00800000; ?  beacon filter

            // 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;
        
    }
    else
    {
        // Prevent transmission until entire frame is loaded
        // (which will prevent TX underruns)
        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
        if (!sendingCTSRTS)
            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;
        uint32 intrMaskNow = HW_INTR_MASK;
        
        intrStatus &= intrMaskNow;
        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)
        {
            #if AIROHA_PWR_CALIBRATION	
            // TX_START interrupt:
            // Control register is at address 0x52.  Bit-0 will enable the TX-START
            // interrupt (you will need to write this bit to a 1 to enable the interrupt).
            // Bit-1 will indicate that a TX-START interrupt occurred.  Bit-2 will be the
            // OFDM (1) or PSK/CCK (0) indication. Bit-3 will indicate that the transmitter is still on.
                // All 8 interrupt sources are used
            // so this will need to be shared existing one, RX-OVER interrupt. If you get
            // an RX-OVER interrupt and Bit-1 is set, it is a TX-START interrupt -
            // otherwise it is a receive overrun.  You will need to clear Bit-1 once
            // you process the TX-START interrupt.
            uint32 txstartStatus = HW_SSID_LEN;
            if (txstartStatus  & (0x02 << 8)) /* is tx started? */
            {
            	#ifdef AIROHA_PWR_CALIBRATION_DEBUG			
                _wapc.txStartCount++;
                #endif
                if(txstartStatus & (0x08 << 8)) /*is the tx still on? */
                {
                	tx_event_flags_set(&airoha_pwr_cal_group, TX_START_EVENT, TX_OR);    

	                #ifdef AIROHA_PWR_CALIBRATION_DEBUG			
	                _wapc.txStillOn++;
	                #endif
                        if(txstartStatus & (0x04 << 8))  
                        {
                           // Set for OFDM
                          //  _wapc.Modulation = _WIFI_OFDM;
                            #ifdef AIROHA_PWR_CALIBRATION_DEBUG
                            _wapc.ofdmCount++;
                            #endif
                        }
                        else  
                        {  
                            // Set for PSK/CCK
                           // _wapc.Modulation = _WIFI_PSK_CCK;
                            #ifdef AIROHA_PWR_CALIBRATION_DEBUG
                            _wapc.pskCount++;
                            #endif
                        }
                  
                        
                    txstartStatus &= ~(0x02 << 8);
                    HW_SSID_LEN = txstartStatus;
                            
                    // Only disable interrupts for normal mode of operation. Manufacturing
                    // code will control interrupt for calibration process.
                    if(!_wapc.ForceADCRead)
                    {
                        HW_SSID_LEN &=0xffff00ff;
                    }
                }
                else
                {
                    txstartStatus &= ~(0x02 << 8);
                    HW_SSID_LEN = txstartStatus;
                }
            }
            else
            #endif //AIROHA_PWR_CALIBRATION
                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);
             
#if AIROHA_TRANSCEIVER
                rxFrame.rssi = (rxFrame.frameHdr.rx.rssiLNA << 5) | rxFrame.frameHdr.rx.rssiVGA;
                                                          
                if (rf_chip == RF_AIROHA_2236)
                {
                    // Convert received signal strength to dbm
                    gain = lnaTable_al2236[rxFrame.frameHdr.rx.rssiLNA] + 2*rxFrame.frameHdr.rx.rssiVGA;
                    if (gain > 92)
                        rxFrame.rx_signal = -96;
                    else if (gain > 87)
                        rxFrame.rx_signal = gainTable_al2236[gain - 88];
                    else
                        rxFrame.rx_signal = 4 - gain;
                }
                else
                {
                    /* Convert received signal strength to dbm for RF_AIROHA_7230 */
                    if (rf_band == RF_24GHZ)
                    {
                        gain = lnaTable_al7230_24ghz[rxFrame.frameHdr.rx.rssiLNA] + 2*rxFrame.frameHdr.rx.rssiVGA;
                        rxFrame.rx_signal = 2 - gain;
                    }
                    else
                    {
                        gain = lnaTable_al7230_50ghz[rxFrame.frameHdr.rx.rssiLNA] + 2*rxFrame.frameHdr.rx.rssiVGA;
                        rxFrame.rx_signal = -5 - gain;
                    }
                    
                    
                }
#else
                // Convert received signal strength to dbm
                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;
#endif

                // 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;
}

#if AIROHA_PWR_CALIBRATION
void enableTxStartInt (BOOLEAN on)
{
    if (on)
        HW_SSID_LEN |= 0x1 << 8;
    else 
        HW_SSID_LEN &= 0xffff00ff;	
}
void _wifi_Airoha (unsigned long value)
{
    // _wifi_WriteRF ((char) (value & 0xfuL), value);
    switch(rf_chip)
    {
        case RF_AIROHA_2236:
            WriteRF(9,  value >> 4);
            break;
        case RF_AIROHA_7230:
            WriteRF(11,  value >> 4);
            break;
        default:
            break;
    }
}

BOOLEAN isContTXOn (void)
{
#define CONT_TX  0x00100000
    if (HW_GEN_STATUS & CONT_TX)
        return TRUE;
    else
        return FALSE;
    
}
BOOLEAN isContOFDM (void)
{
	return isOFDM;
}

static int beaconTestOn = 0;
BOOLEAN isBeaconTestOn (void)
{
	return beaconTestOn;
}

#endif //AIROHA_PWR_CALIBRATION

//
// Get the complete frame that is being received
// @param buf Buffer to copy frame into, length field contains frame size
//
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 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
            HWReadFifo (buf->body+EXTIV_SIZE, buf->length-32);
            
    }

    // Get remaining data from receive FIFO
    else
        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 routine scales down the transmit power level passed to
 * it down to a value appropriate for this hardware.  Hardware
 * limitations may cause the signal to violate emissions standards
 * if the transmit power is turned up too high.  The amount of
 * power we can use is determined by the frequency band. 
 *
 * Frequency Band   Max Power   Medium Power    Low Power
 * ==============   =========   ============    ==========
 *  802.11b         17          12              8
 *  802.11g         12          10              8
 *  802.11a         8/10        6               4
 *
 * The value of unscaledTxPower is interpreted as follows:
 *
 * Range                    Interpretation
 * ======================   ===============
 * 0 - 8                    Low Power
 * 9 - 12                   Medium Power
 * 13 - 16                  Maximum Power
 *
 * The return value is the value scaled to the appropriate band.
 */
int wlnMacScaleTxPower(int unscaledTxPower)
{
#if defined(WI9P_AIROHA_7230_TX_POWER_SCALING) || defined(WIEM9210_AIROHA_7230_TX_POWER_SCALING)
#define MAX_BG_BAND_CHANNEL_INDEX      (16)

#define BAND_A      (0)
#define BAND_B      (1)
#define BAND_G      (2)
#define MAX_BANDS   (3)

#define INDEX_MAXIMUM       (0)
#define INDEX_MEDIUM        (1)
#define INDEX_LOW           (2)
#define MAX_SCALED_INDEX    (3)

#define LOW_POWER_MAX       (8)
#define MEDIUM_POWER_MAX    (12)
#define HI_POWER_MAX        (16)
#if defined(WI9P_AIROHA_7230_TX_POWER_SCALING)
    /*
     * Table for Wi9P values.  Note that band A max is 8 dBm.
     */
    const int scaledTxValues[MAX_BANDS][MAX_SCALED_INDEX] =
    {
/*               Maximum    Medium  Low */
/*               =======    ======  === */
/* Band A */    {8,         6,      4},
/* Band B */    {16,        12,     8},
/* Band G */    {12,        10,     8}
    };
#endif
#if defined(WIEM9210_AIROHA_7230_TX_POWER_SCALING)
    /*
     * Table for WiEM9210 values.  Note that band A max is 10 dBm.
     */
    const int scaledTxValues[MAX_BANDS][MAX_SCALED_INDEX] =
    {
/*               Maximum    Medium  Low */
/*               =======    ======  === */
/* Band A */    {10,        6,      4},
/* Band B */    {16,        12,     8},
/* Band G */    {12,        10,     8}
    };
#endif
    unsigned bandIndex, powerIndex;
    int result = unscaledTxPower;

    if ((rf_chip == RF_AIROHA_7230) && (unscaledTxPower != 0))
    {
        switch (macParams.band)
        {
            case WLN_BAND_ALL:
            case WLN_BAND_A:
            default:
                /*
                 * Band A is worse case for power level.  Default to this.
                 */
                bandIndex = BAND_A;
                break;
            case WLN_BAND_B:
                bandIndex = BAND_B;
                break;
            case WLN_BAND_BG:
                /*
                 * When the band selection is bg, we will be switching between b 
                 * and g bands as error rates change, so assume worse case, that
                 * it is the g band.
                 */
                bandIndex = BAND_G;
                break;
        }
        if (unscaledTxPower <= LOW_POWER_MAX)
        {
            powerIndex = INDEX_LOW;
        }
        else if (unscaledTxPower <= MEDIUM_POWER_MAX)
        {
            powerIndex = INDEX_MEDIUM;
        }
        else
        {
            powerIndex = INDEX_MAXIMUM;
        }
    
        result = scaledTxValues[bandIndex][powerIndex];
    }
    
    return result;
#else  /* if not a platform that requires power scaling */
    return unscaledTxPower;
#endif
}


    
//
// This is used to set the transmit power.  
// Value is in dbm and will be limited to 0-16 dbm.
//
// The power level must be passed as a dBm value between
// 0 and 16.
//
void MacSetTxPowerUnscaled(int value)
{
#if AIROHA_TRANSCEIVER
            
#if AIROHA_PWR_CALIBRATION
    if (value < 0)
        value = 0;
    else if (value > 17)
        value = 17;
    __wifi_SetPower(value);
#else  //AIROHA_PWR_CALIBRATION
    
    switch(rf_chip)
    {
        case RF_AIROHA_2236:
    
            if (value <= 0)
                value = 1;
            else if (value > 16)
                value = 16;

            WriteRF(9, 0x05440 | powerTable_2236[value -1]);  

            break;
        
        case RF_AIROHA_7230:		
            if (value < 0)
                value = 1;
            else if (value > 16)
                value = 16;

            WriteRF(11, 0x08040 | powerTable_7230[value -1]);

            break;
        
        case RF_MAXIM_2829:
    
            if (value < 0x40)
                WriteRF(12, powerTable[value]);
            else
                WriteRF(12, powerTable[15]);    		 
        
            break;
        
        case RF_UBEC_2453:
            break;
        
        default:
            break;			
    }
#endif //AIROHA_PWR_CALIBRATION
#else	
    if (value < 0)
        value = 0;
    else if (value > 15)
        value = 15;

    WriteRF (5, 0x19e40 | powerTable[value]);
#endif    
}



void MacSetTxPower(int value)
{
    epStatus *pSta = rootEndPoint[0];
    
#if AIROHA_TRANSCEIVER
    /*
     * Scale the transmit power value as necessary so that we do not violate
     * emissions standards.
     */
    value = wlnMacScaleTxPower(value);          
            
#if AIROHA_PWR_CALIBRATION
    if (value == 16 && (getPowerCalibrationVersion() != CALIBRATION_VERSION_1))
        value = 17;
        
    if (value < 0)
        value = 0;
    else if (value > 17)
        value = 17;
    value = wlnApplyTxPowerConstraint(value, global_chan);  
#else  //AIROHA_PWR_CALIBRATION
    
    switch(rf_chip)
    {
        case RF_AIROHA_2236:
    
            if (value < 0)
                value = 0;
            else if (value > 16)
                value = 16;

            /*
             * Now apply any local Tx power constraints.
             */
            value = wlnApplyTxPowerConstraint(value, global_chan);   

            break;
        
        case RF_AIROHA_7230:		
            if (value < 0)
                value = 1;
            else if (value > 16)
                value = 16;

            /*
             * Now apply any local Tx power constraints.
             */
            value = wlnApplyTxPowerConstraint(value, global_chan);   

            break;
        
        case RF_MAXIM_2829:
            break;
        
        case RF_UBEC_2453:
            break;
        
        default:
            break;			
    }
#endif //AIROHA_PWR_CALIBRATION
#else	
    if (value < 0)
        value = 0;
    else if (value > 15)
        value = 15;

#endif    
    MacSetTxPowerUnscaled(value);
    naDot11.currentTxPower = value;
    
    //update the status
    pSta->macStatus.tx_power = value;
}


/* Enable the RF testing functionality if needed */
#if BSP_RF_TESTING

static wln_bss bss_save = WLN_BSS_NONE;

// This buffer is used as the transmit buffer for testing the
// continuous transmit FCC test.
unsigned char fcc_txbuffer[64];
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};
static unsigned char radio_txbuffer[1024];

/* determine if the channel is in B or BG band */
BOOLEAN isBOrBGOnly(void)
{
    if ((macParams.band == WLN_BAND_BG) || (macParams.band == WLN_BAND_B))
        return TRUE;
    else
        return FALSE;		
}

/* determine if the channel is in A ONLY band */
BOOLEAN isAOnly(void)
{
    if (macParams.band == WLN_BAND_A)
        return TRUE;
    else
        return FALSE;		
}


/* Set the power directly in the RF transceiver chip for RF testing purposes */
void MacSetDirectTxPower(int value)
{
    switch(rf_chip)
    {
        case RF_AIROHA_2236:
            if (value < 0)
                value = 0;
            else if (value > 63)
                value = 63;
            
            WriteRF(9, 0x05440 | value);  /* 0-63 */
            break;
        
        case RF_AIROHA_7230:
            if (value < 0x40)
                WriteRF(11, 0x08040 | value);
            else
                WriteRF(11, 0x08040 | 0x3f);  	
            break;
        
        case RF_MAXIM_2829:
            if (value < 0x40)
                WriteRF(12, value);
            else
                WriteRF(12, 0x3f);    		 
            break;
        
        case RF_UBEC_2453:
            break;
        
        default:
            break;			
    }
}


//
// 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;
    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);
}

//
// 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] = 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);
}

//
// 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.
//
extern TX_THREAD wln_thread;
void MacContinuousTransmit(int enable, unsigned int transmit_mode, unsigned int transmit_rate)
{
    int level;
    uint32 data;
    epStatus *pSta = rootEndPoint[0];
	
    if (transmit_rate > 3)
        isOFDM = TRUE;
    else
        isOFDM = FALSE;

    if (isRF_AIROHA_7230())
    	data = 0x0;
    else
    	data = 0x04000000;
    	
    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;
        
        tx_thread_suspend(&wln_thread);
	
	while ((HW_GEN_CONTROL & GEN_TXFIFOEMPTY) == 0)
		;
		
        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;
         HW_CONF1 |= TX_CTL;	//piper

        /* set to continuous transmit; test bit too */
        HW_GEN_STATUS = data; 
          
        /* start transmiting */
        HW_MAC_CONTROL = CTRL_TXREQ;
#if AIROHA_PWR_CALIBRATION       
        _wapc.Rawdata = 0;
        _wapc.AvgData = 0;
        _wapc.AvgHistory = 0;
#endif
    }
    else
    {
    	if (isRF_AIROHA_7230())
    		data =0x30000000;
    	else
    	        data = 0x34000000;
    	        
        /* disable continuous transmit */
        switch(transmit_mode)
        {
            case 0:
                HW_GEN_STATUS = data; 
                break;

            case 1:
                HW_GEN_STATUS = data;

                break;

            case 2:
                HW_GEN_STATUS = data;
                break;
                
            case 3:
                //restore normal mode of operation
                //CC HW_GEN_CONTROL = 0x13780001;
                HW_GEN_STATUS = data;
                //HW_GEN_CONTROL &= ~GEN_TESTMODE;       
                HW_CONF1 &= ~TX_CTL  ;		//piper
                break;        		

            case 4:
                HW_GEN_STATUS = data;
                break;
                                
            default:
                HW_GEN_STATUS = data;       		
                break;	
        }

        macParams.bss_type = bss_save;
        pSta->macStatus.state = WLN_ST_SCANNING;
        
        /* enable common mac interrupts */
        HW_INTR_STATUS = 0xff;
        resetTxFifo();
        HW_INTR_MASK |= INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

#if AIROHA_PWR_CALIBRATION        
        _wapc.Rawdata = 0;
        _wapc.AvgData = 0;
        _wapc.AvgHistory = 0;
#endif        
        tx_thread_resume(&wln_thread);
       
    }

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

/*transmit a beacon every tx_frame_period units*/
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; 
}

/* Build a 1024/128 bytes frame. */
void MacRadioTXRandomBuffer( unsigned int transmit_rate, unsigned int tx_frame_length)
{
    int i;

    if (transmit_rate > 3)
        isOFDM = TRUE;
    else
        isOFDM = FALSE;


    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
}

void MacRadioTXBeacon(int enable, unsigned int transmit_rate, unsigned int tx_frame_period, unsigned int tx_frame_length)
{
    int level;
    epStatus *pSta = rootEndPoint[0];
    
    if (transmit_rate > 3)
        isOFDM = TRUE;
    else
        isOFDM = FALSE;


    /* 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;
        
        tx_thread_suspend(&wln_thread);
	
	while ((HW_GEN_CONTROL & GEN_TXFIFOEMPTY) == 0)
		;
#if AIROHA_PWR_CALIBRATION		
	beaconTestOn = 1;
#endif
        MacRadioPrepareTXBeacon(tx_frame_period);

        MacRadioTXRandomBuffer(transmit_rate, tx_frame_length);        

         /* disable mac interrupts */
        //HW_INTR_MASK = 0;
        HW_INTR_MASK |= INTR_RXOVERRUN;
              
        /* set ad-hoc mode of operation */
        HW_MAC_CONTROL |= (CTRL_IBSS|CTRL_BEACONTX);

#if AIROHA_PWR_CALIBRATION        
        _wapc.Rawdata = 0;
        _wapc.AvgData = 0;
        _wapc.AvgHistory = 0;
#endif         
    }
    else
    {
    	HW_MAC_CONTROL &= ~(CTRL_IBSS|CTRL_BEACONTX);
        HW_GEN_CONTROL &= ~GEN_BEACEN;
#if AIROHA_PWR_CALIBRATION	
	beaconTestOn = 0;
	#endif
	
        /* enable common mac interrupts */
        HW_INTR_STATUS = 0xff;
        resetTxFifo();
        HW_INTR_MASK |= INTR_RXFIFO|INTR_TXEND|INTR_TIMEOUT|INTR_ABORT;

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

#if AIROHA_PWR_CALIBRATION        
        _wapc.Rawdata = 0;
        _wapc.AvgData = 0;
        _wapc.AvgHistory = 0;
#endif              
        tx_thread_resume(&wln_thread);
    }

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

// 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 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;  
             	
         while ((HW_GEN_CONTROL & GEN_TXFIFOEMPTY) == 0)
		 ;  	
             
         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);
}

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

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

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

   (void) offset;
   (void) data;    
}

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

#if 0
    uint8 data;

    data = REG8(offset);
    return data;
#endif
 
    return 0xFF;    
}

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


uint16 MacReadReg16(unsigned int offset)
{
    uint16 data;

    data = REG16(offset);
    return data;
}

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


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;
    epStatus *pSta = rootEndPoint[0];

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

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

        //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;
        pSta->staState = SS_WAIT;
    }

    /* 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;
    
    if (transmit_rate > 3)
        isOFDM = TRUE;
    else
        isOFDM = FALSE;


    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;

        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;
        staState = SS_WAIT;
    }

    /* 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

#ifdef MAC_PS_ENABLED
/*
 * This API backs up the required transceiver register value and holds the
 * transceiver reset line. This API can also be called in power save mode 
 * before entering deep sleep mode. 
 */
void MacEnterSleepMode(void)
{
    TX_INTERRUPT_SAVE_AREA;
    
    TX_DISABLE;
    
    while (HW_RSSI_AES & AES_BUSY)
        ;
    
    while ((HW_GEN_CONTROL & GEN_TXFIFOEMPTY) == 0)     //wait for tx fifo empty
                ;
        
    savedRegs[INDX_GEN_CONTROL] = HW_GEN_CONTROL;
    savedRegs[INDX_GEN_STATUS]  = HW_GEN_STATUS;
    savedRegs[INDX_RSSI_AES]    = HW_RSSI_AES & ~AES_BUSY;
    savedRegs[INDX_INTR_MASK]   = HW_INTR_MASK;
    savedRegs[INDX_SPI_CTRL]    = HW_SPI_CTRL;
    savedRegs[INDX_CONF1]       = HW_CONF1;
    savedRegs[INDX_CONF2]       = HW_CONF2;
    savedRegs[INDX_OUT_CTRL]    = HW_OUT_CTRL;
    savedRegs[INDX_MAC_CONTROL] = HW_MAC_CONTROL;

    ShutdownHW();    
    
    TX_RESTORE;

    // held the transceiver in reset mode
    PIO_CLR(WLN_PS_CNTRL_PIN);

}

/*
 * This API releases the transceiver reset line and writes back the stored 
 * transceiver register value. This API can also be called in power save mode 
 * after coming out of the sleep mode. 
 */
void MacEnterActiveMode(void)
{
    int i;
    
    // release the transceiver reset line
    PIO_SET(WLN_PS_CNTRL_PIN);

    tx_thread_sleep(NS_MILLISECONDS_TO_TICKS(11));

    // store the registers back
    HW_GEN_STATUS  = 0x30000000; // savedRegs[INDX_GEN_STATUS];
    
    HW_RSSI_AES    = savedRegs[INDX_RSSI_AES];
    HW_INTR_MASK   = savedRegs[INDX_INTR_MASK];
    HW_SPI_CTRL    = savedRegs[INDX_SPI_CTRL];
    HW_CONF1       = savedRegs[INDX_CONF1];
    HW_CONF2       = savedRegs[INDX_CONF2];
    HW_AES_MODE    = /*0x10; */ 0;
    HW_OUT_CTRL    = savedRegs[INDX_OUT_CTRL];
    HW_MAC_CONTROL = savedRegs[INDX_MAC_CONTROL];
    
    // set bit-11 in the general control register to a 1 to start the processors
    HW_GEN_CONTROL |= DSP_MACASSIST_ENABLE;

    // set the TX-hold bit
    HW_GEN_CONTROL = 0x37720080;    	
    
    // clear the TX-FIFO memory
    for (i=0; i<448; i++)
        HW_DATA_FIFO = 0;    

    // reset the TX-FIFO
    HW_GEN_CONTROL = 0x377200C0; 	 
    
    // release the TX-hold and reset 	
    HW_GEN_CONTROL = 0x37720000;     	
   
    HW_GEN_CONTROL = (savedRegs[INDX_GEN_CONTROL] | 0x37000000 | GEN_RXEN);

        HW_INTR_STATUS = 0xff; //clear all interrupt status
        HW_INTR_STATUS = 0x0;
        
    NAEnableIsr (INTR_ID);
}

#endif  // MAC_PS_ENABLED

//reset tx FIFO
void resetTxFifo(void)
{
        HW_GEN_CONTROL |= GEN_TXFIFORST;
        HW_GEN_CONTROL &= ~ GEN_TXFIFORST;                  
}
