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;
|
||
}
|