⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phantomeppsrlapi.c

📁 用Ardence RTX SDK开发的EPP并口驱动程序.
💻 C
📖 第 1 页 / 共 3 页
字号:
//////////////////////////////////////////////////////////////////
//
// PhantomEPPSRLAPI.c - C file
//
// This file was generated using the RTX Device Driver Wizard. 
//   
//////////////////////////////////////////////////////////////////

#include "PhantomEPPSrl.h"                         
#include "PhantomEPPSrlAPI.h"
#include "PhantomRegisters.h"

//
// Global Variables
//
extern UCB ucb;
extern HANDLE hDriver;

//
// Driver Entry initialization
//
DWORD DriverCreateDevice();
DWORD DriverCreateDispatch();
DWORD AllocParPort();
VOID  SetPortMode();
DWORD PingDevice();
BOOL CheckStatus();

// Driver controller handler
ULONG RTFCNDCL DriverDeviceControl(PTRP pIrp);

//
// Driver read/write operation
//
VOID PreReadWritePhantom(PHANTOM_READ_WRITE_BLOCK   *pBlockData);
VOID PostReadWritePhantom(PHANTOM_READ_WRITE_BLOCK   *pBlockData);
DWORD ReadWritePhantom();
VOID SetWatchdogTimeout();
BOOLEAN ManageWatchDog(PUCHAR   pReadBuffer,
					   PUCHAR   pWriteBuffer,
					   PUCHAR   pPrevWatchdogOut,
					   PUCHAR   pWatchdogErrorCount);
DWORD ClearWatchdogTimeout(BOOLEAN bWaitForCancel);

//
// Driver timer operation
//
DWORD EnableSoftwareTimerEvent(HANDLE hEvent,ULONG SoftwareTimerPeriodMs);
DWORD EnableTimerEvent(HANDLE hEvent);
DWORD DisableSoftwareTimerEvent();
DWORD DisableTimerEvent();

//
// Driver ISR operation
//
DWORD EnableInterrupts();
DWORD DisableInterrupts();
DWORD RegistryEnableInterrupts(BOOLEAN* pWasChanged);
BOOLEAN DriverInterruptServiceRoutine();
BOOLEAN HandleInterrupt();

//
// Routine for Driver
//
int RTFCNDCL DriverSoftwareTimerDPCRoutine(PVOID unused);
int RTFCNDCL DriverTimeoutDPCRoutine(PVOID unused);
int RTFCNDCL DriverInterruptDPCRoutine(PVOID unused);

//
// Close the Driver
//
DWORD DriverCloseDispatch();
DWORD FreeParPort();
VOID DriverUnload();
DWORD DriverShutdown(PTRP Irp);

//
// Local copy functions.
//
VOID RtCopyMemory(UCHAR  *Destination,UCHAR  *Source,LONG  Length)
{
	LONG zero = 0;
	while (Length-- > zero)
		*Destination++ = *Source++;
}

VOID DriverUCBInit()
{
	ucb.m_DeviceNumber = 0;
	ucb.m_DeviceIndex = 0;
	ucb.m_nFileCount = 0;

	ucb.m_SignalEventHandle = NULL;
	ucb.m_SignalEventObject = NULL;
	ucb.m_SignalEventCount = 0;

	ucb.m_SoftwareTimerEnabled = FALSE;
	ucb.m_SoftwareTimer = NULL;
	ucb.m_SoftwareTimerDPC = NULL;

	ucb.m_ParPortAllocated = FALSE;
	ucb.m_ParPortInterruptAllocated = FALSE;
	ucb.m_PPT_BYTE_PRESENT = FALSE;
	ucb.m_PPT_1284_3_PRESENT = FALSE;
	ucb.m_PPT_ECP_PRESENT = FALSE;
	ucb.m_PPT_EPP_32_PRESENT = FALSE;
	ucb.m_PPT_EPP_PRESENT = FALSE;
	ucb.m_RegistryEnableInterruptsChanged = FALSE;

	ucb.m_ChannelMask = 0;
	ucb.m_EnableSoftwareWatchdog = FALSE;
	ucb.m_TimeoutTimer = NULL;
	ucb.m_TimeoutDPC = NULL;
	ucb.m_TimeoutEvent = NULL;
	ucb.m_TimeoutCount = FALSE;
	ucb.m_IsClose = TRUE;
}

//
//1 DriverEntry 驱动入口
//
DWORD DriverCreateDevice()
{
	int i;
	PPORT_OUTPUT  pRegsOut;
	DWORD status = STATUS_SUCCESS; 
	
	RtPrintf("PHANTOMEPP:RTX Driver Entry call.\n");
	ucb.m_nFileCount = 0;

	//
	// Setup access to the I/O space, this is not required in an
	// RTSS process
	//
	if ( !RtEnablePortIo ( ucb.baseAddress, EPP_IO_RANGE ) )
	{
		return ERROR_PORT_IO_FAILURE;
	}  

	// Finally initialize client data for EPP block transfers
	for (i = 0; i < PHANTOM_MAX_CHANNELS; i++)
	{
		pRegsOut = (PPORT_OUTPUT) ucb.m_WriteBuffers[i];
		pRegsOut->usDToA0 = 0x7FF;
		pRegsOut->usDToA1 = 0x7FF;
		pRegsOut->usDToA2 = 0x7FF;

		ucb.m_PrevWatchdogOut[i] = 0;
		ucb.m_WatchdogErrorCount[i] = 0;
	}

	// Initialize kernel objects for managing the software interrupt timer
	ucb.m_SoftwareTimerDPC = DriverSoftwareTimerDPCRoutine;

	// create the timer object
	if (!(ucb.m_SoftwareTimer = RtCreateTimer(NULL, 	// Security - NULL is none
									0,                  // Stack size - 0 is use default
									ucb.m_SoftwareTimerDPC, // Timer handler
									NULL,               // context (argument to handler)
									RT_PRIORITY_MAX,    // Priority
									CLOCK_FASTEST)))    // Use fastest available clock
		return STATUS_UNSUCCESSFUL;


	ucb.m_SoftwareTimerEnabled = TRUE;// default use soft timer

	// Initialize kernel objects for managing the watchdog timeout callback
	ucb.m_TimeoutDPC = DriverTimeoutDPCRoutine;

	// create the timer object
	if (!(ucb.m_TimeoutTimer = RtCreateTimer(NULL, 		// Security - NULL is none
									0,                  // Stack size - 0 is use default
									ucb.m_TimeoutDPC,	// Timer handler
									NULL,               // context (argument to handler)
									RT_PRIORITY_MAX,    // Priority
									CLOCK_FASTEST)))    // Use fastest available clock
		return STATUS_UNSUCCESSFUL;


	ucb.m_TimeoutEvent = RtCreateEvent(NULL,TRUE,FALSE,NULL);

	ucb.m_TimeoutCount = 0;

	// initiate the ParPort is unalloc 
	ucb.m_ParPortAllocated = FALSE;

	//status = DriverCreateDispatch();

	return status;
}

//
//2 NTCreate 打开驱动文件时创建派发例程
//
DWORD DriverCreateDispatch()
{
	DWORD status = STATUS_SUCCESS;

	RtPrintf("PHANTOMEPP:DriverCreateDispatch call.\n");

	// Allocate the ParPort for the first file handle
	if (++ucb.m_nFileCount == 1)
	{
		status = AllocParPort();

		if (status == STATUS_SUCCESS)
		{
			SetPortMode();
			PingDevice();
		}
	}

	//pIrp->IoStatus.Information = 0;
	//pIrp->IoStatus.Status = status;
	//IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return status;
}

DWORD AllocParPort()
{
	DWORD status = STATUS_SUCCESS;

	if (ucb.m_ParPortAllocated == FALSE)
	{
		//RtPrintf("PHANTOMEPP:Allocating ParPort.\n");

		//status = utilityBusIoControl(pDeviceExtension->m_ParPortDeviceObject,
		//	IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE,
		//	NULL,
		//	0,
		//	NULL,
		//	0);
		//if (!NT_SUCCESS(status == STATUS_SUCCESS))
		//{
		//	KdPrint("PHANTOMEPP:PARALLEL_PORT_ALLOCATE Unexpected Failure\n"));

		//	utilityLogError(pDeviceExtension->m_DeviceObject, 
		//		PHANTOMEPP_PARALLEL_PORT_ALLOCATE_FAILED, 
		//		PHANTOMEPP_ERROR_VALUE_BASE + 120,
		//		status, 
		//		NULL, 0);

		//	goto FINISH;
		//}

		ucb.m_ParPortAllocated = TRUE;
	}

//FINISH:

	return status;
}

