mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1726 lines
61 KiB
1726 lines
61 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1993 - 1999
|
|
|
|
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"
|
|
#include "hwecp.h"
|
|
|
|
VOID ParCleanupHwEcpPort(IN PDEVICE_EXTENSION Extension)
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
PUCHAR Controller;
|
|
NTSTATUS nError = STATUS_SUCCESS;
|
|
// UCHAR bDCR; // Contents of DCR
|
|
|
|
Controller = Extension->Controller;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 001 (PS2 Mode).
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
WRITE_PORT_UCHAR(Controller + ECR_OFFSET, DEFAULT_ECR_PS2);
|
|
#else
|
|
WRITE_PORT_UCHAR(Extension->EcrController + ECR_OFFSET, DEFAULT_ECR_PS2);
|
|
#endif
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_PS2;
|
|
|
|
ParCleanupSwEcpPort(Extension);
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 000 (Compatibility Mode).
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
// Nothing to do!
|
|
#else
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
WRITE_PORT_UCHAR(Controller + ECR_OFFSET, DEFAULT_ECR_COMPATIBILITY);
|
|
#else
|
|
WRITE_PORT_UCHAR(Extension->EcrController + ECR_OFFSET, DEFAULT_ECR_COMPATIBILITY);
|
|
#endif
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_COMPATIBILITY;
|
|
}
|
|
|
|
VOID ParEcpHwDrainShadowBuffer(
|
|
IN Queue *pShadowBuffer,
|
|
IN PUCHAR lpsBufPtr,
|
|
IN ULONG dCount,
|
|
OUT ULONG *fifoCount)
|
|
{
|
|
*fifoCount = 0;
|
|
|
|
if (Queue_IsEmpty(pShadowBuffer)) {
|
|
ParDump2(PARINFO,("ParEcpHwDrainShadowBuffer: No data in Shadow\r\n"));
|
|
return;
|
|
}
|
|
|
|
while ( dCount > 0 ) {
|
|
// LAC FRAME 13Jan98
|
|
// 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.
|
|
ParDump2(PARERRORS,("ParEcpHwDrainShadowBuffer: ShadowBuffer Bad\r\n"));
|
|
return;
|
|
}
|
|
ParDump2(PARINFO,("ParEcpHwDrainShadowBuffer: read data byte %02x\r\n",(int)*lpsBufPtr));
|
|
lpsBufPtr++;
|
|
dCount--; // Decrement count.
|
|
(*fifoCount)++;
|
|
}
|
|
|
|
#if DBG
|
|
if (*fifoCount) {
|
|
ParTimerCheck(("ParEcpHwDrainShadowBuffer: read %d bytes from shadow\r\n", *fifoCount ));
|
|
}
|
|
#endif
|
|
ParDump2( PARINFO, ("ParEcpHwDrainShadowBuffer: read %d bytes from shadow\r\n", *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 PDEVICE_EXTENSION Extension)
|
|
{
|
|
NTSTATUS nError = STATUS_SUCCESS;
|
|
Queue *pShadowBuffer;
|
|
UCHAR bData;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
PUCHAR wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET; // IO address of ECP Data FIFO
|
|
PUCHAR wPortECR = Extension->Controller + ECR_OFFSET; // IO address of Extended Control Register (ECR)
|
|
#else
|
|
PUCHAR wPortDFIFO = Extension->EcrController; // IO address of ECP Data FIFO
|
|
PUCHAR wPortECR = Extension->EcrController + ECR_OFFSET; // IO address of Extended Control Register (ECR)
|
|
#endif
|
|
|
|
// 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 = &(Extension->ShadowBuffer);
|
|
while ((READ_PORT_UCHAR(wPortECR) & ECR_FIFO_EMPTY) == 0 )
|
|
{
|
|
// LAC FRAME 13Jan98
|
|
// Break out the Port Read so we can observe the data if needed
|
|
bData = READ_PORT_UCHAR(wPortDFIFO);
|
|
if (FALSE == Queue_Enqueue(pShadowBuffer, bData)) // Put byte in queue.
|
|
{
|
|
ParDump2(PARERRORS, ( "ParEcpHwEmptyFIFO: Shadow buffer full, FIFO not empty\r\n" ));
|
|
nError = STATUS_BUFFER_OVERFLOW;
|
|
goto ParEcpHwEmptyFIFO_ExitLabel;
|
|
}
|
|
ParDump2(PARINFO,("ParEcpHwEmptyFIFO: Enqueue data %02x\r\n",(int)bData));
|
|
}
|
|
|
|
if( ( !Queue_IsEmpty(pShadowBuffer) && (Extension->P12843DL.bEventActive) )) {
|
|
KeSetEvent(Extension->P12843DL.Event, 0, FALSE);
|
|
}
|
|
|
|
ParEcpHwEmptyFIFO_ExitLabel:
|
|
return nError;
|
|
} // ParEcpHwEmptyFIFO
|
|
|
|
// LAC ENTEREXIT 5Dec97
|
|
//=========================================================
|
|
// HardwareECP::ExitForwardPhase
|
|
//
|
|
// Description : Exit from HWECP Forward Phase to the common phase
|
|
// (FWD IDLE, PS/2)
|
|
//
|
|
// Input Parameters : Controller, pPortInfoStruct
|
|
//
|
|
// Modifies :
|
|
//
|
|
// Pre-conditions :
|
|
//
|
|
// Post-conditions :
|
|
//
|
|
// Returns :
|
|
//
|
|
//=========================================================
|
|
NTSTATUS ParEcpHwExitForwardPhase( IN PDEVICE_EXTENSION Extension )
|
|
{
|
|
NTSTATUS status;
|
|
PUCHAR wPortECR; // I/O address of ECR
|
|
|
|
ParDump2( PARENTRY, ("ParEcpHwExitForwardPhase: Entry\r\n") );
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Extension->Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
|
|
// 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( Extension );
|
|
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
ParDumpReg(PAREXIT, ("ParEcpHwExitForwardPhase: Exit[%d]", NT_SUCCESS(status)),
|
|
wPortECR,
|
|
Extension->Controller + OFFSET_DCR,
|
|
Extension->Controller + OFFSET_DSR);
|
|
|
|
return( status );
|
|
}
|
|
|
|
// LAC ENTEREXIT 5Dec97
|
|
//=========================================================
|
|
// HardwareECP::EnterReversePhase
|
|
//
|
|
// Description : Go from the common phase to HWECP Reverse Phase
|
|
//
|
|
// Input Parameters : Controller, pPortInfoStruct
|
|
//
|
|
// Modifies :
|
|
//
|
|
// Pre-conditions :
|
|
//
|
|
// Post-conditions :
|
|
//
|
|
// Returns :
|
|
//
|
|
//=========================================================
|
|
NTSTATUS ParEcpHwEnterReversePhase( IN PDEVICE_EXTENSION Extension )
|
|
{
|
|
NTSTATUS status;
|
|
PUCHAR Controller;
|
|
PUCHAR wPortECR; // I/O address of Extended Control Register
|
|
PUCHAR wPortDCR; // I/O address of Device Control Register
|
|
UCHAR dcr;
|
|
|
|
// ParTimerCheck(("ParEcpHwEnterReversePhase: Start\r\n"));
|
|
Controller = Extension->Controller;
|
|
#if (0 == PARCHIP_ECR_ARBITRATOR)
|
|
wPortECR = Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
wPortDCR = Controller + OFFSET_DCR;
|
|
|
|
|
|
ParDumpReg(PARENTRY, ("ParEcpHwEnterReversePhase: Enter"),
|
|
wPortECR,
|
|
wPortDCR,
|
|
Controller + OFFSET_DSR);
|
|
|
|
// EnterReversePhase assumes that we are in PHASE_FORWARD_IDLE,
|
|
// and that the ECPMode is set to PS/2 mode at entry.
|
|
//volatile UCHAR ecr = READ_PORT_UCHAR( Controller + ECR_OFFSET ) & 0xe0;
|
|
//HPKAssert( ((PHASE_FORWARD_IDLE == pPortInfoStruct->CurrentPhase) && (0x20 == ecr)),
|
|
// ("HardwareECP::EnterReversePhase: Bad initial state (%d/%x)\r\n",(int)pPortInfoStruct->CurrentPhase,(int)ecr) );
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 001 (PS2 Mode).
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_PS2;
|
|
|
|
if ( Extension->ModeSafety == SAFE_MODE ) {
|
|
|
|
// Reverse the bus first (using ECP::EnterReversePhase)
|
|
status = ParEcpEnterReversePhase(Extension);
|
|
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) )
|
|
{
|
|
ParDump2(PARERRORS,("ParEcpHwEnterReversePhase: State 40 failed\r\n"));
|
|
status = ParEcpHwRecoverPort( Extension, RECOVER_28 );
|
|
if ( NT_SUCCESS(status))
|
|
status = STATUS_LINK_FAILED;
|
|
goto ParEcpHwEnterReversePhase_ExitLabel;
|
|
}
|
|
else
|
|
{
|
|
ParDump2(PARECPTRACE, ("ParEcpHwEnterReversePhase: Phase_RevIdle. Setup HW ECR\r\n"));
|
|
Extension->CurrentPhase = PHASE_REVERSE_IDLE;
|
|
}
|
|
}
|
|
} else {
|
|
//----------------------------------------------------------------------
|
|
// Set Dir=1 in DCR for reading.
|
|
//----------------------------------------------------------------------
|
|
dcr = READ_PORT_UCHAR( wPortDCR ); // Get content of DCR.
|
|
dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
|
|
WRITE_PORT_UCHAR(wPortDCR, dcr);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 011 (ECP Mode). DmaEnable=0.
|
|
//----------------------------------------------------------------------
|
|
ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: Before Setting Harware DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
status = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
if ( !NT_SUCCESS(status) )
|
|
{
|
|
ParDump2(PARERRORS,("ParEcpHwEnterReversePhase: TrySetChipMode failed\r\n"));
|
|
}
|
|
#else
|
|
WRITE_PORT_UCHAR( wPortECR, DEFAULT_ECR_ECP );
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_ECP;
|
|
|
|
ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: After Setting Harware Before nStrobe and nAutoFd DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set nStrobe=0 and nAutoFd=0 in DCR, so that ECP HW can control.
|
|
//----------------------------------------------------------------------
|
|
dcr = READ_PORT_UCHAR( wPortDCR ); // Get content of DCR.
|
|
dcr = UPDATE_DCR( dcr, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE);
|
|
WRITE_PORT_UCHAR( wPortDCR, dcr );
|
|
|
|
ParDump2(PARECPTRACE,("ParEcpHwEnterReversePhase: After nStrobe and nAutoFd DCR - %x.\n", READ_PORT_UCHAR(wPortDCR) ));
|
|
|
|
// Set the phase variable to ReverseIdle
|
|
Extension->CurrentPhase = PHASE_REVERSE_IDLE;
|
|
|
|
ParEcpHwEnterReversePhase_ExitLabel:
|
|
// ParTimerCheck(("ParEcpHwEnterReversePhase: End\r\n"));
|
|
ParDumpReg(PAREXIT, ("ParEcpHwEnterReversePhase: Exit[%d]", NT_SUCCESS(status)),
|
|
wPortECR,
|
|
wPortDCR,
|
|
Controller + OFFSET_DSR);
|
|
|
|
return( status );
|
|
}
|
|
|
|
//=========================================================
|
|
// HardwareECP::ExitReversePhase
|
|
//
|
|
// Description : Get out of HWECP Reverse Phase to the common state
|
|
//
|
|
// Input Parameters : Controller, pPortInfoStruct
|
|
//
|
|
// Modifies :
|
|
//
|
|
// Pre-conditions :
|
|
//
|
|
// Post-conditions :
|
|
//
|
|
// Returns :
|
|
//
|
|
//=========================================================
|
|
NTSTATUS ParEcpHwExitReversePhase( IN PDEVICE_EXTENSION Extension )
|
|
{
|
|
NTSTATUS nError = STATUS_SUCCESS;
|
|
UCHAR bDCR;
|
|
UCHAR bECR;
|
|
PUCHAR wPortECR;
|
|
PUCHAR wPortDCR;
|
|
PUCHAR Controller;
|
|
|
|
ParDump2( PARENTRY, ("ParEcpHwExitReversePhase: Entry\r\n") );
|
|
// ParTimerCheck(("ParEcpHwExitReversePhase: Start\r\n"));
|
|
Controller = Extension->Controller;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
wPortDCR = Controller + OFFSET_DCR;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set status byte to indicate Reverse To Forward Mode.
|
|
//----------------------------------------------------------------------
|
|
Extension->CurrentPhase = PHASE_REV_TO_FWD;
|
|
|
|
if ( Extension->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 = READ_PORT_UCHAR(wPortDCR); // Get content of DCR.
|
|
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE );
|
|
WRITE_PORT_UCHAR(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 ) )
|
|
{
|
|
ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: Periph failed state 48/49.\r\n"));
|
|
nError = ParEcpHwRecoverPort( Extension, RECOVER_37 ); // Reset port.
|
|
if (NT_SUCCESS(nError))
|
|
{
|
|
ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: State 48/49 Failure. RecoverPort Invoked.\r\n"));
|
|
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 = READ_PORT_UCHAR(wPortECR); // Get content of ECR.
|
|
if ((bECR & ECR_FIFO_EMPTY) == 0) // Check if FIFO is not empty.
|
|
{
|
|
if ((nError = ParEcpHwEmptyFIFO(Extension)) != STATUS_SUCCESS)
|
|
{
|
|
ParDump2( PARERRORS, ("ParEcpHwExitReversePhase: Attempt to empty ECP chip failed.\r\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 );
|
|
WRITE_PORT_UCHAR(wPortDCR, bDCR );
|
|
|
|
} // SAFE_MODE
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to PS2 Mode so we can change bus direction.
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_PS2;
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set Dir=0 (Write) in DCR.
|
|
//----------------------------------------------------------------------
|
|
bDCR = READ_PORT_UCHAR(wPortDCR);
|
|
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
|
|
WRITE_PORT_UCHAR(wPortDCR, bDCR );
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR back to ECP Mode. DmaEnable=0.
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
nError = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_ECP);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_ECP;
|
|
|
|
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
|
|
// ParTimerCheck(("ParEcpHwExitReversePhase: End\r\n"));
|
|
ParDumpReg(PAREXIT, ("ParEcpHwExitReversePhase: Exit[%d]", NT_SUCCESS(nError)),
|
|
wPortECR,
|
|
wPortDCR,
|
|
Extension->Controller + OFFSET_DSR);
|
|
|
|
return(nError);
|
|
}
|
|
|
|
BOOLEAN
|
|
ParEcpHwHaveReadData (
|
|
IN PDEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
Queue *pQueue;
|
|
|
|
// check shadow buffer
|
|
pQueue = &(Extension->ShadowBuffer);
|
|
if (!Queue_IsEmpty(pQueue)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// check periph
|
|
if (ParEcpHaveReadData(Extension))
|
|
return TRUE;
|
|
|
|
// Check if FIFO is not empty.
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
return (BOOLEAN)( (UCHAR)0 == (READ_PORT_UCHAR(Extension->Controller + ECR_OFFSET) & ECR_FIFO_EMPTY) );
|
|
#else
|
|
return (BOOLEAN)( (UCHAR)0 == (READ_PORT_UCHAR(Extension->EcrController + ECR_OFFSET) & ECR_FIFO_EMPTY) );
|
|
#endif
|
|
}
|
|
|
|
NTSTATUS
|
|
ParEcpHwHostRecoveryPhase(
|
|
IN PDEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
NTSTATUS nError = 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 (!Extension->bIsHostRecoverSupported)
|
|
{
|
|
ParDump2( PARENTRY, ( "ParEcpHwHostRecoveryPhase: Host Recovery not supported\r\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ParDump2( PARENTRY, ( "ParEcpHwHostRecoveryPhase: Host Recovery Start\r\n"));
|
|
|
|
// Calculate I/O port addresses for common registers
|
|
pPortDCR = Extension->Controller + OFFSET_DCR;
|
|
pPortDSR = Extension->Controller + OFFSET_DSR;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
pPortECR = Controller + OFFSET_ECR;
|
|
#else
|
|
pPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
|
|
// Set the ECR to mode 001 (PS2 Mode)
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
// Don't need to flip to Byte mode. The ECR arbitrator will handle this.
|
|
#else
|
|
WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_PS2);
|
|
#endif
|
|
Extension->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 = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
|
|
bDCR = UPDATE_DCR( bDCR, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
|
|
WRITE_PORT_UCHAR(pPortDCR, bDCR );
|
|
|
|
// Check the DCR to see if it has been stomped on
|
|
bDCR = READ_PORT_UCHAR( 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 = READ_PORT_UCHAR( 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 );
|
|
WRITE_PORT_UCHAR( 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( Extension->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 );
|
|
WRITE_PORT_UCHAR( 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( Extension->Controller,
|
|
DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
|
|
IEEE_MAXTIME_TL))
|
|
{
|
|
// Let the host drive the bus again.
|
|
bDCR = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
|
|
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
|
|
WRITE_PORT_UCHAR(pPortDCR, bDCR );
|
|
|
|
// Recovery is complete, let the caller decide what to do now
|
|
nError = STATUS_SUCCESS;
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
}
|
|
else
|
|
{
|
|
nError = STATUS_IO_TIMEOUT;
|
|
ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: Error prior to state 75 \r\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nError = STATUS_IO_TIMEOUT;
|
|
ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: Error prior to state 73 \r\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if DVRH_BUS_RESET_ON_ERROR
|
|
BusReset(pPortDCR); // Pass in the dcr address
|
|
#endif
|
|
ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: VE_LINK_FAILURE \r\n"));
|
|
nError = STATUS_LINK_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParDump2( PARERRORS, ( "ParEcpHwHostRecoveryPhase: VE_PORT_STOMPED \r\n"));
|
|
nError = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
|
|
if (!NT_SUCCESS(nError))
|
|
{
|
|
// Make sure both HostAck and HostClk are high before leaving
|
|
// Also let the host drive the bus again.
|
|
bDCR = READ_PORT_UCHAR( pPortDCR );
|
|
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
|
|
WRITE_PORT_UCHAR( pPortDCR, bDCR );
|
|
|
|
// [[REVISIT]] pSDCB->wCurrentPhase = PHASE_UNKNOWN;
|
|
}
|
|
|
|
// Set the ECR to ECP mode, disable DMA
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
nError = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_ECP);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_ECP;
|
|
|
|
ParDump2( PAREXIT, ( "ParEcpHwHostRecoveryPhase:: Exit %d\r\n", NT_SUCCESS(nError)));
|
|
return(nError);
|
|
}
|
|
|
|
NTSTATUS
|
|
ParEcpHwRead(
|
|
IN PDEVICE_EXTENSION Extension,
|
|
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:
|
|
|
|
Extension - 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 nError = 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
|
|
ULONG dFifoCount = 0; // Amount of data pulled from FIFO shadow at start of read
|
|
PUCHAR wPortDSR = Extension->Controller + DSR_OFFSET;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
PUCHAR wPortECR = Extension->Controller + ECR_OFFSET;
|
|
PUCHAR wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET;
|
|
#else
|
|
PUCHAR wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
PUCHAR wPortDFIFO = Extension->EcrController;
|
|
#endif
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
LARGE_INTEGER WaitOverallTimer;
|
|
LARGE_INTEGER StartOverallTimer;
|
|
LARGE_INTEGER EndOverallTimer;
|
|
#else
|
|
LARGE_INTEGER WaitPerByteTimer;
|
|
LARGE_INTEGER StartPerByteTimer;
|
|
LARGE_INTEGER EndPerByteTimer;
|
|
BOOLEAN bResetTimer = TRUE;
|
|
#endif
|
|
ULONG wBurstCount; // Calculated amount of data in FIFO
|
|
UCHAR ecrFIFO;
|
|
|
|
ParTimerCheck(("ParEcpHwRead: Start BufferSize[%d]\r\n", BufferSize));
|
|
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
// Look for limit to overall time spent in this routine. If bytes are just barely
|
|
// trickling in, we don't want to stay here forever.
|
|
WaitOverallTimer.QuadPart = (990 * 10 * 1000) + KeQueryTimeIncrement();
|
|
// WaitOverallTimer.QuadPart = (DEFAULT_RECEIVE_TIMEOUT * 10 * 1000) + KeQueryTimeIncrement();
|
|
#else
|
|
WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement();
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set status byte to indicate Reverse Transfer Phase.
|
|
//----------------------------------------------------------------------
|
|
Extension->CurrentPhase = PHASE_REVERSE_XFER;
|
|
|
|
//----------------------------------------------------------------------
|
|
// We've already checked the shadow in ParRead. So go right to the
|
|
// Hardware FIFO and pull more data across.
|
|
//----------------------------------------------------------------------
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
KeQueryTickCount(&StartOverallTimer); // Start the timer
|
|
#else
|
|
KeQueryTickCount(&StartPerByteTimer); // Start the timer
|
|
#endif
|
|
|
|
ParEcpHwRead_ReadLoopStart:
|
|
//------------------------------------------------------------------
|
|
// Determine whether the FIFO has any data and respond accordingly
|
|
//------------------------------------------------------------------
|
|
ecrFIFO = (UCHAR)(READ_PORT_UCHAR(wPortECR) & (UCHAR)ECR_FIFO_MASK);
|
|
|
|
if (ECR_FIFO_FULL == ecrFIFO)
|
|
{
|
|
ParDump2(PARINFO, ("ParEcpHwRead: ECR_FIFO_FULL\r\n"));
|
|
wBurstCount = ( dCount > Extension->FifoDepth ? Extension->FifoDepth : dCount );
|
|
dCount -= wBurstCount;
|
|
|
|
#if (1 == PAR_USE_BUFFER_READ_WRITE)
|
|
READ_PORT_BUFFER_UCHAR(wPortDFIFO, lpsBufPtr, wBurstCount);
|
|
lpsBufPtr += wBurstCount;
|
|
ParDump2(PARINFO,("ParEcpHwRead: Read FIFOBurst\r\n"));
|
|
#else
|
|
while ( wBurstCount-- )
|
|
{
|
|
*lpsBufPtr = READ_PORT_UCHAR(wPortDFIFO);
|
|
ParDump2(PARINFO,("ParEcpHwRead: Full FIFO: Read byte value %02x\r\n",(int)*lpsBufPtr));
|
|
lpsBufPtr++;
|
|
}
|
|
#endif
|
|
#if (0 == DVRH_USE_HW_MAXTIME)
|
|
bResetTimer = TRUE;
|
|
#endif
|
|
}
|
|
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 = READ_PORT_UCHAR(wPortDFIFO);
|
|
lpsBufPtr++;
|
|
dCount--;
|
|
#if (0 == DVRH_USE_HW_MAXTIME)
|
|
bResetTimer = TRUE;
|
|
#endif
|
|
}
|
|
else // ECR_FIFO_EMPTY
|
|
{
|
|
|
|
ParDump2(PARINFO, ("ParEcpHwRead: ECR_FIFO_EMPTY\r\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.
|
|
#if (0 == DVRH_USE_HW_MAXTIME)
|
|
bResetTimer = FALSE;
|
|
#endif
|
|
} // ECR_FIFO_EMPTY a.k.a. else clause of (ECR_FIFO_FULL == ecrFIFO)
|
|
|
|
if (dCount == 0)
|
|
goto ParEcpHwRead_ReadLoopEnd;
|
|
else
|
|
{
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
// Limit the overall time we spend in this loop.
|
|
KeQueryTickCount(&EndOverallTimer);
|
|
if (((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement()) > WaitOverallTimer.QuadPart)
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
goto ParEcpHwRead_ReadLoopStart;
|
|
ParEcpHwRead_ReadLoopEnd:
|
|
|
|
ParDump2(PARECPTRACE,("ParEcpHwRead: Phase_RevIdle\r\n"));
|
|
Extension->CurrentPhase = PHASE_REVERSE_IDLE;
|
|
|
|
*BytesTransferred = BufferSize - dCount; // Set current count.
|
|
|
|
Extension->log.HwEcpReadCount += *BytesTransferred;
|
|
|
|
if (0 == *BytesTransferred)
|
|
{
|
|
bDSR = READ_PORT_UCHAR(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.
|
|
//
|
|
ParDump2(PARERRORS, ("ParEcpHwRead: read timout with nPeriphRequest asserted and no data read\r\n"));
|
|
nError = STATUS_IO_TIMEOUT;
|
|
if ((TRUE == Extension->P12843DL.bEventActive) ) {
|
|
//
|
|
// Signal transport that it should try another read
|
|
//
|
|
KeSetEvent(Extension->P12843DL.Event, 0, FALSE);
|
|
}
|
|
}
|
|
}
|
|
ParTimerCheck(("ParEcpHwRead: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(nError), *BytesTransferred));
|
|
|
|
ParDumpReg(PAREXIT, ("ParEcpHwRead: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(nError), *BytesTransferred),
|
|
wPortECR,
|
|
Extension->Controller + OFFSET_DCR,
|
|
Extension->Controller + OFFSET_DSR);
|
|
|
|
return nError;
|
|
} // ParEcpHwRead
|
|
|
|
NTSTATUS
|
|
ParEcpHwRecoverPort(
|
|
PDEVICE_EXTENSION Extension,
|
|
UCHAR bRecoverCode
|
|
)
|
|
{
|
|
NTSTATUS nError = 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
|
|
|
|
ParDump2( PARENTRY, ( "ParEcpHwRecoverPort: enter %d\r\n", bRecoverCode ));
|
|
|
|
// Calculate I/O port addresses for common registers
|
|
wPortDCR = Extension->Controller + OFFSET_DCR;
|
|
wPortDSR = Extension->Controller + OFFSET_DSR;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Extension->Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
wPortData = Extension->Controller + OFFSET_DATA;
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Check if port is stomped.
|
|
//----------------------------------------------------------------------
|
|
bDCR = READ_PORT_UCHAR(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
|
|
ParDump2( PARERRORS, ( "!ParEcpHwRecoverPort: port stomped.\r\n"));
|
|
nError = 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(Extension );
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to PS2 Mode so we can change bus direction.
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
Extension->ClearChipMode( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_PS2);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_PS2;
|
|
|
|
//----------------------------------------------------------------------
|
|
// Assert nSelectIn low, nInit high, nStrobe high, and nAutoFd high.
|
|
//----------------------------------------------------------------------
|
|
bDCR = READ_PORT_UCHAR(wPortDCR); // Get content of DCR.
|
|
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
|
WRITE_PORT_UCHAR(wPortDCR, bDCR);
|
|
WRITE_PORT_UCHAR(wPortData, bRecoverCode); // Output the error ID
|
|
KeStallExecutionProcessor(100); // Hold long enough to capture
|
|
WRITE_PORT_UCHAR(wPortData, 0); // Now clear the data lines.
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 000 (Compatibility Mode).
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
// Nothing needs to be done here.
|
|
#else
|
|
WRITE_PORT_UCHAR(wPortECR, DEFAULT_ECR_COMPATIBILITY);
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_COMPATIBILITY;
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Check for any link errors if nothing bad found yet.
|
|
//----------------------------------------------------------------------
|
|
bDSR = READ_PORT_UCHAR(wPortDSR); // Get content of DSR.
|
|
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
|
|
|
|
if (NT_SUCCESS(nError))
|
|
{
|
|
if (bDSRmasked != 0xDF)
|
|
{
|
|
ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR Exp value: 0xDF, Act value: 0x%X\r\n", bDSRmasked));
|
|
|
|
// Get DSR again just to make sure...
|
|
bDSR = READ_PORT_UCHAR(wPortDSR); // Get content of DSR.
|
|
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
|
|
|
|
if ( (bDSRmasked == CHKPRNOFF1) || (bDSRmasked == CHKPRNOFF2) ) // Check for printer off.
|
|
{
|
|
ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR value: 0x%X, Printer Off.\r\n", bDSRmasked));
|
|
nError = STATUS_DEVICE_POWERED_OFF;
|
|
}
|
|
else
|
|
{
|
|
if (bDSRmasked == CHKNOCABLE) // Check for cable unplugged.
|
|
{
|
|
ParDump2( PARERRORS, ("!ParEcpHwRecoverPort: DSR value: 0x%X, Cable Unplugged.\r\n", bDSRmasked));
|
|
nError = STATUS_DEVICE_NOT_CONNECTED;
|
|
}
|
|
else
|
|
{
|
|
nError = STATUS_LINK_FAILED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set status byte to indicate Compatibility Mode.
|
|
//----------------------------------------------------------------------
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
|
|
ParDump2( PAREXIT, ( "ParEcpHwRecoverPort: exit, return = 0x%X\r\n", NT_SUCCESS(nError) ));
|
|
|
|
return nError;
|
|
|
|
} // ParEcpHwRecoverPort
|
|
|
|
NTSTATUS
|
|
ParEcpHwSetAddress(
|
|
IN PDEVICE_EXTENSION Extension,
|
|
IN UCHAR Address
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the ECP Address.
|
|
|
|
Arguments:
|
|
|
|
Extension - Supplies the device extension.
|
|
|
|
Address - The bus address to be set.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS nError = 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;
|
|
|
|
ParDump2( PARENTRY, ("ParEcpHwSetAddress, Start\r\n"));
|
|
|
|
// Calculate I/O port addresses for common registers
|
|
wPortDSR = Extension->Controller + DSR_OFFSET;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Extension->Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
wPortAFIFO = Extension->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
|
|
Extension->CurrentPhase = PHASE_FORWARD_XFER;
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// Send ECP channel address to AFIFO.
|
|
//----------------------------------------------------------------------
|
|
if ( ! ( TEST_ECR_FIFO( READ_PORT_UCHAR( wPortECR), ECR_FIFO_EMPTY ) ? TRUE :
|
|
CheckPort( wPortECR, ECR_FIFO_MASK, ECR_FIFO_EMPTY,
|
|
IEEE_MAXTIME_TL ) ) )
|
|
{
|
|
nError = ParEcpHwHostRecoveryPhase(Extension);
|
|
ParDump2(PARERRORS, ("ParEcpHwSetAddress: FIFO full, timeout sending ECP channel address\r\n"));
|
|
nError = 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).
|
|
WRITE_PORT_UCHAR(wPortAFIFO, (UCHAR)(Address | 0x80));
|
|
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS(nError) )
|
|
{
|
|
// 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 ( Extension->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 = READ_PORT_UCHAR( wPortECR );
|
|
bDSR = READ_PORT_UCHAR( 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)
|
|
{
|
|
ParDump2( PARERRORS, ("ParEcpHwSetAddress, timeout during synch\r\n"));
|
|
bDone = TRUE;
|
|
nError = ParEcpHwHostRecoveryPhase(Extension);
|
|
nError = STATUS_IO_DEVICE_ERROR;
|
|
}
|
|
}
|
|
} // of while...
|
|
} // if bSynchWrites...
|
|
}
|
|
|
|
if ( NT_SUCCESS(nError) )
|
|
{
|
|
// Update the state to reflect that we are back in an idle phase
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
}
|
|
else if ( nError == STATUS_IO_DEVICE_ERROR )
|
|
{
|
|
// Update the state to reflect that we are back in an idle phase
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
}
|
|
|
|
ParDumpReg(PAREXIT, ("ParEcpHwSetAddress: Exit[%d]", NT_SUCCESS(nError)),
|
|
wPortECR,
|
|
Extension->Controller + OFFSET_DCR,
|
|
wPortDSR);
|
|
|
|
return nError;
|
|
}
|
|
|
|
NTSTATUS
|
|
ParEcpHwSetupPhase(
|
|
IN PDEVICE_EXTENSION Extension
|
|
)
|
|
/*++
|
|
|
|
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
|
|
|
|
ParDump2(PARENTRY,("HardwareECP::SetupPhase: Start\r\n"));
|
|
|
|
// Calculate I/O port addresses for common registers
|
|
pPortDCR = Extension->Controller + OFFSET_DCR;
|
|
pPortDSR = Extension->Controller + OFFSET_DSR;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
pPortECR = Extension->Controller + ECR_OFFSET;
|
|
#else
|
|
pPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
|
|
// 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 = READ_PORT_UCHAR(pPortDCR); // Get content of DCR.
|
|
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE );
|
|
WRITE_PORT_UCHAR( pPortDCR, bDCR );
|
|
|
|
// for some reason dvdr doesn't want an extra check in UNSAFE_MODE
|
|
if ( Extension->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(Extension->Controller, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
|
|
IEEE_MAXTIME_TL ) )
|
|
{
|
|
// Any failure leaves us in an unknown state to recover from.
|
|
Extension->CurrentPhase = PHASE_UNKNOWN;
|
|
Status = STATUS_IO_DEVICE_ERROR;
|
|
goto HWECP_SetupPhaseExitLabel;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Set the ECR to mode 001 (PS2 Mode).
|
|
//----------------------------------------------------------------------
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
Status = Extension->TrySetChipMode ( Extension->PortContext, ECR_ECP_PIO_MODE );
|
|
#else
|
|
WRITE_PORT_UCHAR(pPortECR, DEFAULT_ECR_PS2);
|
|
#endif
|
|
// 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 );
|
|
WRITE_PORT_UCHAR( pPortDCR, bDCR );
|
|
|
|
// Set the ECR to ECP mode, disable DMA
|
|
#if (1 == PARCHIP_ECR_ARBITRATOR)
|
|
// Nothing needs to be done here
|
|
#else
|
|
WRITE_PORT_UCHAR( pPortECR, DEFAULT_ECR_ECP );
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_ECP;
|
|
|
|
// If setup was successful, mark the new ECP phase.
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
HWECP_SetupPhaseExitLabel:
|
|
|
|
ParDump2(PARENTRY,("HardwareECP::SetupPhase: End [%d]\r\n", NT_SUCCESS(Status)));
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS ParEcpHwWaitForEmptyFIFO(IN PDEVICE_EXTENSION Extension)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will babysit the Fifo.
|
|
|
|
Arguments:
|
|
|
|
Extension - 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 = Extension->Controller + OFFSET_DSR;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Extension->Controller + ECR_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
#endif
|
|
wPortDCR = Extension->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 = READ_PORT_UCHAR(wPortECR);
|
|
bDSR = READ_PORT_UCHAR(wPortDSR);
|
|
bDCR = READ_PORT_UCHAR(wPortDCR);
|
|
|
|
#if 0
|
|
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
|
|
ParDump2( PARERRORS, ("ParEcpHwWaitForEmptyFIFO: timeout during synch\r\n"));
|
|
status = STATUS_IO_TIMEOUT;
|
|
bDone = TRUE;
|
|
}
|
|
}
|
|
} // of while...
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ParEcpHwWrite(
|
|
IN PDEVICE_EXTENSION Extension,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes data to the peripheral using the ECP protocol under hardware
|
|
control.
|
|
|
|
Arguments:
|
|
|
|
Extension - 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;
|
|
// ULONG i;
|
|
// UCHAR dcr;
|
|
UCHAR dsr, ecr;
|
|
UCHAR ecrFIFO;
|
|
LARGE_INTEGER WaitPerByteTimer;
|
|
LARGE_INTEGER StartPerByteTimer;
|
|
LARGE_INTEGER EndPerByteTimer;
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
LARGE_INTEGER WaitOverallTimer;
|
|
LARGE_INTEGER StartOverallTimer;
|
|
LARGE_INTEGER EndOverallTimer;
|
|
#endif
|
|
BOOLEAN bResetTimer = TRUE;
|
|
ULONG wBurstCount; // Length of burst to write when FIFO empty
|
|
PUCHAR pBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
wPortDSR = Extension->Controller + DSR_OFFSET;
|
|
#if (0 == DVRH_USE_PARPORT_ECP_ADDR)
|
|
wPortECR = Extension->Controller+ ECR_OFFSET;
|
|
wPortDFIFO = Extension->Controller + ECP_DFIFO_OFFSET;
|
|
#else
|
|
wPortECR = Extension->EcrController + ECR_OFFSET;
|
|
wPortDFIFO = Extension->EcrController;
|
|
#endif
|
|
pBuffer = Buffer;
|
|
|
|
ParTimerCheck(("ParEcpHwWrite: Start bytesToWrite[%d]\r\n", bytesToWrite));
|
|
|
|
Status = ParTestEcpWrite(Extension);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Extension->CurrentPhase = PHASE_UNKNOWN;
|
|
Extension->Connected = FALSE;
|
|
ParDump2(PARERRORS,("ParEcpHwWrite: Invalid Entry State\r\n"));
|
|
goto ParEcpHwWrite_ExitLabel; // Use a goto so we can see Debug info located at the end of proc!
|
|
}
|
|
|
|
Extension->CurrentPhase = PHASE_FORWARD_XFER;
|
|
//----------------------------------------------------------------------
|
|
// Setup Timer Stuff.
|
|
//----------------------------------------------------------------------
|
|
// we wait up to 35 milliseconds.
|
|
WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
WaitOverallTimer.QuadPart = (330 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
|
|
//WaitOverallTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
|
|
#endif
|
|
|
|
// Set up the overall timer that limits how much time is spent per call
|
|
// to this function.
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
KeQueryTickCount(&StartOverallTimer);
|
|
#endif
|
|
|
|
// 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)(READ_PORT_UCHAR(wPortECR) & ECR_FIFO_MASK);
|
|
|
|
if ( ECR_FIFO_EMPTY == ecrFIFO )
|
|
{
|
|
wBurstCount = (bytesToWrite > Extension->FifoDepth) ? Extension->FifoDepth : bytesToWrite;
|
|
bytesToWrite -= wBurstCount;
|
|
|
|
#if (PAR_USE_BUFFER_READ_WRITE == 1)
|
|
ParDump2(PARINFO,("ParEcpHwWrite: FIFOBurst\r\n"));
|
|
WRITE_PORT_BUFFER_UCHAR(wPortDFIFO, pBuffer, wBurstCount);
|
|
pBuffer += wBurstCount;
|
|
#else
|
|
while ( wBurstCount-- )
|
|
{
|
|
ParDump2(PARINFO,("ParEcpHwWrite: FIFOBurst: %02x\r\n",(int)*pBuffer));
|
|
WRITE_PORT_UCHAR(wPortDFIFO, *pBuffer++);
|
|
}
|
|
#endif
|
|
|
|
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.
|
|
ParDump2(PARINFO,("ParEcpHwWrite: OneByte: %02x\r\n",(int)*pBuffer));
|
|
WRITE_PORT_UCHAR(wPortDFIFO, *pBuffer++);
|
|
bytesToWrite--;
|
|
bResetTimer = TRUE;
|
|
}
|
|
else { // ECR_FIFO_FULL
|
|
ParDump2(PARINFO,("ParEcpHwWrite: ECR_FIFO_FULL ecr=%02x\r\n",(int)READ_PORT_UCHAR(wPortECR)));
|
|
// 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 )
|
|
{
|
|
ParDump2(PARINFO,("ParEcpHwWrite: ECR_FIFO_FULL Reset Timer\r\n"));
|
|
KeQueryTickCount(&StartPerByteTimer);
|
|
bResetTimer = FALSE;
|
|
}
|
|
|
|
KeQueryTickCount(&EndPerByteTimer);
|
|
if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart)
|
|
{
|
|
ParDump2(PARERRORS,("ParEcpHwWrite: ECR_FIFO_FULL Timeout ecr=%02x\r\n",(int)READ_PORT_UCHAR(wPortECR)));
|
|
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.
|
|
}
|
|
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
// Limit the overall time we spend in this loop, in case the
|
|
// peripheral is taking data at a slow overall rate.
|
|
KeQueryTickCount(&EndOverallTimer);
|
|
if ((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement() > WaitOverallTimer.QuadPart)
|
|
{
|
|
ParDump2(PARERRORS,("ParEcpHwWrite: OverAll Timer expired!\r\n"));
|
|
Status = STATUS_TIMEOUT;
|
|
goto HWECP_WriteLoop_End;
|
|
}
|
|
#endif
|
|
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 (Extension->bSynchWrites )
|
|
{
|
|
BOOLEAN bDone = FALSE;
|
|
|
|
ParDump2(PARINFO,("ParEcpHwWrite: Waiting for FIFO to empty\r\n"));
|
|
#if (0 == DVRH_USE_HW_MAXTIME)
|
|
KeQueryTickCount(&StartPerByteTimer);
|
|
#endif
|
|
while ( ! bDone )
|
|
{
|
|
ecr = READ_PORT_UCHAR(wPortECR);
|
|
dsr = READ_PORT_UCHAR(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 ) )
|
|
{
|
|
ParDump2(PARINFO,("ParEcpHwWrite: FIFO is now empty\r\n"));
|
|
// FIFO is empty, exit without error.
|
|
bDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if (1 == DVRH_USE_HW_MAXTIME)
|
|
KeQueryTickCount(&EndOverallTimer);
|
|
if ((EndOverallTimer.QuadPart - StartOverallTimer.QuadPart) * KeQueryTimeIncrement() > WaitOverallTimer.QuadPart)
|
|
#else
|
|
KeQueryTickCount(&EndPerByteTimer);
|
|
if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart)
|
|
#endif
|
|
{
|
|
ParDump2(PARERRORS,("ParEcpHwWrite: FIFO didn't empty. dsr[%x] ecr[%x]\r\n", dsr, ecr));
|
|
// FIFO not empty, timeout occurred, exit with error.
|
|
Status = STATUS_TIMEOUT;
|
|
bDone = TRUE;
|
|
//HPKAssertOnError(0, ("ZIP_FTP, timeout during synch\r\n"));
|
|
}
|
|
}
|
|
} // of while...
|
|
}
|
|
}
|
|
|
|
Extension->CurrentPhase = PHASE_FORWARD_IDLE;
|
|
|
|
ParEcpHwWrite_ExitLabel:
|
|
|
|
*BytesTransferred = BufferSize - bytesToWrite;
|
|
|
|
Extension->log.HwEcpWriteCount += *BytesTransferred;
|
|
|
|
ParTimerCheck(("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(Status), (long)*BytesTransferred));
|
|
// ParDumpReg(PAREXIT | PARECPTRACE, ("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(Status), (long)*BytesTransferred),
|
|
ParDumpReg(PAREXIT, ("ParEcpHwWrite: Exit[%d] BytesTransferred[%d]", NT_SUCCESS(Status), (long)*BytesTransferred),
|
|
wPortECR,
|
|
Extension->Controller + OFFSET_DCR,
|
|
wPortDSR);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
ParEnterEcpHwMode(
|
|
IN PDEVICE_EXTENSION Extension,
|
|
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;
|
|
|
|
ParDump2(PARENTRY,("ParEnterEcpHwMode: Start EcrController %x\n", Extension->EcrController));
|
|
Controller = Extension->Controller;
|
|
|
|
if ( Extension->ModeSafety == SAFE_MODE ) {
|
|
if (DeviceIdRequest) {
|
|
Status = IeeeEnter1284Mode (Extension, ECP_EXTENSIBILITY | DEVICE_ID_REQ);
|
|
} else {
|
|
Status = IeeeEnter1284Mode (Extension, ECP_EXTENSIBILITY);
|
|
}
|
|
} else {
|
|
ParDump2(PARINFO, ("ParEnterEcpHwMode:: UNSAFE_MODE.\n"));
|
|
Extension->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);
|
|
#if (0 == PARCHIP_ECR_ARBITRATOR)
|
|
WRITE_PORT_UCHAR( Controller + ECR_OFFSET, DEFAULT_ECR_PS2 );
|
|
#endif
|
|
Extension->PortHWMode = HW_MODE_PS2;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = ParEcpHwSetupPhase(Extension);
|
|
Extension->bSynchWrites = TRUE; // NOTE this is a temp hack!!! dvrh
|
|
if (!Extension->bShadowBuffer)
|
|
{
|
|
Queue_Create(&(Extension->ShadowBuffer), Extension->FifoDepth * 2);
|
|
Extension->bShadowBuffer = TRUE;
|
|
}
|
|
Extension->IsIeeeTerminateOk = TRUE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
ParIsEcpHwSupported(
|
|
IN PDEVICE_EXTENSION Extension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine determines whether or not ECP mode is suported
|
|
in the write direction by trying to negotiate when asked.
|
|
|
|
Arguments:
|
|
|
|
Extension - The device extension.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (Extension->BadProtocolModes & ECP_HW_NOIRQ)
|
|
return FALSE;
|
|
|
|
if (Extension->ProtocolModesSupported & ECP_HW_NOIRQ)
|
|
return TRUE;
|
|
|
|
if (!(Extension->HardwareCapabilities & PPT_ECP_PRESENT))
|
|
return FALSE;
|
|
|
|
if (0 == Extension->FifoWidth)
|
|
return FALSE;
|
|
|
|
if (Extension->ProtocolModesSupported & ECP_SW)
|
|
return TRUE;
|
|
|
|
// Must use HWECP Enter and Terminate for this test.
|
|
// Internel state machines will fail otherwise. --dvrh
|
|
Status = ParEnterEcpHwMode (Extension, FALSE);
|
|
ParTerminateHwEcpMode (Extension);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
Extension->ProtocolModesSupported |= ECP_HW_NOIRQ;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
ParTerminateHwEcpMode(
|
|
IN PDEVICE_EXTENSION Extension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine terminates the interface back to compatibility mode.
|
|
|
|
Arguments:
|
|
|
|
Controller - Supplies the parallel port's controller address.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ParDump2( PARENTRY, ("HWECP::Terminate Entry CurrentPhase %d\r\n", Extension->CurrentPhase));
|
|
// 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 ( Extension->ModeSafety == SAFE_MODE ) {
|
|
|
|
switch (Extension->CurrentPhase)
|
|
{
|
|
case PHASE_FORWARD_IDLE: // Legal state to terminate
|
|
{
|
|
break;
|
|
}
|
|
case PHASE_REVERSE_IDLE: // Flip the bus so we can terminate
|
|
{
|
|
NTSTATUS status = ParEcpHwExitReversePhase( Extension );
|
|
|
|
if ( STATUS_SUCCESS == status )
|
|
{
|
|
status = ParEcpEnterForwardPhase(Extension );
|
|
}
|
|
else
|
|
{
|
|
ParDump2( PARERRORS, ("HWECP::Terminate Couldn't flip the bus\r\n"));
|
|
}
|
|
break;
|
|
}
|
|
case PHASE_FORWARD_XFER:
|
|
case PHASE_REVERSE_XFER:
|
|
{
|
|
ParDump2( PARERRORS, ("HWECP::Terminate invalid wCurrentPhase (XFer in progress) \r\n"));
|
|
//status = VE_BUSY;
|
|
// Dunno what to do here. We probably will confuse the peripheral.
|
|
break;
|
|
}
|
|
// LAC TERMINATED 13Jan98
|
|
// Included PHASE_TERMINATE in the switch so we won't return an
|
|
// error if we are already terminated.
|
|
case PHASE_TERMINATE:
|
|
{
|
|
// We are already terminated, nothing to do
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ParDump2( PARERRORS, ("ECP::Terminate VE_CORRUPT: invalid CurrentPhase %d\r\n", Extension->CurrentPhase));
|
|
//status = VE_CORRUPT;
|
|
// Dunno what to do here. We're lost and don't have a map to figure
|
|
// out where we are!
|
|
break;
|
|
}
|
|
}
|
|
|
|
ParDump2(PARINFO, ("HWECP::Terminate - Test ECPChanAddr\r\n"));
|
|
|
|
ParEcpHwWaitForEmptyFIFO(Extension);
|
|
ParCleanupHwEcpPort(Extension);
|
|
IeeeTerminate1284Mode (Extension);
|
|
} else {
|
|
ParCleanupHwEcpPort(Extension);
|
|
ParDump2(PARINFO, ("HWECP::Terminate - UNSAFE_MODE\r\n"));
|
|
Extension->Connected = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|