//////////////////////////////////////////////////////////////////////
// File - prvdrv_lib.c
//
// Library for accessing the PRVDRV card.
// Code was generated by Driver Wizard.
// It accesses the hardware via WinDriver functions.
// 
//////////////////////////////////////////////////////////////////////

#include "prvdrv_lib.h"
#include <stdio.h>

// this string is set to an error message, if one occurs
CHAR PRVDRV_ErrorString[1024];

// internal data structures
typedef struct PRVDRV_STRUCT
{
    HANDLE hWD;
    WD_CARD_REGISTER cardReg;
} PRVDRV_STRUCT;

// internal function used by PRVDRV_Open()
void PRVDRV_SetCardElements(PRVDRV_HANDLE hPRVDRV);

BOOL PRVDRV_Open (PRVDRV_HANDLE *phPRVDRV)
{
    PRVDRV_HANDLE hPRVDRV = (PRVDRV_HANDLE) malloc (sizeof (PRVDRV_STRUCT));

    WD_VERSION ver;

    *phPRVDRV = NULL;
    PRVDRV_ErrorString[0] = '\0';
    BZERO(*hPRVDRV);

    PRVDRV_RegisterWinDriver();

    hPRVDRV->cardReg.hCard = 0;
    hPRVDRV->hWD = WD_Open();

    // check if handle valid & version OK
    if (hPRVDRV->hWD==INVALID_HANDLE_VALUE)
    {
        sprintf( PRVDRV_ErrorString, "Cannot open WinDriver device\n");
        goto Exit;
    }

    BZERO(ver);
    WD_Version(hPRVDRV->hWD,&ver);
    if (ver.dwVer<WD_VER)
    {
        sprintf( PRVDRV_ErrorString, "error - incorrect WinDriver version\n");
        goto Exit;
    }

    PRVDRV_SetCardElements(hPRVDRV);
    hPRVDRV->cardReg.fCheckLockOnly = FALSE;
    WD_CardRegister (hPRVDRV->hWD, &hPRVDRV->cardReg);
    if (hPRVDRV->cardReg.hCard==0)
    {
        sprintf ( PRVDRV_ErrorString, "error - could not lock device.\n");
        goto Exit;
    }

    // Open finished OK
    *phPRVDRV = hPRVDRV;
    return TRUE;

Exit:
    // Error during Open
    if (hPRVDRV->cardReg.hCard) 
        WD_CardUnregister(hPRVDRV->hWD, &hPRVDRV->cardReg);
    if (hPRVDRV->hWD!=INVALID_HANDLE_VALUE)
        WD_Close(hPRVDRV->hWD);
    free (hPRVDRV);
    return FALSE;
}

void PRVDRV_Close(PRVDRV_HANDLE hPRVDRV)
{
    // unregister card
    if (hPRVDRV->cardReg.hCard) 
        WD_CardUnregister(hPRVDRV->hWD, &hPRVDRV->cardReg);

    // close WinDriver
    WD_Close(hPRVDRV->hWD);

    free (hPRVDRV);
}

void PRVDRV_RegisterWinDriver()
{
    HANDLE hWD;
    WD_LICENSE lic;

    hWD = WD_Open();
    if (hWD!=INVALID_HANDLE_VALUE)
    {
         strcpy(lic.cLicense, "73e846476e577cc6373ca2.Parvus Corporation - Troy Takach");
         WD_License(hWD, &lic);
         WD_Close(hWD);
    }
}

void PRVDRV_SetCardElements(PRVDRV_HANDLE hPRVDRV)
{
    int i=0;
    WD_ITEMS* pItem;
    hPRVDRV->cardReg.Card.dwItems = PRVDRV_ITEMS;
    pItem = &hPRVDRV->cardReg.Card.Item[0];

	pItem[PRVDRV_IORange1].item = ITEM_IO;
    pItem[PRVDRV_IORange1].fNotSharable = TRUE;
    pItem[PRVDRV_IORange1].I.IO.dwAddr = PRVDRV_IORange1_ADDR;
    pItem[PRVDRV_IORange1].I.IO.dwBytes = PRVDRV_IORange1_BYTES;


    pItem[PRVDRV_IORange2].item = ITEM_IO;
    pItem[PRVDRV_IORange2].fNotSharable = TRUE;
    pItem[PRVDRV_IORange2].I.IO.dwAddr = PRVDRV_IORange2_ADDR;
    pItem[PRVDRV_IORange2].I.IO.dwBytes = PRVDRV_IORange2_BYTES;

    pItem[PRVDRV_IORange3].item = ITEM_IO;
    pItem[PRVDRV_IORange3].fNotSharable = TRUE;
    pItem[PRVDRV_IORange3].I.IO.dwAddr = PRVDRV_IORange3_ADDR;
    pItem[PRVDRV_IORange3].I.IO.dwBytes = PRVDRV_IORange3_BYTES;

    pItem[PRVDRV_IORange4].item = ITEM_IO;
    pItem[PRVDRV_IORange4].fNotSharable = TRUE;
    pItem[PRVDRV_IORange4].I.IO.dwAddr = PRVDRV_IORange4_ADDR;
    pItem[PRVDRV_IORange4].I.IO.dwBytes = PRVDRV_IORange4_BYTES;

}