VOID  SetPortMode()
{
	PUCHAR  nPortBase = ucb.baseAddress;

	// Instruct the ECP chip to emulate EPP
	if(ucb.m_PPT_ECP_PRESENT == TRUE)
	{
		//RtPrintf("PHANTOMEPP:Setting EPP emulation mode in ECR register.\n");
		WriteECR(nPortBase, (ReadECR(nPortBase) & 0x1F) | 0x80);
	}

	/*
	Before you can start any EPP cycles by reading and writing to the EPP Data and
	Address Ports, the port must be configured correctly. In the idle state, an EPP
	port should have it's nAddress Strobe, nData Strobe, nWrite and nReset lines
	inactive, high. Some ports require you to set this up before starting any EPP Cycle.
	Therefore our first task is to manually initialise these lines using the SPP Registers.
	Writing XXXX0100 to the control port will do this. 
	*/

	/*
	On some cards, if the Parallel Port is placed in reverse mode, a EPP Write cycle
	cannot be performed. Therefore it is also wise to place the Parallel Port in forward
	mode before using EPP. Clearing Bit 5 of the Control Register should result in an more
	enjoyable programming session, without tearing your hair out. 
	*/

	WriteControl(nPortBase, (ReadControl(nPortBase) & 0xC0) | 0x04);

	// Reset the timeout bit
	WriteStatus(nPortBase, ReadStatus(nPortBase) | 0x01);
}

DWORD PingDevice()
{
	UCHAR      i;
	int        numPassedTests = 0;
	UCHAR      watchDogIn     = 0;
	UCHAR      watchDogOut    = 0;
	UCHAR      watchDogSaved  = 0;
	PUCHAR     nPortBase       = ucb.baseAddress;

	// First validate the parallel port status register
	if (!CheckStatus(nPortBase))
	{
		return STATUS_UNSUCCESSFUL;
	}

	WriteAddress(nPortBase, OFFSET_WDOG_CNTR_IN);
	ReadBlock(nPortBase, &watchDogSaved, 1);

	for(i = 1; i < NUM_PING_TESTS; i++)
	{
		watchDogOut = i;
		WriteAddress(nPortBase,OFFSET_WDOG_CNTR_OUT);
		WriteBlock(nPortBase,&watchDogOut, 1);

		WriteAddress(nPortBase,OFFSET_WDOG_CNTR_IN);
		ReadBlock(nPortBase, &watchDogIn, 1);
		if (watchDogIn == watchDogOut)
		{
			numPassedTests += 1;
		}
		else
		{
			return STATUS_UNSUCCESSFUL;
		}
	}

	WriteAddress(nPortBase, OFFSET_WDOG_CNTR_OUT);
	WriteBlock(nPortBase, &watchDogSaved, 1);

	return STATUS_SUCCESS;
}


BOOL CheckStatus()
{
	UCHAR   status;
	PUCHAR  nPortBase;

	/*
	The EPP Timeout bit we have already discussed. When this bit is set, the EPP port
	may not function correctly. A common scenario is always reading 0xFF from either
	the Address or Data Cycles. This bit should be cleared for reliable operation,
	and constantly checked. 
	*/
	nPortBase = ucb.baseAddress;
	status = ReadStatus(nPortBase);

	if (TEST_BIT(status, EPP_STATUS_TIMEOUT))
	{
		WriteStatus(nPortBase, status | (UCHAR)(1 << EPP_STATUS_TIMEOUT));

		// If the timeout flag is still up, try suppressing it by writing 0 
		// to that bit
		if (TEST_BIT(ReadStatus(nPortBase), EPP_STATUS_TIMEOUT))
		{
			WriteStatus(nPortBase, status & ~0x01);
		} 
	}

	/*
	Paper Out, Select and Error are not defined in the EPP handshake. These lines can
	be utilised in any way by the user. The status of these lines can be determined
	at anytime by viewing the SPP Status Register. Unfortunately there are no spare
	output's. This can become a hassle regularly. 
	*/

	if (TEST_BIT(status, EPP_STATUS_TIMEOUT))
	{
		//RtPrintf("PHANTOMEPP:EPP Timeout: 0x%08X.\n", status);
		return FALSE;
	}

	if (TEST_BIT(status, EPP_STATUS_nBUSY) == 0)
	{
		//RtPrintf("PHANTOMEPP:EPP Busy: 0x%08X.\n", status);
		return FALSE;
	}

	return TRUE;

}

//
//3 User space controller 用户空间发出控制处理,过程是=>允许定时器 ->读写状态/控制/数据寄存器
//
ULONG RTFCNDCL DriverDeviceControl(PTRP pIrp)
{
	ULONG       currentIoControlCode;
	ULONG       inBufferLength;      /* Input buffer length */
	ULONG       outBufferLength;     /* Output buffer length */
	PUCHAR      pIoBuffer;           /* pointer to Input and output buffer */
	PUCHAR      nPortBase;
	DWORD		status = STATUS_SUCCESS;

	nPortBase       = ucb.baseAddress;
	inBufferLength  = pIrp->dwInBufferSize;
	outBufferLength = pIrp->dwOutBufferSize;
	pIoBuffer       = pIrp->lpBuffer;
	currentIoControlCode = pIrp->dwCommand;
	
	pIrp->dwBytesReturned = 0;
	pIrp->dwStatus = STATUS_UNSUCCESSFUL;

	if (IOCTL_OPEN_DEVICE == currentIoControlCode)
	{
		RtPrintf("PHANTOMEPP:IOCTL_OPEN_DEVICE\n");

		status = DriverCreateDispatch();

		pIrp->dwBytesReturned = 0; /* Output Buffer Size */
		pIrp->dwStatus     = status;

		//IoCompleteRequest( pIrp, IO_NO_INCREMENT ); 
		goto FINISH;
	}

	if (IOCTL_OPEN_CLOSE == currentIoControlCode)
	{
		RtPrintf("PHANTOMEPP:IOCTL_OPEN_DEVICE\n");
		status = DriverCloseDispatch();

		pIrp->dwBytesReturned = 0; /* Output Buffer Size */
		pIrp->dwStatus     = status;

		//IoCompleteRequest( pIrp, IO_NO_INCREMENT ); 
		goto FINISH;
	}

	if (IOCTL_READ_WRITE_PHANTOM == currentIoControlCode)
	{
		if (inBufferLength == sizeof(PHANTOM_READ_WRITE_BLOCK) &&
			outBufferLength == sizeof(PHANTOM_READ_WRITE_BLOCK))
		{
			PreReadWritePhantom((PHANTOM_READ_WRITE_BLOCK*) pIoBuffer);

			status = ReadWritePhantom();

			if (status == STATUS_SUCCESS)
			{
				PostReadWritePhantom((PHANTOM_READ_WRITE_BLOCK*) pIoBuffer);

				// Reset the timeout callback used for the software watchdog
				ClearWatchdogTimeout(FALSE);

				if (ucb.m_EnableSoftwareWatchdog)
				{
					SetWatchdogTimeout();
				}
			}
		}
		else
		{
			status = STATUS_UNSUCCESSFUL;
		}

		/* Output Buffer Size */
		if(status == STATUS_SUCCESS)
		{
			pIrp->dwBytesReturned = outBufferLength;
		}
		else
		{
			pIrp->dwBytesReturned = 0; 
		}

		pIrp->dwStatus = status;
		//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
		goto FINISH;
	}

	if (IOCTL_READ_STATUS_REGISTER == currentIoControlCode)
	{
		UCHAR                       statusRegister;

		//RtPrintf("PHANTOMEPP:IOCTL_READ_STATUS_REGISTER\n");
		statusRegister = ReadStatus(nPortBase);
		pIoBuffer[0]   = statusRegister;
		pIrp->dwBytesReturned = 1; /* Output Buffer Size */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -