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

  1. #include "pch.h"
  2. // experimental vars - to tweek debugging for this thread
  3. ULONG x1; // set nonzero to disable port acquisition
  4. ULONG x2; // set nonzero to try to select LPT1.0 and negotiate/terminate ECP_HW_NOIRQ
  5. ULONG x3; // set nonzero to try to negotiate the periph to ECP and then terminate
  6. ULONG x4;
  7. ULONG t1; // timeout between thread polls (in ms)
  8. ULONG t2; // time to sit on port before releasing it (in ms)
  9. VOID
  10. P5FdoThread(
  11. IN PFDO_EXTENSION Fdx
  12. )
  13. {
  14. LARGE_INTEGER timeOut1;
  15. NTSTATUS status;
  16. UCHAR deviceStatus;
  17. PCHAR devId;
  18. BOOLEAN requestRescan;
  19. const ULONG pollingFailureThreshold = 10; // pick an arbitrary but reasonable number
  20. do {
  21. if( PowerStateIsAC ) {
  22. PPT_SET_RELATIVE_TIMEOUT_IN_MILLISECONDS( timeOut1, (WarmPollPeriod * 1000) );
  23. } else {
  24. // running on batteries - use a longer (4x) timeout
  25. PPT_SET_RELATIVE_TIMEOUT_IN_MILLISECONDS( timeOut1, (WarmPollPeriod * 1000 * 4) );
  26. }
  27. status = KeWaitForSingleObject(&Fdx->FdoThreadEvent, Executive, KernelMode, FALSE, &timeOut1);
  28. if( Fdx->TimeToTerminateThread ) {
  29. //
  30. // another thread (PnP REMOVE handler) has requested that we die and is likely waiting on us to do so
  31. //
  32. DD((PCE)Fdx,DDT,"P5FdoThread - killing self\n");
  33. PsTerminateSystemThread( STATUS_SUCCESS );
  34. }
  35. if( !PowerStateIsAC ) {
  36. // Still on Batteries - don't "poll for printers" - just go back to sleep
  37. continue;
  38. }
  39. if( STATUS_TIMEOUT == status ) {
  40. if( NULL == Fdx->EndOfChainPdo ) {
  41. // try to acquire port
  42. if( PptTryAllocatePort( Fdx ) ) {
  43. DD((PCE)Fdx,DDT,"P5FdoThread - port acquired\n");
  44. requestRescan = FALSE;
  45. // check for something connected
  46. deviceStatus = GetStatus(Fdx->PortInfo.Controller);
  47. if( PAR_POWERED_OFF(deviceStatus) ||
  48. PAR_NOT_CONNECTED(deviceStatus) ||
  49. PAR_NO_CABLE(deviceStatus) ) {
  50. // doesn't appear to be anything connected - do nothing
  51. DD((PCE)Fdx,DDT,"P5FdoThread - nothing connected? - deviceStatus = %02x\n",deviceStatus);
  52. } else {
  53. // we might have something connected
  54. // try a device ID to confirm
  55. DD((PCE)Fdx,DDT,"P5FdoThread - might be something connected - deviceStatus = %02x\n",deviceStatus);
  56. devId = P4ReadRawIeee1284DeviceId( Fdx->PortInfo.Controller );
  57. if( devId ) {
  58. PCHAR mfg, mdl, cls, des, aid, cid;
  59. // RawIeee1284 string includes 2 bytes of length data at beginning
  60. DD((PCE)Fdx,DDT,"P5FdoThread - EndOfChain device detected <%s>\n",(devId+2));
  61. ParPnpFindDeviceIdKeys( &mfg, &mdl, &cls, &des, &aid, &cid, devId+2 );
  62. if( mfg && mdl ) {
  63. DD((PCE)Fdx,DDT,"P5FdoThread - found mfg - <%s>\n",mfg);
  64. DD((PCE)Fdx,DDT,"P5FdoThread - found mdl - <%s>\n",mdl);
  65. requestRescan = TRUE;
  66. }
  67. ExFreePool( devId );
  68. } else {
  69. DD((PCE)Fdx,DDT,"P5FdoThread - no EndOfChain device detected - NULL devId\n");
  70. }
  71. if( requestRescan ) {
  72. // we appear to have retrieved a valid 1284 ID, reset failure counter
  73. Fdx->PollingFailureCounter = 0;
  74. } else {
  75. // Our heuristics tell us that there is something
  76. // connected to the port but we are unable to retrieve
  77. // a valid IEEE 1284 Device ID
  78. if( ++(Fdx->PollingFailureCounter) > pollingFailureThreshold ) {
  79. // too many consecutive failures - we're burning CPU for no good reason, give up and die
  80. Fdx->TimeToTerminateThread = TRUE;
  81. // don't delay before killing self
  82. KeSetEvent( &Fdx->FdoThreadEvent, 0, FALSE );
  83. }
  84. }
  85. }
  86. DD((PCE)Fdx,DDT,"P5FdoThread - freeing port\n");
  87. PptFreePort( Fdx );
  88. if( requestRescan ) {
  89. DD((PCE)Fdx,DDT,"P5FdoThread - requesting Rescan\n");
  90. IoInvalidateDeviceRelations( Fdx->PhysicalDeviceObject, BusRelations );
  91. }
  92. } else {
  93. DD((PCE)Fdx,DDT,"P5FdoThread - unable to acquire port\n");
  94. }
  95. } else {
  96. DD((PCE)Fdx,DDT,"P5FdoThread - already have EndOfChain device\n");
  97. }
  98. }
  99. } while( TRUE );
  100. }
  101. NTSTATUS
  102. P5FdoCreateThread(
  103. PFDO_EXTENSION Fdx
  104. )
  105. {
  106. NTSTATUS status;
  107. HANDLE handle;
  108. OBJECT_ATTRIBUTES objAttrib;
  109. DD((PCE)Fdx,DDT,"P5CreateFdoWorkerThread - %s - enter\n",Fdx->Location);
  110. // Start the thread - save referenced pointer to thread in our extension
  111. InitializeObjectAttributes( &objAttrib, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
  112. status = PsCreateSystemThread( &handle, THREAD_ALL_ACCESS, &objAttrib, NULL, NULL, P5FdoThread, Fdx );
  113. if( STATUS_SUCCESS == status ) {
  114. // We've got the thread. Now get a pointer to it.
  115. status = ObReferenceObjectByHandle( handle, THREAD_ALL_ACCESS, NULL, KernelMode, &Fdx->ThreadObjectPointer, NULL );
  116. if( STATUS_SUCCESS == status ) {
  117. // Now that we have a reference to the thread we can simply close the handle.
  118. ZwClose(handle);
  119. } else {
  120. Fdx->TimeToTerminateThread = TRUE;
  121. }
  122. DD((PCE)Fdx,DDT,"ParCreateSystemThread - %s - SUCCESS\n",Fdx->Location);
  123. } else {
  124. DD((PCE)Fdx,DDT,"ParCreateSystemThread - %s FAIL - status = %x\n",Fdx->Location, status);
  125. }
  126. return status;
  127. }