////////////////////////////////////////////////////////////////
// File - V3pbclib.h
//
// Library for 'WinDriver for V3 Semiconductor PBC family of devices. 
// The basic idea is to get a handle for the board
// with V3PBC_Open() and use it in the rest of the program
// when calling WD functions.  Call V3PBC_Close() when done.
// 
////////////////////////////////////////////////////////////////

#ifndef _PBCLIB_H_
#define _PBCLIB_H_

#include "../../samples/shared/pci_regs.h"
#include "../../samples/shared/bits.h"

#ifdef __cplusplus
extern "C" {
#endif

enum { V3PBCLIB_VER = 100 };
    
// PCI Configuration registers definitions 
enum {
    V3PBC_PCI_VENDOR      = 0x00,
    V3PBC_PCI_DEVICE      = 0x02,
    V3PBC_PCI_CMD         = 0x04,
    V3PBC_PCI_STAT        = 0x06,
    V3PBC_PCI_CC_REV      = 0x08,
    V3PBC_PCI_HDR_CFG     = 0x0c,
    V3PBC_PCI_IO_BASE     = 0x10,
    V3PBC_PCI_BASE0       = 0x14,
    V3PBC_PCI_BASE1       = 0x18,
    V3PBC_PCI_SUB_VENDOR  = 0x2c,
    V3PBC_PCI_SUB_ID      = 0x2e,
    V3PBC_PCI_ROM         = 0x30,
    V3PBC_PCI_BPARM       = 0x3c,
    V3PBC_PCI_MAP0        = 0x40,
    V3PBC_PCI_MAP1        = 0x44,
    V3PBC_INT_STAT        = 0x48,
    V3PBC_INT_CFG         = 0x4c,
    V3PBC_LB_BASE0        = 0x54,
    V3PBC_LB_BASE1        = 0x58,
    V3PBC_LB_MAP0         = 0x5e,
    V3PBC_LB_MAP1         = 0x62,
    V3PBC_LB_IO_BASE      = 0x6e,
    V3PBC_FIFO_CFG        = 0x70,
    V3PBC_FIFO_PRIORITY   = 0x72,
    V3PBC_FIFO_STAT       = 0x74,
    V3PBC_LB_ISTAT        = 0x76,
    V3PBC_LB_IMASK        = 0x77,
    V3PBC_SYSTEM          = 0x78,
    V3PBC_LB_CFG          = 0x7a,
    V3PBC_DMA_PCI_ADDR0   = 0x80,
    V3PBC_DMA_LOCAL_ADDR0 = 0x84,
    V3PBC_DMA_LENGTH0     = 0x88,  // mask off upper 8 bits 
    V3PBC_DMA_CSR0        = 0x8b,
    V3PBC_DMA_CTLB_ADR0   = 0x8c,
    V3PBC_DMA_PCI_ADDR1   = 0x90,
    V3PBC_DMA_LOCAL_ADDR1 = 0x94,
    V3PBC_DMA_LENGTH1     = 0x98,  // mask off upper 8 bits 
    V3PBC_DMA_CSR1        = 0x9b,
    V3PBC_DMA_CTLB_ADR1   = 0x9c,
    V3PBC_IFL_TAIL        = 0xa0, // implemented on revision B2
    V3PBC_IFL_HEAD        = 0xa4, // implemented on revision B2
    V3PBC_IPL_TAIL        = 0xa8, // implemented on revision B2
    V3PBC_IPL_HEAD        = 0xac, // implemented on revision B2
    V3PBC_OPL_TAIL        = 0xb0, // implemented on revision B2
    V3PBC_OPL_HEAD        = 0xb4, // implemented on revision B2
    V3PBC_OFL_TAIL        = 0xb8, // implemented on revision B2
    V3PBC_OFL_HEAD        = 0xbc, // implemented on revision B2
    V3PBC_MAIL_DATA0      = 0xc0,
    V3PBC_MAIL_DATA1      = 0xc1,
    V3PBC_MAIL_DATA2      = 0xc2,
    V3PBC_MAIL_DATA3      = 0xc3,
    V3PBC_MAIL_DATA4      = 0xc4,
    V3PBC_MAIL_DATA5      = 0xc5,
    V3PBC_MAIL_DATA6      = 0xc6,
    V3PBC_MAIL_DATA7      = 0xc7,
    V3PBC_MAIL_DATA8      = 0xc8,
    V3PBC_MAIL_DATA9      = 0xc9,
    V3PBC_MAIL_DATA10     = 0xca,
    V3PBC_MAIL_DATA11     = 0xcb,
    V3PBC_MAIL_DATA12     = 0xcc,
    V3PBC_MAIL_DATA13     = 0xcd,
    V3PBC_MAIL_DATA14     = 0xce,
    V3PBC_MAIL_DATA15     = 0xcf,
    V3PBC_MAIL_IEWR       = 0xd0,
    V3PBC_MAIL_IERD       = 0xd2,
    V3PBC_LB_MAIL_IEWR    = 0xd4,
    V3PBC_LB_MAIL_IERD    = 0xd6,
    V3PBC_MAIL_WR_STAT    = 0xd8,
    V3PBC_MAIL_RD_STAT    = 0xda,
    V3PBC_QBA_MAP         = 0xdc // implemented on revision B2
};

typedef enum {
    V3PBC_REV_A  = 0,
    V3PBC_REV_B0 = 1,
    V3PBC_REV_B1 = 2,
    V3PBC_REV_B3 = 3,
} V3PBC_REV;

typedef enum
{
    V3PBC_ADDR_IO_BASE = AD_PCI_BAR0,
    V3PBC_ADDR_BASE0   = AD_PCI_BAR1,
    V3PBC_ADDR_BASE1   = AD_PCI_BAR2,
    V3PBC_ADDR_ROM     = AD_PCI_BAR_EPROM
} V3PBC_ADDR;

typedef enum
{
    V3PBC_MODE_BYTE   = 0,
    V3PBC_MODE_WORD   = 1,
    V3PBC_MODE_DWORD  = 2
} V3PBC_MODE;

enum { V3PBC_RANGE_REG = 0x00000100 };

typedef struct V3PBC_STRUCT *V3PBCHANDLE;

typedef struct
{
    DWORD dwCounter;   // number of interrupts received
    DWORD dwLost;      // number of interrupts not yet dealt with
    BOOL fStopped;     // was interrupt disabled during wait
    DWORD dwStatusReg; // value of status register when interrupt occured
} V3PBC_INT_RESULT;
typedef void (WINAPI *V3PBC_INT_HANDLER)( V3PBCHANDLE hV3, V3PBC_INT_RESULT *intResult);

typedef struct
{
    WD_INTERRUPT Int;
    HANDLE hThread;
    WD_TRANSFER Trans[2];
    V3PBC_INT_HANDLER funcIntHandler;
} V3PBC_INTERRUPT;

typedef struct
{
    DWORD dwLocalBase;
    DWORD dwMask;
    DWORD dwBytes;
    DWORD dwAddr;
    DWORD dwAddrDirect;
    BOOL  fIsMemory;
} V3PBC_ADDR_DESC;

typedef struct V3PBC_STRUCT
{
    HANDLE hWD;
    WD_CARD cardLock;
    WD_PCI_SLOT pciSlot;
    WD_CARD_REGISTER cardReg;
    V3PBC_ADDR_DESC addrDesc[AD_PCI_BARS];
    BOOL   fUseInt;
    V3PBC_INTERRUPT Int;
    DWORD  dwReg_PCI_MAP0;
} V3PBC_STRUCT;

typedef enum
{
    V3_DMA_0 = 0,
    V3_DMA_1 = 1
} V3_DMA_CHANNEL;

// options for V3PBC_Open
enum { V3PBC_OPEN_USE_INT =   0x1 };

// Count number of cards in PCI bus with given VendorID / DeviceID 
// dwVendorID / dwDeviceID -    the VendorID / DeviceID of cards to count
// dwVendorId - PCI Vendor ID to detect. If 0, detects cards from all vendors.
// dwDeviceId - PCI Device ID to detect. If 0, detects all devices.
// if both are '0', counts all PCI cards
DWORD V3PBC_CountCards (DWORD dwVendorID, DWORD dwDeviceID);

// Opens a handle to a V3PBC card.  The handle will be used in future calls to the card
// nCardNum - differentiates between cards with same VendorID / DeviceID on the bus (0,1,...)
// dwOptions - 0 if no interrupts needed, or V3PBC_OPEN_USE_INT for use of interrupts in session
// You may use the wildcard option in dwDeviceID / dwVendorID (i.e. use '0') to open all
// cards detected in V3PBC_CountCards (use a loop...)
BOOL V3PBC_Open (V3PBCHANDLE *phV3, DWORD dwVendorID, DWORD dwDeviceID, DWORD nCardNum, DWORD dwOptions);

// must be called when ending session.  Frees handle to card.
void V3PBC_Close (V3PBCHANDLE hV3);

// returns TRUE if addrSpace exists
BOOL V3PBC_IsAddrSpaceActive(V3PBCHANDLE hV3, V3PBC_ADDR addrSpace);

// returns the V3 PBC silicon revision (equates defined in V3PBC_REV)
DWORD V3PBC_GetRevision(V3PBCHANDLE hV3);

// Read a block of data from card to buffer
// buf - buffer to read data into
// addrSpace - Address space on card to read from 
// dwLocalAddr - offset of address to read, in the address space
// dwBytes - number of bytes to read

// Write a block of data from buffer to card 
// buf - buffer to write data from
// addrSpace - Address space on card to write to
// dwLocalAddr - offset of address to write to, in the address space
// dwBytes - number of bytes to write

// The following functions Read/Write a Byte/Word/DWord to/from an address space on the card
// addrSpace - Address space on card to read to / write from 
// dwOffset - offset of address to read to / write from, in the address space
// data - the data to write.
BYTE V3PBC_ReadSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset);
void V3PBC_WriteSpaceByte (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, BYTE data);
WORD V3PBC_ReadSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset);
void V3PBC_WriteSpaceWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, WORD data);
DWORD V3PBC_ReadSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset);
void V3PBC_WriteSpaceDWord (V3PBCHANDLE hV3, V3PBC_ADDR addrSpace, DWORD dwOffset, DWORD data);
// Block transfers
void V3PBC_ReadSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf, 
                    DWORD dwBytes, V3PBC_ADDR addrSpace);
void V3PBC_WriteSpaceBlock (V3PBCHANDLE hV3, DWORD dwOffset, PVOID buf, 
                     DWORD dwBytes, V3PBC_ADDR addrSpace);

// The following functions Read/Write a Byte/Word/DWord to/from a local address on the card
// dwLocalAddr - local address to read to / write from
// data - the data to write.
BYTE V3PBC_ReadByte (V3PBCHANDLE hV3, DWORD dwLocalAddr);
void V3PBC_WriteByte (V3PBCHANDLE hV3, DWORD dwLocalAddr, BYTE data);
WORD V3PBC_ReadWord (V3PBCHANDLE hV3, DWORD dwLocalAddr);
void V3PBC_WriteWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, WORD data);
DWORD V3PBC_ReadDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr);
void V3PBC_WriteDWord (V3PBCHANDLE hV3, DWORD dwLocalAddr, DWORD data);
// Block transfers
void V3PBC_ReadBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes);
void V3PBC_WriteBlock (V3PBCHANDLE hV3, DWORD dwLocalAddr, PVOID buf, DWORD dwBytes);

// The following functions Read/Write a Byte/Word/DWord to/from a register
// data - the data to write.
void V3PBC_WriteRegByte (V3PBCHANDLE hV3, DWORD dwReg, BYTE bData);
BYTE V3PBC_ReadRegByte (V3PBCHANDLE hV3, DWORD dwReg);
void V3PBC_WriteRegWord (V3PBCHANDLE hV3, DWORD dwReg, WORD wData);
WORD V3PBC_ReadRegWord (V3PBCHANDLE hV3, DWORD dwReg);
void V3PBC_WriteRegDWord (V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData);
DWORD V3PBC_ReadRegDWord (V3PBCHANDLE hV3, DWORD dwReg);

// Enable / Disable interrupt handler routines
BOOL V3PBC_IntIsEnabled (V3PBCHANDLE hV3);
BOOL V3PBC_IntEnable (V3PBCHANDLE hV3, V3PBC_INT_HANDLER funcIntHandler);
void V3PBC_IntDisable (V3PBCHANDLE hV3);

// access PCI configuration registers
DWORD V3PBC_ReadPCIReg(V3PBCHANDLE hV3, DWORD dwReg);
void V3PBC_WritePCIReg(V3PBCHANDLE hV3, DWORD dwReg, DWORD dwData);

// Initializes the WD_DMA structure (see windrvr.h) and allocates a contiguous buffer
BOOL V3PBC_DMAOpen(V3PBCHANDLE hV3, WD_DMA *pDMA, DWORD dwBytes);

// Frees the DMA handle, and frees the allocated contiguous buffer
void V3PBC_DMAClose(V3PBCHANDLE hV3, WD_DMA *pDMA);

// Start DMA to/from card.
// pDMA - initialized with V3PBC_DMAOpen
// fRead - TRUE: read from card to buffer.  FALSE: write from buffer to card
// fBlocking - TRUE: wait until DMA is done
// dwBytes - number of bytes to transfer (must be a multiple of 4)
// dwOffset - offset in DMA buffer to read to / write from.
// dwLocalAddr - local address on card to write to / read from
BOOL V3PBC_DMAStart(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel, WD_DMA *pDMA, BOOL fRead,
    BOOL fBlocking, DWORD dwBytes, DWORD dwOffset, DWORD dwLocalAddr);

// Used to test if DMA is done. (Use when V3PBC_DMAStart was called with fBlocking==FALSE) 
BOOL V3PBC_DMAIsDone(V3PBCHANDLE hV3, V3_DMA_CHANNEL dmaChannel);

// Sends a reset signal to the card, for a period of 'wDelay' milliseconds
void V3PBC_PulseLocalReset(V3PBCHANDLE hV3, WORD wDelay);

// initialize I2C bus
void V3PBC_EEPROMInit(V3PBCHANDLE hV3);

// Programs one byte to the EEPROM
// bAddr - address to write to 
// bData - data to write
BOOL V3PBC_EEPROMWrite(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE bData);

// Reads one byte to the EEPROM
// bAddr - address to read from  
// bData - data read.
BOOL V3PBC_EEPROMRead(V3PBCHANDLE hV3, BYTE bSlaveAddr, BYTE bAddr, BYTE *bData);

// this string is set to an error message, if one occurs
extern CHAR V3PBC_ErrorString[];

// System register bit equates 
enum {
    SYSTEM_RST_OUT   = BIT15,
    SYSTEM_LOCK      = BIT14,
    SYSTEM_SPROM_EN  = BIT13,
    SYSTEM_SCL       = BIT12,
    SYSTEM_SDA_OUT   = BIT11,
    SYSTEM_SDA_IN    = BIT10
};

enum { SYSTEM_UNLOCK_TOKEN   = 0xa05f };

// I2C Bus states
enum {
    I2C_WRITE = 0,
    I2C_READ = 1
};

// number of times a master will try and write to a slave device 
enum { I2C_RETRY = 10 };
enum { I2C_1010  = 0x50 };

enum { SYSTEM_SDA_IN_SHIFT   = 10 };


#ifdef __cplusplus
}
#endif

#endif