⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hwecp.c

📁 鼠标Windows驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/*++

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 + -