📄 phantomeppsrlapi.c
字号:
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_WRITE_STATUS_REGISTER == currentIoControlCode)
{
UCHAR statusRegister;
//RtPrintf("PHANTOMEPP:IOCTL_WRITE_STATUS_REGISTER\n");
statusRegister = pIoBuffer[0];
WriteStatus(nPortBase, statusRegister);
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_READ_CONTROL_REGISTER == currentIoControlCode)
{
UCHAR controlRegister;
//RtPrintf("PHANTOMEPP:IOCTL_READ_STATUS_REGISTER\n");
controlRegister = ReadControl(nPortBase);
pIoBuffer[0] = controlRegister;
pIrp->dwBytesReturned = 1; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_WRITE_CONTROL_REGISTER == currentIoControlCode)
{
UCHAR controlRegister;
//RtPrintf("PHANTOMEPP:IOCTL_WRITE_CONTROL_REGISTER\n");
controlRegister = pIoBuffer[0];
WriteControl(nPortBase,controlRegister);
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_READ_BYTE == currentIoControlCode)
{
UCHAR dataAddress;
UCHAR dataValue;
//RtPrintf("PHANTOMEPP:IOCTL_READ_BYTE\n");
dataAddress = pIoBuffer[0];
// Note that IOCTL_WRITE_BYTE only works for the first channel.
// The pass-thru facility only works when performing a burst
// read/write.
if (dataAddress >= 0 && dataAddress < INPUT_LENGTH)
{
WriteAddress(nPortBase, dataAddress);
dataValue = ReadByte(nPortBase);
pIoBuffer[0] = dataAddress;
pIoBuffer[1] = dataValue;
pIrp->dwBytesReturned = 2; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
}
else
{
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = STATUS_UNSUCCESSFUL;
}
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_WRITE_BYTE == currentIoControlCode)
{
UCHAR dataAddress;
UCHAR dataValue;
//RtPrintf("PHANTOMEPP:IOCTL_WRITE_BYTE\n");
dataAddress = pIoBuffer[0];
dataValue = pIoBuffer[1];
// Note that IOCTL_WRITE_BYTE only works for the first channel.
// The pass-thru facility only works when performing a burst
// read/write.
if (dataAddress >= INPUT_LENGTH &&
dataAddress < (INPUT_LENGTH + OUTPUT_LENGTH))
{
ULONG nIndex;
WriteAddress(nPortBase, dataAddress);
WriteByte(nPortBase, dataValue);
// Also update the WriteBuffers cache.
nIndex = dataAddress - INPUT_LENGTH;
ucb.m_WriteBuffers[0][nIndex] = dataValue;
status = STATUS_SUCCESS;
}
else
{
// Invalid address
status = STATUS_UNSUCCESSFUL;
}
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = status;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_READ_ECR_REGISTER == currentIoControlCode)
{
UCHAR dataAddress;
UCHAR dataValue;
//RtPrintf("PHANTOMEPP:IOCTL_READ_ECR\n");
dataAddress = pIoBuffer[0];
WriteAddress(nPortBase, dataAddress);
dataValue = ReadECR(nPortBase);
pIoBuffer[0] = dataAddress;
pIoBuffer[1] = dataValue;
pIrp->dwBytesReturned = 2; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_WRITE_ECR_REGISTER == currentIoControlCode)
{
UCHAR dataAddress;
UCHAR dataValue;
//RtPrintf("PHANTOMEPP:IOCTL_WRITE_ECR\n");
dataAddress = pIoBuffer[0];
dataValue = pIoBuffer[1];
WriteAddress(nPortBase, dataAddress);
WriteECR(nPortBase, dataValue);
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_PING_DEVICE == currentIoControlCode)
{
//RtPrintf("PHANTOMEPP:IOCTL_PING_DEVICE\n");
status = PingDevice();
pIrp->dwBytesReturned = 0; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_ENABLE_TIMER_EVENT == currentIoControlCode)
{
RtPrintf("PHANTOMEPP:IOCTL_ENABLE_TIMER_EVENT\n");
if (inBufferLength == sizeof(PHANTOM_ENABLE_TIMER_EVENT))
{
PPHANTOM_ENABLE_TIMER_EVENT pEventData = (PHANTOM_ENABLE_TIMER_EVENT*)pIoBuffer;
if (pEventData->UseSoftwareTimer)
{
pEventData->EventHandle = RtdDriverGetEvent(hDriver);
status = EnableSoftwareTimerEvent(
pEventData->EventHandle,
pEventData->SoftwareTimerPeriodMs);
}
else
{
status = EnableInterrupts();
if (status == STATUS_SUCCESS)
{
status = EnableTimerEvent(
pEventData->EventHandle);
}
}
}
else
{
status = STATUS_UNSUCCESSFUL;
}
pIrp->dwBytesReturned = 0;
pIrp->dwStatus = status;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_DISABLE_TIMER_EVENT == currentIoControlCode)
{
RtPrintf("PHANTOMEPP:IOCTL_DISABLE_TIMER_EVENT\n");
if (ucb.m_SoftwareTimerEnabled)
{
status = DisableSoftwareTimerEvent();
}
else
{
status = DisableTimerEvent();
if (status == STATUS_SUCCESS)
{
status = DisableInterrupts();
}
}
pIrp->dwBytesReturned = 0;
pIrp->dwStatus = status;
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
if (IOCTL_READ_EVENT_COUNT == currentIoControlCode)
{
if (outBufferLength == sizeof(ULONG))
{
ULONG *outputBuffer = (ULONG*)pIoBuffer;
outputBuffer[0] = ucb.m_SignalEventCount;
pIrp->dwBytesReturned = outBufferLength; /* Output Buffer Size */
pIrp->dwStatus = STATUS_SUCCESS;
}
else
{
pIrp->dwBytesReturned = 0;
pIrp->dwStatus = STATUS_UNSUCCESSFUL;
}
//IoCompleteRequest( pIrp, IO_NO_INCREMENT );
goto FINISH;
}
RtPrintf("PHANTOMEPP:Unsupported IOCTL Call\n");
status = STATUS_UNSUCCESSFUL;
pIrp->dwStatus = status;
pIrp->dwBytesReturned = 0;
//IoCompleteRequest(pIrp, IO_NO_INCREMENT);
FINISH:
return status;
}
//
// Copies data to be written into persistent write buffer
//
VOID PreReadWritePhantom(PHANTOM_READ_WRITE_BLOCK *pBlockData)
{
ULONG i;
UCHAR uMask;
// Make sure this routine is multiprocessor safe
//KeAcquireSpinLock(&ucb.m_SpinLock, &restoreIrql);
ucb.m_ChannelMask = pBlockData->ChannelMask;
ucb.m_EnableSoftwareWatchdog = pBlockData->EnableSoftwareWatchdog;
for (i = 0; i < PHANTOM_MAX_CHANNELS; i++)
{
uMask = 1 << i;
// Copy the data to write from the PHANTOM_READ_WRITE_BLOCK struct
// Maintain this data for refreshing the device later
if ((pBlockData->ChannelMask & uMask) != 0)
{
RtCopyMemory(ucb.m_WriteBuffers[i],pBlockData->Values[i],pBlockData->WriteCount[i]);
}
}
//KeReleaseSpinLock(&ucb.m_SpinLock, restoreIrql);
}
//
// Copies previously read data into a PHANTOM_READ_WRITE_BLOCK to be
// buffered to usermode
//
VOID PostReadWritePhantom(PHANTOM_READ_WRITE_BLOCK *pBlockData)
{
ULONG i;
UCHAR uMask;
// Make sure this routine is multiprocessor safe
//KeAcquireSpinLock(&ucb.m_SpinLock, &restoreIrql);
for (i = 0; i < PHANTOM_MAX_CHANNELS; i++)
{
uMask = 1 << i;
// Copy the data read into the PHANTOM_READ_WRITE_BLOCK struct
// to be buffered back to usermode
if ((pBlockData->ChannelMask & uMask) != 0)
{
RtCopyMemory(pBlockData->Values[i],ucb.m_ReadBuffers[i],pBlockData->ReadCount[i]);
}
}
//KeReleaseSpinLock(&ucb.m_SpinLock, restoreIrql);
}
DWORD ReadWritePhantom()
{
ULONG i;
UCHAR uNextChannels;
DWORD status = STATUS_UNSUCCESSFUL;
// Make sure this routine is multiprocessor safe
//KeAcquireSpinLock(&ucb.m_SpinLock, &restoreIrql);
// Validate that the port is operable
if (!CheckStatus(ucb.baseAddress))
{
goto FINISH;
}
// Reset the address and allow the device to internally increment it
// as well as pass-thru read/write data to chained devices. Unfortunately,
// the PhantomEPP firmware does not behave as documented in the
// "Phantom EPP System Specification Rev 9". We are not able to perform
// burst read/write with the pass-thru Phantom without first performing
// a burst read/write with the initial Phantom. This prevents us from
// supporting a more general block transfer API
WriteAddress(ucb.baseAddress, 0x00);
for (i = 0; i < PHANTOM_MAX_CHANNELS; i++)
{
// Read a block of data from the EPP board
ReadBlock(ucb.baseAddress,
ucb.m_ReadBuffers[i],
INPUT_LENGTH);
// Update the watchdog counter and validate the echo register
if (!ManageWatchDog(ucb.m_ReadBuffers[i],
ucb.m_WriteBuffers[i],
&ucb.m_PrevWatchdogOut[i],
&ucb.m_WatchdogErrorCount[i]))
{
goto FINISH;
}
// Write a block of data to the EPP board
WriteBlock(ucb.baseAddress,
ucb.m_WriteBuffers[i],
OUTPUT_LENGTH);
// Break early if there are no other channels to be serviced
uNextChannels = ucb.m_ChannelMask >> (i + 1);
if (uNextChannels == 0)
break;
}
// Make sure that the ACK line of the status register has been supressed
if (!HandleInterrupt())
{
goto FINISH;
}
status = STATUS_SUCCESS;
FINISH:
//KeReleaseSpinLock(&ucb.m_SpinLock, restoreIrql);
return status;
}
VOID SetWatchdogTimeout()
{
LARGE_INTEGER DueTime;
DueTime.QuadPart = SOFTWARE_WATCHDOG_TIMEOUT;
//KeAcquireSpinLock(&ucb.m_SpinLock, &restoreIrql);
RtSetTimerRelative(ucb.m_TimeoutTimer, &DueTime,NULL);
// Mark a flag that the timer has been set
ucb.m_TimeoutCount += 1;
//KeReleaseSpinLock(&ucb.m_SpinLock, restoreIrql);
}
BOOLEAN ManageWatchDog(PUCHAR pReadBuffer,
PUCHAR pWriteBuffer,
PUCHAR pPrevWatchdogOut,
PUCHAR pWatchdogErrorCount)
{
PPORT_INPUT pRegsIn = (PPORT_INPUT)pReadBuffer;
PPORT_OUTPUT pRegsOut = (PPORT_OUTPUT)pWriteBuffer;
if ((pRegsIn->ucMiscIn & WDOG_IS_OK) == 0)
{
//RtPrintf("PHANTOMEPP:Watchdog Not OK\n");
}
// Validate the consistency of the watchdog echo register
if (pRegsIn->ucWatchdogCntrIn == *pPrevWatchdogOut)
{
// Reset the watchdog error count as long as we're getting
// correct input/output echoing
*pWatchdogErrorCount = 0;
}
else
{
// The watchdog value was not echoed so record an error
*pWatchdogErrorCount += 1;
// Bail if we've deteced 3 or more errors
if (*pWatchdogErrorCount >= 3)
{
*pWatchdogErrorCount = 0;
return FALSE;
}
}
// Increment the watchdog counter
*pPrevWatchdogOut += 1;
pRegsOut->ucWatchdogCntrOut = *pPrevWatchdogOut;
return TRUE;
}
DWORD ClearWatchdogTimeout(BOOLEAN bWaitForCancel)
{
DWORD status = STATUS_SUCCESS;
LARGE_INTEGER TimeRemaining;
DWORD Timeout;
BOOLEAN bTimerCancelled;
//KeAcquireSpinLock(&pDeviceExtension->m_SpinLock, &restoreIrql);
// Cancel the pending watchdog timeout
bTimerCancelled = RtCancelTimer(&ucb.m_TimeoutTimer,&TimeRemaining);
// Optionally wait for the DPC routine to finish in the case where
// the timer had been set, signaled and we are waiting for the DPC to finish
if (!bTimerCancelled && ucb.m_TimeoutCount && bWaitForCancel)
{
Timeout = SOFTWARE_WATCHDOG_TIMEOUT;
status = RtWaitForSingleObject(ucb.m_TimeoutEvent,Timeout);
}
// Timer has been cleared so reset the timeout count
ucb.m_TimeoutCount = 0;
//KeReleaseSpinLock(&pDeviceExtension->m_SpinLock, restoreIrql);
return status;
}
DWORD EnableSoftwareTimerEvent(HANDLE hEvent,ULONG SoftwareTimerPeriodMs)
{
DWORD status = STATUS_SUCCESS;
// First setup the timer event as usual
status = EnableTimerEvent(hEvent);
if (status != STATUS_SUCCESS)
return status;
// Now we can raise IRQL and manage the assignment
//KeAcquireSpinLock(&pDeviceExtension->m_SpinLock, &restoreIrql);
// Mark the timer enabled flag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -