191 lines
6.4 KiB
C
191 lines
6.4 KiB
C
|
#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;
|
|||
|
}
|