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

📄 hwecp.c

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

    Pdx           - Supplies the device extension.

    Buffer              - Supplies the buffer to write from.

    BufferSize          - Supplies the number of bytes in the buffer.

    BytesTransferred     - Returns the number of bytes transferred.
    
Return Value:

    None.

--*/
{
    PUCHAR          wPortDSR;
    PUCHAR          wPortECR;
    PUCHAR          wPortDFIFO;
    ULONG           bytesToWrite = BufferSize;
    UCHAR           dsr;
    UCHAR           ecr;
    UCHAR           ecrFIFO;
    LARGE_INTEGER   WaitPerByteTimer;
    LARGE_INTEGER   StartPerByteTimer;
    LARGE_INTEGER   EndPerByteTimer;
    BOOLEAN         bResetTimer = TRUE;
    ULONG           wBurstCount;    // Length of burst to write when FIFO empty
    PUCHAR          pBuffer;
    NTSTATUS        status = STATUS_SUCCESS;
    
    wPortDSR   = Pdx->Controller + DSR_OFFSET;
    wPortECR   = Pdx->EcrController + ECR_OFFSET;
    wPortDFIFO = Pdx->EcrController;
    pBuffer    = Buffer;

    status = ParTestEcpWrite(Pdx);
    if (!NT_SUCCESS(status)) {
        P5SetPhase( Pdx, PHASE_UNKNOWN );                     
        Pdx->Connected = FALSE;                                
        DD((PCE)Pdx,DDT,"ParEcpHwWrite: Invalid Entry State\n");
        goto ParEcpHwWrite_ExitLabel;       // Use a goto so we can see Debug info located at the end of proc!
    }

    P5SetPhase( Pdx, PHASE_FORWARD_XFER );
    //----------------------------------------------------------------------
    // Setup Timer Stuff.
    //----------------------------------------------------------------------
    // we wait up to 35 milliseconds.
    WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement();  // 35ms

    // Set up the timer that limits the time allowed for per-byte handshakes.
    KeQueryTickCount(&StartPerByteTimer);
    
    //----------------------------------------------------------------------
    // Send the data to the DFIFO.
    //----------------------------------------------------------------------

HWECP_WriteLoop_Start:

    //------------------------------------------------------------------
    // Determine whether the FIFO has space and respond accordingly.
    //------------------------------------------------------------------
    ecrFIFO = (UCHAR)(P5ReadPortUchar(wPortECR) & ECR_FIFO_MASK);

    if ( ECR_FIFO_EMPTY == ecrFIFO ) {
        wBurstCount = (bytesToWrite > Pdx->FifoDepth) ? Pdx->FifoDepth : bytesToWrite;
        bytesToWrite -= wBurstCount;
        
        P5WritePortBufferUchar(wPortDFIFO, pBuffer, wBurstCount);
        pBuffer += wBurstCount;
        
        bResetTimer = TRUE;
    } else if (ECR_FIFO_SOME_DATA == ecrFIFO) {
        // Write just one byte at a time, since we don't know exactly how much
        // room there is in the FIFO.
        P5WritePortUchar(wPortDFIFO, *pBuffer++);
        bytesToWrite--;
        bResetTimer = TRUE;
    } else {    //  ECR_FIFO_FULL
        // Need to figure out whether to keep attempting to send, or to quit
        // with a timeout status.
        
        // Reset the per-byte timer if a byte was received since the last
        // timer check.
        if ( bResetTimer ) {
            KeQueryTickCount(&StartPerByteTimer);
            bResetTimer = FALSE;
        }
        
        KeQueryTickCount(&EndPerByteTimer);
        if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart) {
            status = STATUS_TIMEOUT;
            // Peripheral is either busy or stalled.  If the peripheral
            // is busy then they should be using SWECP to allow for
            // relaxed timings.  Let's punt!
            goto HWECP_WriteLoop_End;
        }
    }

    if (bytesToWrite == 0) {
        goto HWECP_WriteLoop_End; // Transfer completed.
    }

    goto HWECP_WriteLoop_Start; // Start over
    
HWECP_WriteLoop_End:

    if ( NT_SUCCESS(status) ) {
        // If there have been no previous errors, and synchronous writes
        // have been requested, wait for the FIFO to empty and the last
        // handshake of PeriphAck to complete before returning success.
        if (Pdx->bSynchWrites ) {
            BOOLEAN         bDone = FALSE;
            

            KeQueryTickCount(&StartPerByteTimer);

            while( !bDone ) {
                ecr = P5ReadPortUchar(wPortECR);
                dsr = P5ReadPortUchar(wPortDSR);
                // LLL/CGM 10/9/95: tighten up DSR test - PeriphClk should be high
                if ( TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) &&
                     TEST_DSR( dsr, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
                    // FIFO is empty, exit without error.
                    bDone = TRUE;
                } else {

                    KeQueryTickCount(&EndPerByteTimer);
                    if ((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement() > WaitPerByteTimer.QuadPart) {
                        // FIFO not empty, timeout occurred, exit with error.
                        status = STATUS_TIMEOUT;
                        bDone = TRUE;
                    }
                }
            } // of while...
        }
    }

    P5SetPhase( Pdx, PHASE_FORWARD_IDLE );

ParEcpHwWrite_ExitLabel:

    *BytesTransferred = BufferSize - bytesToWrite;
    
    Pdx->log.HwEcpWriteCount += *BytesTransferred;
    
    DD((PCE)Pdx,DDT,"ParEcpHwWrite: exit w/status=%x, BytesTransferred=%d, dsr=%02x dcr=%02x, ecr=%02x\n",
       status, *BytesTransferred, P5ReadPortUchar(wPortDSR), P5ReadPortUchar(Pdx->Controller + OFFSET_DCR), P5ReadPortUchar(wPortECR));

#if 1 == DBG_SHOW_BYTES
    if( DbgShowBytes ) {
        if( NT_SUCCESS( status ) && (*BytesTransferred > 0) ) {
            const ULONG maxBytes = 32;
            ULONG i;
            PUCHAR bytePtr = (PUCHAR)Buffer;
            DbgPrint("W: ");
            for( i=0 ; (i < *BytesTransferred) && (i < maxBytes) ; ++i ) {
                DbgPrint("%02x ",*bytePtr++);
            }
            if( *BytesTransferred > maxBytes ) {
                DbgPrint("... ");
            }
            DbgPrint("zz\n");
        }
    }
#endif

    return status;
}

