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

📄 spp.c

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

Copyright (C) Microsoft Corporation, 1993 - 1999

Module Name:

    spp.c

Abstract:

    This module contains the code for standard parallel ports
    (centronics mode).

Author:

    Anthony V. Ercolano 1-Aug-1992
    Norbert P. Kusters 22-Oct-1993

Environment:

    Kernel mode

Revision History :

--*/

#include "pch.h"

ULONG
SppWriteLoopPI(
    IN  PUCHAR  Controller,
    IN  PUCHAR  WriteBuffer,
    IN  ULONG   NumBytesToWrite,
    IN  ULONG   BusyDelay
    );
    
ULONG
SppCheckBusyDelay(
    IN  PPDO_EXTENSION   Pdx,
    IN  PUCHAR              WriteBuffer,
    IN  ULONG               NumBytesToWrite
    );

NTSTATUS
ParEnterSppMode(
    IN  PPDO_EXTENSION   Pdx,
    IN  BOOLEAN             DeviceIdRequest
    )
{
    UNREFERENCED_PARAMETER( DeviceIdRequest );

    DD((PCE)Pdx,DDT,"ParEnterSppMode: Enter!\n");

    P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
    Pdx->Connected = TRUE;	
    return STATUS_SUCCESS;
}

ULONG
SppWriteLoopPI(
    IN  PUCHAR  Controller,
    IN  PUCHAR  WriteBuffer,
    IN  ULONG   NumBytesToWrite,
    IN  ULONG   BusyDelay
    )

/*++

Routine Description:

    This routine outputs the given write buffer to the parallel port
    using the standard centronics protocol.

Arguments:

    Controller  - Supplies the base address of the parallel port.

    WriteBuffer - Supplies the buffer to write to the port.

    NumBytesToWrite - Supplies the number of bytes to write out to the port.

    BusyDelay   - Supplies the number of microseconds to delay before
                    checking the busy bit.

Return Value:

    The number of bytes successfully written out to the parallel port.

--*/

{
    ULONG   i;
    UCHAR   DeviceStatus;
    BOOLEAN atPassiveIrql = FALSE;

    if( KeGetCurrentIrql() == PASSIVE_LEVEL ) {
        atPassiveIrql = TRUE;
    }

    if (!BusyDelay) {
        BusyDelay = 1;
    }

    for (i = 0; i < NumBytesToWrite; i++) {

        DeviceStatus = GetStatus(Controller);

        if (PAR_ONLINE(DeviceStatus)) {

            //
            // Anytime we write out a character we will restart
            // the count down timer.
            //

            P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);

            KeStallExecutionProcessor(1);

            StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                      PAR_CONTROL_SLIN |
                                      PAR_CONTROL_NOT_INIT |
                                      PAR_CONTROL_STROBE));

            KeStallExecutionProcessor(1);

            StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                      PAR_CONTROL_SLIN |
                                      PAR_CONTROL_NOT_INIT));

            KeStallExecutionProcessor(BusyDelay);

        } else {
            DD(NULL,DDT,"spp::SppWriteLoopPI - DeviceStatus = %x - NOT ONLINE\n", DeviceStatus);
            break;
        }
    }

    DD(NULL,DDT,"SppWriteLoopPI - exit - bytes written = %ld\n",i);

    return i;
}

ULONG
SppCheckBusyDelay(
    IN  PPDO_EXTENSION   Pdx,
    IN  PUCHAR              WriteBuffer,
    IN  ULONG               NumBytesToWrite
    )

/*++

Routine Description:

    This routine determines if the current busy delay setting is
    adequate for this printer.

Arguments:

    Pdx       - Supplies the device extension.

    WriteBuffer     - Supplies the write buffer.

    NumBytesToWrite - Supplies the size of the write buffer.

Return Value:

    The number of bytes strobed out to the printer.

--*/

