📄 hwecp.c
字号:
/*++
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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -