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

📄 chipmode.c

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

Copyright (C) Microsoft Corporation, 1993 - 1999

Module Name:

    parmode.c

Abstract:

    This is the main module for Extended Parallel Port (ECP) and
    Enhanced Parallel Port (EPP) detection.  This module 
    will detect for invalid chipshets and do ECR detection 
    for ECP and EPP hardware support if the invalid chipset
    is not found.

Author:

    Don Redford (v-donred) 4-Mar-1998

Environment:

    Kernel mode

Revision History :

--*/

#include "pch.h"

#define USE_PARCHIP_ECRCONTROLLER 1


NTSTATUS
PptDetectChipFilter(
    IN  PFDO_EXTENSION   Fdx
    )

/*++

Routine Description:

    This routine is called once per DeviceObject to see if the filter driver 
    for detecting parallel chip capabilities is there and to get the chip
    capabilities if there of the port in question.
    
Arguments:

    Fdx   - Supplies the device extension.

Return Value:

    STATUS_SUCCESS  - if we were able detect the chip and modes possible.
   !STATUS_SUCCESS  - otherwise.

--*/

{
    NTSTATUS                    Status = STATUS_NO_SUCH_DEVICE;
    PIRP                        Irp;
    KEVENT                      Event;
    IO_STATUS_BLOCK             IoStatus;
    UCHAR                       ecrLast;
    PUCHAR                      Controller, EcpController;
            
    Controller = Fdx->PortInfo.Controller;
    EcpController = Fdx->PnpInfo.EcpController;
    
    // Setting variable to FALSE to make sure we do not acidentally succeed
    Fdx->ChipInfo.success = FALSE;

    // Setting the Address to send to the filter driver to check the chips
    Fdx->ChipInfo.Controller = Controller;

    // Setting the Address to send to the filter driver to check the chips
    Fdx->ChipInfo.EcrController = EcpController;

#ifndef USE_PARCHIP_ECRCONTROLLER
    // if there is not value in the ECR controller then PARCHIP and PARPORT
    // will conflict and PARCHIP will not work with PARPORT unless we
    // use the ECR controller found by PARCHIP.
    if ( !EcpController ) {
         return Status;
    }
#endif    
    //
    // Initialize
    //
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    // Send a Pointer to the ChipInfo structure to and from the filter
    Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_PARCHIP_CONNECT,
                                         Fdx->ParentDeviceObject, 
                                         &Fdx->ChipInfo,
                                         sizeof(PARALLEL_PARCHIP_INFO),
                                         &Fdx->ChipInfo,
                                         sizeof(PARALLEL_PARCHIP_INFO),
                                         TRUE, &Event, &IoStatus);

    if (!Irp) { 
        // couldn't create an IRP
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Call down to our parent and see if Filter is present
    //
    Status = IoCallDriver(Fdx->ParentDeviceObject, Irp);
            
    if (Status == STATUS_PENDING) {
        KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
        Status = Irp->IoStatus.Status;
    }
            
    //
    // If successful then we have a filter driver and we need to get the modes supported
    //
    if ( NT_SUCCESS(Status) ) {

        //
        // check to see if the filter driver was able to determine the I/O chip
        //
        if ( Fdx->ChipInfo.success ) {
            Fdx->PnpInfo.HardwareCapabilities = Fdx->ChipInfo.HardwareModes;
#ifdef USE_PARCHIP_ECRCONTROLLER
            // only replace it if defined
            if ( Fdx->PnpInfo.EcpController != Fdx->ChipInfo.EcrController ) {
                Fdx->PnpInfo.EcpController = Fdx->ChipInfo.EcrController;
                EcpController = Fdx->PnpInfo.EcpController;
            }
#endif
            // Set variable to say we have a filter driver
            Fdx->FilterMode = TRUE;
        }
    }

    // if there is a filter and ECP capable we need to get the Fifo Size
    if ( Fdx->FilterMode && Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {

        Status = Fdx->ChipInfo.ParChipSetMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );

        // if able to set ECP mode
        if ( NT_SUCCESS( Status ) ) {
            PUCHAR wPortECR;

            wPortECR = EcpController + ECR_OFFSET;

            // get value from ECR reg & save it
            ecrLast = P5ReadPortUchar( wPortECR );

            // Determining Fifo Size
            PptDetermineFifoWidth(Fdx);    
            PptDetermineFifoDepth(Fdx);

            // return ecr to original
            P5WritePortUchar( wPortECR, ecrLast);

            Status = Fdx->ChipInfo.ParChipClearMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );
        }    
    
    }    

    return Status;
}

NTSTATUS
PptDetectPortType(
    IN  PFDO_EXTENSION   Fdx
    )

