|
|
/*++
Copyright (C) Microsoft Corporation, 1993 - 2000
Module Name:
hwecp.c
Abstract:
This module contains code for the host to utilize HardwareECP if it has been detected and successfully enabled.
Author:
Robbie Harris (Hewlett-Packard) 21-May-1998
Environment:
Kernel mode
Revision History :
--*/
#include "pch.h"
VOID ParCleanupHwEcpPort( IN PPDO_EXTENSION Pdx ) /*++
Routine Description:
Cleans up prior to a normal termination from ECP mode. Puts the port HW back into Compatibility mode.
Arguments:
Controller - Supplies the parallel port's controller address.
Return Value:
None.
--*/ { //----------------------------------------------------------------------
// Set the ECR to mode 001 (PS2 Mode).
//----------------------------------------------------------------------
Pdx->ClearChipMode( Pdx->PortContext, ECR_ECP_PIO_MODE ); Pdx->PortHWMode = HW_MODE_PS2; ParCleanupSwEcpPort(Pdx);
//----------------------------------------------------------------------
// Set the ECR to mode 000 (Compatibility Mode).
//----------------------------------------------------------------------
Pdx->PortHWMode = HW_MODE_COMPATIBILITY; }
// Drain data from Shadow Buffer
VOID PptEcpHwDrainShadowBuffer( IN Queue *pShadowBuffer, IN PUCHAR lpsBufPtr, IN ULONG dCount, OUT ULONG *fifoCount) { *fifoCount = 0; if( Queue_IsEmpty( pShadowBuffer ) ) { return; }
while( dCount > 0 ) { // Break out the Queue_Dequeue from the pointer increment so we can
// observe the data if needed.
if( FALSE == Queue_Dequeue( pShadowBuffer, lpsBufPtr ) ) { // Get byte from queue.
return; } ++lpsBufPtr; --dCount; // Decrement count.
++(*fifoCount); } }
//============================================================================
// NAME: HardwareECP::EmptyFIFO()
//
// Empties HW FIFO into a shadow buffer. This must be done before
// turning the direction from reverse to forward, if the printer has
// stuffed data in that no one has read yet.
//
// PARAMETERS:
// Controller - Supplies the base address of the parallel port.
//
// RETURNS: STATUS_SUCCESS or ....
//
// NOTES:
// Called ZIP_EmptyFIFO in the original 16 bit code.
//
//============================================================================
NTSTATUS ParEcpHwEmptyFIFO(IN PPDO_EXTENSION Pdx) { NTSTATUS nError = STATUS_SUCCESS; Queue *pShadowBuffer; UCHAR bData; PUCHAR wPortDFIFO = Pdx->EcrController; // IO address of ECP Data FIFO
PUCHAR wPortECR = Pdx->EcrController + ECR_OFFSET; // IO address of Extended Control Register (ECR)
// While data exists in the FIFO, read it and put it into shadow buffer.
// If the shadow buffer fills up before the FIFO is exhausted, an
// error condition exists.
pShadowBuffer = &(Pdx->ShadowBuffer);
#if 1 == DBG_SHOW_BYTES
if( DbgShowBytes ) { DbgPrint("r: "); } #endif
while ((P5ReadPortUchar(wPortECR) & ECR_FIFO_EMPTY) == 0 ) { // Break out the Port Read so we can observe the data if needed
bData = P5ReadPortUchar(wPortDFIFO);
#if 1 == DBG_SHOW_BYTES
if( DbgShowBytes ) { DbgPrint("%02x ",bData); } #endif
// Put byte in queue.
if (FALSE == Queue_Enqueue(pShadowBuffer, bData)) { DD((PCE)Pdx,DDT,"ParEcpHwEmptyFIFO - Shadow buffer full, FIFO not empty\n"); nError = STATUS_BUFFER_OVERFLOW; goto ParEcpHwEmptyFIFO_ExitLabel; } } #if 1 == DBG_SHOW_BYTES
if( DbgShowBytes ) { DbgPrint("zz\n"); } #endif
if( ( !Queue_IsEmpty(pShadowBuffer) && (Pdx->P12843DL.bEventActive) )) { KeSetEvent(Pdx->P12843DL.Event, 0, FALSE); }
ParEcpHwEmptyFIFO_ExitLabel: return nError; }
//=========================================================
// HardwareECP::ExitForwardPhase
//
// Description : Exit from HWECP Forward Phase to the common phase (FWD IDLE, PS/2)
//
//=========================================================
NTSTATUS ParEcpHwExitForwardPhase( IN PPDO_EXTENSION Pdx ) { NTSTATUS status;
DD((PCE)Pdx,DDT,"ParEcpHwExitForwardPhase\n"); // First, there could be data in the FIFO. Wait for it to empty
// and then put the bus in the common state (PHASE_FORWARD_IDLE with
// ECRMode set to PS/2
status = ParEcpHwWaitForEmptyFIFO( Pdx );
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
return status; }
//=========================================================
// HardwareECP::EnterReversePhase
//
// Description : Go from the common phase to HWECP Reverse Phase
//
//=========================================================
NTSTATUS PptEcpHwEnterReversePhase( IN PPDO_EXTENSION Pdx ) { NTSTATUS status; PUCHAR Controller; PUCHAR wPortECR; // I/O address of Extended Control Register
PUCHAR wPortDCR; // I/O address of Device Control Register
UCHAR dcr; Controller = Pdx->Controller; wPortECR = Pdx->EcrController + ECR_OFFSET; wPortDCR = Controller + OFFSET_DCR;
// EnterReversePhase assumes that we are in PHASE_FORWARD_IDLE,
// and that the ECPMode is set to PS/2 mode at entry.
//----------------------------------------------------------------------
// Set the ECR to mode 001 (PS2 Mode).
//----------------------------------------------------------------------
Pdx->ClearChipMode( Pdx->PortContext, ECR_ECP_PIO_MODE ); // We need to be in PS/2 (BiDi) mode in order to disable the host
// driving the data lines when we flip the direction bit in the DCR.
// This is a requirement for entering ECP state 38 in the 1284 spec.
// Changed - 2000-02-11
status = Pdx->TrySetChipMode( Pdx->PortContext, ECR_BYTE_MODE ); // ignore status - subsequent operations may still work
Pdx->PortHWMode = HW_MODE_PS2;
if ( Pdx->ModeSafety == SAFE_MODE ) {
// Reverse the bus first (using ECP::EnterReversePhase)
status = ParEcpEnterReversePhase(Pdx); if ( NT_SUCCESS(status) ) { //----------------------------------------------------------------------
// Wait for nAckReverse low (ECP State 40)
//----------------------------------------------------------------------
if ( !CHECK_DSR(Controller, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL) ) { DD((PCE)Pdx,DDT,"PptEcpHwEnterReversePhase: State 40 failed\n"); status = ParEcpHwRecoverPort( Pdx, RECOVER_28 ); if ( NT_SUCCESS(status)) status = STATUS_LINK_FAILED; goto PptEcpHwEnterReversePhase_ExitLabel; } else { P5SetPhase( Pdx, PHASE_REVERSE_IDLE ); } } } else { //----------------------------------------------------------------------
// Set Dir=1 in DCR for reading.
//----------------------------------------------------------------------
dcr = P5ReadPortUchar( wPortDCR ); // Get content of DCR.
dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ); P5WritePortUchar(wPortDCR, dcr); }
//----------------------------------------------------------------------
// Set the ECR to mode 011 (ECP Mode). DmaEnable=0.
//----------------------------------------------------------------------
status = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE ); if ( !NT_SUCCESS(status) ) { DD((PCE)Pdx,DDT,"PptEcpHwEnterReversePhase - TrySetChipMode failed\n"); } Pdx->PortHWMode = HW_MODE_ECP;
//----------------------------------------------------------------------
// Set nStrobe=0 and nAutoFd=0 in DCR, so that ECP HW can control.
//----------------------------------------------------------------------
dcr = P5ReadPortUchar( wPortDCR ); // Get content of DCR.
dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE); P5WritePortUchar( wPortDCR, dcr );
// Set the phase variable to ReverseIdle
P5SetPhase( Pdx, PHASE_REVERSE_IDLE );
PptEcpHwEnterReversePhase_ExitLabel:
return status; }
//=========================================================
// HardwareECP::ExitReversePhase
//
// Description : Get out of HWECP Reverse Phase to the common state
//
//=========================================================
NTSTATUS ParEcpHwExitReversePhase( IN PPDO_EXTENSION Pdx ) { NTSTATUS nError = STATUS_SUCCESS; UCHAR bDCR; UCHAR bECR; PUCHAR wPortECR; PUCHAR wPortDCR; PUCHAR Controller;
DD((PCE)Pdx,DDT,"ParEcpHwExitReversePhase - enter\n"); Controller = Pdx->Controller; wPortECR = Pdx->EcrController + ECR_OFFSET; wPortDCR = Controller + OFFSET_DCR;
//----------------------------------------------------------------------
// Set status byte to indicate Reverse To Forward Mode.
//----------------------------------------------------------------------
P5SetPhase( Pdx, PHASE_REV_TO_FWD ); if ( Pdx->ModeSafety == SAFE_MODE ) {
//----------------------------------------------------------------------
// Assert nReverseRequest high. This should stop further data transfer
// into the FIFO. [[REVISIT: does the chip handle this correctly
// if it occurs in the middle of a byte transfer (states 43-46)??
// Answer (10/9/95) no, it doesn't!!]]
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE ); P5WritePortUchar(wPortDCR, bDCR );
//----------------------------------------------------------------------
// Wait for PeriphAck low and PeriphClk high (ECP state 48) together
// with nAckReverse high (ECP state 49).
//----------------------------------------------------------------------
if( !CHECK_DSR(Controller, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE, DEFAULT_RECEIVE_TIMEOUT) ) { DD((PCE)Pdx,DDW,"ParEcpHwExitReversePhase: Periph failed state 48/49.\n"); nError = ParEcpHwRecoverPort( Pdx, RECOVER_37 ); // Reset port.
if( NT_SUCCESS(nError) ) { return STATUS_LINK_FAILED; } return nError; }
//-----------------------------------------------------------------------
// Empty the HW FIFO of any bytes that may have already come in.
// This must be done before changing ECR modes because the FIFO is reset
// when that occurs.
//-----------------------------------------------------------------------
bECR = P5ReadPortUchar(wPortECR); // Get content of ECR.
if ((bECR & ECR_FIFO_EMPTY) == 0) { // Check if FIFO is not empty.
if( (nError = ParEcpHwEmptyFIFO(Pdx)) != STATUS_SUCCESS ) { DD((PCE)Pdx,DDT,"ParEcpHwExitReversePhase: Attempt to empty ECP chip failed.\n"); return nError; } }
//----------------------------------------------------------------------
// Assert HostAck and HostClk high. [[REVISIT: is this necessary?
// should already be high...]]
//----------------------------------------------------------------------
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE ); P5WritePortUchar(wPortDCR, bDCR );
} // SAFE_MODE
//----------------------------------------------------------------------
// Set the ECR to PS2 Mode so we can change bus direction.
//----------------------------------------------------------------------
Pdx->ClearChipMode( Pdx->PortContext, ECR_ECP_PIO_MODE ); Pdx->PortHWMode = HW_MODE_PS2;
//----------------------------------------------------------------------
// Set Dir=0 (Write) in DCR.
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ); P5WritePortUchar(wPortDCR, bDCR );
//----------------------------------------------------------------------
// Set the ECR back to ECP Mode. DmaEnable=0.
//----------------------------------------------------------------------
nError = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE ); Pdx->PortHWMode = HW_MODE_ECP;
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
return nError; }
BOOLEAN PptEcpHwHaveReadData ( IN PPDO_EXTENSION Pdx ) { Queue *pQueue;
// check shadow buffer
pQueue = &(Pdx->ShadowBuffer); if (!Queue_IsEmpty(pQueue)) { return TRUE; }
// check periph
if (ParEcpHaveReadData(Pdx)) return TRUE;
// Check if FIFO is not empty.
return (BOOLEAN)( (UCHAR)0 == (P5ReadPortUchar(Pdx->EcrController + ECR_OFFSET) & ECR_FIFO_EMPTY) ); }
NTSTATUS ParEcpHwHostRecoveryPhase( IN PPDO_EXTENSION Pdx ) { NTSTATUS status = STATUS_SUCCESS; PUCHAR pPortDCR; // I/O address of Device Control Register
PUCHAR pPortDSR; // I/O address of Device Status Register
PUCHAR pPortECR; // I/O address of Extended Control Register
UCHAR bDCR; // Contents of DCR
UCHAR bDSR; // Contents of DSR
if( !Pdx->bIsHostRecoverSupported ) { return STATUS_SUCCESS; }
DD((PCE)Pdx,DDT,"ParEcpHwHostRecoveryPhase - enter\n");
// Calculate I/O port addresses for common registers
pPortDCR = Pdx->Controller + OFFSET_DCR; pPortDSR = Pdx->Controller + OFFSET_DSR; pPortECR = Pdx->EcrController + ECR_OFFSET;
// Set the ECR to mode 001 (PS2 Mode)
// Don't need to flip to Byte mode. The ECR arbitrator will handle this.
Pdx->PortHWMode = HW_MODE_PS2; // Set Dir=1 in DCR to disable host bus drive, because the peripheral may
// try to drive the bus during host recovery phase. We are not really going
// to let any data handshake across, because we don't set HostAck low, and
// we don't enable the ECP chip during this phase.
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ); P5WritePortUchar(pPortDCR, bDCR ); // Check the DCR to see if it has been stomped on
bDCR = P5ReadPortUchar( pPortDCR ); if( TEST_DCR( bDCR, DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE ) ) { // DCR ok, now test DSR for valid state, ignoring PeriphAck since it could change
bDSR = P5ReadPortUchar( pPortDSR ); // 11/21/95 LLL, CGM: change test to look for XFlag high
if( TEST_DSR( bDSR, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) { // Drop ReverseRequest to initiate host recovery
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE, DONT_CARE ); P5WritePortUchar( pPortDCR, bDCR ); // Wait for nAckReverse response
// 11/21/95 LLL, CGM: tightened test to include PeriphClk and XFlag.
// "ZIP_HRP: state 73, DSR"
if( CHECK_DSR( Pdx->Controller, DONT_CARE, ACTIVE, INACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL) ) { // Yes, raise nReverseRequest, HostClk and HostAck (HostAck high so HW can drive)
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, ACTIVE ); P5WritePortUchar( pPortDCR, bDCR );
// Wait for nAckReverse response
// 11/21/95 LLL, CGM: tightened test to include XFlag and PeriphClk.
// "ZIP_HRP: state 75, DSR"
if( CHECK_DSR( Pdx->Controller, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL) ) { // Let the host drive the bus again.
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE ); P5WritePortUchar(pPortDCR, bDCR ); // Recovery is complete, let the caller decide what to do now
status = STATUS_SUCCESS; P5SetPhase( Pdx, PHASE_FORWARD_IDLE ); } else { status = STATUS_IO_TIMEOUT; DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase - error prior to state 75\n"); } } else { status = STATUS_IO_TIMEOUT; DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase - error prior to state 73\n"); } } else { #if DVRH_BUS_RESET_ON_ERROR
BusReset(pPortDCR); // Pass in the dcr address
#endif
DD((PCE)Pdx,DDT, "ParEcpHwHostRecoveryPhase: VE_LINK_FAILURE \n"); status = STATUS_LINK_FAILED; } } else { DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase: VE_PORT_STOMPED\n"); status = STATUS_DEVICE_PROTOCOL_ERROR; } if (!NT_SUCCESS(status)) { // Make sure both HostAck and HostClk are high before leaving
// Also let the host drive the bus again.
bDCR = P5ReadPortUchar( pPortDCR ); bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE ); P5WritePortUchar( pPortDCR, bDCR ); // [[REVISIT]] pSDCB->wCurrentPhase = PHASE_UNKNOWN;
}
// Set the ECR to ECP mode, disable DMA
status = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE );
Pdx->PortHWMode = HW_MODE_ECP; DD((PCE)Pdx,DDT,"ParEcpHwHostRecoveryPhase - Exit w/status = %x\n", status);
return status; }
NTSTATUS ParEcpHwRead( IN PPDO_EXTENSION Pdx, IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG BytesTransferred )
/*++
Routine Description:
This routine performs a 1284 ECP mode read under Hardware control into the given buffer for no more than 'BufferSize' bytes.
Arguments:
Pdx - Supplies the device extension.
Buffer - Supplies the buffer to read into.
BufferSize - Supplies the number of bytes in the buffer.
BytesTransferred - Returns the number of bytes transferred.
--*/
{ NTSTATUS status = STATUS_SUCCESS; PUCHAR lpsBufPtr = (PUCHAR)Buffer; // Pointer to buffer cast to desired data type
ULONG dCount = BufferSize; // Working copy of caller's original request count
UCHAR bDSR; // Contents of DSR
UCHAR bPeriphRequest; // Calculated state of nPeriphReq signal, used in loop
PUCHAR wPortDSR = Pdx->Controller + DSR_OFFSET; PUCHAR wPortECR = Pdx->EcrController + ECR_OFFSET; PUCHAR wPortDFIFO = Pdx->EcrController; LARGE_INTEGER WaitPerByteTimer; LARGE_INTEGER StartPerByteTimer; LARGE_INTEGER EndPerByteTimer; BOOLEAN bResetTimer = TRUE; ULONG wBurstCount; // Calculated amount of data in FIFO
UCHAR ecrFIFO; WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); //----------------------------------------------------------------------
// Set status byte to indicate Reverse Transfer Phase.
//----------------------------------------------------------------------
P5SetPhase( Pdx, PHASE_REVERSE_XFER ); //----------------------------------------------------------------------
// We've already checked the shadow in ParRead. So go right to the
// Hardware FIFO and pull more data across.
//----------------------------------------------------------------------
KeQueryTickCount(&StartPerByteTimer); // Start the timer
ParEcpHwRead_ReadLoopStart: //------------------------------------------------------------------
// Determine whether the FIFO has any data and respond accordingly
//------------------------------------------------------------------
ecrFIFO = (UCHAR)(P5ReadPortUchar(wPortECR) & (UCHAR)ECR_FIFO_MASK); if (ECR_FIFO_FULL == ecrFIFO) {
wBurstCount = ( dCount > Pdx->FifoDepth ? Pdx->FifoDepth : dCount ); dCount -= wBurstCount; P5ReadPortBufferUchar(wPortDFIFO, lpsBufPtr, wBurstCount); lpsBufPtr += wBurstCount;
bResetTimer = TRUE;
} else if (ECR_FIFO_SOME_DATA == ecrFIFO) { // Read just one byte at a time, since we don't know exactly how much is
// in the FIFO.
*lpsBufPtr = P5ReadPortUchar(wPortDFIFO); lpsBufPtr++; dCount--;
bResetTimer = TRUE;
} else { // ECR_FIFO_EMPTY
DD((PCE)Pdx,DDW,"ParEcpHwRead - ECR_FIFO_EMPTY - slow or bad periph?\n"); // Nothing to do. We either have a slow peripheral or a bad peripheral.
// We don't have a good way to figure out if its bad. Let's chew up our
// time and hope for the best.
bResetTimer = FALSE;
} // ECR_FIFO_EMPTY a.k.a. else clause of (ECR_FIFO_FULL == ecrFIFO)
if (dCount == 0) goto ParEcpHwRead_ReadLoopEnd; else {
// Limit the overall time we spend in this loop.
if (bResetTimer) { bResetTimer = FALSE; KeQueryTickCount(&StartPerByteTimer); // Restart the timer
} else { KeQueryTickCount(&EndPerByteTimer); if (((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement()) > WaitPerByteTimer.QuadPart) goto ParEcpHwRead_ReadLoopEnd; }
}
goto ParEcpHwRead_ReadLoopStart;
ParEcpHwRead_ReadLoopEnd:
P5SetPhase( Pdx, PHASE_REVERSE_IDLE ); *BytesTransferred = BufferSize - dCount; // Set current count.
Pdx->log.HwEcpReadCount += *BytesTransferred; if (0 == *BytesTransferred) { bDSR = P5ReadPortUchar(wPortDSR); bPeriphRequest = (UCHAR)TEST_DSR( bDSR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE ); // Only flag a timeout error if the device still said it had data to send.
if ( bPeriphRequest ) { //
// Periph still says that it has data, but we timed out trying to read the data.
//
DD((PCE)Pdx,DDE,"ParEcpHwRead - read timout with nPeriphRequest asserted and no data read - error - STATUS_IO_TIMEOUT\n"); status = STATUS_IO_TIMEOUT; if ((TRUE == Pdx->P12843DL.bEventActive) ) { //
// Signal transport that it should try another read
//
KeSetEvent(Pdx->P12843DL.Event, 0, FALSE); } } }
DD((PCE)Pdx,DDT,"ParEcpHwRead: Exit - 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("R: "); for( i=0 ; (i < *BytesTransferred) && (i < maxBytes ) ; ++i ) { DbgPrint("%02x ",*bytePtr++); } if( *BytesTransferred > maxBytes ) { DbgPrint("... "); } DbgPrint("zz\n"); } } #endif
return status; } // ParEcpHwRead
NTSTATUS ParEcpHwRecoverPort( PPDO_EXTENSION Pdx, UCHAR bRecoverCode ) { NTSTATUS status = STATUS_SUCCESS; PUCHAR wPortDCR; // IO address of Device Control Register (DCR)
PUCHAR wPortDSR; // IO address of Device Status Register (DSR)
PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
PUCHAR wPortData; // IO address of Data Register
UCHAR bDCR; // Contents of DCR
UCHAR bDSR; // Contents of DSR
UCHAR bDSRmasked; // DSR after masking low order bits
DD((PCE)Pdx,DDT,"ParEcpHwRecoverPort: enter %d\n", bRecoverCode );
// Calculate I/O port addresses for common registers
wPortDCR = Pdx->Controller + OFFSET_DCR; wPortDSR = Pdx->Controller + OFFSET_DSR; wPortECR = Pdx->EcrController + ECR_OFFSET; wPortData = Pdx->Controller + OFFSET_DATA;
//----------------------------------------------------------------------
// Check if port is stomped.
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); // Get content of DCR.
if ( ! TEST_DCR( bDCR, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE, DONT_CARE ) ) { #if DVRH_BUS_RESET_ON_ERROR
BusReset(wPortDCR); // Pass in the dcr address
#endif
DD((PCE)Pdx,DDE,"ParEcpHwRecoverPort - port stomped\n"); status = STATUS_DEVICE_PROTOCOL_ERROR; }
//----------------------------------------------------------------------
// Attempt a termination phase to get the peripheral recovered.
// Ignore the error return, we've already got that figured out.
//----------------------------------------------------------------------
IeeeTerminate1284Mode(Pdx );
//----------------------------------------------------------------------
// Set the ECR to PS2 Mode so we can change bus direction.
//----------------------------------------------------------------------
Pdx->ClearChipMode( Pdx->PortContext, ECR_ECP_PIO_MODE ); Pdx->PortHWMode = HW_MODE_PS2;
//----------------------------------------------------------------------
// Assert nSelectIn low, nInit high, nStrobe high, and nAutoFd high.
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, ACTIVE ); P5WritePortUchar(wPortDCR, bDCR); P5WritePortUchar(wPortData, bRecoverCode); // Output the error ID
KeStallExecutionProcessor(100); // Hold long enough to capture
P5WritePortUchar(wPortData, 0); // Now clear the data lines.
//----------------------------------------------------------------------
// Set the ECR to mode 000 (Compatibility Mode).
//----------------------------------------------------------------------
// Nothing needs to be done here.
Pdx->PortHWMode = HW_MODE_COMPATIBILITY;
//----------------------------------------------------------------------
// Check for any link errors if nothing bad found yet.
//----------------------------------------------------------------------
bDSR = P5ReadPortUchar(wPortDSR); // Get content of DSR.
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
if( NT_SUCCESS(status) ) {
if (bDSRmasked != 0xDF) {
DD((PCE)Pdx,DDE,"ParEcpHwRecoverPort - DSR Exp value: 0xDF, Act value: 0x%X\n",bDSRmasked);
// Get DSR again just to make sure...
bDSR = P5ReadPortUchar(wPortDSR); // Get content of DSR.
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
if( (CHKPRNOFF1 == bDSRmasked ) || (CHKPRNOFF2 == bDSRmasked ) ) { // Check for printer off.
DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Printer Off\n", bDSRmasked); status = STATUS_DEVICE_POWERED_OFF; } else { if( CHKNOCABLE == bDSRmasked ) { // Check for cable unplugged.
DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Cable Unplugged\n",bDSRmasked); status = STATUS_DEVICE_NOT_CONNECTED; } else { DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Unknown error\n",bDSRmasked); status = STATUS_LINK_FAILED; } } } }
//----------------------------------------------------------------------
// Set status byte to indicate Compatibility Mode.
//----------------------------------------------------------------------
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
return status;
} // ParEcpHwRecoverPort
NTSTATUS ParEcpHwSetAddress( IN PPDO_EXTENSION Pdx, IN UCHAR Address )
/*++
Routine Description:
Sets the ECP Address. Arguments:
Pdx - Supplies the device extension.
Address - The bus address to be set. Return Value:
None.
--*/ { NTSTATUS status = STATUS_SUCCESS; PUCHAR wPortDSR; // IO address of Device Status Register
PUCHAR wPortECR; // IO address of Extended Control Register
PUCHAR wPortAFIFO; // IO address of ECP Address FIFO
UCHAR bDSR; // Contents of DSR
UCHAR bECR; // Contents of ECR
BOOLEAN bDone;
DD((PCE)Pdx,DDT,"ParEcpHwSetAddress, Start\n");
// Calculate I/O port addresses for common registers
wPortDSR = Pdx->Controller + DSR_OFFSET; wPortECR = Pdx->EcrController + ECR_OFFSET; wPortAFIFO = Pdx->Controller + AFIFO_OFFSET;
//----------------------------------------------------------------------
// Check for any link errors.
//----------------------------------------------------------------------
//ZIP_CHECK_PORT( DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
// "ZIP_SCA: init DCR", RECOVER_40, errorExit );
//ZIP_CHECK_LINK( DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
// "ZIP_SCA: init DSR", RECOVER_41, errorExit );
// Set state to indicate ECP forward transfer phase
P5SetPhase( Pdx, PHASE_FORWARD_XFER );
//----------------------------------------------------------------------
// Send ECP channel address to AFIFO.
//----------------------------------------------------------------------
if ( ! ( TEST_ECR_FIFO( P5ReadPortUchar( wPortECR), ECR_FIFO_EMPTY ) ? TRUE : CheckPort( wPortECR, ECR_FIFO_MASK, ECR_FIFO_EMPTY, IEEE_MAXTIME_TL ) ) ) {
status = ParEcpHwHostRecoveryPhase(Pdx); DD((PCE)Pdx,DDT,"ParEcpHwSetAddress: FIFO full, timeout sending ECP channel address\n"); status = STATUS_IO_DEVICE_ERROR;
} else {
// Send the address byte. The most significant bit must be set to distinquish
// it as an address (as opposed to a run-length compression count).
P5WritePortUchar(wPortAFIFO, (UCHAR)(Address | 0x80)); }
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 device to
// complete the last PeriphAck handshake before returning success.
if ( Pdx->bSynchWrites ) {
LARGE_INTEGER Wait; LARGE_INTEGER Start; LARGE_INTEGER End;
// we wait up to 35 milliseconds.
Wait.QuadPart = (IEEE_MAXTIME_TL * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
KeQueryTickCount(&Start);
bDone = FALSE; while ( ! bDone ) { bECR = P5ReadPortUchar( wPortECR ); bDSR = P5ReadPortUchar( wPortDSR ); // LLL/CGM 10/9/95: Tighten up link test - PeriphClk high
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) && TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) { bDone = TRUE;
} else {
KeQueryTickCount(&End);
if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart) { DD((PCE)Pdx,DDT,"ParEcpHwSetAddress, timeout during synch\n"); bDone = TRUE; status = ParEcpHwHostRecoveryPhase(Pdx); status = STATUS_IO_DEVICE_ERROR; }
}
} // of while...
} // if bSynchWrites...
}
if ( NT_SUCCESS(status) ) { // Update the state to reflect that we are back in an idle phase
P5SetPhase( Pdx, PHASE_FORWARD_IDLE ); } else if ( status == STATUS_IO_DEVICE_ERROR ) { // Update the state to reflect that we are back in an idle phase
P5SetPhase( Pdx, PHASE_FORWARD_IDLE ); }
return status; }
NTSTATUS ParEcpHwSetupPhase( IN PPDO_EXTENSION Pdx ) /*++
Routine Description:
This routine performs 1284 Setup Phase.
Arguments:
Controller - Supplies the port address.
Return Value:
STATUS_SUCCESS - Successful negotiation.
otherwise - Unsuccessful negotiation.
--*/ { NTSTATUS Status = STATUS_SUCCESS; PUCHAR pPortDCR; // IO address of Device Control Register (DCR)
PUCHAR pPortDSR; // IO address of Device Status Register (DSR)
PUCHAR pPortECR; // IO address of Extended Control Register (ECR)
UCHAR bDCR; // Contents of DCR
// Calculate I/O port addresses for common registers
pPortDCR = Pdx->Controller + OFFSET_DCR; pPortDSR = Pdx->Controller + OFFSET_DSR; pPortECR = Pdx->EcrController + ECR_OFFSET;
// Get the DCR and make sure port hasn't been stomped
//ZIP_CHECK_PORT( DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
// "ZIP_SP: init DCR", RECOVER_44, exit1 );
// Set HostAck low
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE ); P5WritePortUchar( pPortDCR, bDCR );
// for some reason dvdr doesn't want an extra check in UNSAFE_MODE
if ( Pdx->ModeSafety == SAFE_MODE ) { // Wait for nAckReverse to go high
// LLL/CGM 10/9/95: look for PeriphAck low, PeriphClk high as per 1284 spec.
if ( !CHECK_DSR(Pdx->Controller, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL ) ) { // Any failure leaves us in an unknown state to recover from.
P5SetPhase( Pdx, PHASE_UNKNOWN ); Status = STATUS_IO_DEVICE_ERROR; goto HWECP_SetupPhaseExitLabel; } }
//----------------------------------------------------------------------
// Set the ECR to mode 001 (PS2 Mode).
//----------------------------------------------------------------------
Status = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE ); // Set DCR: DIR=0 for output, HostAck and HostClk high so HW can drive
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE ); P5WritePortUchar( pPortDCR, bDCR );
// Set the ECR to ECP mode, disable DMA
Pdx->PortHWMode = HW_MODE_ECP;
// If setup was successful, mark the new ECP phase.
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
Status = STATUS_SUCCESS;
HWECP_SetupPhaseExitLabel:
DD((PCE)Pdx,DDT,"ParEcpHwSetupPhase - exit w/status=%x\n",Status);
return Status; }
NTSTATUS ParEcpHwWaitForEmptyFIFO(IN PPDO_EXTENSION Pdx) /*++
Routine Description:
This routine will babysit the Fifo.
Arguments:
Pdx - The device extension.
Return Value:
NTSTATUS.
--*/ { UCHAR bDSR; // Contents of DSR
UCHAR bECR; // Contents of ECR
UCHAR bDCR; // Contents of ECR
BOOLEAN bDone = FALSE; PUCHAR wPortDSR; PUCHAR wPortECR; PUCHAR wPortDCR; LARGE_INTEGER Wait; LARGE_INTEGER Start; LARGE_INTEGER End; NTSTATUS status = STATUS_SUCCESS;
// Calculate I/O port addresses for common registers
wPortDSR = Pdx->Controller + OFFSET_DSR; wPortECR = Pdx->EcrController + ECR_OFFSET; wPortDCR = Pdx->Controller + OFFSET_DCR;
Wait.QuadPart = (330 * 10 * 1000) + KeQueryTimeIncrement(); // 330ms
KeQueryTickCount(&Start);
//--------------------------------------------------------------------
// wait for the FIFO to empty and the last
// handshake of PeriphAck to complete before returning success.
//--------------------------------------------------------------------
while ( ! bDone ) { bECR = P5ReadPortUchar(wPortECR); bDSR = P5ReadPortUchar(wPortDSR); bDCR = P5ReadPortUchar(wPortDCR); #if 0 // one bit differs - keep alternate around until we know which to really use
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) && TEST_DCR( bDCR, INACTIVE, ***INACTIVE***, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) && TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) { #else
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) && TEST_DCR( bDCR, INACTIVE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) && TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) { #endif
// FIFO is empty, exit without error.
bDone = TRUE;
} else { KeQueryTickCount(&End); if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart) { // FIFO not empty, timeout occurred, exit with error.
// NOTE: There is not a good way to determine how many bytes
// are stuck in the fifo
DD((PCE)Pdx,DDT,"ParEcpHwWaitForEmptyFIFO: timeout during synch\n"); status = STATUS_IO_TIMEOUT; bDone = TRUE; } } } // of while...
return status; }
NTSTATUS ParEcpHwWrite( IN PPDO_EXTENSION Pdx, IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG BytesTransferred ) /*++
Routine Description:
Writes data to the peripheral using the ECP protocol under hardware control. Arguments:
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; }
|