📄 hwecp.c
字号:
Pdx - Supplies the device extension.
Buffer - Supplies the buffer to write from.
BufferSize - Supplies the number of bytes in the buffer.
BytesTransferred - Returns the number of bytes transferred.
Return Value:
None.
--*/
{
PUCHAR wPortDSR;
PUCHAR wPortECR;
PUCHAR wPortDFIFO;
ULONG bytesToWrite = BufferSize;
UCHAR dsr;
UCHAR ecr;
UCHAR ecrFIFO;
LARGE_INTEGER WaitPerByteTimer;
LARGE_INTEGER StartPerByteTimer;
LARGE_INTEGER EndPerByteTimer;
BOOLEAN bResetTimer = TRUE;
ULONG wBurstCount; // Length of burst to write when FIFO empty
PUCHAR pBuffer;
NTSTATUS status = STATUS_SUCCESS;
wPortDSR = Pdx->Controller + DSR_OFFSET;
wPortECR = Pdx->EcrController + ECR_OFFSET;
wPortDFIFO = Pdx->EcrController;
pBuffer = Buffer;
status = ParTestEcpWrite(Pdx);
if (!NT_SUCCESS(status)) {
P5SetPhase( Pdx, PHASE_UNKNOWN );
Pdx->Connected = FALSE;
DD((PCE)Pdx,DDT,"ParEcpHwWrite: Invalid Entry State\n");
goto ParEcpHwWrite_ExitLabel; // Use a goto so we can see Debug info located at the end of proc!
}
P5SetPhase( Pdx, PHASE_FORWARD_XFER );
//----------------------------------------------------------------------
// Setup Timer Stuff.
//----------------------------------------------------------------------
// we wait up to 35 milliseconds.
WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
// Set up the timer that limits the time allowed for per-byte handshakes.
KeQueryTickCount(&StartPerByteTimer);
//----------------------------------------------------------------------
// Send the data to the DFIFO.
//----------------------------------------------------------------------
HWECP_WriteLoop_Start:
//------------------------------------------------------------------
// Determine whether the FIFO has space and respond accordingly.
//------------------------------------------------------------------
ecrFIFO = (UCHAR)(P5ReadPortUchar(wPortECR) & ECR_FIFO_MASK);
if ( ECR_FIFO_EMPTY == ecrFIFO ) {
wBurstCount = (bytesToWrite > Pdx->FifoDepth) ? Pdx->FifoDepth : bytesToWrite;
bytesToWrite -= wBurstCount;
P5WritePortBufferUchar(wPortDFIFO, pBuffer, wBurstCount);
pBuffer += wBurstCount;
bResetTimer = TRUE;
} else if (ECR_FIFO_SOME_DATA == ecrFIFO) {
// Write just one byte at a time, since we don't know exactly how much
// room there is in the FIFO.
P5WritePortUchar(wPortDFIFO, *pBuffer++);
bytesToWrite--;
bResetTimer = TRUE;
} else { // ECR_FIFO_FULL
// Need to figure out whether to keep attempting to send, or to quit
// with a timeout status.
// Reset the per-byte timer if a byte was received since the last
// timer check.
if ( bResetTimer ) {
KeQueryTickCount(&StartPerByteTimer);
bResetTimer = FALSE;
}
KeQueryTickCount(&EndPerByteTimer);
if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart) {
status = STATUS_TIMEOUT;
// Peripheral is either busy or stalled. If the peripheral
// is busy then they should be using SWECP to allow for
// relaxed timings. Let's punt!
goto HWECP_WriteLoop_End;
}
}
if (bytesToWrite == 0) {
goto HWECP_WriteLoop_End; // Transfer completed.
}
goto HWECP_WriteLoop_Start; // Start over
HWECP_WriteLoop_End:
if ( NT_SUCCESS(status) ) {
// If there have been no previous errors, and synchronous writes
// have been requested, wait for the FIFO to empty and the last
// handshake of PeriphAck to complete before returning success.
if (Pdx->bSynchWrites ) {
BOOLEAN bDone = FALSE;
KeQueryTickCount(&StartPerByteTimer);
while( !bDone ) {
ecr = P5ReadPortUchar(wPortECR);
dsr = P5ReadPortUchar(wPortDSR);
// LLL/CGM 10/9/95: tighten up DSR test - PeriphClk should be high
if ( TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) &&
TEST_DSR( dsr, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
// FIFO is empty, exit without error.
bDone = TRUE;
} else {
KeQueryTickCount(&EndPerByteTimer);
if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart) {
// FIFO not empty, timeout occurred, exit with error.
status = STATUS_TIMEOUT;
bDone = TRUE;
}
}
} // of while...
}
}
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
ParEcpHwWrite_ExitLabel:
*BytesTransferred = BufferSize - bytesToWrite;
Pdx->log.HwEcpWriteCount += *BytesTransferred;
DD((PCE)Pdx,DDT,"ParEcpHwWrite: exit w/status=%x, BytesTransferred=%d, dsr=%02x dcr=%02x, ecr=%02x\n",
status, *BytesTransferred, P5ReadPortUchar(wPortDSR), P5ReadPortUchar(Pdx->Controller + OFFSET_DCR), P5ReadPortUchar(wPortECR));
#if 1 == DBG_SHOW_BYTES
if( DbgShowBytes ) {
if( NT_SUCCESS( status ) && (*BytesTransferred > 0) ) {
const ULONG maxBytes = 32;
ULONG i;
PUCHAR bytePtr = (PUCHAR)Buffer;
DbgPrint("W: ");
for( i=0 ; (i < *BytesTransferred) && (i < maxBytes) ; ++i ) {
DbgPrint("%02x ",*bytePtr++);
}
if( *BytesTransferred > maxBytes ) {
DbgPrint("... ");
}
DbgPrint("zz\n");
}
}
#endif
return status;
}
NTSTATUS
ParEnterEcpHwMode(
IN PPDO_EXTENSION Pdx,
IN BOOLEAN DeviceIdRequest
)
/*++
Routine Description:
This routine performs 1284 negotiation with the peripheral to the
ECP mode protocol.
Arguments:
Controller - Supplies the port address.
DeviceIdRequest - Supplies whether or not this is a request for a device
id.
Return Value:
STATUS_SUCCESS - Successful negotiation.
otherwise - Unsuccessful negotiation.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PUCHAR Controller;
Controller = Pdx->Controller;
if ( Pdx->ModeSafety == SAFE_MODE ) {
if (DeviceIdRequest) {
Status = IeeeEnter1284Mode (Pdx, ECP_EXTENSIBILITY | DEVICE_ID_REQ);
} else {
Status = IeeeEnter1284Mode (Pdx, ECP_EXTENSIBILITY);
}
} else {
Pdx->Connected = TRUE;
}
// LAC ENTEREXIT 5Dec97
// Make sure that the ECR is in PS/2 mode, and that wPortHWMode
// has the correct value. (This is the common entry mode);
Pdx->PortHWMode = HW_MODE_PS2;
if (NT_SUCCESS(Status)) {
Status = ParEcpHwSetupPhase(Pdx);
Pdx->bSynchWrites = TRUE; // NOTE this is a temp hack!!! dvrh
if (!Pdx->bShadowBuffer)
{
Queue_Create(&(Pdx->ShadowBuffer), Pdx->FifoDepth * 2);
Pdx->bShadowBuffer = TRUE;
}
Pdx->IsIeeeTerminateOk = TRUE;
}
return Status;
}
BOOLEAN
ParIsEcpHwSupported(
IN PPDO_EXTENSION Pdx
)
/*++
Routine Description:
This routine determines whether or not ECP mode is suported
in the write direction by trying to negotiate when asked.
Arguments:
Pdx - The device extension.
Return Value:
BOOLEAN.
--*/
{
NTSTATUS Status;
if (Pdx->BadProtocolModes & ECP_HW_NOIRQ)
return FALSE;
if (Pdx->ProtocolModesSupported & ECP_HW_NOIRQ)
return TRUE;
if (!(Pdx->HardwareCapabilities & PPT_ECP_PRESENT))
return FALSE;
if (0 == Pdx->FifoWidth)
return FALSE;
if (Pdx->ProtocolModesSupported & ECP_SW)
return TRUE;
// Must use HWECP Enter and Terminate for this test.
// Internel state machines will fail otherwise. --dvrh
Status = ParEnterEcpHwMode (Pdx, FALSE);
ParTerminateHwEcpMode (Pdx);
if (NT_SUCCESS(Status)) {
Pdx->ProtocolModesSupported |= ECP_HW_NOIRQ;
return TRUE;
}
return FALSE;
}
VOID
ParTerminateHwEcpMode(
IN PPDO_EXTENSION Pdx
)
/*++
Routine Description:
This routine terminates the interface back to compatibility mode.
Arguments:
Controller - Supplies the parallel port's controller address.
Return Value:
None.
--*/
{
// Need to check current phase -- if its reverse, need to flip bus
// If its not forward -- its an incorrect phase and termination will fail.
if( Pdx->ModeSafety == SAFE_MODE ) {
switch( Pdx->CurrentPhase ) {
case PHASE_FORWARD_IDLE: // Legal state to terminate from
break;
case PHASE_TERMINATE: // already terminated, nothing to do
DD((PCE)Pdx,DDW,"ParTerminateHwEcpMode - Already Terminated - Why are we trying to terminate again?\n");
goto target_exit;
break;
case PHASE_REVERSE_IDLE: // Flip bus to forward so we can terminate
{
NTSTATUS status = ParEcpHwExitReversePhase( Pdx );
if( STATUS_SUCCESS == status ) {
status = ParEcpEnterForwardPhase( Pdx );
}
}
break;
case PHASE_FORWARD_XFER:
case PHASE_REVERSE_XFER:
default:
DD((PCE)Pdx,DDE,"ParTerminateHwEcpMode - Invalid Phase [%x] for termination\n", Pdx->CurrentPhase);
// Don't know what to do here!?!
}
ParEcpHwWaitForEmptyFIFO( Pdx );
ParCleanupHwEcpPort( Pdx );
IeeeTerminate1284Mode( Pdx );
} else {
// UNSAFE_MODE
ParCleanupHwEcpPort(Pdx);
Pdx->Connected = FALSE;
}
target_exit:
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -