// Declarations for AIOWDM driver

#ifndef DRIVER_H
#define DRIVER_H

#ifdef _WIN64
	typedef ULONGLONG UNATIVE;
#else
	typedef ULONG UNATIVE;
#endif

#define LOCAL_UNICODE_STRING(__NEW_NAME__, __NEW_SIZE__) \
	WCHAR __NEW_NAME__##Buf[__NEW_SIZE__]; \
	UNICODE_STRING __NEW_NAME__ = { 0, __NEW_SIZE__ * sizeof(WCHAR), __NEW_NAME__##Buf }

#define DRIVERNAME "AIOWDM"				// for use in messages
#define LDRIVERNAME L"AIOWDM"				// for use in UNICODE string constants

#define DEVICE_DEVICE_NAME L"\\Device\\AIOWDMCoreDevice"
#define AIOWDM_DEVICE_NAME L"\\DosDevices\\AIOWDMCore"

#if DBG
	#define DBGONLY(_X_) _X_
#else
	#define DBGONLY(_X_)
#endif

/*
#undef PAGEDCODE
#define PAGEDCODE LOCKEDCODE
#undef PAGEDDATA
#define PAGEDDATA LOCKEDDATA
*/

///////////////////////////////////////////////////////////////////////////////
// Device extension structure

typedef struct _DEVICE_EXTENSION DEVICE_EXTENSION, *PDEVICE_EXTENSION;

enum DEVSTATE
{
	STOPPED,								// device stopped
	WORKING,								// started and working
	PENDINGSTOP,							// stop pending
	PENDINGREMOVE,							// remove pending
	SURPRISEREMOVED,						// removed by surprise
	REMOVED,								// removed
};

enum BARIDs
{
	biStatus = 0,
	biMain = 1,
	biAux = 2,
	biMemMain = 3,
};

enum Operations
{
	opNONE = 'N',
	opINBYTE = 'R',
	opOUTBYTE = 'W',
	opOUTFFS = '#',	   // "out FFs", or "OUT, FFS!".  Writes FF to n consecutive registers
	opIRQCLR_ADIO = '_', // hardcoded mPCIe-ADIO Clear all IRQs
	opIRQEN_ADIO = '+',  // hardcoded mPCIe-ADIO Enable FAF IRQ
	opIRQDIS_ADIO = '-', // hardcoded mPCIe-ADIO Disable all IRQs
	opECHO = 'H', // read then write what was read to the same place; calculates size like # does
};

typedef struct _IOACTION
{
	BARIDs BarID;
	Operations Operation;
	UCHAR Offset;
	UCHAR Data;
} IOACTION, *PIOACTION;

const IOACTION BlankIOAction = { biMain, opNONE, 0, 0, };

typedef enum _TBarType { btNone, btMemory, btIO, btMappedIO } TBarType;
typedef struct _TBarData
{
	TBarType BarType;
	PUCHAR Base;
	ULONG Size;
	PHYSICAL_ADDRESS UnmappedBase;
} TBarData, *TPBarData;

const TBarData BlankBarData = { btNone, NULL, 0, {0, 0, }, };



typedef BOOLEAN TSubISR(PDEVICE_EXTENSION pdx);
typedef TSubISR *TPSubISR;

typedef struct _TCOSScheme
{
	UCHAR StartOff, Size, Stride;
} TCOSScheme, *TPCOSScheme;



#define BYTES_PER_DMA_XFER 8
//Current max is PCIe-DIO-144.
#define MAX_DMA_CHANNELS 6
#define DMA_BUFFER_SIZE 0x10000
typedef struct _TDMAUserRead TDMAUserRead, *TPDMAUserRead;
struct _TDMAUserRead
{
	PVOID pBuffer;
	ULONG BufferSize;
	PIRP pPendingIRP;
	TPDMAUserRead pNext;
};

typedef struct _TDMALink TDMALink, *TPDMALink;
struct _TDMALink
{
	PDMA_ADAPTER pAdapter;
	PULONG pBuffer;
	ULONG BufferSize;
	PHYSICAL_ADDRESS LogicalAddress;
};

typedef struct _TDMAChannelData TDMAChannelData, *TPDMAChannelData;
struct _TDMAChannelData
{
	ULONG iDMALink;
	TDMALink DMALink[2];
	TPDMAUserRead pFirstRead, pLastRead;
	TPDMAUserRead pFirstFreeRead, pLastFreeRead;
	BOOLEAN bDMAWrote;
	ULONG DMASizeUsed;
};

typedef enum _TCardType { ctGeneric, ctAIOProto, ctADIO, ctAAAIO, ctHMAIO, ctDIO144 } TCardType;

struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT DeviceObject;			// device object this extension belongs to
	PDEVICE_OBJECT LowerDeviceObject;		// next lower driver in same stack
	PDEVICE_OBJECT Pdo;						// the PDO
	IO_REMOVE_LOCK RemoveLock;				// removal control locking structure
	UNICODE_STRING ifname;					// interface name
	DEVSTATE state;							// current state of device
	DEVSTATE prevstate;						// state prior to removal query
	DEVICE_POWER_STATE devpower;			// current device power state
	SYSTEM_POWER_STATE syspower;			// current system power state
	DEVICE_POWER_STATE PerfBoundary;		// context restore very expensive from >= this power state
	POWER_SEQUENCE oldseq;					// old power sequence numbers
	DEVICE_CAPABILITIES devcaps;			// copy of most recent device capabilities
	LONG handles;							// # open handles
	// TBarData StatusBar, MainBar, AuxBar; // refactored out in favor of .BAR[biStatus| biMain | biAux]
	TBarData BAR[6];

	ULONG DeviceID;							// The card's PCI device ID or ISA virtual device ID
	IOACTION IAm;							// how to find out if the device is generating an IRQ
	IOACTION Disable;						// how to disable IRQs
	IOACTION Clear;							// how to clear IRQs
	IOACTION Enable;						// how to enable IRQs
	BOOLEAN bNeedsEnable, bNeedsDPC;
	ULONG ISRType;
	PVOID pISRConnectionContext;
	PVOID IntInfo;
	ULONG InterruptOccurred;
	ULONG InterruptRequested;
	PIRP PendingIrp;
	BOOLEAN HasPendingIrp;
	long IRQIndex;
	KIRQL MyDIRQL;
	TPSubISR SubISR;
	ULONG COSSize;
	ULONG Bench;
	BOOLEAN bRealDevice; //false if central device(just for global commands)
	TCOSScheme COSScheme;
	TCardType CardType;
	BOOLEAN bDMAAheadOfTime;
	ULONG DMAChannels;

	BOOLEAN GotIRQ; //true if device has IRQ

	//PUCHAR portbase;						// I/O port base address
	//ULONG nports;							// number of assigned ports
	//PUCHAR StatusBase;
	//USHORT UnmappedBase, UnmappedAuxBase;
	//BOOLEAN mappedport;						// true if we mapped port addr in StartDevice
	ULONG DMALinkCt, DMALinkDeallocate;
	TDMAChannelData DMAChannel[MAX_DMA_CHANNELS];
	BOOLEAN bDMAGoing;
	ULONG ADIOEnableType;
};

typedef struct _TCARDINFO
{
	ULONG DeviceID;
	ULONG BaseAddress;
} TCARDINFO, *PCARDINFO;

typedef struct _TPORTOP
{
	USHORT Address;
	UCHAR Flags;
	UCHAR Size;
	union
	{
		UCHAR Data8;
		USHORT Data16;
		ULONG Data32;
	} ;
} TPORTOP, *PPORTOP;


/* J2H modified unused struct to support InBar for either memory or I/O */
/* TODO: Rename _TMEMOP and family to "TRegisterOp" or something -- J2H */
typedef struct _TMEMOP
{
	ULONG Offset;
	UCHAR BAR;
	UCHAR Padding0;
	UCHAR Flags; // unused
	UCHAR Size;
	union
	{
		UCHAR Data8;
		USHORT Data16;
		ULONG Data32;
	} ;
} TMEMOP, *PMEMOP;

#define POF_RELATIVE 0x01

///////////////////////////////////////////////////////////////////////////////
// global functions

VOID RemoveDevice(IN PDEVICE_OBJECT fdo);
NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info);
NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status);
NTSTATUS ForwardAndWait(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
NTSTATUS SendDeviceSetPower(PDEVICE_EXTENSION fdo, DEVICE_POWER_STATE state, BOOLEAN wait = FALSE);
VOID SendAsyncNotification(PVOID context);
VOID EnableAllInterfaces(PDEVICE_EXTENSION pdx, BOOLEAN enable);
VOID DeregisterAllInterfaces(PDEVICE_EXTENSION pdx);
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated);
VOID StopDevice(PDEVICE_OBJECT fdo, BOOLEAN oktouch = FALSE);

// bar-based I/O handlers

TBarData BarFromResource(CM_PARTIAL_RESOURCE_DESCRIPTOR & Resource);
void DelBar(TBarData & Bar);

UCHAR InBar8(const TBarData & Bar, ULONG Offset);
USHORT InBar16(const TBarData & Bar, ULONG Offset);
ULONG InBar32(const TBarData & Bar, ULONG Offset);
void InBarStr8(const TBarData & Bar, ULONG Offset, PUCHAR pIntoBuf, ULONG Count);
void InBarStr16(const TBarData & Bar, ULONG Offset, PUSHORT pIntoBuf, ULONG Count);
void InBarStr32(const TBarData & Bar, ULONG Offset, PULONG pIntoBuf, ULONG Count);
void OutBar8(const TBarData & Bar, ULONG Offset, UCHAR Data);
void OutBar16(const TBarData & Bar, ULONG Offset, USHORT Data);
void OutBar32(const TBarData & Bar, ULONG Offset, ULONG Data);
void OutBarStr8(const TBarData & Bar, ULONG Offset, PUCHAR pFromBuf, ULONG Count);
void OutBarStr16(const TBarData & Bar, ULONG Offset, PUSHORT pFromBuf, ULONG Count);
void OutBarStr32(const TBarData & Bar, ULONG Offset, PULONG pFromBuf, ULONG Count);
void OutBar8M(const TBarData & Bar, ULONG Offset, UCHAR Count, PUCHAR pData);

// I/O request handlers

NTSTATUS DispatchCreate(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS DispatchClose(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS DispatchPower(PDEVICE_OBJECT fdo, PIRP Irp);
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp);

extern BOOLEAN win98;
extern UNICODE_STRING servkey;
extern UNICODE_STRING UDebugKey;

// DMA-only
VOID DMAUserReadsFreeAndComplete(TPDMAUserRead pFreeReads, NTSTATUS CompleteStatus);

// IRQ handling

VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pdx);
TSubISR NoSubISR;
TSubISR BaseSubISR;
BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PVOID corrupt);

VOID DoIOAction(PDEVICE_EXTENSION pdx, IOACTION Action);
UCHAR QueryIAm(PDEVICE_EXTENSION pdx, IOACTION Action);
VOID InCOSData(PDEVICE_EXTENSION pdx, PIRP Irp, ULONG COSSize);

#define MAX_SLOTS_OPEN 16
extern PDEVICE_EXTENSION GlobalExtension[MAX_SLOTS_OPEN];

// string manipulation for registry debug

void UStrAddStr(UNICODE_STRING & ToStr, PWCHAR pFrom);
void UStrAddStr(UNICODE_STRING & ToStr, PCHAR pFrom);
void UStrAdd8(UNICODE_STRING & ToStr, UCHAR From);
void UStrAdd16(UNICODE_STRING & ToStr, USHORT From);
void UStrAdd32(UNICODE_STRING & ToStr, ULONG From);
void UStrAdd64(UNICODE_STRING & ToStr, ULONGLONG From);
void UStrAddN(UNICODE_STRING & ToStr, ULONGLONG From);
void UStrAddPtr(UNICODE_STRING & ToStr, PVOID From);
void UStrAddAddr(UNICODE_STRING & ToStr, const TBarData & Bar, ULONG Offset);
void UStrNullTerminate(UNICODE_STRING & ToStr);

NTSTATUS GetClearIOFor(PDEVICE_EXTENSION);
NTSTATUS GetDIDFor(PDEVICE_EXTENSION pdx);

// registry debug

NTSTATUS WriteRegDWord(UNICODE_STRING & UKeyPath, UNICODE_STRING & UValueName, ULONG Data);
NTSTATUS WriteRegDWord(UNICODE_STRING & UKeyPath, PWCHAR ValueName, ULONG Data);
NTSTATUS ReadRegDWord(UNICODE_STRING & UKeyPath, UNICODE_STRING & UValueName, ULONG & Data);
NTSTATUS ReadRegDWord(UNICODE_STRING & UKeyPath, PWCHAR ValueName, ULONG & Data);

NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, UNICODE_STRING & UValueName, UNICODE_STRING & UValueData);
NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, PWCHAR ValueName, UNICODE_STRING & UValueData);
NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, UNICODE_STRING & UValueName, PWCHAR ValueData);
NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, PWCHAR ValueName, PWCHAR ValueData);
NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, ULONG ValueNum, UNICODE_STRING & UValueData);
NTSTATUS WriteRegStr(UNICODE_STRING & UKeyPath, ULONG ValueNum, PWCHAR ValueData);

NTSTATUS WriteRegBinary(UNICODE_STRING & UKeyPath, UNICODE_STRING & UValueName, unsigned long Len, PVOID pValueData);
NTSTATUS WriteRegBinary(UNICODE_STRING & UKeyPath, PWCHAR ValueName, unsigned long Len, PVOID pValueData);

extern ULONG iLogEvent;

#if DBG
void DbgLogString(PWCHAR msg);
#else
#define DbgLogString(msg)
#endif

#endif // DRIVER_H