📄 fdopnp.c
字号:
#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 + -