NTSTATUS
ParEnterEcpHwMode(
    IN  PPDO_EXTENSION   Pdx,
    IN  BOOLEAN             DeviceIdRequest
    )
/*++

Routine Description:

    This routine performs 1284 negotiation with the peripheral to the
    ECP mode protocol.

Arguments:

    Controller      - Supplies the port address.

    DeviceIdRequest - Supplies whether or not this is a request for a device
                        id.

Return Value:

    STATUS_SUCCESS  - Successful negotiation.

    otherwise       - Unsuccessful negotiation.

--*/
{
    NTSTATUS Status = STATUS_SUCCESS;
    PUCHAR Controller;

    Controller = Pdx->Controller;

    if ( Pdx->ModeSafety == SAFE_MODE ) {
        if (DeviceIdRequest) {
            Status = IeeeEnter1284Mode (Pdx, ECP_EXTENSIBILITY | DEVICE_ID_REQ);
        } else {
            Status = IeeeEnter1284Mode (Pdx, ECP_EXTENSIBILITY);
        }
    } else {
        Pdx->Connected = TRUE;
    }
    
    // LAC ENTEREXIT  5Dec97
    // Make sure that the ECR is in PS/2 mode, and that wPortHWMode
    // has the correct value.  (This is the common entry mode);
    Pdx->PortHWMode = HW_MODE_PS2;

    if (NT_SUCCESS(Status)) {
        Status = ParEcpHwSetupPhase(Pdx);
        Pdx->bSynchWrites = TRUE;     // NOTE this is a temp hack!!!  dvrh
        if (!Pdx->bShadowBuffer)
        {
            Queue_Create(&(Pdx->ShadowBuffer), Pdx->FifoDepth * 2);		
            Pdx->bShadowBuffer = TRUE;
        }
        Pdx->IsIeeeTerminateOk = TRUE;
    }

    return Status;
}

BOOLEAN
ParIsEcpHwSupported(
    IN  PPDO_EXTENSION   Pdx
    )
/*++

Routine Description:

    This routine determines whether or not ECP mode is suported
    in the write direction by trying to negotiate when asked.

Arguments:

    Pdx  - The device extension.

Return Value:

    BOOLEAN.

--*/
{
    NTSTATUS Status;

    if (Pdx->BadProtocolModes & ECP_HW_NOIRQ)
        return FALSE;

    if (Pdx->ProtocolModesSupported & ECP_HW_NOIRQ)
        return TRUE;

    if (!(Pdx->HardwareCapabilities & PPT_ECP_PRESENT))
        return FALSE;

    if (0 == Pdx->FifoWidth)
        return FALSE;
        
    if (Pdx->ProtocolModesSupported & ECP_SW)
        return TRUE;

    // Must use HWECP Enter and Terminate for this test.
    // Internel state machines will fail otherwise.  --dvrh
    Status = ParEnterEcpHwMode (Pdx, FALSE);
    ParTerminateHwEcpMode (Pdx);

    if (NT_SUCCESS(Status)) {

        Pdx->ProtocolModesSupported |= ECP_HW_NOIRQ;
        return TRUE;
    }
    return FALSE;
}

VOID
ParTerminateHwEcpMode(
    IN  PPDO_EXTENSION  Pdx
    )
/*++

Routine Description:

    This routine terminates the interface back to compatibility mode.

Arguments:

    Controller  - Supplies the parallel port's controller address.

Return Value:

    None.

--*/
{

    // Need to check current phase -- if its reverse, need to flip bus
    // If its not forward -- its an incorrect phase and termination will fail.
    if( Pdx->ModeSafety == SAFE_MODE ) {

        switch( Pdx->CurrentPhase ) {

        case  PHASE_FORWARD_IDLE:  // Legal state to terminate from
            break;

        case PHASE_TERMINATE:      // already terminated, nothing to do
            DD((PCE)Pdx,DDW,"ParTerminateHwEcpMode - Already Terminated - Why are we trying to terminate again?\n");
            goto target_exit;
            break;

        case PHASE_REVERSE_IDLE:   // Flip bus to forward so we can terminate
            {
                NTSTATUS status = ParEcpHwExitReversePhase( Pdx );
            	if( STATUS_SUCCESS == status ) {
                    status = ParEcpEnterForwardPhase( Pdx );
                }
            }
            break;

        case  PHASE_FORWARD_XFER:
        case  PHASE_REVERSE_XFER:
        default:
            DD((PCE)Pdx,DDE,"ParTerminateHwEcpMode - Invalid Phase [%x] for termination\n", Pdx->CurrentPhase);
            // Don't know what to do here!?!
        }

        ParEcpHwWaitForEmptyFIFO( Pdx );

        ParCleanupHwEcpPort( Pdx );

        IeeeTerminate1284Mode( Pdx );

    } else {
        // UNSAFE_MODE
        ParCleanupHwEcpPort(Pdx);
        Pdx->Connected = FALSE;
    }

target_exit:

    return;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -