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

📄 fdopnp.c

📁 鼠标Windows驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
#include "pch.h"

VOID
PptDellNationalPC87364WorkAround( PUCHAR EcpController )
{
    PUCHAR  ecr      = EcpController+2;  // generic chipset Extended Control Register
    PUCHAR  eir      = EcpController+3;  // PC87364 chipset Extended Index   Register
    PUCHAR  edr      = EcpController+4;  // PC87364 chipset Extended Data    Register
    ULONG   delay    = 5;                // in microseconds (arbitrary - this seems to work)
    KIRQL   oldIrql;

    //
    // Raise IRQL to prevent BIOS from touching the registers at the
    // same time that we're updating them. This is a complete hack
    // since according to PnP we own the registers, but do it anyway
    // since we know that BIOS touches these same registers.
    //
    KeRaiseIrql( HIGH_LEVEL, &oldIrql );

    KeStallExecutionProcessor( delay );
    P5WritePortUchar( ecr, 0x15 );
    KeStallExecutionProcessor( delay );
    P5WritePortUchar( eir, 0x02 );
    KeStallExecutionProcessor( delay );
    P5WritePortUchar( edr, 0x90 );
    KeStallExecutionProcessor( delay );

    KeLowerIrql( oldIrql );
}

NTSTATUS
PptFdoStartDevice(
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp
) 
/*++dvdf8

Routine Description:

    This function handles PnP IRP_MN_START IRPs.

     - Wait for the bus driver and any drivers beneath 
         us in the driver stack to handle this first.
     - Get, validate, and save the resources given to us by PnP.
     - Assign IDs to and get a count of 1284.3 daisy chain devices
         connected to the port.
     - Determine the capabilities of the chipset (BYTE, EPP, ECP).
     - Set our PnP device interface state to trigger
         an interface arrival callback to anyone listening 
         on our GUID.

Arguments:

    DeviceObject - The target device for the IRP
    Irp          - The IRP

Return Value:

    STATUS_SUCCESS              - on success,
    an appropriate error status - otherwise

--*/
{
    PFDO_EXTENSION  fdx = DeviceObject->DeviceExtension;
    NTSTATUS        status;
    BOOLEAN         foundPort = FALSE;
    BOOLEAN         foundIrq  = FALSE;
    BOOLEAN         foundDma  = FALSE;


    //
    // This IRP must be handled first by the parent bus driver
    //   and then by each higher driver in the device stack.
    //
    status = PptPnpBounceAndCatchPnpIrp(fdx, Irp);
    if( !NT_SUCCESS( status ) && ( status != STATUS_NOT_SUPPORTED ) ) {
        // Someone below us in the driver stack explicitly failed the START.
        goto targetExit;
    }

    //
    // Extract resources from CM_RESOURCE_LIST and save them in our extension.
    //
    status = PptPnpStartScanCmResourceList(fdx, Irp, &foundPort, &foundIrq, &foundDma);
    if( !NT_SUCCESS( status ) ) {
        goto targetExit;
    }

    //
    // Do our resources appear to be valid?
    //
    status = PptPnpStartValidateResources(DeviceObject, foundPort, foundIrq, foundDma);
    if( !NT_SUCCESS( status ) ) {
        goto targetExit;
    }


    //
    // Check if ACPI set a flag for us based on entries in
    // BIOSINFO.INF to indicate that we are running on a Dell machine
    // with an incorrectly programmed National PC87364 SuperIO
    // chipset. If so try to work around the problem here so that the
    // user doesn't need to flash the BIOS to get the parallel port to
    // work.
    //
    // Symptoms of the problem are that the parallel port Data Lines
    // are wedged to all zeros regardless of the setting of the bits
    // in the parallel port data register or the Direction bit in the
    // control register.
    //
    // If the port base address is 0x3BC then this won't work and the
    // user will need to go to Device Manager and change the LPT port
    // resource settings to either 0x378 or 0x278 for the base
    // register address. We believe that ACPI defaults to a port base
    // address of 0x378 so this workaround should generally work.
    //
    {
        ULONG DellNationalPC87364 = 0;

        //
        // Check registry to see if ACPI set the flag based on
        // BIOSINFO.INF to indicate that we should try the workaround.
        //
        PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"DellNationalPC87364", &DellNationalPC87364 );

        if( DellNationalPC87364 ) {

            //
            // we have a Dell machine with a National PC87364 chipset
            // and a version of BIOS that we believe doesn't
            // initialize the parallel port so that it works under
            // Win2k or WinXP.
            //

            if( fdx->PnpInfo.SpanOfEcpController > 4 ) {

                //
                // We have the extra Ecp registers needed to try the
                // workaround without stepping on I/O register space
                // owned by someone else.
                //

                if( ( (PUCHAR)0x678 == fdx->PnpInfo.EcpController ) ||
                    ( (PUCHAR)0x778 == fdx->PnpInfo.EcpController ) ) {

                    //
                    // The parallel port base register and ECP
                    // registers are located at one of the two
                    // traditional address ranges: ECP at 0x400 offset
                    // from base register address of 0x278 or 0x378,
                    // so let's try the workaround to try to unwedge
                    // the port data lines.
                    //

                    PptDellNationalPC87364WorkAround( fdx->PnpInfo.EcpController );
                }
            }
        }

    } // end new block scope for Dell/National chipset workaround


    //
    // Initialize the IEEE 1284.3 "bus" by assigning IDs [0..3] to 
    //   the 1284.3 daisy chain devices connected to the port. This
    //   function also gives us a count of the number of such 
    //   devices connected to the port.
    //
    fdx->PnpInfo.Ieee1284_3DeviceCount = PptInitiate1284_3( fdx );
    
    //
    // Determine the hardware modes supported (BYTE, ECP, EPP) by
    //   the parallel port chipset and save this information in our extension.
    //

    // Check to see if the filter parchip is there and use the modes it can set
    status = PptDetectChipFilter( fdx );

    // if filter driver was not found use our own generic port detection
    if ( !NT_SUCCESS( status ) ) {
        PptDetectPortType( fdx );
    }

    
    //
    // Register w/WMI
    //
    status = PptWmiInitWmi( DeviceObject );
    if( !NT_SUCCESS( status ) ) {
        goto targetExit;
    }


    //
    // Signal those who registered for PnP interface change notification 
    //   on our GUID that we have STARTED (trigger an INTERFACE_ARRIVAL
    //   PnP callback).
    //
    status = IoSetDeviceInterfaceState( &fdx->DeviceInterface, TRUE );
    if( !NT_SUCCESS(status) ) {
        status = STATUS_NOT_SUPPORTED;
    } else {
        fdx->DeviceInterfaceState = TRUE;
    }

