Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

190 lines
6.4 KiB

#include "pch.h"
// experimental vars - to tweek debugging for this thread
ULONG x1; // set nonzero to disable port acquisition
ULONG x2; // set nonzero to try to select LPT1.0 and negotiate/terminate ECP_HW_NOIRQ
ULONG x3; // set nonzero to try to negotiate the periph to ECP and then terminate
ULONG x4;
ULONG t1; // timeout between thread polls (in ms)
ULONG t2; // time to sit on port before releasing it (in ms)
VOID
P5FdoThread(
IN PFDO_EXTENSION Fdx
)
{
LARGE_INTEGER timeOut1;
NTSTATUS status;
UCHAR deviceStatus;
PCHAR devId;
BOOLEAN requestRescan;
const ULONG pollingFailureThreshold = 10; // pick an arbitrary but reasonable number
do {
if( PowerStateIsAC ) {
PPT_SET_RELATIVE_TIMEOUT_IN_MILLISECONDS( timeOut1, (WarmPollPeriod * 1000) );
} else {
// running on batteries - use a longer (4x) timeout
PPT_SET_RELATIVE_TIMEOUT_IN_MILLISECONDS( timeOut1, (WarmPollPeriod * 1000 * 4) );
}
status = KeWaitForSingleObject(&Fdx->FdoThreadEvent, Executive, KernelMode, FALSE, &timeOut1);
if( Fdx->TimeToTerminateThread ) {
//
// another thread (PnP REMOVE handler) has requested that we die and is likely waiting on us to do so
//
DD((PCE)Fdx,DDT,"P5FdoThread - killing self\n");
PsTerminateSystemThread( STATUS_SUCCESS );
}
if( !PowerStateIsAC ) {
// Still on Batteries - don't "poll for printers" - just go back to sleep
continue;
}
if( STATUS_TIMEOUT == status ) {
if( NULL == Fdx->EndOfChainPdo ) {
// try to acquire port
if( PptTryAllocatePort( Fdx ) ) {
DD((PCE)Fdx,DDT,"P5FdoThread - port acquired\n");
requestRescan = FALSE;
// check for something connected
deviceStatus = GetStatus(Fdx->PortInfo.Controller);
if( PAR_POWERED_OFF(deviceStatus) ||
PAR_NOT_CONNECTED(deviceStatus) ||
PAR_NO_CABLE(deviceStatus) ) {
// doesn't appear to be anything connected - do nothing
DD((PCE)Fdx,DDT,"P5FdoThread - nothing connected? - deviceStatus = %02x\n",deviceStatus);
} else {
// we might have something connected
// try a device ID to confirm
DD((PCE)Fdx,DDT,"P5FdoThread - might be something connected - deviceStatus = %02x\n",deviceStatus);
devId = P4ReadRawIeee1284DeviceId( Fdx->PortInfo.Controller );
if( devId ) {
PCHAR mfg, mdl, cls, des, aid, cid;
// RawIeee1284 string includes 2 bytes of length data at beginning
DD((PCE)Fdx,DDT,"P5FdoThread - EndOfChain device detected <%s>\n",(devId+2));
ParPnpFindDeviceIdKeys( &mfg, &mdl, &cls, &des, &aid, &cid, devId+2 );
if( mfg && mdl ) {
DD((PCE)Fdx,DDT,"P5FdoThread - found mfg - <%s>\n",mfg);
DD((PCE)Fdx,DDT,"P5FdoThread - found mdl - <%s>\n",mdl);
requestRescan = TRUE;
}
ExFreePool( devId );
} else {
DD((PCE)Fdx,DDT,"P5FdoThread - no EndOfChain device detected - NULL devId\n");
}
if( requestRescan ) {
// we appear to have retrieved a valid 1284 ID, reset failure counter
Fdx->PollingFailureCounter = 0;
} else {
// Our heuristics tell us that there is something
// connected to the port but we are unable to retrieve
// a valid IEEE 1284 Device ID
if( ++(Fdx->PollingFailureCounter) > pollingFailureThreshold ) {
// too many consecutive failures - we're burning CPU for no good reason, give up and die
Fdx->TimeToTerminateThread = TRUE;
// don't delay before killing self
KeSetEvent( &Fdx->FdoThreadEvent, 0, FALSE );
}
}
}
DD((PCE)Fdx,DDT,"P5FdoThread - freeing port\n");
PptFreePort( Fdx );
if( requestRescan ) {
DD((PCE)Fdx,DDT,"P5FdoThread - requesting Rescan\n");
IoInvalidateDeviceRelations( Fdx->PhysicalDeviceObject, BusRelations );
}
} else {
DD((PCE)Fdx,DDT,"P5FdoThread - unable to acquire port\n");
}
} else {
DD((PCE)Fdx,DDT,"P5FdoThread - already have EndOfChain device\n");
}
}
} while( TRUE );
}
NTSTATUS
P5FdoCreateThread(
PFDO_EXTENSION Fdx
)
{
NTSTATUS status;
HANDLE handle;
OBJECT_ATTRIBUTES objAttrib;
DD((PCE)Fdx,DDT,"P5CreateFdoWorkerThread - %s - enter\n",Fdx->Location);
// Start the thread - save referenced pointer to thread in our extension
InitializeObjectAttributes( &objAttrib, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
status = PsCreateSystemThread( &handle, THREAD_ALL_ACCESS, &objAttrib, NULL, NULL, P5FdoThread, Fdx );
if( STATUS_SUCCESS == status ) {
// We've got the thread. Now get a pointer to it.
status = ObReferenceObjectByHandle( handle, THREAD_ALL_ACCESS, NULL, KernelMode, &Fdx->ThreadObjectPointer, NULL );
if( STATUS_SUCCESS == status ) {
// Now that we have a reference to the thread we can simply close the handle.
ZwClose(handle);
} else {
Fdx->TimeToTerminateThread = TRUE;
}
DD((PCE)Fdx,DDT,"ParCreateSystemThread - %s - SUCCESS\n",Fdx->Location);
} else {
DD((PCE)Fdx,DDT,"ParCreateSystemThread - %s FAIL - status = %x\n",Fdx->Location, status);
}
return status;
}