{
    PUCHAR          Controller;
    ULONG           BusyDelay;
    LARGE_INTEGER   Start;
    LARGE_INTEGER   PerfFreq;
    LARGE_INTEGER   End;
    LARGE_INTEGER   GetStatusTime;
    LARGE_INTEGER   CallOverhead;
    UCHAR           DeviceStatus;
    ULONG           i;
    ULONG           NumberOfCalls;
    ULONG           maxTries;
    KIRQL           OldIrql = PASSIVE_LEVEL;

    UNREFERENCED_PARAMETER( NumBytesToWrite );

    Controller = Pdx->Controller;
    BusyDelay  = Pdx->BusyDelay;
    
    // If the current busy delay value is 10 or greater then something
    // is weird and settle for 10.

    if (Pdx->BusyDelay >= 10) {
        Pdx->BusyDelayDetermined = TRUE;
        return 0;
    }

    // Take some performance measurements.

    if (0 == SppNoRaiseIrql)
        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

    Start = KeQueryPerformanceCounter(&PerfFreq);
    
    DeviceStatus = GetStatus(Controller);
    
    End = KeQueryPerformanceCounter(&PerfFreq);
    
    GetStatusTime.QuadPart = End.QuadPart - Start.QuadPart;

    Start = KeQueryPerformanceCounter(&PerfFreq);
    End   = KeQueryPerformanceCounter(&PerfFreq);
    
    if (0 == SppNoRaiseIrql)
        KeLowerIrql(OldIrql);

    CallOverhead.QuadPart = End.QuadPart - Start.QuadPart;
    
    GetStatusTime.QuadPart -= CallOverhead.QuadPart;
    
    if (GetStatusTime.QuadPart <= 0) {
        GetStatusTime.QuadPart = 1;
    }

    // Figure out how many calls to 'GetStatus' can be made in 20 us.

    NumberOfCalls = (ULONG) (PerfFreq.QuadPart*20/GetStatusTime.QuadPart/1000000) + 1;

    //
    // - check to make sure the device is ready to receive a byte before we start clocking
    //    data out
    // 
    // DVDF - 25Jan99 - added check
    // 

    //
    // - nothing magic about 25 - just catch the case where NumberOfCalls may be bogus
    //    and try something reasonable - empirically NumberOfCalls has ranged from 8-24
    //
    maxTries = (NumberOfCalls > 25) ? 25 : NumberOfCalls;

    for( i = 0 ; i < maxTries ; i++ ) {
        // spin for slow device to get ready to receive data - roughly 20us max
        DeviceStatus = GetStatus( Controller );
        if( PAR_ONLINE( DeviceStatus ) ) {
            // break out of loop as soon as device is ready
            break;
        }
    }
    if( !PAR_ONLINE( DeviceStatus ) ) {
        // device is still not online - bail out
        return 0;
    }

    // The printer is ready to accept a byte.  Strobe one out
    // and check out the reaction time for BUSY.

    if (BusyDelay) {

        if (0 == SppNoRaiseIrql)
            KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

        P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);
        KeStallExecutionProcessor(1);
        StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                  PAR_CONTROL_SLIN |
                                  PAR_CONTROL_NOT_INIT |
                                  PAR_CONTROL_STROBE));
        KeStallExecutionProcessor(1);
        StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                  PAR_CONTROL_SLIN |
                                  PAR_CONTROL_NOT_INIT));
        KeStallExecutionProcessor(BusyDelay);

        for (i = 0; i < NumberOfCalls; i++) {
            DeviceStatus = GetStatus(Controller);
            if (!(DeviceStatus & PAR_STATUS_NOT_BUSY)) {
                break;
            }
        }

        if (0 == SppNoRaiseIrql)
            KeLowerIrql(OldIrql);

    } else {

        if (0 == SppNoRaiseIrql)
            KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

        P5WritePortUchar(Controller + PARALLEL_DATA_OFFSET, *WriteBuffer++);
        KeStallExecutionProcessor(1);
        StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                  PAR_CONTROL_SLIN |
                                  PAR_CONTROL_NOT_INIT |
                                  PAR_CONTROL_STROBE));
        KeStallExecutionProcessor(1);
        StoreControl(Controller, (PAR_CONTROL_WR_CONTROL |
                                  PAR_CONTROL_SLIN |
                                  PAR_CONTROL_NOT_INIT));

        for (i = 0; i < NumberOfCalls; i++) {
            DeviceStatus = GetStatus(Controller);
            if (!(DeviceStatus & PAR_STATUS_NOT_BUSY)) {
                break;
            }
        }

        if (0 == SppNoRaiseIrql)
            KeLowerIrql(OldIrql);
    }

    if (i == 0) {

        // In this case the BUSY was set as soon as we checked it.
        // Use this busyDelay with the PI code.

        Pdx->UsePIWriteLoop = TRUE;
        Pdx->BusyDelayDetermined = TRUE;

    } else if (i == NumberOfCalls) {

        // In this case the BUSY was never seen.  This is a very fast
        // printer so use the fastest code possible.

        Pdx->BusyDelayDetermined = TRUE;

    } else {

        // The test failed.  The lines showed not BUSY and then BUSY
        // without strobing a byte in between.

        Pdx->UsePIWriteLoop = TRUE;
        Pdx->BusyDelay++;
    }

    return 1;
}

NTSTATUS
SppWrite(
    IN  PPDO_EXTENSION Pdx,
    IN  PVOID             Buffer,
    IN  ULONG             BytesToWrite,
    OUT PULONG            BytesTransferred
    )

/*++

Routine Description:

Arguments:

    Pdx   - Supplies the device extension.

Return Value:

    None.

--*/
{
    NTSTATUS            status;
    UCHAR               DeviceStatus;
    ULONG               TimerStart;
    LONG                CountDown;
    PUCHAR              IrpBuffer;
    LARGE_INTEGER       StartOfSpin;
    LARGE_INTEGER       NextQuery;
    LARGE_INTEGER       Difference;
    BOOLEAN             DoDelays;
    BOOLEAN             PortFree;
    ULONG               NumBytesWritten; 
    ULONG               LoopNumber;
    ULONG               NumberOfBusyChecks;
    ULONG               MaxBusyDelay;
    ULONG               MaxBytes;
    
    DD((PCE)Pdx,DDT,"SppWrite - enter, BytesToWrite = %d\n",BytesToWrite);

    *BytesTransferred = 0; // initialize to none

    IrpBuffer  = (PUCHAR)Buffer;
    MaxBytes   = BytesToWrite;
    TimerStart = Pdx->TimerStart;
    CountDown  = (LONG)TimerStart;
    
    NumberOfBusyChecks = 9;
    MaxBusyDelay = 0;
    
    // Turn off the strobe in case it was left on by some other device sharing the port.
    StoreControl(Pdx->Controller, (PAR_CONTROL_WR_CONTROL |
                                         PAR_CONTROL_SLIN |
                                         PAR_CONTROL_NOT_INIT));

PushSomeBytes:

    //
    // While we are strobing data we don't want to get context
    // switched away.  Raise up to dispatch level to prevent that.
    //
    // The reason we can't afford the context switch is that
    // the device can't have the data strobe line on for more
    // than 500 microseconds.
    //

⌨️ 快捷键说明

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