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.

1053 lines
31 KiB

  1. #include "pch.h"
  2. VOID
  3. PptDellNationalPC87364WorkAround( PUCHAR EcpController )
  4. {
  5. PUCHAR ecr = EcpController+2; // generic chipset Extended Control Register
  6. PUCHAR eir = EcpController+3; // PC87364 chipset Extended Index Register
  7. PUCHAR edr = EcpController+4; // PC87364 chipset Extended Data Register
  8. ULONG delay = 5; // in microseconds (arbitrary - this seems to work)
  9. KIRQL oldIrql;
  10. //
  11. // Raise IRQL to prevent BIOS from touching the registers at the
  12. // same time that we're updating them. This is a complete hack
  13. // since according to PnP we own the registers, but do it anyway
  14. // since we know that BIOS touches these same registers.
  15. //
  16. KeRaiseIrql( HIGH_LEVEL, &oldIrql );
  17. KeStallExecutionProcessor( delay );
  18. P5WritePortUchar( ecr, 0x15 );
  19. KeStallExecutionProcessor( delay );
  20. P5WritePortUchar( eir, 0x02 );
  21. KeStallExecutionProcessor( delay );
  22. P5WritePortUchar( edr, 0x90 );
  23. KeStallExecutionProcessor( delay );
  24. KeLowerIrql( oldIrql );
  25. }
  26. NTSTATUS
  27. PptFdoStartDevice(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp
  30. )
  31. /*++dvdf8
  32. Routine Description:
  33. This function handles PnP IRP_MN_START IRPs.
  34. - Wait for the bus driver and any drivers beneath
  35. us in the driver stack to handle this first.
  36. - Get, validate, and save the resources given to us by PnP.
  37. - Assign IDs to and get a count of 1284.3 daisy chain devices
  38. connected to the port.
  39. - Determine the capabilities of the chipset (BYTE, EPP, ECP).
  40. - Set our PnP device interface state to trigger
  41. an interface arrival callback to anyone listening
  42. on our GUID.
  43. Arguments:
  44. DeviceObject - The target device for the IRP
  45. Irp - The IRP
  46. Return Value:
  47. STATUS_SUCCESS - on success,
  48. an appropriate error status - otherwise
  49. --*/
  50. {
  51. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  52. NTSTATUS status;
  53. BOOLEAN foundPort = FALSE;
  54. BOOLEAN foundIrq = FALSE;
  55. BOOLEAN foundDma = FALSE;
  56. //
  57. // This IRP must be handled first by the parent bus driver
  58. // and then by each higher driver in the device stack.
  59. //
  60. status = PptPnpBounceAndCatchPnpIrp(fdx, Irp);
  61. if( !NT_SUCCESS( status ) && ( status != STATUS_NOT_SUPPORTED ) ) {
  62. // Someone below us in the driver stack explicitly failed the START.
  63. goto targetExit;
  64. }
  65. //
  66. // Extract resources from CM_RESOURCE_LIST and save them in our extension.
  67. //
  68. status = PptPnpStartScanCmResourceList(fdx, Irp, &foundPort, &foundIrq, &foundDma);
  69. if( !NT_SUCCESS( status ) ) {
  70. goto targetExit;
  71. }
  72. //
  73. // Do our resources appear to be valid?
  74. //
  75. status = PptPnpStartValidateResources(DeviceObject, foundPort, foundIrq, foundDma);
  76. if( !NT_SUCCESS( status ) ) {
  77. goto targetExit;
  78. }
  79. //
  80. // Check if ACPI set a flag for us based on entries in
  81. // BIOSINFO.INF to indicate that we are running on a Dell machine
  82. // with an incorrectly programmed National PC87364 SuperIO
  83. // chipset. If so try to work around the problem here so that the
  84. // user doesn't need to flash the BIOS to get the parallel port to
  85. // work.
  86. //
  87. // Symptoms of the problem are that the parallel port Data Lines
  88. // are wedged to all zeros regardless of the setting of the bits
  89. // in the parallel port data register or the Direction bit in the
  90. // control register.
  91. //
  92. // If the port base address is 0x3BC then this won't work and the
  93. // user will need to go to Device Manager and change the LPT port
  94. // resource settings to either 0x378 or 0x278 for the base
  95. // register address. We believe that ACPI defaults to a port base
  96. // address of 0x378 so this workaround should generally work.
  97. //
  98. {
  99. ULONG DellNationalPC87364 = 0;
  100. //
  101. // Check registry to see if ACPI set the flag based on
  102. // BIOSINFO.INF to indicate that we should try the workaround.
  103. //
  104. PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"DellNationalPC87364", &DellNationalPC87364 );
  105. if( DellNationalPC87364 ) {
  106. //
  107. // we have a Dell machine with a National PC87364 chipset
  108. // and a version of BIOS that we believe doesn't
  109. // initialize the parallel port so that it works under
  110. // Win2k or WinXP.
  111. //
  112. if( fdx->PnpInfo.SpanOfEcpController > 4 ) {
  113. //
  114. // We have the extra Ecp registers needed to try the
  115. // workaround without stepping on I/O register space
  116. // owned by someone else.
  117. //
  118. if( ( (PUCHAR)0x678 == fdx->PnpInfo.EcpController ) ||
  119. ( (PUCHAR)0x778 == fdx->PnpInfo.EcpController ) ) {
  120. //
  121. // The parallel port base register and ECP
  122. // registers are located at one of the two
  123. // traditional address ranges: ECP at 0x400 offset
  124. // from base register address of 0x278 or 0x378,
  125. // so let's try the workaround to try to unwedge
  126. // the port data lines.
  127. //
  128. PptDellNationalPC87364WorkAround( fdx->PnpInfo.EcpController );
  129. }
  130. }
  131. }
  132. } // end new block scope for Dell/National chipset workaround
  133. //
  134. // Initialize the IEEE 1284.3 "bus" by assigning IDs [0..3] to
  135. // the 1284.3 daisy chain devices connected to the port. This
  136. // function also gives us a count of the number of such
  137. // devices connected to the port.
  138. //
  139. fdx->PnpInfo.Ieee1284_3DeviceCount = PptInitiate1284_3( fdx );
  140. //
  141. // Determine the hardware modes supported (BYTE, ECP, EPP) by
  142. // the parallel port chipset and save this information in our extension.
  143. //
  144. // Check to see if the filter parchip is there and use the modes it can set
  145. status = PptDetectChipFilter( fdx );
  146. // if filter driver was not found use our own generic port detection
  147. if ( !NT_SUCCESS( status ) ) {
  148. PptDetectPortType( fdx );
  149. }
  150. //
  151. // Register w/WMI
  152. //
  153. status = PptWmiInitWmi( DeviceObject );
  154. if( !NT_SUCCESS( status ) ) {
  155. goto targetExit;
  156. }
  157. //
  158. // Signal those who registered for PnP interface change notification
  159. // on our GUID that we have STARTED (trigger an INTERFACE_ARRIVAL
  160. // PnP callback).
  161. //
  162. status = IoSetDeviceInterfaceState( &fdx->DeviceInterface, TRUE );
  163. if( !NT_SUCCESS(status) ) {
  164. status = STATUS_NOT_SUPPORTED;
  165. } else {
  166. fdx->DeviceInterfaceState = TRUE;
  167. }
  168. targetExit:
  169. if( NT_SUCCESS( status ) ) {
  170. //
  171. // Note in our extension that we have successfully STARTED.
  172. //
  173. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  174. PptSetFlags( fdx->PnpState, PPT_DEVICE_STARTED );
  175. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  176. // create warm poll thread to poll for printer arrivals
  177. if( NULL == fdx->ThreadObjectPointer ) {
  178. ULONG DisableWarmPoll;
  179. fdx->PollingFailureCounter = 0; // reset counter
  180. // check for registry flag to disable "polling for printers"
  181. DisableWarmPoll = 0; // if non-zero then do not poll for printer arrivals
  182. PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"DisableWarmPoll", &DisableWarmPoll );
  183. if( 0 == DisableWarmPoll ) {
  184. // how frequently should we check for printer arrivals? (in seconds)
  185. // (WarmPollPeriod is a driver global)
  186. PptRegGetDword( RTL_REGISTRY_SERVICES, L"Parport\\Parameters", L"WarmPollPeriod", &WarmPollPeriod );
  187. if( WarmPollPeriod < 5 ) {
  188. WarmPollPeriod = 5;
  189. } else {
  190. if( WarmPollPeriod > 20 ) {
  191. WarmPollPeriod = 20;
  192. }
  193. }
  194. DD((PCE)fdx,DDT,"P5FdoThread - WarmPollPeriod = %d seconds\n",WarmPollPeriod);
  195. // side effect: set fdx->ThreadObjectPointer on SUCCESS
  196. P5FdoCreateThread( fdx );
  197. }
  198. }
  199. }
  200. P4CompleteRequest( Irp, status, 0 );
  201. PptReleaseRemoveLock( &fdx->RemoveLock, Irp );
  202. return status;
  203. }
  204. NTSTATUS
  205. PptFdoQueryRemove(
  206. IN PDEVICE_OBJECT DeviceObject,
  207. IN PIRP Irp
  208. )
  209. /*++dvdf8
  210. Routine Description:
  211. This function handles PnP IRP_MN_QUERY_REMOVE_DEVICE.
  212. FAIL the request if there are open handles, SUCCEED otherwise.
  213. This function is identical to PptPnpQueryStopDevice() except
  214. for the flag that gets set in fdx->PnpState.
  215. Arguments:
  216. DeviceObject - The target device for the IRP
  217. Irp - The IRP
  218. Return Value:
  219. STATUS_SUCCESS - No open handles - SUCCEED IRP
  220. STATUS_DEVICE_BUSY - Open handles - FAIL IRP
  221. --*/
  222. {
  223. //
  224. // Always succeed query - PnP will veto Query Remove on our behalf if
  225. // there are open handles
  226. //
  227. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  228. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  229. PptSetFlags( fdx->PnpState, ( PPT_DEVICE_REMOVE_PENDING | PPT_DEVICE_PAUSED ) );
  230. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  231. Irp->IoStatus.Status = STATUS_SUCCESS;
  232. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
  233. }
  234. NTSTATUS
  235. PptFdoRemoveDevice(
  236. IN PDEVICE_OBJECT Fdo,
  237. IN PIRP Irp
  238. )
  239. /*++dvdf8
  240. Routine Description:
  241. This function handles PnP IRP_MN_REMOVE_DEVICE.
  242. Notify those listening on our device interface GUID that
  243. we have gone away, wait until all other IRPs that the
  244. device is processing have drained, and clean up.
  245. Arguments:
  246. Fdo - The target device for the IRP
  247. Irp - The IRP
  248. Return Value:
  249. Status returned from IoCallDriver.
  250. --*/
  251. {
  252. PFDO_EXTENSION fdx = Fdo->DeviceExtension;
  253. NTSTATUS status;
  254. //
  255. // clean up any child PDOs that are still here
  256. //
  257. if( fdx->RawPortPdo ) {
  258. PDEVICE_OBJECT pdo = fdx->RawPortPdo;
  259. DD((PCE)fdx,DDT,"PptFdoRemoveDevice - have RawPortPdo - cleaning up\n");
  260. P4DestroyPdo( pdo );
  261. fdx->RawPortPdo = NULL;
  262. }
  263. if( fdx->EndOfChainPdo ) {
  264. PDEVICE_OBJECT pdo = fdx->EndOfChainPdo;
  265. DD((PCE)fdx,DDT,"PptFdoRemoveDevice - have EndOfChainPdo - cleaning up\n");
  266. P4DestroyPdo( pdo );
  267. fdx->EndOfChainPdo = NULL;
  268. }
  269. {
  270. LONG daisyChainId;
  271. const LONG daisyChainMaxId = 1;
  272. for( daisyChainId = 0 ; daisyChainId <= daisyChainMaxId ; ++daisyChainId ) {
  273. if( fdx->DaisyChainPdo[ daisyChainId ] ) {
  274. PDEVICE_OBJECT pdo = fdx->DaisyChainPdo[ daisyChainId ];
  275. DD((PCE)fdx,DDT,"PptFdoRemoveDevice - have DaisyChainPdo[%d] - cleaning up\n",daisyChainId);
  276. P4DestroyPdo( pdo );
  277. fdx->DaisyChainPdo[ daisyChainId ] = NULL;
  278. }
  279. }
  280. }
  281. //
  282. // RMT - if fdx->DevDeletionListHead non-empty - clean it up?
  283. //
  284. PptAssert( IsListEmpty( &fdx->DevDeletionListHead) );
  285. //
  286. // Set flags in our extension to indicate that we have received
  287. // IRP_MN_REMOVE_DEVICE so that we can fail new requests as appropriate.
  288. //
  289. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  290. PptSetFlags( fdx->PnpState, PPT_DEVICE_REMOVED );
  291. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  292. //
  293. // if we still have a worker thread, kill it
  294. //
  295. {
  296. PVOID threadObjPointer = InterlockedExchangePointer( &fdx->ThreadObjectPointer, NULL );
  297. if( threadObjPointer ) {
  298. // set the flag for the worker thread to kill itself
  299. fdx->TimeToTerminateThread = TRUE;
  300. // wake thread so it can kill self
  301. KeSetEvent( &fdx->FdoThreadEvent, 0, TRUE );
  302. // wait for the thread to die
  303. KeWaitForSingleObject( threadObjPointer, Executive, KernelMode, FALSE, NULL );
  304. // allow the system to release the thread object
  305. ObDereferenceObject( threadObjPointer );
  306. }
  307. }
  308. //
  309. // Unregister w/WMI
  310. //
  311. IoWMIRegistrationControl(Fdo, WMIREG_ACTION_DEREGISTER);
  312. //
  313. // Tell those listening on our device interface GUID that we have
  314. // gone away. Ignore status from the call since we can do
  315. // nothing on failure.
  316. //
  317. IoSetDeviceInterfaceState( &fdx->DeviceInterface, FALSE );
  318. fdx->DeviceInterfaceState = FALSE;
  319. //
  320. // Pass the IRP down the stack and wait for all other IRPs
  321. // that are being processed by the device to drain.
  322. //
  323. Irp->IoStatus.Status = STATUS_SUCCESS;
  324. IoSkipCurrentIrpStackLocation( Irp );
  325. status = IoCallDriver( fdx->ParentDeviceObject, Irp );
  326. PptReleaseRemoveLockAndWait( &fdx->RemoveLock, Irp );
  327. //
  328. // Clean up pool allocations
  329. //
  330. RtlFreeUnicodeString( &fdx->DeviceName);
  331. RtlFreeUnicodeString( &fdx->DeviceInterface );
  332. if( fdx->PnpInfo.PortName ) {
  333. ExFreePool( fdx->PnpInfo.PortName );
  334. fdx->PnpInfo.PortName = NULL;
  335. }
  336. if( fdx->Location ) {
  337. ExFreePool( fdx->Location );
  338. fdx->Location = NULL;
  339. }
  340. //
  341. // Detach and delete our device object.
  342. //
  343. IoDetachDevice( fdx->ParentDeviceObject );
  344. IoDeleteDevice( Fdo );
  345. return status;
  346. }
  347. NTSTATUS
  348. PptFdoCancelRemove(
  349. IN PDEVICE_OBJECT DeviceObject,
  350. IN PIRP Irp
  351. )
  352. /*++dvdf8
  353. Routine Description:
  354. This function handles PnP IRP_MN_CANCEL_REMOVE_DEVICE.
  355. If we previously SUCCEEDed a QUERY_REMOVE (PPT_DEVICE_REMOVE_PENDING
  356. flag is set) then we reset the appropriate device state flags
  357. and resume normal operation. Otherwise treat this as an
  358. informational message.
  359. This function is identical to PptPnpCancelStopDevice() except for
  360. the fdx->PnpState.
  361. Arguments:
  362. DeviceObject - The target device for the IRP
  363. Irp - The IRP
  364. Return Value:
  365. Status returned from IoCallDriver.
  366. --*/
  367. {
  368. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  369. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  370. if( fdx->PnpState & PPT_DEVICE_REMOVE_PENDING ) {
  371. PptClearFlags( fdx->PnpState, ( PPT_DEVICE_REMOVE_PENDING | PPT_DEVICE_PAUSED ) );
  372. }
  373. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  374. Irp->IoStatus.Status = STATUS_SUCCESS;
  375. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
  376. }
  377. NTSTATUS
  378. PptFdoStopDevice(
  379. IN PDEVICE_OBJECT DeviceObject,
  380. IN PIRP Irp
  381. )
  382. /*++dvdf8
  383. Routine Description:
  384. This function handles PnP IRP_MN_STOP_DEVICE.
  385. We previously SUCCEEDed QUERY_STOP. Set flags
  386. to indicate that we are now STOPPED.
  387. Arguments:
  388. DeviceObject - The target device for the IRP
  389. Irp - The IRP
  390. Return Value:
  391. Status returned from IoCallDriver.
  392. --*/
  393. {
  394. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  395. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  396. //
  397. // Assert that we are in a STOP_PENDING state.
  398. //
  399. ASSERT( fdx->PnpState & PPT_DEVICE_STOP_PENDING );
  400. ASSERT( fdx->PnpState & PPT_DEVICE_PAUSED );
  401. //
  402. // PPT_DEVICE_PAUSED remains set
  403. //
  404. PptSetFlags( fdx->PnpState, PPT_DEVICE_STOPPED );
  405. PptClearFlags( fdx->PnpState, ( PPT_DEVICE_STOP_PENDING | PPT_DEVICE_STARTED ) );
  406. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  407. Irp->IoStatus.Status = STATUS_SUCCESS;
  408. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock(fdx, Irp);
  409. }
  410. NTSTATUS
  411. PptFdoQueryStop(
  412. IN PDEVICE_OBJECT DeviceObject,
  413. IN PIRP Irp
  414. )
  415. /*++dvdf8
  416. Routine Description:
  417. This function handles PnP IRP_MN_QUERY_STOP_DEVICE.
  418. FAIL the request if there are open handles, SUCCEED otherwise.
  419. Other drivers may cache pointers to the parallel port registers that
  420. they obtained via IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO and there
  421. is currently no mechanism to find and inform all such drivers that the
  422. parallel port registers have changed and their their cached pointers are
  423. now invalid without breaking legacy drivers.
  424. This function is identical to PptPnpQueryStopDevice() except
  425. for the flag that gets set in fdx->PnpState.
  426. Arguments:
  427. DeviceObject - The target device for the IRP
  428. Irp - The IRP
  429. Return Value:
  430. STATUS_SUCCESS - No open handles - SUCCEED IRP
  431. STATUS_DEVICE_BUSY - Open handles - FAIL IRP
  432. --*/
  433. {
  434. NTSTATUS status = STATUS_SUCCESS;
  435. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  436. BOOLEAN handlesOpen;
  437. //
  438. // RMT - dvdf - race condition - small timing window - sequence:
  439. // 1. Test indicates no open handles - decide to SUCCEED QUERY_STOP
  440. // 2. CREATE arrives and is SUCCEEDED - open handle
  441. // 3. We SUCCEED QUERY_STOP
  442. // 4. Client obtains register addresses via IOCTL
  443. // 5. PnP Rebalances us - registers change
  444. // 6. Client acquires port via IOCTL
  445. // 7. Client tries to access registers at pre-rebalance location
  446. // 8. BOOM!!!
  447. //
  448. ExAcquireFastMutex( &fdx->OpenCloseMutex );
  449. handlesOpen = (BOOLEAN)( fdx->OpenCloseRefCount > 0 );
  450. ExReleaseFastMutex( &fdx->OpenCloseMutex );
  451. if( handlesOpen ) {
  452. status = STATUS_DEVICE_BUSY;
  453. P4CompleteRequest( Irp, status, Irp->IoStatus.Information );
  454. PptReleaseRemoveLock( &fdx->RemoveLock, Irp );
  455. } else {
  456. Irp->IoStatus.Status = STATUS_SUCCESS;
  457. status = PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
  458. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  459. PptSetFlags( fdx->PnpState, ( PPT_DEVICE_STOP_PENDING | PPT_DEVICE_PAUSED ) );
  460. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  461. }
  462. return status;
  463. }
  464. NTSTATUS
  465. PptFdoCancelStop(
  466. IN PDEVICE_OBJECT DeviceObject,
  467. IN PIRP Irp
  468. )
  469. /*++dvdf8
  470. Routine Description:
  471. This function handles PnP IRP_MN_CANCEL_STOP_DEVICE.
  472. If we previously SUCCEEDed a QUERY_STOP (PPT_DEVICE_STOP_PENDING
  473. flag is set) then we reset the appropriate device state flags
  474. and resume normal operation. Otherwise treat this as an
  475. informational message.
  476. This function is identical to PptPnpCancelRemoveDevice() except for
  477. the fdx->PnpState.
  478. Arguments:
  479. DeviceObject - The target device for the IRP
  480. Irp - The IRP
  481. Return Value:
  482. Status returned from IoCallDriver.
  483. --*/
  484. {
  485. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  486. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  487. if( fdx->PnpState & PPT_DEVICE_STOP_PENDING ) {
  488. PptClearFlags( fdx->PnpState, ( PPT_DEVICE_STOP_PENDING | PPT_DEVICE_PAUSED ) );
  489. }
  490. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  491. Irp->IoStatus.Status = STATUS_SUCCESS;
  492. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
  493. }
  494. NTSTATUS
  495. PptFdoQueryDeviceRelations(
  496. IN PDEVICE_OBJECT DeviceObject,
  497. IN PIRP Irp
  498. )
  499. /*++
  500. Routine Description:
  501. This function handles PnP IRP_MN_QUERY_DEVICE_RELATIONS.
  502. Arguments:
  503. DeviceObject - The target device for the IRP
  504. Irp - The IRP
  505. Return Value:
  506. STATUS_SUCCESS - on success,
  507. an appropriate error status - otherwise
  508. --*/
  509. {
  510. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  511. DEVICE_RELATION_TYPE type = irpSp->Parameters.QueryDeviceRelations.Type;
  512. if( BusRelations == type ) {
  513. return PptFdoHandleBusRelations( DeviceObject, Irp );
  514. } else {
  515. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock(DeviceObject->DeviceExtension, Irp);
  516. }
  517. }
  518. NTSTATUS
  519. PptFdoFilterResourceRequirements(
  520. IN PDEVICE_OBJECT DeviceObject,
  521. IN PIRP Irp
  522. )
  523. /*++dvdf8
  524. Routine Description:
  525. This function handles PnP IRP_MN_FILTER_RESOURCE_REQUIREMENTS IRPs.
  526. - Wait for the bus driver and any drivers beneath
  527. us in the driver stack to handle this first.
  528. - Query the registry to find the type of filtering desired.
  529. - Filter out IRQ resources as specified by the registry setting.
  530. Arguments:
  531. DeviceObject - The target device for the IRP
  532. Irp - The IRP
  533. Return Value:
  534. STATUS_SUCCESS - on success,
  535. an appropriate error status - otherwise
  536. --*/
  537. {
  538. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  539. ULONG filterResourceMethod = PPT_FORCE_USE_NO_IRQ;
  540. PIO_RESOURCE_REQUIREMENTS_LIST pResourceRequirementsIn;
  541. NTSTATUS status;
  542. //
  543. // DDK Rule: Add on the way down, modify on the way up. We are modifying
  544. // the resource list so let the drivers beneath us handle this IRP first.
  545. //
  546. status = PptPnpBounceAndCatchPnpIrp(fdx, Irp);
  547. if( !NT_SUCCESS(status) && (status != STATUS_NOT_SUPPORTED) ) {
  548. // Someone below us in the driver stack explicitly failed the IRP.
  549. goto targetExit;
  550. }
  551. //
  552. // Find the "real" resource requirments list, either the PnP list
  553. // or the list created by another driver in the stack.
  554. //
  555. if ( Irp->IoStatus.Information == 0 ) {
  556. //
  557. // No one else has created a new resource list. Use the original
  558. // list from the PnP Manager.
  559. //
  560. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation( Irp );
  561. pResourceRequirementsIn = IrpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
  562. if (pResourceRequirementsIn == NULL) {
  563. //
  564. // NULL list, nothing to do.
  565. //
  566. goto targetExit;
  567. }
  568. } else {
  569. //
  570. // Another driver has created a new resource list. Use the list that they created.
  571. //
  572. pResourceRequirementsIn = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
  573. }
  574. //
  575. // Check the registry to find out the desired type of resource filtering.
  576. //
  577. // The following call sets the default value for filterResourceMethod
  578. // if the registry query fails.
  579. //
  580. PptRegGetDeviceParameterDword( fdx->PhysicalDeviceObject,
  581. (PWSTR)L"FilterResourceMethod",
  582. &filterResourceMethod );
  583. DD((PCE)fdx,DDT,"filterResourceMethod=%x\n",filterResourceMethod);
  584. //
  585. // Do filtering based on registry setting.
  586. //
  587. switch( filterResourceMethod ) {
  588. case PPT_FORCE_USE_NO_IRQ:
  589. //
  590. // Registry setting dictates that we should refuse to accept IRQ resources.
  591. //
  592. // * This is the default behavior which means that we make the IRQ available
  593. // for legacy net and sound cards that may not work if they cannot get
  594. // the IRQ.
  595. //
  596. // - If we find a resource alternative that does not contain an IRQ resource
  597. // then we remove those resource alternatives that do contain IRQ
  598. // resources from the list of alternatives.
  599. //
  600. // - Otherwise we have to play hardball. Since all resource alternatives
  601. // contain IRQ resources we simply "nuke" the IRQ resource descriptors
  602. // by changing their resource Type from CmResourceTypeInterrupt to
  603. // CmResourceTypeNull.
  604. //
  605. DD((PCE)fdx,DDT,"PPT_FORCE_USE_NO_IRQ\n");
  606. if( PptPnpFilterExistsNonIrqResourceList( pResourceRequirementsIn ) ) {
  607. DD((PCE)fdx,DDT,"Found Resource List with No IRQ - Filtering\n");
  608. PptPnpFilterRemoveIrqResourceLists( pResourceRequirementsIn );
  609. } else {
  610. DD((PCE)fdx,DDT,"Did not find Resource List with No IRQ - Nuking IRQ resource descriptors\n");
  611. PptPnpFilterNukeIrqResourceDescriptorsFromAllLists( pResourceRequirementsIn );
  612. }
  613. break;
  614. case PPT_TRY_USE_NO_IRQ:
  615. //
  616. // Registry setting dictates that we should TRY to give up IRQ resources.
  617. //
  618. // - If we find a resource alternative that does not contain an IRQ resource
  619. // then we remove those resource alternatives that do contain IRQ
  620. // resources from the list of alternatives.
  621. //
  622. // - Otherwise we do nothing.
  623. //
  624. DD((PCE)fdx,DDT,"PPT_TRY_USE_NO_IRQ\n");
  625. if( PptPnpFilterExistsNonIrqResourceList(pResourceRequirementsIn) ) {
  626. DD((PCE)fdx,DDT,"Found Resource List with No IRQ - Filtering\n");
  627. PptPnpFilterRemoveIrqResourceLists(pResourceRequirementsIn);
  628. } else {
  629. // leave the IO resource list as is
  630. DD((PCE)fdx,DDT,"Did not find Resource List with No IRQ - Do nothing\n");
  631. }
  632. break;
  633. case PPT_ACCEPT_IRQ:
  634. //
  635. // Registry setting dictates that we should NOT filter out IRQ resources.
  636. //
  637. // - Do nothing.
  638. //
  639. DD((PCE)fdx,DDT,"PPT_ACCEPT_IRQ\n");
  640. break;
  641. default:
  642. //
  643. // Invalid registry setting.
  644. //
  645. // - Do nothing.
  646. //
  647. // RMT dvdf - May be desirable to write an error log entry here.
  648. //
  649. DD((PCE)fdx,DDE,"ERROR:IGNORED: bad filterResourceMethod=%x\n", filterResourceMethod);
  650. }
  651. targetExit:
  652. //
  653. // Preserve Irp->IoStatus.Information because it may point to a
  654. // buffer and we don't want to cause a memory leak.
  655. //
  656. P4CompleteRequest( Irp, status, Irp->IoStatus.Information );
  657. PptReleaseRemoveLock(&fdx->RemoveLock, Irp);
  658. return status;
  659. }
  660. NTSTATUS
  661. PptFdoSurpriseRemoval(
  662. IN PDEVICE_OBJECT DeviceObject,
  663. IN PIRP Irp
  664. )
  665. /*++dvdf6
  666. Routine Description:
  667. This function handles PnP IRP_MN_SURPRISE_REMOVAL.
  668. Set flags accordingly in our extension, notify those
  669. listening on our device interface GUID that
  670. we have gone away, and pass the IRP down the
  671. driver stack.
  672. Arguments:
  673. DeviceObject - The target device for the IRP
  674. Irp - The IRP
  675. Return Value:
  676. Status returned from IoCallDriver.
  677. --*/
  678. {
  679. PFDO_EXTENSION fdx = DeviceObject->DeviceExtension;
  680. //
  681. // Set flags in our extension to indicate that we have received
  682. // IRP_MN_SURPRISE_REMOVAL so that we can fail new requests
  683. // as appropriate.
  684. //
  685. ExAcquireFastMutex( &fdx->ExtensionFastMutex );
  686. PptSetFlags( fdx->PnpState, PPT_DEVICE_SURPRISE_REMOVED );
  687. ExReleaseFastMutex( &fdx->ExtensionFastMutex );
  688. //
  689. // Fail outstanding allocate/select requests for the port
  690. //
  691. {
  692. PIRP nextIrp;
  693. KIRQL cancelIrql;
  694. IoAcquireCancelSpinLock(&cancelIrql);
  695. while( !IsListEmpty( &fdx->WorkQueue ) ) {
  696. nextIrp = CONTAINING_RECORD( fdx->WorkQueue.Blink, IRP, Tail.Overlay.ListEntry );
  697. nextIrp->Cancel = TRUE;
  698. nextIrp->CancelIrql = cancelIrql;
  699. nextIrp->CancelRoutine = NULL;
  700. PptCancelRoutine( DeviceObject, nextIrp );
  701. // PptCancelRoutine() releases the cancel SpinLock so we need to reaquire
  702. IoAcquireCancelSpinLock( &cancelIrql );
  703. }
  704. IoReleaseCancelSpinLock( cancelIrql );
  705. }
  706. //
  707. // Tell those listening on our device interface GUID that we have
  708. // gone away. Ignore status from the call since we can do
  709. // nothing on failure.
  710. //
  711. IoSetDeviceInterfaceState( &fdx->DeviceInterface, FALSE );
  712. fdx->DeviceInterfaceState = FALSE;
  713. //
  714. // Succeed, pass the IRP down the stack, and release the RemoveLock.
  715. //
  716. Irp->IoStatus.Status = STATUS_SUCCESS;
  717. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock( fdx, Irp );
  718. }
  719. NTSTATUS
  720. PptFdoDefaultPnpHandler(
  721. IN PDEVICE_OBJECT DeviceObject,
  722. IN PIRP Irp
  723. )
  724. /*++dvdf8
  725. Routine Description:
  726. This function is the default handler for PnP IRPs.
  727. All PnP IRPs that are not explicitly handled by another
  728. routine (via an entry in the PptPnpDispatchFunctionTable[]) are
  729. handled by this routine.
  730. - Pass the IRP down the stack to the device below us in the
  731. driver stack and release our device RemoveLock.
  732. Arguments:
  733. DeviceObject - The target device for the IRP
  734. Irp - The IRP
  735. Return Value:
  736. STATUS_SUCCESS - on success,
  737. an appropriate error status - otherwise
  738. --*/
  739. {
  740. return PptPnpPassThroughPnpIrpAndReleaseRemoveLock(DeviceObject->DeviceExtension, Irp);
  741. }
  742. PDRIVER_DISPATCH
  743. PptFdoPnpDispatchTable[] =
  744. {
  745. PptFdoStartDevice, // IRP_MN_START_DEVICE 0x00
  746. PptFdoQueryRemove, // IRP_MN_QUERY_REMOVE_DEVICE 0x01
  747. PptFdoRemoveDevice, // IRP_MN_REMOVE_DEVICE 0x02
  748. PptFdoCancelRemove, // IRP_MN_CANCEL_REMOVE_DEVICE 0x03
  749. PptFdoStopDevice, // IRP_MN_STOP_DEVICE 0x04
  750. PptFdoQueryStop, // IRP_MN_QUERY_STOP_DEVICE 0x05
  751. PptFdoCancelStop, // IRP_MN_CANCEL_STOP_DEVICE 0x06
  752. PptFdoQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS 0x07
  753. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_INTERFACE 0x08
  754. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_CAPABILITIES 0x09
  755. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCES 0x0A
  756. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B
  757. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_DEVICE_TEXT 0x0C
  758. PptFdoFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D
  759. PptFdoDefaultPnpHandler, // no such PnP request 0x0E
  760. PptFdoDefaultPnpHandler, // IRP_MN_READ_CONFIG 0x0F
  761. PptFdoDefaultPnpHandler, // IRP_MN_WRITE_CONFIG 0x10
  762. PptFdoDefaultPnpHandler, // IRP_MN_EJECT 0x11
  763. PptFdoDefaultPnpHandler, // IRP_MN_SET_LOCK 0x12
  764. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_ID 0x13
  765. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE 0x14
  766. PptFdoDefaultPnpHandler, // IRP_MN_QUERY_BUS_INFORMATION 0x15
  767. PptFdoDefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16
  768. PptFdoSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 0x17
  769. PptFdoDefaultPnpHandler // IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18
  770. };
  771. NTSTATUS
  772. PptFdoPnp(
  773. IN PDEVICE_OBJECT Fdo,
  774. IN PIRP Irp
  775. )
  776. {
  777. PFDO_EXTENSION fdx = Fdo->DeviceExtension;
  778. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  779. NTSTATUS status;
  780. // diagnostic
  781. PptFdoDumpPnpIrpInfo( Fdo, Irp );
  782. //
  783. // Acquire RemoveLock to prevent DeviceObject from being REMOVED
  784. // while we are using it. If we are unable to acquire the RemoveLock
  785. // then the DeviceObject has already been REMOVED.
  786. //
  787. status = PptAcquireRemoveLock( &fdx->RemoveLock, Irp);
  788. if( STATUS_SUCCESS != status ) {
  789. return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  790. }
  791. //
  792. // RemoveLock is held. Forward the request to the appropriate handler.
  793. //
  794. // Note that the handler must release the RemoveLock prior to returning
  795. // control to this function.
  796. //
  797. if( irpSp->MinorFunction < arraysize(PptFdoPnpDispatchTable) ) {
  798. return PptFdoPnpDispatchTable[ irpSp->MinorFunction ]( Fdo, Irp );
  799. } else {
  800. return PptFdoDefaultPnpHandler( Fdo, Irp );
  801. }
  802. }