// General read/write function
void PRVDRV_ReadWriteBlock(PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset, BOOL fRead, PVOID buf, DWORD dwBytes, PRVDRV_MODE mode)
{
    WD_TRANSFER trans;
    BOOL fMem = hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY;
    BZERO(trans);
    if (fRead)
    {
        if (mode==PRVDRV_MODE_BYTE) trans.cmdTrans = fMem ? RM_SBYTE : RP_SBYTE;
        else if (mode==PRVDRV_MODE_WORD) trans.cmdTrans = fMem ? RM_SWORD : RP_SWORD;
        else if (mode==PRVDRV_MODE_DWORD) trans.cmdTrans = fMem ? RM_SDWORD : RP_SDWORD;
    }
    else
    {
        if (mode==PRVDRV_MODE_BYTE) trans.cmdTrans = fMem ? WM_SBYTE : WP_SBYTE;
        else if (mode==PRVDRV_MODE_WORD) trans.cmdTrans = fMem ? WM_SWORD : WP_SWORD;
        else if (mode==PRVDRV_MODE_DWORD) trans.cmdTrans = fMem ? WM_SDWORD : WP_SDWORD;
    }
    if (fMem)
        trans.dwPort = hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwTransAddr;
    else trans.dwPort = hPRVDRV->cardReg.Card.Item[addrSpace].I.IO.dwAddr;
    trans.dwPort += dwOffset;

    trans.fAutoinc = TRUE;
    trans.dwBytes = dwBytes;
    trans.dwOptions = 0;
    trans.Data.pBuffer = buf;
    WD_Transfer (hPRVDRV->hWD, &trans);
}

BYTE PRVDRV_ReadByte (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset)
{
    BYTE data;
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PBYTE pData = (PBYTE) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        data = *pData; // read from the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, TRUE, &data, sizeof (BYTE), PRVDRV_MODE_BYTE);
    return data;
}

WORD PRVDRV_ReadWord (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset)
{
    WORD data;
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PWORD pData = (PWORD) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        data = *pData; // read from the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, TRUE, &data, sizeof (WORD), PRVDRV_MODE_WORD);
    return data;
}

DWORD PRVDRV_ReadDword (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset)
{
    DWORD data;
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PDWORD pData = (PDWORD) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        data = *pData; // read from the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, TRUE, &data, sizeof (DWORD), PRVDRV_MODE_DWORD);
    return data;
}

void PRVDRV_WriteByte (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset, BYTE data)
{
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PBYTE pData = (PBYTE) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        *pData = data; // write to the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, FALSE, &data, sizeof (BYTE), PRVDRV_MODE_BYTE);
}

void PRVDRV_WriteWord (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset, WORD data)
{
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PWORD pData = (PWORD) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        *pData = data; // write to the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, FALSE, &data, sizeof (WORD), PRVDRV_MODE_WORD);
}

void PRVDRV_WriteDword (PRVDRV_HANDLE hPRVDRV, PRVDRV_ADDR addrSpace, DWORD dwOffset, DWORD data)
{
    if (hPRVDRV->cardReg.Card.Item[addrSpace].item==ITEM_MEMORY)
    {
        PDWORD pData = (PDWORD) (hPRVDRV->cardReg.Card.Item[addrSpace].I.Mem.dwUserDirectAddr + dwOffset);
        *pData = data; // write to the memory mapped range directly
    }
    else PRVDRV_ReadWriteBlock( hPRVDRV, addrSpace, dwOffset, FALSE, &data, sizeof (DWORD), PRVDRV_MODE_DWORD);
}

