📄 phantomeppsrlapi.c
字号:
//////////////////////////////////////////////////////////////////
//
// 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 + -