// =============================================
// prvdrv_dll.c - lowest level generic driver
// =============================================
// (c) Copyright 2000
// The Parvus Corporation
// 396 Ironwood Drive
// Salt Lake City, UT 84115
// Tel:      (801) 483-1533
// Fax:      (801) 483-1523
// Web:      www.parvus.com
// Email:    parvus@parvus.com
// ---------------------------------------------
//   Revision History:
// ---------------------------------------------
//
//   10/15/2000 CG - V1.00.00 release
//	 10/22/2000 CG - Add RemoveAllShadow() function
//	 06/07/2002 GATJR - Fixed write size error,  All BYTE save rather BYTE, WORD, DWORD
//
// ---------------------------------------------
//
// This module is intended to be compiled together with the
// modules "prvdrv_lib.h" and "prvdrv_lib.c" which are generated
// by the WinDriver Wizard.
//
// This module is also intended to be used with a higher level
// layer in constructing the DLL to be used with specific boards
// that have different I/O or memory configurations.
//
// ---------------------------------------------

// -------------
// Include Files
// -------------

#include <stdlib.h>
#include <malloc.h>
#include "prvdrv_lib.h"
#include "prvdrv.h"


// ----------------------------------
// Internal WinDriver Data Structures
// ----------------------------------

typedef struct PRVDRV_STRUCT
{
    HANDLE hWD;
    WD_CARD_REGISTER cardReg;
} PRVDRV_STRUCT;


// ----------
// Local Data
// ----------

static PRVDRV_HANDLE	hPRVDRV = NULL;
static PRVDRV_RANGES	range;

// ----------------
// Shadow Structure
// ----------------

#define nSHADOWS	25							// allow up to 25 shadowed items
#define ASSIGNED	0xE5AF03C9					// magic number

typedef struct PRVDRV_SHADOW
{
	unsigned int	  assigned;					// ASSIGNED if assigned, else not assigned
	PRVDRV_ACCESSTYPE mde;						// mode PRVDRV_IO, PRVDRV_MEM
	PRVDRV_WORDSIZE   sze;						// size PRVDRV_BYTE, etc
	unsigned int	  rnge;						// range index for I/O or MEM, 0,1,2 etc
	unsigned int	  offset;					// offset from base for shadow
	unsigned int	  shadowval;				// current shadow value
} PRVDRV_SHADOW;

static PRVDRV_SHADOW Shadow[nSHADOWS];			// array of shadow values

// ----------------
// Local Prototypes
// ----------------

static unsigned int prvdrv_Read1(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset);		// offset from base for read


// =======================
// LOCAL support functions
// =======================

// ----------------------------------------------------------------
// prvdrv_InitRanges() - Initialize the I/O and Memory Information
// ----------------------------------------------------------------
static void prvdrv_InitRange(void)
{
	unsigned int i;
    WD_ITEMS*	pItem;

	// Initialize the shadow memory
	for (i=0; i<nSHADOWS; i++) Shadow[i].assigned = 0; // mark as unassigned

	// Initialize the memory and i/o ranges
	range.nRanges	= 0;
	range.nIo		= 0;
	range.nMem		= 0;
	if (!hPRVDRV) return;

	// Find and setup the ranges
	range.nRanges = hPRVDRV->cardReg.Card.dwItems;
    pItem = &hPRVDRV->cardReg.Card.Item[0];

	for (i=0; i < range.nRanges; i++)
	{
		switch (pItem[i].item)
		{
			case ITEM_IO:
				if (range.nIo >= MAX_IO) break;
				range.io[range.nIo].base  = pItem[i].I.IO.dwAddr;
				range.io[range.nIo].bytes = pItem[i].I.IO.dwBytes;
				range.io[range.nIo].offset= i;
				range.nIo++;
				break;
			case ITEM_MEMORY:
				if (range.nMem >= MAX_MEM) break;
				range.mem[range.nMem].base  = pItem[i].I.Mem.dwPhysicalAddr;
				range.mem[range.nMem].bytes = pItem[i].I.Mem.dwBytes;
				range.mem[range.nMem].offset= i;
				range.nMem++;
				break;
			default:
				break;
		}
	}
}

// =================================================
// DLL callable functions - Organized alphabetically
// =================================================

// ------------------------------------------------------
// prvdrv_CardRanges() - Return the I/O and Memory Ranges
// ------------------------------------------------------
PRVDRV_RANGES* prvdrv_CardRanges(void)
{
	if (!hPRVDRV) return(NULL);
	else return(&range);
}

// ------------------------------------------
// prvdrv_ClearBit() - Clear bit in the Range
// ------------------------------------------
void prvdrv_ClearBit(PRVDRV_ACCESSTYPE mde, PRVDRV_WORDSIZE sze, unsigned int rnge, unsigned int offset, unsigned int bit)
{
	unsigned int dta;

	// normalize the bit (all other checks done with read/write)
	switch (sze)
	{
		case PRVDRV_BYTE:
			offset += (bit / 8);
			bit     = bit % 8;
			break;
		case PRVDRV_WORD:
			offset += (bit / 16);
			bit     = bit % 16;
			break;
		case PRVDRV_DWORD:
			offset += (bit / 32);
			bit     = bit % 32;
			break;
		default:
			return;
	}

	dta = prvdrv_ReadShadow(mde, sze, rnge, offset);
	dta &= ~(((unsigned int)(1)) << bit);
	prvdrv_Write(mde, sze, rnge, offset,dta);
}

// ----------------------------------
// prvdrv_Close() - Terminate the DLL
// ----------------------------------
void prvdrv_Close(void)
{
	if (hPRVDRV) PRVDRV_Close(hPRVDRV);
	hPRVDRV	 = NULL;
}

// -------------------------------------------------
// prvdrv_ErrorString() - Return the DLL ErrorString
// -------------------------------------------------
char* prvdrv_ErrorString(void)
{
	return((char*)PRVDRV_ErrorString);
}

// ------------------------------------------
// prvdrv_GetBit() - Get bit in the Range
// ------------------------------------------
unsigned int prvdrv_GetBit(PRVDRV_ACCESSTYPE mde, PRVDRV_WORDSIZE sze, unsigned int rnge, unsigned int offset, unsigned int bit)
{
	unsigned int dta;

	// normalize the bit (all other checks done with read/write)
	switch (sze)
	{
		case PRVDRV_BYTE:
			offset += (bit / 8);
			bit     = bit % 8;
			break;
		case PRVDRV_WORD:
			offset += (bit / 16);
			bit     = bit % 16;
			break;
		case PRVDRV_DWORD:
			offset += (bit / 32);
			bit     = bit % 32;
			break;
		default:
			return 0;
	}

	dta = prvdrv_Read(mde, sze, rnge, offset);
	dta &= (((unsigned int)(1)) << bit);
	return dta;
}

// ----------------------------------
// prvdrv_Open() - Initialize the DLL
// ----------------------------------
PRVDRV_RESULT prvdrv_Open(void)
{
	// Internal Initialization
	hPRVDRV = NULL;								// No pointer to WinDriver control
	
	// Driver Initialization
    PRVDRV_RegisterWinDriver();
    if (!PRVDRV_Open(&hPRVDRV))
	{
        // Error - Use prvdrv_ErrorString()
		hPRVDRV = NULL;
		prvdrv_InitRange();
		return PRVDRV_FAIL;
    }
	else
	{
		// OK return
		prvdrv_InitRange();
		return PRVDRV_OK;
	}
}

// -----------------------------------------
// prvdrv_Read() - Read an item from a Range
// -----------------------------------------
unsigned int prvdrv_Read(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset)		// offset from base for read
{
	// Various range and validity checks
	if (!hPRVDRV) return 0;

	if (mde == PRVDRV_IO)
	{
		if (rnge >= range.nIo) return 0;
		if (offset >= range.io[rnge].bytes) return 0;
	}
	else if (mde == PRVDRV_MEM)
	{
		if (rnge >= range.nMem) return 0;
		if (offset >= range.mem[rnge].bytes) return 0;
	}
	else return 0;
	return prvdrv_Read1(mde,sze,rnge,offset);	// Do the actual read
}

// ---------------------------------------------------------
// prvdrv_Read1() - Read an item from a Range - after checks
// ----------------------------------------------------------
static unsigned int prvdrv_Read1(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset)		// offset from base for read
{
	unsigned int rslt;
	// Do the read based on size
	switch (sze)
	{
		case PRVDRV_BYTE:
			rslt = (unsigned int)PRVDRV_ReadByte(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the adress space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset);				// the offset
			break;
		case PRVDRV_WORD:
			rslt = (unsigned int)PRVDRV_ReadWord(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the adress space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset);				// the offset
			break;
		case PRVDRV_DWORD:
			rslt = (unsigned int)PRVDRV_ReadDword(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the adress space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset);				// the offset
			break;
	}
	return rslt;
}

// --------------------------------------------
// prvdrv_ReadBlock() - Read a block from Range
// --------------------------------------------
void prvdrv_ReadBlock(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset,		// offset from base for read
				void*			  pblk,			// pointer to block to write back to
				unsigned int	  len)			// number of items to write
{
	BYTE*	pbyte;								// set up pointer types for each type
	WORD*	pword;
	DWORD*	pdword;
	unsigned int i;
	unsigned int val;

	switch (sze)
	{
		case PRVDRV_BYTE:
			pbyte = (BYTE*)pblk;
			for (i=0; i<len; i++)
			{
				val = prvdrv_Read(mde,sze,rnge,offset+i);
				*pbyte = (BYTE)val;
				pbyte++;
			}
			break;
		case PRVDRV_WORD:
			pword = (WORD*)pblk;
			for (i=0; i<len; i++)
			{
				val = prvdrv_Read(mde,sze,rnge,offset+i);
				*pword = (WORD)val;
				pword++;
			}
			break;
		case PRVDRV_DWORD:
			pdword = (DWORD*)pblk;
			for (i=0; i<len; i++)
			{
				val = prvdrv_Read(mde,sze,rnge,offset+i);
				*pdword = (BYTE)val;
				pdword++;
			}
			break;
	}
	return;
}

// ----------------------------------------------------------------
// prvdrv_ReadShadow() - Read a range item from Shadow or from Real
// ----------------------------------------------------------------
unsigned int prvdrv_ReadShadow(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset)		// offset from base for read
{
	// Variables
	unsigned int j;

	// Various range and validity checks
	if (!hPRVDRV) return 0;

	if (mde == PRVDRV_IO)
	{
		if (rnge >= range.nIo) return 0;
		if (offset >= range.io[rnge].bytes) return 0;
	}
	else if (mde == PRVDRV_MEM)
	{
		if (rnge >= range.nMem) return 0;
		if (offset >= range.mem[rnge].bytes) return 0;
	}
	else return 0;

	// Check for Shadow
	for (j=0; j<nSHADOWS; j++)					// find matching shadow
	{
		if (Shadow[j].assigned != ASSIGNED) break;	// its assigned sequentially
		if (
			Shadow[j].mde == mde &&				// copy mode
			Shadow[j].rnge == rnge &&			// which range
			Shadow[j].offset == offset			// calculate offset
		   )
		{
			return Shadow[j].shadowval;			// return the shadow value
		}
	}
	return prvdrv_Read1(mde,sze,rnge,offset);	// Do the actual read
}

// -------------------------------------------
// prvdrv_RemoveAllShadow() - Reset the Shadow
// -------------------------------------------
void prvdrv_RemoveAllShadow(void)
{
	int i;
	for (i=0; i<nSHADOWS; i++)
	{
		Shadow[i].assigned=0; // mark as unassigned
	}
}

// ----------------------------------------
// prvdrv_SetBit() - Set a bit in the Range
// ----------------------------------------
void prvdrv_SetBit(PRVDRV_ACCESSTYPE mde, PRVDRV_WORDSIZE sze, unsigned int rnge, unsigned int offset, unsigned int bit)
{
	unsigned int dta;

	// normalize the bit (all other checks done with read/write)
	switch (sze)
	{
		case PRVDRV_BYTE:
			offset += (bit / 8);
			bit     = bit % 8;
			break;
		case PRVDRV_WORD:
			offset += (bit / 16);
			bit     = bit % 16;
			break;
		case PRVDRV_DWORD:
			offset += (bit / 32);
			bit     = bit % 32;
			break;
		default:
			return;
	}

	dta = prvdrv_ReadShadow(mde, sze, rnge, offset);
	dta |= ((unsigned int)(1)) << bit;
	prvdrv_Write(mde, sze, rnge, offset,dta);
}

// ------------------------------------------------------------
// prvdrv_SetShadow() - Set a Range to be Shadowed (write-only)
// ------------------------------------------------------------
void prvdrv_SetShadow(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset,		// offset from base for shadow
				unsigned int	  items)		// number of items to shadow
{
	unsigned int i,j;

	j = 0;
	for (i=0; i<items; i++)
	{
		while (j < nSHADOWS && Shadow[j].assigned==ASSIGNED) j++; // find first available slot
		if (j==nSHADOWS) return;				// no slots left - could add error return here
		Shadow[j].assigned=ASSIGNED;			// assign it
		Shadow[j].mde = mde;					// copy mode
		Shadow[j].rnge = rnge;					// which range
		Shadow[j].offset = offset+i;			// calculate offset
		Shadow[j].shadowval = 0;				// initialize shadow to zero
		j++;									// move to next slot
	}
	return;
}

// ----------------------------------------------
// prvdrv_ToggleBit() - Toggle a bit in the Range
// ----------------------------------------------
void prvdrv_ToggleBit(PRVDRV_ACCESSTYPE mde, PRVDRV_WORDSIZE sze, unsigned int rnge, unsigned int offset, unsigned int bit)
{
	unsigned int dta;

	// normalize the bit (all other checks done with read/write)
	switch (sze)
	{
		case PRVDRV_BYTE:
			offset += (bit / 8);
			bit     = bit % 8;
			break;
		case PRVDRV_WORD:
			offset += (bit / 16);
			bit     = bit % 16;
			break;
		case PRVDRV_DWORD:
			offset += (bit / 32);
			bit     = bit % 32;
			break;
		default:
			return;
	}

	dta = prvdrv_ReadShadow(mde, sze, rnge, offset);
	dta ^= (((unsigned int)(1)) << bit);
	prvdrv_Write(mde, sze, rnge, offset,dta);
}

// -----------------------------------------
// prvdrv_Write() - Write an item to a Range
// -----------------------------------------
void prvdrv_Write(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset,		// offset from base for read
				unsigned int	  val)			// value to be written
{
	// Variables
	unsigned int j;

	// Various range and validity checks
	if (!hPRVDRV) return;

	if (mde == PRVDRV_IO)
	{
		if (rnge >= range.nIo) return;
		if (offset >= range.io[rnge].bytes) return;
	}
	else if (mde == PRVDRV_MEM)
	{
		if (rnge >= range.nMem) return;
		if (offset >= range.mem[rnge].bytes) return;
	}
	else return;

	// Check for Shadow
	for (j=0; j<nSHADOWS; j++)					// find matching shadow
	{
		if (Shadow[j].assigned != ASSIGNED) break;	// its assigned sequentially
		if (
			Shadow[j].mde == mde &&				// copy mode
			Shadow[j].rnge == rnge &&			// which range
			Shadow[j].offset == offset			// calculate offset
		   )
		{
			Shadow[j].shadowval = val;			// capture the new value being shadowed
			break;								// we're done with copying shadow
		}
	}
	
	// Do the write based on size
	switch (sze)
	{
		case PRVDRV_BYTE:
			PRVDRV_WriteByte(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the address space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset,				// the offset
					(BYTE)val);					// the value
			break;
		case PRVDRV_WORD:
			PRVDRV_WriteWord(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the address space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset,				// the offset
					(WORD)val);					// the value
			break;
		case PRVDRV_DWORD:
			PRVDRV_WriteDword(
					hPRVDRV,					// the handle
					mde == PRVDRV_IO			// the address space range
						? range.io[rnge].offset
						: range.mem[rnge].offset,
					(DWORD)offset,				// the offset
					(DWORD)val);					// the value
			break;
	}
	return;
}

// ----------------------------------------------
// prvdrv_WriteBlock() - Write a block to a Range
// ----------------------------------------------
void prvdrv_WriteBlock(
				PRVDRV_ACCESSTYPE mde,			// mode PRVDRV_IO, PRVDRV_MEM
				PRVDRV_WORDSIZE   sze,			// size PRVDRV_BYTE, etc
				unsigned int	  rnge,			// range index for I/O or MEM, 0,1,2 etc
				unsigned int	  offset,		// offset from base for read
				void*			  pblk,			// pointer to block to write
				unsigned int	  len)			// number of items to write
{
	BYTE*	pbyte;								// set up pointer types for each type
	WORD*	pword;
	DWORD*	pdword;
	unsigned int i;

	switch (sze)
	{
		case PRVDRV_BYTE:
			pbyte = (BYTE*)pblk;
			for (i=0; i<len; i++)
			{
				prvdrv_Write(mde,sze,rnge,offset+i,(unsigned int)(*pbyte));
				pbyte++;
			}
			break;
		case PRVDRV_WORD:
			pword = (WORD*)pblk;
			for (i=0; i<len; i++)
			{
				prvdrv_Write(mde,sze,rnge,offset+i,(unsigned int)(*pword));
				pword++;
			}
			break;
		case PRVDRV_DWORD:
			pdword = (DWORD*)pblk;
			for (i=0; i<len; i++)
			{
				prvdrv_Write(mde,sze,rnge,offset+i,(unsigned int)(*pdword));
				pdword++;
			}
			break;
	}
	return;
}


// ********************************************************************
// VB FUNCTIONS
// ********************************************************************

// MDE
#define	VB_IO 0
#define	VB_MEM 1

// SZE
#define VB_BYTE 0
#define VB_WORD 1
#define VB_DWORD 2

// RESULT
#define VB_OK 0
#define VB_FAIL 1
#define VB_CLOSED 2

static	PRVDRV_ACCESSTYPE Bmde;
static	PRVDRV_WORDSIZE Bsze;
static 	unsigned int Brnge;
static 	unsigned int Boffset;

static int vbFIX(long VBmde, long VBsze, long VBrnge, long VBoffset)
{
	// Fix MDE
	switch (VBmde)
	{
		case VB_IO:
			Bmde = PRVDRV_IO;
			break;
		case VB_MEM:
			Bmde = PRVDRV_MEM;
			break;
		default:
			return(-1);
	}

	// Fix SZE
	switch (VBsze)
	{
		case VB_BYTE:
			Bsze = PRVDRV_BYTE;
			break;
		case VB_WORD:
			Bsze = PRVDRV_WORD;
			break;
		case VB_DWORD:
			Bsze = PRVDRV_DWORD;
			break;
		default:
			return(-1);
	}

	// Fix RNGE
	Brnge = (unsigned int)((unsigned long)VBrnge);

	// Fix OFFSET
	Boffset = (unsigned int)((unsigned long)VBoffset);

	return(0);
}

// ---------------------------------------
// Map VB functions to "C" functions above
// ---------------------------------------

void WINAPI vbdrv_CardRanges
   (
	  unsigned int* nRanges,
	  unsigned int* nIo,
	  unsigned int* nMem,
	  unsigned int* ioBase,
	  unsigned int* ioBytes,
	  unsigned int* ioOffset,
	  unsigned int* memBase,
	  unsigned int* memBytes,
	  unsigned int* memOffset
   )
{
	unsigned int i;
	*nRanges	= range.nRanges;
	*nIo		= range.nIo;
	*nMem		= range.nMem;
	for (i=0; i<range.nIo; i++)
	{
		ioBase[i]  = range.io[i].base;
		ioBytes[i] = range.io[i].bytes;
		ioOffset[i]= range.io[i].offset;
	}
	for (i=0; i<range.nMem; i++)
	{
		memBase[i]  = range.mem[i].base;
		memBytes[i] = range.mem[i].bytes;
		memOffset[i]= range.mem[i].offset;
	}
}

void WINAPI vbdrv_ClearBit(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBbit)
{
	unsigned int Bbit;
	Bbit = (unsigned int)((unsigned long)VBbit);
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	prvdrv_ClearBit(Bmde,Bsze,Brnge,Boffset,Bbit);
	return;
}

void WINAPI vbdrv_Close(void)
{
	prvdrv_Close();
	return;
}

// ***FIX***
void WINAPI vbdrv_ErrorString(void)
{
	return;
}

long WINAPI vbdrv_GetBit(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBbit)
{
	unsigned int Bbit;
	Bbit = (unsigned int)((unsigned long)VBbit);
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return 0;
	return((long)((int)prvdrv_GetBit(Bmde,Bsze,Brnge,Boffset,Bbit)));
}

long WINAPI vbdrv_Open()
{
	PRVDRV_RESULT rslt;
	long Brslt;
	rslt = prvdrv_Open();
	switch (rslt)
	{
		case PRVDRV_OK:
			Brslt = VB_OK;
			break;
		case PRVDRV_CLOSED:
			Brslt = VB_CLOSED;
			break;
		case PRVDRV_FAIL:
		default:
			Brslt = VB_FAIL;
			break;
	}
	return(Brslt);
}

long WINAPI vbdrv_Read(long VBmde, long VBsze, long VBrnge, long VBoffset)
{
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return 0;
	return((long)((int)prvdrv_Read(Bmde,Bsze,Brnge,Boffset)));
}

void WINAPI vbdrv_ReadBlock(long VBmde, long VBsze, long VBrnge, long VBoffset, long* VBpblk, long VBlen)
{
	void*			Bpblk;
	unsigned int	Blen,i;
	if (VBlen <= 0) return;

	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	Bpblk = (void*)((unsigned int)((unsigned long)VBpblk));
	Blen  = (unsigned int)((unsigned long)VBlen);
	switch (Bsze)
	{
		case PRVDRV_BYTE:
			Bpblk = malloc(VBlen);
			break;
		case PRVDRV_WORD:
			Bpblk = malloc(VBlen*2);
			break;
		case PRVDRV_DWORD:
			Bpblk = malloc(VBlen*4);
			break;
	}
	prvdrv_ReadBlock(Bmde,Bsze,Brnge,Boffset,Bpblk,Blen);
	for (i=0; i<Blen; i++) switch (Bsze)
	{
		case PRVDRV_BYTE:
			VBpblk[i] = (long)(unsigned long)(((unsigned char*)Bpblk)[i]); // do we want sign propogation?
			break;
		case PRVDRV_WORD:
			VBpblk[i] = (long)(unsigned long)(((unsigned short*)Bpblk)[i]); // do we want sign propogation?
			break;
		case PRVDRV_DWORD:
			VBpblk[i] = (long)(((int*)Bpblk)[i]);
			break;
	}
	free(Bpblk);
}

long WINAPI vbdrv_ReadShadow(long VBmde, long VBsze, long VBrnge, long VBoffset)
{
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return 0;
	return((long)((int)prvdrv_ReadShadow(Bmde,Bsze,Brnge,Boffset)));
}

void WINAPI vbdrv_RemoveAllShadow(void)
{
	prvdrv_RemoveAllShadow();
}

void WINAPI vbdrv_SetBit(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBbit)
{
	unsigned int Bbit;
	Bbit = (unsigned int)((unsigned long)VBbit);
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	prvdrv_SetBit(Bmde,Bsze,Brnge,Boffset,Bbit);
}

void WINAPI vbdrv_SetShadow(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBitems)
{
	unsigned int Bitems;
	Bitems = (unsigned int)((unsigned long)VBitems);
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	prvdrv_SetShadow(Bmde,Bsze,Brnge,Boffset,Bitems);
}

void WINAPI vbdrv_ToggleBit(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBbit)
{
	unsigned int Bbit;
	Bbit = (unsigned int)((unsigned long)VBbit);
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	prvdrv_ToggleBit(Bmde,Bsze,Brnge,Boffset,Bbit);
}

void WINAPI vbdrv_Write(long VBmde, long VBsze, long VBrnge, long VBoffset, long VBval)
{
	unsigned int Bval;
	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	Bval = (unsigned int)((unsigned long)VBval);
	prvdrv_Write(Bmde,Bsze,Brnge,Boffset,Bval);
}

void WINAPI vbdrv_WriteBlock(long VBmde, long VBsze, long VBrnge, long VBoffset, long* VBpblk, long VBlen)
{
	void*			Bpblk;
	unsigned int	Blen,i;
	if (VBlen <= 0) return;

	if (vbFIX(VBmde,VBsze,VBrnge,VBoffset)) return;
	Bpblk = (void*)((unsigned int)((unsigned long)VBpblk));
	Blen  = (unsigned int)((unsigned long)VBlen);
	switch (Bsze)
	{
		case PRVDRV_BYTE:
			Bpblk = malloc(VBlen);
			break;
		case PRVDRV_WORD:
			Bpblk = malloc(VBlen*2);
			break;
		case PRVDRV_DWORD:
			Bpblk = malloc(VBlen*4);
			break;
	}
	for (i=0; i<Blen; i++) switch (Bsze)
	{
		case PRVDRV_BYTE:
			(((unsigned char*)Bpblk)[i]) = (unsigned char)(VBpblk[i]);
			break;
		case PRVDRV_WORD:
			(((unsigned short*)Bpblk)[i]) = (unsigned short)(VBpblk[i]);
			break;
		case PRVDRV_DWORD:
			(((unsigned int*)Bpblk)[i]) = (unsigned int)(VBpblk[i]);
			break;
	}
	prvdrv_WriteBlock(Bmde,Bsze,Brnge,Boffset,Bpblk,Blen);
	free(Bpblk);
}


#ifdef STILL_AN_EXAMPLE_OF_STRING
// ********************************************************************

char* WINAPI vbdrv_PassString(char* ptrVB_IO)
{
	strcpy(SavedString,ptrVB_IO+28);
	return pSavedString;
}

char* WINAPI vbdrv_ReturnString(char* ptrVB_IO)
{
	strcpy(ptrVB_IO+110,SavedString);
	return pSavedString;
}

// ********************************************************************
#endif // STILL_AN_EXAMPLE_OF_STRING

