#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#include <mcxproto.h>

#define DBG_DIOC	if(1)fprintf

//
// AcksysIoControl executes a synchronous DeviceIoControl.
// This function is provided since the OVERLAPPED arg to DeviceIoControl is
// mandatory, and we usually want to wait for the result. The OVERLAPPED struct
// is ignored if the port was not open with FILE_FLAG_OVERLAPPED (dixit Win32).
// This function can be called from multiple threads (untested).
//
// Arguments:
//	Same as DeviceIoControl, least the OVERLAPPED struct.
//
// Returns:
//	Same as DeviceIoControl.
//	GetLastError() may also indicate CreateEvent/GetOverlappedResult/
//	ResetEvent failures.
//
// Note:
//	This implementation is slow (calls CreateEvent/CloseHandle on each
//	call), but supports multithreading (untested).
//
BOOL AcksysIoControl(
	HANDLE file,
	DWORD func,
	LPVOID in, DWORD nin,
	LPVOID out, DWORD nout,
	DWORD *ret)
{
	DWORD rcnt;
	BOOL rc = FALSE;
	OVERLAPPED overlap;

	// setup an overlapped struct.
	overlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	if(overlap.hEvent == NULL)
		return rc;

	// Do the DeviceIoControl.
	if(!DeviceIoControl(file, func, in, nin, out, nout, &rcnt, &overlap)) {
		if(GetLastError() == ERROR_IO_PENDING) {
			// wait for the result
			if(GetOverlappedResult(file, &overlap, &rcnt,TRUE)
			  && ResetEvent(overlap.hEvent)) {
				rc = TRUE;
			}
			// else, an error occurred in GetOverlapped/ResetEvent
		}
		// else, a real error occurred in DeviceIoControl
	} else {
		rc = TRUE;
	}

	// free the event.
	CloseHandle(overlap.hEvent);
	return rc;
}

//
// AcksysCmdAuto executes a synchronous SERIAL_IOCTL_CMD_AUTO.
// AcksysCmd executes a synchronous SERIAL_IOCTL_CMD.
// This function can be called from multiple threads (untested).
//
// Arguments:
//	file	device handle
//	pcmd	pointer to an initialized MCC_CMD struct
//		in which Cb.length should indicate the required data length
//
// Returns:
//	Same as DeviceIoControl.
//	GetLastError() may also indicate CreateEvent/GetOverlappedResult/
//	ResetEvent failures.
//
// Note:
//	These functions are implemented as macros
//
BOOL AcksysCmdRetCount_;
/*****
BOOL AcksysCmdAuto(HANDLE file, PMCC_CMD pcmd)
{
	DWORD retCount;
	DWORD count = MCX_DIRECT_IO_BUFFER_SIZE(pcmd->Cb.length);

	return AcksysIoControl(file, IOCTL_SERIAL_CMD_AUTO,
			pcmd, count, pcmd, count, &retCount);
}

BOOL AcksysCmd(HANDLE file, PMCC_CMD pcmd)
{
	DWORD retCount;
	DWORD count = MCX_DIRECT_IO_BUFFER_SIZE(pcmd->Cb.length);

	return AcksysIoControl(file, IOCTL_SERIAL_CMD,
			pcmd, count, pcmd, count, &retCount);
}
*****/