/*++

Routine Description:

    This routine is called once per DeviceObject to detect the type of 
    parallel chip capabilities of the port in question.
    
Arguments:

    Fdx   - Supplies the device extension.

Return Value:

    STATUS_SUCCESS  - if we were able detect the chip and modes possible.
   !STATUS_SUCCESS  - otherwise.

--*/

{
    NTSTATUS                    Status;
    UNICODE_STRING              ParportPath;
    RTL_QUERY_REGISTRY_TABLE    RegTable[2];
    ULONG                       IdentifierHex = 12169;
    ULONG                       zero = 0;

    //
    // -- May want to get detection order from Registry.
    // -- May also want to store/retrieve last known good configuration in/from registry.
    // -- Finally we should set a registry flag during dection so that we'll know
    //    if we crashed while attempting to detect and not try it again.
    //
    RtlInitUnicodeString(&ParportPath, (PWSTR)L"Parport");

    // Setting up to get the Parport info
    RtlZeroMemory( RegTable, sizeof(RegTable) );

    RegTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    RegTable[0].Name = (PWSTR)L"ModeCheckedStalled";
    RegTable[0].EntryContext = &IdentifierHex;
    RegTable[0].DefaultType = REG_DWORD;
    RegTable[0].DefaultData = &zero;
    RegTable[0].DefaultLength = sizeof(ULONG);

    //
    // Querying the registry for Parport to see if we tried to go check mode and we crashed
    // the registry key would still be there 
    //
    Status = RtlQueryRegistryValues(
                                RTL_REGISTRY_SERVICES,
                                ParportPath.Buffer,
                                RegTable,
                                NULL,
                                NULL );

    //
    // if registry key is there then we will just check ECP and Byte
    //
    if ( !(NT_SUCCESS( Status ) && IdentifierHex == 0) && (Status != STATUS_OBJECT_NAME_NOT_FOUND) ) {

        // dvtw, Check for ECP anyway!  We just won't turn it on

        PptDetectEcpPort(Fdx);
        PptDetectBytePort(Fdx);

        if( Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_BYTE_PRESENT) ) {
            return STATUS_SUCCESS;
        } else {
            return STATUS_NO_SUCH_DEVICE;
        }
    }
    
    IdentifierHex = 12169;
    // Write the registry key out there just in case we crash
    Status = RtlWriteRegistryValue(
                                RTL_REGISTRY_SERVICES,
                                ParportPath.Buffer,
                                (PWSTR)L"ModeCheckedStalled",
                                REG_DWORD,
                                &IdentifierHex,
                                sizeof(ULONG) );
            
    //
    // Now we can start detecting the parallel port chip capabilities
    //
    Status = PptDetectPortCapabilities( Fdx );

    // Delete the registry key out there since we finished
    Status = RtlDeleteRegistryValue( RTL_REGISTRY_SERVICES, ParportPath.Buffer, (PWSTR)L"ModeCheckedStalled" ); 
    return Status;
}

NTSTATUS
PptDetectPortCapabilities(
    IN  PFDO_EXTENSION   Fdx
    )

/*++

Routine Description:

    This is the "default" detection code, which looks for an ECR.  If the ECR
    is present it tries to set mode 100b in <7:5>. If it sticks we'll call it
    EPP.

Arguments:

    Fdx   - Supplies the device extension.

Return Value:

    STATUS_SUCCESS  - if the port type was detected.
   !STATUS_SUCCESS  - otherwise.

--*/

{
    NTSTATUS    Status;

    PptDetectEcpPort( Fdx );
    
    // dvdr 
    // 
    // if we did not detect an ECR for ECP mode and ECP mode failed
    // EPP mode would fail also
    // Also cannot have EPP mode at an address that ends with a "C"
    // 
    if ( (Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT) &&
         (((ULONG_PTR)Fdx->PortInfo.Controller & 0x0F) != 0x0C) ) {

        // Need to check for National chipsets before trying EPP mode
        // dvdr - need to add detection for old Winbond

        Status = PptFindNatChip( Fdx );

        if ( NT_SUCCESS( Status ) ) {
            if ( !Fdx->NationalChipFound ) {
                // National chipset was NOT found so we can see if generic EPP is supported

                PptDetectEppPortIfDot3DevicePresent( Fdx );

                if( !Fdx->CheckedForGenericEpp ) {
                    // we didn't have a dot3 device to use for screening, do check anyway
                    //   if user has explicitly requested EPP detection
                    PptDetectEppPortIfUserRequested( Fdx );
                }
            } else {
                // National chipset was found so can't do generic EPP
                Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
            }
        }
    } else {
        // ECP failed no check for Generic EPP
        Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
    }

    PptDetectBytePort( Fdx );
    
    if (Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_EPP_PRESENT | PPT_BYTE_PRESENT) ) {
        return STATUS_SUCCESS;
    }

    return STATUS_NO_SUCH_DEVICE;    
}

VOID
PptDetectEcpPort(
    IN  PFDO_EXTENSION   Fdx
    )
    
/*++
      
Routine Description:
      
    This routine looks for the presence of an ECR register to determine that
      it has ECP.
      
Arguments:
      
    Fdx           - Supplies the device extension of the device we are
                            reporting resources for.
      
Return Value:
      
    None.
      
--*/
    
{
    PUCHAR  Controller;
    PUCHAR  wPortDCR;       // IO address of Device Control Register (DCR)
    PUCHAR  wPortECR;       // IO address of Extended Control Register (ECR)
    UCHAR   ecrLast, ecr, dcr;
    
    Controller = Fdx->PortInfo.Controller;
    wPortDCR = Controller + DCR_OFFSET;

    if( 0 == Fdx->PnpInfo.EcpController ) {
        // PnP didn't give us an ECP Register set - we're done here
        return;
    }
    wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;

    ecrLast = ecr = P5ReadPortUchar(wPortECR);

    // Initialize the DCR's nAutoFeed and nStrobe to a harmless combination
    // that could be returned by the ECR, but is not likely to be returned if
    // the ECR isn't present.  Depending on the host's address decode logic,
    // reading a non-existant ECR could have one of two results:  the ECR address
    // could decode on top of the DCR, so we'll read the value we are about to set.
    // Alternately, we might just read a floating bus and get a random value.
    dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, INACTIVE, ACTIVE );
    P5WritePortUchar( wPortDCR, dcr );

    ecrLast = ecr = P5ReadPortUchar(wPortECR);
    
    
    // Attempt to read the ECR.  If ECP hardware is present, the ECR register's
    // bit 1 and bit 0 should read a 00 (some data in the FIFO), 01 (FIFO empty),
    // or 10 (FIFO full).  If we read a 11 (illegal combination) then we know for
    // sure that no ECP hardware is present.  Also, a valid ECR should never return
    // 0xFF (but a nonexistant register probably would), so we'll test for that 
    // specific value also.
    if ( ( TEST_ECR_FIFO( ecr, ECR_FIFO_MASK ) ) || ( ecrLast == 0xFF ) ) {
        // ECR[1:0] returned a value of 11, so this can't be hardware ECP.
        DD((PCE)Fdx,DDT,"ParMode::PptDetectEcpPort:  illegal FIFO status\n");

        // Restore the DCR so that all lines are inactive.
        dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
        P5WritePortUchar( wPortDCR, dcr );
        return;
    }

    // OK, so we got either a 00, 01, or 10 for ECR[1:0].  If it was 10, the
    if( TEST_ECR_FIFO( ecr, ECR_FIFO_FULL ) ) { // Looking for ECR[1:0] of 10...

        // The ECR[1:0] returned 10.  This is a legal value, but possibly the
        // hardware might have just decoded the DCR and we merely read back the
        // DCR value we set earlier.  Or, we might have just read back a value
        // that was hanging on the bus due to bus capacitance.  So, we'll change 
        // the DCR, read the ECR again, and see if the two registers continue to 
        // track each other.  If they do track, we'll conclude that there is no
        // ECP hardware.

        // Put the DCR's nAutoFeed and nStrobe register bits back to zero.
        dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
        P5WritePortUchar( wPortDCR, dcr );

        // Read the ECR again
        ecr = P5ReadPortUchar( wPortECR );

        if ( TEST_ECR_FIFO( ecr, ECR_FIFO_SOME_DATA ) ) {
            // ECR[1:0] is tracking DCR[1:0], so this can't be hardware ECP.

            // Restore the DCR so that all lines are inactive.
            dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
            P5WritePortUchar( wPortDCR, dcr );
            return;
        }
    }
    
    // If we get this far, then the ECR appears to be returning something valid that
    // doesn't track the DCR.  It is beginning to look promising.  We're going
    // to take a chance, and write the ECR to put the chip in compatiblity
    // mode.  Doing so will reset the FIFO, so when we read FIFO status it should
    // come back empty.  However, if we're wrong and this isn't ECP hardware, the
    // value we're about to write will turn on 1284Active (nSelectIn) and this might
    // cause headaches for the peripheral.
    P5WritePortUchar( wPortECR, DEFAULT_ECR_COMPATIBILITY );

⌨️ 快捷键说明

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