targetExit:

    if( NT_SUCCESS( status ) ) {

        // 
        // Note in our extension that we have successfully STARTED.
        //
        ExAcquireFastMutex( &fdx->ExtensionFastMutex );
        PptSetFlags( fdx->PnpState, PPT_DEVICE_STARTED );
        ExReleaseFastMutex( &fdx->ExtensionFastMutex );

        // create warm poll thread to poll for printer arrivals
        if( NULL == fdx->ThreadObjectPointer ) {

            ULONG DisableWarmPoll;

            fdx->PollingFailureCounter = 0; // reset counter

            // check for registry flag to disable "polling for printers"
            DisableWarmPoll = 0;      // if non-zero then do not poll for printer arrivals
            PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"DisableWarmPoll", &DisableWarmPoll );

            if( 0 == DisableWarmPoll ) {

                // how frequently should we check for printer arrivals? (in seconds)
                // (WarmPollPeriod is a driver global)
                PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"WarmPollPeriod", &WarmPollPeriod );
                if( WarmPollPeriod < 5 ) {
                    WarmPollPeriod = 5;
                } else {
                    if( WarmPollPeriod > 20 ) {
                        WarmPollPeriod = 20;
                    }
                }
                DD((PCE)fdx,DDT,"P5FdoThread - WarmPollPeriod = %d seconds\n",WarmPollPeriod);
            
                // side effect: set fdx->ThreadObjectPointer on SUCCESS
                P5FdoCreateThread( fdx );
            }

        }

    }

    P4CompleteRequest( Irp, status, 0 );

    PptReleaseRemoveLock( &fdx->RemoveLock, Irp );

    return status;
}


NTSTATUS
PptFdoQueryRemove(
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp
    ) 
/*++dvdf8

Routine Description:

    This function handles PnP IRP_MN_QUERY_REMOVE_DEVICE.

    FAIL the request if there are open handles, SUCCEED otherwise.
    
    This function is identical to PptPnpQueryStopDevice() except
      for the flag that gets set in fdx->PnpState.

Arguments:

    DeviceObject - The target device for the IRP
    Irp          - The IRP

Return Value:

    STATUS_SUCCESS     - No open handles - SUCCEED IRP
    STATUS_DEVICE_BUSY - Open handles - FAIL IRP

--*/
{
    //
    // Always succeed query - PnP will veto Query Remove on our behalf if 
    //   there are open handles
    //

    PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;

    ExAcquireFastMutex( &fdx->ExtensionFastMutex );
    PptSetFlags( fdx->PnpState, ( PPT_DEVICE_REMOVE_PENDING | PPT_DEVICE_PAUSED ) );
    ExReleaseFastMutex( &fdx->ExtensionFastMutex );

    Irp->IoStatus.Status = STATUS_SUCCESS;

    return PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
}


NTSTATUS
PptFdoRemoveDevice(
    IN PDEVICE_OBJECT Fdo, 
    IN PIRP           Irp
    ) 
/*++dvdf8

Routine Description:

    This function handles PnP IRP_MN_REMOVE_DEVICE.

    Notify those listening on our device interface GUID that 
      we have gone away, wait until all other IRPs that the
      device is processing have drained, and clean up.

Arguments:

    Fdo - The target device for the IRP
    Irp          - The IRP

Return Value:

    Status returned from IoCallDriver.

--*/
{
    PFDO_EXTENSION fdx = Fdo->DeviceExtension;
    NTSTATUS          status;

    //
    // clean up any child PDOs that are still here
    //
    if( fdx->RawPortPdo ) {
        PDEVICE_OBJECT pdo = fdx->RawPortPdo;
        DD((PCE)fdx,DDT,"PptFdoRemoveDevice - have RawPortPdo - cleaning up\n");
        P4DestroyPdo( pdo );
        fdx->RawPortPdo = NULL;
    }

    if( fdx->EndOfChainPdo ) {
        PDEVICE_OBJECT pdo = fdx->EndOfChainPdo;
        DD((PCE)fdx,DDT,"PptFdoRemoveDevice - have EndOfChainPdo - cleaning up\n");
        P4DestroyPdo( pdo );
        fdx->EndOfChainPdo = NULL;
    }

    {
        LONG        daisyChainId;
        const LONG  daisyChainMaxId = 1;

⌨️ 快捷键说明

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