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.

2618 lines
69 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. pnpirp.c
  5. Abstract:
  6. This module contains IRP related routines.
  7. Author:
  8. Shie-Lin Tzong (shielint) 13-Sept-1996
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #pragma hdrstop
  13. #if DBG_SCOPE
  14. #define PnpIrpStatusTracking(Status, IrpCode, Device) \
  15. if (PnpIrpMask & (1 << IrpCode)) { \
  16. if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) { \
  17. DbgPrint(" ++ %s Driver ( %wZ ) return status %08lx\n", \
  18. IrpName[IrpCode], \
  19. &Device->DriverObject->DriverName, \
  20. Status); \
  21. } \
  22. }
  23. ULONG PnpIrpMask;
  24. PCHAR IrpName[] = {
  25. "IRP_MN_START_DEVICE - ", // 0x00
  26. "IRP_MN_QUERY_REMOVE_DEVICE - ", // 0x01
  27. "IRP_MN_REMOVE_DEVICE - ", // 0x02
  28. "IRP_MN_CANCEL_REMOVE_DEVICE - ", // 0x03
  29. "IRP_MN_STOP_DEVICE - ", // 0x04
  30. "IRP_MN_QUERY_STOP_DEVICE - ", // 0x05
  31. "IRP_MN_CANCEL_STOP_DEVICE - ", // 0x06
  32. "IRP_MN_QUERY_DEVICE_RELATIONS - ", // 0x07
  33. "IRP_MN_QUERY_INTERFACE - ", // 0x08
  34. "IRP_MN_QUERY_CAPABILITIES - ", // 0x09
  35. "IRP_MN_QUERY_RESOURCES - ", // 0x0A
  36. "IRP_MN_QUERY_RESOURCE_REQUIREMENTS - ", // 0x0B
  37. "IRP_MN_QUERY_DEVICE_TEXT - ", // 0x0C
  38. "IRP_MN_FILTER_RESOURCE_REQUIREMENTS - ", // 0x0D
  39. "INVALID_IRP_CODE - ", //
  40. "IRP_MN_READ_CONFIG - ", // 0x0F
  41. "IRP_MN_WRITE_CONFIG - ", // 0x10
  42. "IRP_MN_EJECT - ", // 0x11
  43. "IRP_MN_SET_LOCK - ", // 0x12
  44. "IRP_MN_QUERY_ID - ", // 0x13
  45. "IRP_MN_QUERY_PNP_DEVICE_STATE - ", // 0x14
  46. "IRP_MN_QUERY_BUS_INFORMATION - ", // 0x15
  47. "IRP_MN_DEVICE_USAGE_NOTIFICATION - ", // 0x16
  48. NULL
  49. };
  50. #else
  51. #define PnpIrpStatusTracking(Status, IrpCode, Device)
  52. #endif
  53. //
  54. // Internal definitions
  55. //
  56. typedef struct _DEVICE_COMPLETION_CONTEXT {
  57. PDEVICE_NODE DeviceNode;
  58. ERESOURCE_THREAD Thread;
  59. ULONG IrpMinorCode;
  60. #if DBG
  61. PVOID Id;
  62. #endif
  63. } DEVICE_COMPLETION_CONTEXT, *PDEVICE_COMPLETION_CONTEXT;
  64. typedef struct _LOCK_MOUNTABLE_DEVICE_CONTEXT{
  65. PDEVICE_OBJECT MountedDevice;
  66. PDEVICE_OBJECT FsDevice;
  67. } LOCK_MOUNTABLE_DEVICE_CONTEXT, *PLOCK_MOUNTABLE_DEVICE_CONTEXT;
  68. //
  69. // Internal references
  70. //
  71. NTSTATUS
  72. IopAsynchronousCall(
  73. IN PDEVICE_OBJECT DeviceObject,
  74. IN PIO_STACK_LOCATION TopStackLocation,
  75. IN PDEVICE_COMPLETION_CONTEXT CompletionContext,
  76. IN NTSTATUS (*CompletionRoutine)(PDEVICE_OBJECT, PIRP, PVOID)
  77. );
  78. NTSTATUS
  79. IopDeviceEjectComplete (
  80. IN PDEVICE_OBJECT DeviceObject,
  81. IN PIRP Irp,
  82. IN PVOID Context
  83. );
  84. NTSTATUS
  85. IopDeviceStartComplete (
  86. IN PDEVICE_OBJECT DeviceObject,
  87. IN PIRP Irp,
  88. IN PVOID Context
  89. );
  90. PDEVICE_OBJECT
  91. IopFindMountableDevice(
  92. IN PDEVICE_OBJECT DeviceObject
  93. );
  94. PDEVICE_OBJECT
  95. IopLockMountedDeviceForRemove(
  96. IN PDEVICE_OBJECT DeviceObject,
  97. IN ULONG IrpMinorCode,
  98. OUT PLOCK_MOUNTABLE_DEVICE_CONTEXT Context
  99. );
  100. VOID
  101. IopUnlockMountedDeviceForRemove(
  102. IN PDEVICE_OBJECT DeviceObject,
  103. IN ULONG IrpMinorCode,
  104. IN PLOCK_MOUNTABLE_DEVICE_CONTEXT Context
  105. );
  106. NTSTATUS
  107. IopFilterResourceRequirementsCall(
  108. IN PDEVICE_OBJECT DeviceObject,
  109. IN PIO_RESOURCE_REQUIREMENTS_LIST ResReqList,
  110. OUT PVOID *Information
  111. );
  112. //
  113. // External reference
  114. //
  115. #ifdef ALLOC_PRAGMA
  116. #pragma alloc_text(PAGE, IopAsynchronousCall)
  117. #pragma alloc_text(PAGE, IopSynchronousCall)
  118. #pragma alloc_text(PAGE, IopStartDevice)
  119. #pragma alloc_text(PAGE, IopEjectDevice)
  120. #pragma alloc_text(PAGE, IopRemoveDevice)
  121. //#pragma alloc_text(PAGE, IopQueryDeviceRelations)
  122. #pragma alloc_text(PAGE, IopQueryDeviceResources)
  123. #pragma alloc_text(PAGE, IopQueryDockRemovalInterface)
  124. #pragma alloc_text(PAGE, IopQueryLegacyBusInformation)
  125. #pragma alloc_text(PAGE, IopQueryPnpBusInformation)
  126. #pragma alloc_text(PAGE, IopQueryResourceHandlerInterface)
  127. #pragma alloc_text(PAGE, IopQueryReconfiguration)
  128. #pragma alloc_text(PAGE, IopFindMountableDevice)
  129. #pragma alloc_text(PAGE, IopFilterResourceRequirementsCall)
  130. #pragma alloc_text(PAGE, IopQueryDeviceState)
  131. #pragma alloc_text(PAGE, IopIncDisableableDepends)
  132. #pragma alloc_text(PAGE, IopDecDisableableDepends)
  133. #pragma alloc_text(PAGE, PpIrpQueryResourceRequirements)
  134. #pragma alloc_text(PAGE, PpIrpQueryID)
  135. #endif // ALLOC_PRAGMA
  136. #if 0
  137. NTSTATUS
  138. IopAsynchronousCall(
  139. IN PDEVICE_OBJECT TargetDevice,
  140. IN PIO_STACK_LOCATION TopStackLocation,
  141. IN PDEVICE_COMPLETION_CONTEXT CompletionContext,
  142. IN NTSTATUS (*CompletionRoutine)(PDEVICE_OBJECT, PIRP, PVOID)
  143. )
  144. /*++
  145. Routine Description:
  146. This function sends an Asynchronous irp to the top level device
  147. object which roots on DeviceObject.
  148. Parameters:
  149. DeviceObject - Supplies the device object of the device being removed.
  150. TopStackLocation - Supplies a pointer to the parameter block for the irp.
  151. CompletionContext -
  152. CompletionRoutine -
  153. Return Value:
  154. NTSTATUS code.
  155. --*/
  156. {
  157. PDEVICE_OBJECT deviceObject;
  158. PIRP irp;
  159. PIO_STACK_LOCATION irpSp;
  160. PAGED_CODE();
  161. //
  162. // Get a pointer to the topmost device object in the stack of devices,
  163. // beginning with the deviceObject.
  164. //
  165. deviceObject = IoGetAttachedDevice(TargetDevice);
  166. //
  167. // Allocate an I/O Request Packet (IRP) for this device removal operation.
  168. //
  169. irp = IoAllocateIrp( (CCHAR) (deviceObject->StackSize), FALSE );
  170. if (!irp) {
  171. return STATUS_INSUFFICIENT_RESOURCES;
  172. }
  173. SPECIALIRP_WATERMARK_IRP(irp, IRP_SYSTEM_RESTRICTED);
  174. //
  175. // Initialize it to failure.
  176. //
  177. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  178. irp->IoStatus.Information = 0;
  179. //
  180. // Get a pointer to the next stack location in the packet. This location
  181. // will be used to pass the function codes and parameters to the first
  182. // driver.
  183. //
  184. irpSp = IoGetNextIrpStackLocation(irp);
  185. //
  186. // Fill in the IRP according to this request.
  187. //
  188. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  189. irp->RequestorMode = KernelMode;
  190. irp->UserIosb = NULL;
  191. irp->UserEvent = NULL;
  192. //
  193. // Copy in the caller-supplied stack location contents
  194. //
  195. *irpSp = *TopStackLocation;
  196. #if DBG
  197. CompletionContext->Id = irp;
  198. #endif
  199. IoSetCompletionRoutine(irp,
  200. CompletionRoutine,
  201. CompletionContext, /* Completion context */
  202. TRUE, /* Invoke on success */
  203. TRUE, /* Invoke on error */
  204. TRUE /* Invoke on cancel */
  205. );
  206. return IoCallDriver( deviceObject, irp );
  207. }
  208. #endif
  209. NTSTATUS
  210. IopSynchronousCall(
  211. IN PDEVICE_OBJECT DeviceObject,
  212. IN PIO_STACK_LOCATION TopStackLocation,
  213. OUT PULONG_PTR Information
  214. )
  215. /*++
  216. Routine Description:
  217. This function sends a synchronous irp to the top level device
  218. object which roots on DeviceObject.
  219. Parameters:
  220. DeviceObject - Supplies the device object of the device being removed.
  221. TopStackLocation - Supplies a pointer to the parameter block for the irp.
  222. Information - Supplies a pointer to a variable to receive the returned
  223. information of the irp.
  224. Return Value:
  225. NTSTATUS code.
  226. --*/
  227. {
  228. PIRP irp;
  229. PIO_STACK_LOCATION irpSp;
  230. IO_STATUS_BLOCK statusBlock;
  231. KEVENT event;
  232. NTSTATUS status;
  233. PDEVICE_OBJECT deviceObject;
  234. PAGED_CODE();
  235. //
  236. // Get a pointer to the topmost device object in the stack of devices,
  237. // beginning with the deviceObject.
  238. //
  239. deviceObject = IoGetAttachedDevice(DeviceObject);
  240. //
  241. // Begin by allocating the IRP for this request. Do not charge quota to
  242. // the current process for this IRP.
  243. //
  244. irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
  245. if (irp == NULL){
  246. return STATUS_INSUFFICIENT_RESOURCES;
  247. }
  248. SPECIALIRP_WATERMARK_IRP(irp, IRP_SYSTEM_RESTRICTED);
  249. //
  250. // Initialize it to failure.
  251. //
  252. irp->IoStatus.Status = statusBlock.Status = STATUS_NOT_SUPPORTED;
  253. irp->IoStatus.Information = statusBlock.Information = 0;
  254. //
  255. // Set the pointer to the status block and initialized event.
  256. //
  257. KeInitializeEvent( &event,
  258. SynchronizationEvent,
  259. FALSE );
  260. irp->UserIosb = &statusBlock;
  261. irp->UserEvent = &event;
  262. //
  263. // Set the address of the current thread
  264. //
  265. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  266. //
  267. // Queue this irp onto the current thread
  268. //
  269. IopQueueThreadIrp(irp);
  270. //
  271. // Get a pointer to the stack location of the first driver which will be
  272. // invoked. This is where the function codes and parameters are set.
  273. //
  274. irpSp = IoGetNextIrpStackLocation(irp);
  275. //
  276. // Copy in the caller-supplied stack location contents
  277. //
  278. *irpSp = *TopStackLocation;
  279. //
  280. // Call the driver
  281. //
  282. status = IoCallDriver(deviceObject, irp);
  283. PnpIrpStatusTracking(status, TopStackLocation->MinorFunction, deviceObject);
  284. //
  285. // If a driver returns STATUS_PENDING, we will wait for it to complete
  286. //
  287. if (status == STATUS_PENDING) {
  288. (VOID) KeWaitForSingleObject( &event,
  289. Executive,
  290. KernelMode,
  291. FALSE,
  292. (PLARGE_INTEGER) NULL );
  293. status = statusBlock.Status;
  294. }
  295. if (Information != NULL) {
  296. *Information = statusBlock.Information;
  297. }
  298. return status;
  299. }
  300. NTSTATUS
  301. IopStartDevice(
  302. IN PDEVICE_OBJECT DeviceObject
  303. )
  304. /*++
  305. Routine Description:
  306. This function sends a start device irp to the top level device
  307. object which roots on DeviceObject.
  308. Parameters:
  309. DeviceObject - Supplies the pointer to the device object of the device
  310. being removed.
  311. Return Value:
  312. NTSTATUS code.
  313. --*/
  314. {
  315. IO_STACK_LOCATION irpSp;
  316. PDEVICE_NODE deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  317. PDEVICE_COMPLETION_CONTEXT completionContext;
  318. NTSTATUS status;
  319. PAGED_CODE();
  320. //
  321. // Initialize the stack location to pass to IopSynchronousCall()
  322. //
  323. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  324. //
  325. // Set the function codes.
  326. //
  327. irpSp.MajorFunction = IRP_MJ_PNP;
  328. irpSp.MinorFunction = IRP_MN_START_DEVICE;
  329. //
  330. // Set the pointers for the raw and translated resource lists
  331. //
  332. irpSp.Parameters.StartDevice.AllocatedResources = deviceNode->ResourceList;
  333. irpSp.Parameters.StartDevice.AllocatedResourcesTranslated = deviceNode->ResourceListTranslated;
  334. status = IopSynchronousCall(DeviceObject, &irpSp, NULL);
  335. return status;
  336. }
  337. NTSTATUS
  338. IopEjectDevice(
  339. IN PDEVICE_OBJECT DeviceObject,
  340. IN OUT PPENDING_RELATIONS_LIST_ENTRY PendingEntry
  341. )
  342. /*++
  343. Routine Description:
  344. This function sends an eject device irp to the top level device
  345. object which roots on DeviceObject.
  346. Parameters:
  347. DeviceObject - Supplies a pointer to the device object of the device being
  348. removed.
  349. Return Value:
  350. NTSTATUS code.
  351. --*/
  352. {
  353. PIO_STACK_LOCATION irpSp;
  354. NTSTATUS status;
  355. PDEVICE_OBJECT deviceObject;
  356. PIRP irp;
  357. PAGED_CODE();
  358. if (PendingEntry->LightestSleepState != PowerSystemWorking) {
  359. //
  360. // We have to warm eject.
  361. //
  362. if (PendingEntry->DockInterface) {
  363. PendingEntry->DockInterface->ProfileDepartureSetMode(
  364. PendingEntry->DockInterface->Context,
  365. PDS_UPDATE_ON_EJECT
  366. );
  367. }
  368. PendingEntry->EjectIrp = NULL;
  369. InitializeListHead( &PendingEntry->Link );
  370. IopQueuePendingEject(PendingEntry);
  371. ExInitializeWorkItem( &PendingEntry->WorkItem,
  372. IopProcessCompletedEject,
  373. PendingEntry);
  374. ExQueueWorkItem( &PendingEntry->WorkItem, DelayedWorkQueue );
  375. return STATUS_SUCCESS;
  376. }
  377. if (PendingEntry->DockInterface) {
  378. //
  379. // Notify dock that now is a good time to update it's hardware profile.
  380. //
  381. PendingEntry->DockInterface->ProfileDepartureSetMode(
  382. PendingEntry->DockInterface->Context,
  383. PDS_UPDATE_ON_INTERFACE
  384. );
  385. PendingEntry->DockInterface->ProfileDepartureUpdate(
  386. PendingEntry->DockInterface->Context
  387. );
  388. if (PendingEntry->DisplaySafeRemovalDialog) {
  389. PpNotifyUserModeRemovalSafe(DeviceObject);
  390. PendingEntry->DisplaySafeRemovalDialog = FALSE;
  391. }
  392. }
  393. //
  394. // Get a pointer to the topmost device object in the stack of devices,
  395. // beginning with the deviceObject.
  396. //
  397. deviceObject = IoGetAttachedDeviceReference(DeviceObject);
  398. //
  399. // Allocate an I/O Request Packet (IRP) for this device removal operation.
  400. //
  401. irp = IoAllocateIrp( (CCHAR) (deviceObject->StackSize), FALSE );
  402. if (!irp) {
  403. PendingEntry->EjectIrp = NULL;
  404. InitializeListHead( &PendingEntry->Link );
  405. IopQueuePendingEject(PendingEntry);
  406. ExInitializeWorkItem( &PendingEntry->WorkItem,
  407. IopProcessCompletedEject,
  408. PendingEntry);
  409. ExQueueWorkItem( &PendingEntry->WorkItem, DelayedWorkQueue );
  410. ObDereferenceObject(deviceObject);
  411. return STATUS_INSUFFICIENT_RESOURCES;
  412. }
  413. SPECIALIRP_WATERMARK_IRP(irp, IRP_SYSTEM_RESTRICTED);
  414. //
  415. // Initialize it to failure.
  416. //
  417. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  418. irp->IoStatus.Information = 0;
  419. //
  420. // Get a pointer to the next stack location in the packet. This location
  421. // will be used to pass the function codes and parameters to the first
  422. // driver.
  423. //
  424. irpSp = IoGetNextIrpStackLocation(irp);
  425. //
  426. // Initialize the stack location to pass to IopSynchronousCall()
  427. //
  428. RtlZeroMemory(irpSp, sizeof(IO_STACK_LOCATION));
  429. //
  430. // Set the function codes.
  431. //
  432. irpSp->MajorFunction = IRP_MJ_PNP;
  433. irpSp->MinorFunction = IRP_MN_EJECT;
  434. //
  435. // Fill in the IRP according to this request.
  436. //
  437. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  438. irp->RequestorMode = KernelMode;
  439. irp->UserIosb = NULL;
  440. irp->UserEvent = NULL;
  441. PendingEntry->EjectIrp = irp;
  442. IopQueuePendingEject(PendingEntry);
  443. IoSetCompletionRoutine(irp,
  444. IopDeviceEjectComplete,
  445. PendingEntry, /* Completion context */
  446. TRUE, /* Invoke on success */
  447. TRUE, /* Invoke on error */
  448. TRUE /* Invoke on cancel */
  449. );
  450. status = IoCallDriver( deviceObject, irp );
  451. ObDereferenceObject(deviceObject);
  452. return status;
  453. }
  454. NTSTATUS
  455. IopDeviceEjectComplete (
  456. IN PDEVICE_OBJECT DeviceObject,
  457. IN PIRP Irp,
  458. IN PVOID Context
  459. )
  460. {
  461. PPENDING_RELATIONS_LIST_ENTRY entry = (PPENDING_RELATIONS_LIST_ENTRY)Context;
  462. PIRP ejectIrp;
  463. UNREFERENCED_PARAMETER( DeviceObject );
  464. ejectIrp = InterlockedExchangePointer(&entry->EjectIrp, NULL);
  465. ASSERT(ejectIrp == NULL || ejectIrp == Irp);
  466. //
  467. // Queue a work item to finish up the eject. We queue a work item because
  468. // we are probably running at dispatch level in some random context.
  469. //
  470. ExInitializeWorkItem( &entry->WorkItem,
  471. IopProcessCompletedEject,
  472. entry);
  473. ExQueueWorkItem( &entry->WorkItem, DelayedWorkQueue );
  474. IoFreeIrp( Irp );
  475. return STATUS_MORE_PROCESSING_REQUIRED;
  476. }
  477. NTSTATUS
  478. IopRemoveDevice (
  479. IN PDEVICE_OBJECT TargetDevice,
  480. IN ULONG IrpMinorCode
  481. )
  482. /*++
  483. Routine Description:
  484. This function sends a requested DeviceRemoval related irp to the top level device
  485. object which roots on TargetDevice. If there is a VPB associated with the
  486. TargetDevice, the corresponding filesystem's VDO will be used. Otherwise
  487. the irp will be sent directly to the target device/ or its assocated device
  488. object.
  489. Parameters:
  490. TargetDevice - Supplies the device object of the device being removed.
  491. Operation - Specifies the operation requested.
  492. The following IRP codes are used with IRP_MJ_DEVICE_CHANGE for removing
  493. devices:
  494. IRP_MN_QUERY_REMOVE_DEVICE
  495. IRP_MN_CANCEL_REMOVE_DEVICE
  496. IRP_MN_REMOVE_DEVICE
  497. IRP_MN_EJECT
  498. Return Value:
  499. NTSTATUS code.
  500. --*/
  501. {
  502. IO_STACK_LOCATION irpSp;
  503. NTSTATUS status;
  504. BOOLEAN isMountable = FALSE;
  505. PDEVICE_OBJECT mountedDevice;
  506. LOCK_MOUNTABLE_DEVICE_CONTEXT lockContext;
  507. PAGED_CODE();
  508. ASSERT(IrpMinorCode == IRP_MN_QUERY_REMOVE_DEVICE ||
  509. IrpMinorCode == IRP_MN_CANCEL_REMOVE_DEVICE ||
  510. IrpMinorCode == IRP_MN_REMOVE_DEVICE ||
  511. IrpMinorCode == IRP_MN_SURPRISE_REMOVAL ||
  512. IrpMinorCode == IRP_MN_EJECT);
  513. if (IrpMinorCode == IRP_MN_REMOVE_DEVICE ||
  514. IrpMinorCode == IRP_MN_QUERY_REMOVE_DEVICE) {
  515. IopUncacheInterfaceInformation(TargetDevice);
  516. }
  517. //
  518. // Initialize the stack location to pass to IopSynchronousCall()
  519. //
  520. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  521. irpSp.MajorFunction = IRP_MJ_PNP;
  522. irpSp.MinorFunction = (UCHAR)IrpMinorCode;
  523. //
  524. // Check to see if there's a VPB anywhere in the device stack. If there
  525. // is then we'll have to lock the stack. This is to make sure that the VPB
  526. // does not go away while the operation is in the file system and that no
  527. // one new can mount on the device if the FS decides to bail out.
  528. //
  529. mountedDevice = IopFindMountableDevice(TargetDevice);
  530. if (mountedDevice != NULL) {
  531. //
  532. // This routine will cause any mount operations on the VPB to fail.
  533. // It will also release the VPB spinlock.
  534. //
  535. mountedDevice = IopLockMountedDeviceForRemove(TargetDevice,
  536. IrpMinorCode,
  537. &lockContext);
  538. isMountable = TRUE;
  539. } else {
  540. ASSERTMSG("Mass storage device does not have VPB - this is odd",
  541. !((TargetDevice->Type == FILE_DEVICE_DISK) ||
  542. (TargetDevice->Type == FILE_DEVICE_CD_ROM) ||
  543. (TargetDevice->Type == FILE_DEVICE_TAPE) ||
  544. (TargetDevice->Type == FILE_DEVICE_VIRTUAL_DISK)));
  545. mountedDevice = TargetDevice;
  546. }
  547. //
  548. // Make the call and return.
  549. //
  550. if (IrpMinorCode == IRP_MN_SURPRISE_REMOVAL || IrpMinorCode == IRP_MN_REMOVE_DEVICE) {
  551. //
  552. // if device was not disableable, we cleanup the tree
  553. // and debug-trace that we surprise-removed a non-disableable device
  554. //
  555. PDEVICE_NODE deviceNode = TargetDevice->DeviceObjectExtension->DeviceNode;
  556. if (deviceNode->UserFlags & DNUF_NOT_DISABLEABLE) {
  557. //
  558. // this device was marked as disableable, update the depends
  559. // before this device disappears
  560. // (by momentarily marking this node as disableable)
  561. //
  562. deviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
  563. IopDecDisableableDepends(deviceNode);
  564. }
  565. }
  566. status = IopSynchronousCall(mountedDevice, &irpSp, NULL);
  567. if (isMountable) {
  568. IopUnlockMountedDeviceForRemove(TargetDevice,
  569. IrpMinorCode,
  570. &lockContext);
  571. //
  572. // Successful query should follow up with invalidation of all volumes
  573. // which have been on this device but which are not currently mounted.
  574. //
  575. if ((IrpMinorCode == IRP_MN_QUERY_REMOVE_DEVICE ||
  576. IrpMinorCode == IRP_MN_SURPRISE_REMOVAL) &&
  577. NT_SUCCESS(status)) {
  578. status = IopInvalidateVolumesForDevice(TargetDevice);
  579. }
  580. }
  581. if (IrpMinorCode == IRP_MN_REMOVE_DEVICE) {
  582. ((PDEVICE_NODE)TargetDevice->DeviceObjectExtension->DeviceNode)->Flags &=
  583. ~(DNF_LEGACY_DRIVER | DNF_REENUMERATE);
  584. }
  585. return status;
  586. }
  587. PDEVICE_OBJECT
  588. IopLockMountedDeviceForRemove(
  589. IN PDEVICE_OBJECT DeviceObject,
  590. IN ULONG IrpMinorCode,
  591. OUT PLOCK_MOUNTABLE_DEVICE_CONTEXT Context
  592. )
  593. /*++
  594. Routine Description:
  595. This routine will scan up the device stack and mark each unmounted VPB it
  596. finds with the VPB_REMOVE_PENDING bit (or clear it in the case of cancel)
  597. and increment (or decrement in the case of cancel) the reference count
  598. in the VPB. This is to ensure that no new file system can get mounted on
  599. the device stack while the remove operation is in place.
  600. The search will terminate once all the attached device objects have been
  601. marked, or once a mounted device object has been marked.
  602. Arguments:
  603. DeviceObject - the PDO we are attempting to remove
  604. IrpMinorCode - the remove-type operation we are going to perform
  605. Context - a context block which must be passed in to the unlock operation
  606. Return Value:
  607. A pointer to the device object stack which the remove request should be
  608. sent to. If a mounted file system was found, this will be the lowest
  609. file system device object in the mounted stack. Otherwise this will be
  610. the PDO which was passed in.
  611. --*/
  612. {
  613. PVPB vpb;
  614. PDEVICE_OBJECT device = DeviceObject;
  615. PDEVICE_OBJECT fsDevice = NULL;
  616. KIRQL oldIrql;
  617. RtlZeroMemory(Context, sizeof(LOCK_MOUNTABLE_DEVICE_CONTEXT));
  618. Context->MountedDevice = DeviceObject;
  619. do {
  620. //
  621. // Walk up each device object in the stack. For each one, if a VPB
  622. // exists, grab the database resource exclusive followed by the
  623. // device lock. Then acquire the Vpb spinlock and perform the
  624. // appropriate magic on the device object.
  625. //
  626. //
  627. // NOTE - Its unfortunate that the locking order includes grabbing
  628. // the device specific lock first followed by the global lock.
  629. //
  630. if(device->Vpb != NULL) {
  631. //
  632. // Grab the device lock. This will ensure that there are no mount
  633. // or verify operations in progress.
  634. //
  635. KeWaitForSingleObject(&(device->DeviceLock),
  636. Executive,
  637. KernelMode,
  638. FALSE,
  639. NULL);
  640. //
  641. // Now set the remove pending flag, which will prevent new mounts
  642. // from occuring on this stack once the current (if existant)
  643. // filesystem dismounts. Filesystems will preserve the flag across
  644. // vpb swaps.
  645. //
  646. IoAcquireVpbSpinLock(&oldIrql);
  647. vpb = device->Vpb;
  648. ASSERT(vpb != NULL);
  649. switch(IrpMinorCode) {
  650. case IRP_MN_QUERY_REMOVE_DEVICE:
  651. case IRP_MN_SURPRISE_REMOVAL:
  652. case IRP_MN_REMOVE_DEVICE: {
  653. vpb->Flags |= VPB_REMOVE_PENDING;
  654. break;
  655. }
  656. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  657. vpb->Flags &= ~VPB_REMOVE_PENDING;
  658. break;
  659. }
  660. default:
  661. break;
  662. }
  663. //
  664. // Note the device object that has the filesystem stack attached.
  665. // We must remember the vpb we referenced that had the fs because
  666. // it may be swapped off of the storage device during a dismount
  667. // operation.
  668. //
  669. if(vpb->Flags & VPB_MOUNTED) {
  670. Context->MountedDevice = device;
  671. fsDevice = vpb->DeviceObject;
  672. }
  673. Context->FsDevice = fsDevice;
  674. IoReleaseVpbSpinLock(oldIrql);
  675. //
  676. // Bump the fs device handle count. This prevent the filesystem filter stack
  677. // from being torn down while a PNP IRP is in progress.
  678. //
  679. if (fsDevice) {
  680. IopIncrementDeviceObjectHandleCount(fsDevice);
  681. }
  682. KeSetEvent(&(device->DeviceLock), IO_NO_INCREMENT, FALSE);
  683. //
  684. // Stop if we hit a device with a mounted filesystem.
  685. //
  686. if (NULL != fsDevice) {
  687. //
  688. // We found and setup a mounted device. Time to return.
  689. //
  690. break;
  691. }
  692. }
  693. oldIrql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  694. device = device->AttachedDevice;
  695. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, oldIrql );
  696. } while (device != NULL);
  697. if(fsDevice != NULL) {
  698. return fsDevice;
  699. }
  700. return Context->MountedDevice;
  701. }
  702. VOID
  703. IopUnlockMountedDeviceForRemove(
  704. IN PDEVICE_OBJECT DeviceObject,
  705. IN ULONG IrpMinorCode,
  706. IN PLOCK_MOUNTABLE_DEVICE_CONTEXT Context
  707. )
  708. {
  709. PDEVICE_OBJECT device = DeviceObject;
  710. do {
  711. KIRQL oldIrql;
  712. //
  713. // Walk up each device object in the stack. For each one, if a VPB
  714. // exists, grab the database resource exclusive followed by the
  715. // device lock. Then acquire the Vpb spinlock and perform the
  716. // appropriate magic on the device object.
  717. //
  718. //
  719. // NOTE - It's unfortunate that the locking order includes grabing
  720. // the device specific lock first followed by the global lock.
  721. //
  722. if (device->Vpb != NULL) {
  723. //
  724. // Grab the device lock. This will ensure that there are no mount
  725. // or verify operations in progress, which in turn will ensure
  726. // that any mounted file system won't go away.
  727. //
  728. KeWaitForSingleObject(&(device->DeviceLock),
  729. Executive,
  730. KernelMode,
  731. FALSE,
  732. NULL);
  733. //
  734. // Now decrement the reference count in the VPB. If the remove
  735. // pending flag has been set in the VPB (if this is a QUERY or a
  736. // REMOVE) then even on a dismount no new file system will be
  737. // allowed onto the device.
  738. //
  739. IoAcquireVpbSpinLock(&oldIrql);
  740. if (IrpMinorCode == IRP_MN_REMOVE_DEVICE) {
  741. device->Vpb->Flags &= ~VPB_REMOVE_PENDING;
  742. }
  743. IoReleaseVpbSpinLock(oldIrql);
  744. KeSetEvent(&(device->DeviceLock), IO_NO_INCREMENT, FALSE);
  745. }
  746. //
  747. // Continue up the chain until we know we hit the device the fs
  748. // mounted on, if any.
  749. //
  750. if (Context->MountedDevice == device) {
  751. //
  752. // Decrement the fs device handle count. This prevented the filesystem filter stack
  753. // from being torn down while a PNP IRP is in progress.
  754. //
  755. if (Context->FsDevice) {
  756. IopDecrementDeviceObjectHandleCount(Context->FsDevice);
  757. }
  758. break;
  759. } else {
  760. oldIrql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  761. device = device->AttachedDevice;
  762. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, oldIrql );
  763. }
  764. } while (device != NULL);
  765. return;
  766. }
  767. PDEVICE_OBJECT
  768. IopFindMountableDevice(
  769. IN PDEVICE_OBJECT DeviceObject
  770. )
  771. /*++
  772. Routine Description:
  773. This routine will scan up the device stack and find a device which could
  774. finds with the VPB_REMOVE_PENDING bit (or clear it in the case of cancel)
  775. and increment (or decrement in the case of cancel) the reference count
  776. in the VPB. This is to ensure that no new file system can get mounted on
  777. the device stack while the remove operation is in place.
  778. The search will terminate once all the attached device objects have been
  779. marked, or once a mounted device object has been marked.
  780. Arguments:
  781. DeviceObject - the PDO we are attempting to remove
  782. IrpMinorCode - the remove-type operation we are going to perform
  783. Context - a context block which must be passed in to the unlock operation
  784. Return Value:
  785. A pointer to the device object stack which the remove request should be
  786. sent to. If a mounted file system was found, this will be the lowest
  787. file system device object in the mounted stack. Otherwise this will be
  788. the PDO which was passed in.
  789. --*/
  790. {
  791. PDEVICE_OBJECT mountableDevice = DeviceObject;
  792. while (mountableDevice != NULL) {
  793. if ((mountableDevice->Flags & DO_DEVICE_HAS_NAME) &&
  794. (mountableDevice->Vpb != NULL)) {
  795. return mountableDevice;
  796. }
  797. mountableDevice = mountableDevice->AttachedDevice;
  798. }
  799. return NULL;
  800. }
  801. NTSTATUS
  802. IopDeviceStartComplete (
  803. IN PDEVICE_OBJECT DeviceObject,
  804. IN PIRP Irp,
  805. IN PVOID Context
  806. )
  807. /*++
  808. Routine Description:
  809. Completion function for an Async Start IRP.
  810. Arguments:
  811. DeviceObject - NULL.
  812. Irp - SetPower irp which has completed
  813. Context - a pointer to the DEVICE_CHANGE_COMPLETION_CONTEXT.
  814. Return Value:
  815. STATUS_MORE_PROCESSING_REQUIRED is returned to IoCompleteRequest
  816. to signify that IoCompleteRequest should not continue processing
  817. the IRP.
  818. --*/
  819. {
  820. PDEVICE_NODE deviceNode = ((PDEVICE_COMPLETION_CONTEXT)Context)->DeviceNode;
  821. ERESOURCE_THREAD LockingThread = ((PDEVICE_COMPLETION_CONTEXT)Context)->Thread;
  822. ULONG oldFlags;
  823. KIRQL oldIrql;
  824. UNREFERENCED_PARAMETER( DeviceObject );
  825. //
  826. // Read state from Irp.
  827. //
  828. #if DBG
  829. if (((PDEVICE_COMPLETION_CONTEXT)Context)->Id != (PVOID)Irp) {
  830. ASSERT(0);
  831. IoFreeIrp (Irp);
  832. ExFreePool(Context);
  833. return STATUS_MORE_PROCESSING_REQUIRED;
  834. }
  835. #endif
  836. #if 0
  837. //
  838. // Most of this is now handled within PipProcessStartPhase2.
  839. //
  840. PnpIrpStatusTracking(Irp->IoStatus.Status, IRP_MN_START_DEVICE, deviceNode->PhysicalDeviceObject);
  841. ExAcquireSpinLock(&IopPnPSpinLock, &oldIrql);
  842. oldFlags = deviceNode->Flags;
  843. deviceNode->Flags &= ~DNF_START_REQUEST_PENDING;
  844. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  845. if (deviceNode->Flags & DNF_STOPPED) {
  846. //
  847. // If the start is initiated by rebalancing, do NOT do enumeration
  848. //
  849. deviceNode->Flags &= ~DNF_STOPPED;
  850. deviceNode->Flags |= DNF_STARTED;
  851. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  852. } else {
  853. //
  854. // Otherwise, we need to queue a request to enumerate the device if DNF_START_REQUEST_PENDING
  855. // is set. (IopStartDevice sets the flag if status of start irp returns pending.)
  856. //
  857. //
  858. deviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY | DNF_STARTED;
  859. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  860. if (oldFlags & DNF_START_REQUEST_PENDING) {
  861. PipRequestDeviceAction( deviceNode->PhysicalDeviceObject,
  862. ReenumerateDeviceTree,
  863. FALSE,
  864. 0,
  865. NULL,
  866. NULL );
  867. }
  868. }
  869. } else {
  870. //
  871. // The start failed. We will remove the device
  872. //
  873. deviceNode->Flags &= ~(DNF_STOPPED | DNF_STARTED);
  874. ExReleaseSpinLock(&IopPnPSpinLock, oldIrql);
  875. SAVE_FAILURE_INFO(deviceNode, Irp->IoStatus.Status);
  876. PipSetDevNodeProblem(deviceNode, CM_PROB_FAILED_START);
  877. }
  878. #endif
  879. //
  880. // Irp processing is complete, free the irp and then return
  881. // more_processing_required which causes IoCompleteRequest to
  882. // stop "completing" this irp any future.
  883. //
  884. IoFreeIrp (Irp);
  885. ExFreePool(Context);
  886. return STATUS_MORE_PROCESSING_REQUIRED;
  887. }
  888. NTSTATUS
  889. IopQueryDeviceRelations(
  890. IN DEVICE_RELATION_TYPE Relations,
  891. IN PDEVICE_OBJECT DeviceObject,
  892. IN BOOLEAN Synchronous,
  893. OUT PDEVICE_RELATIONS *DeviceRelations
  894. )
  895. /*++
  896. Routine Description:
  897. This routine sends query device relation irp to the specified device object.
  898. Parameters:
  899. Relations - specifies the type of relation interested.
  900. DeviceObjet - Supplies the device object of the device being queried.
  901. AsyncOk - Specifies if we can perform Async QueryDeviceRelations
  902. DeviceRelations - Supplies a pointer to a variable to receive the returned
  903. relation information. This must be freed by the caller.
  904. Return Value:
  905. NTSTATUS code.
  906. --*/
  907. {
  908. IO_STACK_LOCATION irpSp;
  909. NTSTATUS status;
  910. PDEVICE_NODE deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  911. PDEVICE_COMPLETION_CONTEXT completionContext;
  912. BOOLEAN requestEnumeration = FALSE;
  913. KIRQL oldIrql;
  914. //
  915. // Initialize the stack location to pass to IopSynchronousCall()
  916. //
  917. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  918. //
  919. // Set the function codes.
  920. //
  921. irpSp.MajorFunction = IRP_MJ_PNP;
  922. irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
  923. //
  924. // Set the pointer to the resource list
  925. //
  926. irpSp.Parameters.QueryDeviceRelations.Type = Relations;
  927. //
  928. // Make the call and return.
  929. //
  930. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)DeviceRelations);
  931. if (Relations == BusRelations) {
  932. deviceNode->CompletionStatus = status;
  933. PipSetDevNodeState( deviceNode, DeviceNodeEnumerateCompletion, NULL );
  934. status = STATUS_SUCCESS;
  935. }
  936. return status;
  937. }
  938. NTSTATUS
  939. IopQueryDeviceResources (
  940. IN PDEVICE_OBJECT DeviceObject,
  941. IN ULONG ResourceType,
  942. OUT PVOID *Resource,
  943. OUT ULONG *Length
  944. )
  945. /*++
  946. Routine Description:
  947. This routine sends irp to queries resources or resource requirements list
  948. of the specified device object.
  949. If the device object is a detected device, its resources will be read from
  950. registry. Otherwise, an irp is sent to the bus driver to query its resources.
  951. Parameters:
  952. DeviceObject - Supplies the device object of the device being queries.
  953. ResourceType - 0 for device resources and 1 for resource requirements list.
  954. Resource - Supplies a pointer to a variable to receive the returned resources
  955. Length - Supplies a pointer to a variable to receive the length of the returned
  956. resources or resource requirements list.
  957. Return Value:
  958. NTSTATUS code.
  959. --*/
  960. {
  961. IO_STACK_LOCATION irpSp;
  962. PDEVICE_NODE deviceNode;
  963. NTSTATUS status;
  964. PIO_RESOURCE_REQUIREMENTS_LIST resReqList, newResources;
  965. ULONG junk;
  966. PCM_RESOURCE_LIST cmList;
  967. PIO_RESOURCE_REQUIREMENTS_LIST filteredList, mergedList;
  968. BOOLEAN exactMatch;
  969. PAGED_CODE();
  970. #if DBG
  971. if ((ResourceType != QUERY_RESOURCE_LIST) &&
  972. (ResourceType != QUERY_RESOURCE_REQUIREMENTS)) {
  973. ASSERT(0);
  974. return STATUS_INVALID_PARAMETER_2;
  975. }
  976. #endif
  977. *Resource = NULL;
  978. *Length = 0;
  979. //
  980. // Initialize the stack location to pass to IopSynchronousCall()
  981. //
  982. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  983. deviceNode = (PDEVICE_NODE) DeviceObject->DeviceObjectExtension->DeviceNode;
  984. if (ResourceType == QUERY_RESOURCE_LIST) {
  985. //
  986. // caller is asked for RESOURCE_LIST. If this is a madeup device, we will
  987. // read it from registry. Otherwise, we ask drivers.
  988. //
  989. if (deviceNode->Flags & DNF_MADEUP) {
  990. status = IopGetDeviceResourcesFromRegistry(
  991. DeviceObject,
  992. ResourceType,
  993. REGISTRY_ALLOC_CONFIG + REGISTRY_FORCED_CONFIG + REGISTRY_BOOT_CONFIG,
  994. Resource,
  995. Length);
  996. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  997. status = STATUS_SUCCESS;
  998. }
  999. return status;
  1000. } else {
  1001. irpSp.MinorFunction = IRP_MN_QUERY_RESOURCES;
  1002. irpSp.MajorFunction = IRP_MJ_PNP;
  1003. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)Resource);
  1004. if (status == STATUS_NOT_SUPPORTED) {
  1005. //
  1006. // If driver doesn't implement this request, it
  1007. // doesn't consume any resources.
  1008. //
  1009. *Resource = NULL;
  1010. status = STATUS_SUCCESS;
  1011. }
  1012. if (NT_SUCCESS(status)) {
  1013. *Length = IopDetermineResourceListSize((PCM_RESOURCE_LIST)*Resource);
  1014. }
  1015. return status;
  1016. }
  1017. } else {
  1018. //
  1019. // Caller is asked for resource requirements list. We will check:
  1020. // if there is a ForcedConfig, it will be converted to resource requirements
  1021. // list and return. Otherwise,
  1022. // If there is an OVerrideConfigVector, we will use it as our
  1023. // FilterConfigVector. Otherwise we ask driver for the config vector and
  1024. // use it as our FilterConfigVector.
  1025. // Finaly, we pass the FilterConfigVector to driver stack to let drivers
  1026. // filter the requirements.
  1027. //
  1028. status = IopGetDeviceResourcesFromRegistry(
  1029. DeviceObject,
  1030. QUERY_RESOURCE_LIST,
  1031. REGISTRY_FORCED_CONFIG,
  1032. Resource,
  1033. &junk);
  1034. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1035. status = IopGetDeviceResourcesFromRegistry(
  1036. DeviceObject,
  1037. QUERY_RESOURCE_REQUIREMENTS,
  1038. REGISTRY_OVERRIDE_CONFIGVECTOR,
  1039. &resReqList,
  1040. &junk);
  1041. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1042. if (deviceNode->Flags & DNF_MADEUP) {
  1043. status = IopGetDeviceResourcesFromRegistry(
  1044. DeviceObject,
  1045. QUERY_RESOURCE_REQUIREMENTS,
  1046. REGISTRY_BASIC_CONFIGVECTOR,
  1047. &resReqList,
  1048. &junk);
  1049. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1050. status = STATUS_SUCCESS;
  1051. resReqList = NULL;
  1052. }
  1053. } else {
  1054. //
  1055. // We are going to ask the bus driver ...
  1056. //
  1057. if (deviceNode->ResourceRequirements) {
  1058. ASSERT(deviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED);
  1059. resReqList = ExAllocatePool(PagedPool, deviceNode->ResourceRequirements->ListSize);
  1060. if (resReqList) {
  1061. RtlCopyMemory(resReqList,
  1062. deviceNode->ResourceRequirements,
  1063. deviceNode->ResourceRequirements->ListSize
  1064. );
  1065. status = STATUS_SUCCESS;
  1066. } else {
  1067. return STATUS_NO_MEMORY;
  1068. }
  1069. } else {
  1070. status = PpIrpQueryResourceRequirements(DeviceObject, &resReqList);
  1071. if (status == STATUS_NOT_SUPPORTED) {
  1072. //
  1073. // If driver doesn't implement this request, it
  1074. // doesn't require any resources.
  1075. //
  1076. status = STATUS_SUCCESS;
  1077. resReqList = NULL;
  1078. }
  1079. }
  1080. }
  1081. if (!NT_SUCCESS(status)) {
  1082. return status;
  1083. }
  1084. }
  1085. //
  1086. // For devices with boot config, we need to filter the resource requirements
  1087. // list against boot config.
  1088. //
  1089. status = IopGetDeviceResourcesFromRegistry(
  1090. DeviceObject,
  1091. QUERY_RESOURCE_LIST,
  1092. REGISTRY_BOOT_CONFIG,
  1093. &cmList,
  1094. &junk);
  1095. if (NT_SUCCESS(status) &&
  1096. (!cmList || cmList->Count == 0 || cmList->List[0].InterfaceType != PCIBus)) {
  1097. status = IopFilterResourceRequirementsList (
  1098. resReqList,
  1099. cmList,
  1100. &filteredList,
  1101. &exactMatch);
  1102. if (cmList) {
  1103. ExFreePool(cmList);
  1104. }
  1105. if (!NT_SUCCESS(status)) {
  1106. if (resReqList) {
  1107. ExFreePool(resReqList);
  1108. }
  1109. return status;
  1110. } else {
  1111. //
  1112. // For non-root-enumerated devices, we merge filtered config with basic config
  1113. // vectors to form a new res req list. For root-enumerated devices, we don't
  1114. // consider Basic config vector.
  1115. //
  1116. if (!(deviceNode->Flags & DNF_MADEUP) &&
  1117. (exactMatch == FALSE || resReqList->AlternativeLists > 1)) {
  1118. status = IopMergeFilteredResourceRequirementsList (
  1119. filteredList,
  1120. resReqList,
  1121. &mergedList
  1122. );
  1123. if (resReqList) {
  1124. ExFreePool(resReqList);
  1125. }
  1126. if (filteredList) {
  1127. ExFreePool(filteredList);
  1128. }
  1129. if (NT_SUCCESS(status)) {
  1130. resReqList = mergedList;
  1131. } else {
  1132. return status;
  1133. }
  1134. } else {
  1135. if (resReqList) {
  1136. ExFreePool(resReqList);
  1137. }
  1138. resReqList = filteredList;
  1139. }
  1140. }
  1141. }
  1142. } else {
  1143. ASSERT(NT_SUCCESS(status));
  1144. //
  1145. // We have Forced Config. Convert it to resource requirements and return it.
  1146. //
  1147. if (*Resource) {
  1148. resReqList = IopCmResourcesToIoResources (0, (PCM_RESOURCE_LIST)*Resource, LCPRI_FORCECONFIG);
  1149. ExFreePool(*Resource);
  1150. if (resReqList) {
  1151. *Resource = (PVOID)resReqList;
  1152. *Length = resReqList->ListSize;
  1153. } else {
  1154. *Resource = NULL;
  1155. *Length = 0;
  1156. status = STATUS_INSUFFICIENT_RESOURCES;
  1157. return status;
  1158. }
  1159. } else {
  1160. resReqList = NULL;
  1161. }
  1162. }
  1163. //
  1164. // If we are here, we have a resource requirements list for drivers to examine ...
  1165. // NOTE: Per Lonny's request, we let drivers filter ForcedConfig
  1166. //
  1167. status = IopFilterResourceRequirementsCall(
  1168. DeviceObject,
  1169. resReqList,
  1170. &newResources
  1171. );
  1172. if (NT_SUCCESS(status)) {
  1173. UNICODE_STRING unicodeName;
  1174. HANDLE handle, handlex;
  1175. #if DBG
  1176. if (newResources == NULL && resReqList) {
  1177. DbgPrint("PnpMgr: Non-NULL resource requirements list filtered to NULL\n");
  1178. }
  1179. #endif
  1180. if (newResources) {
  1181. *Length = newResources->ListSize;
  1182. ASSERT(*Length);
  1183. //
  1184. // Make our own copy of the allocation. We do this so that the
  1185. // verifier doesn't believe the driver has leaked memory if
  1186. // unloaded.
  1187. //
  1188. *Resource = (PVOID) ExAllocatePool(PagedPool, *Length);
  1189. if (*Resource == NULL) {
  1190. ExFreePool(newResources);
  1191. return STATUS_INSUFFICIENT_RESOURCES;
  1192. }
  1193. RtlCopyMemory(*Resource, newResources, *Length);
  1194. ExFreePool(newResources);
  1195. } else {
  1196. *Length = 0;
  1197. *Resource = NULL;
  1198. }
  1199. //
  1200. // Write filtered res req to registry
  1201. //
  1202. status = IopDeviceObjectToDeviceInstance(DeviceObject, &handlex, KEY_ALL_ACCESS);
  1203. if (NT_SUCCESS(status)) {
  1204. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_CONTROL);
  1205. status = IopOpenRegistryKeyEx( &handle,
  1206. handlex,
  1207. &unicodeName,
  1208. KEY_READ
  1209. );
  1210. if (NT_SUCCESS(status)) {
  1211. PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_FILTERED_CONFIG_VECTOR);
  1212. ZwSetValueKey(handle,
  1213. &unicodeName,
  1214. TITLE_INDEX_VALUE,
  1215. REG_RESOURCE_REQUIREMENTS_LIST,
  1216. *Resource,
  1217. *Length
  1218. );
  1219. ZwClose(handle);
  1220. ZwClose(handlex);
  1221. }
  1222. }
  1223. } else {
  1224. //
  1225. // NTRAID #61058-2001/01/05 - ADRIAO
  1226. // We might want to consider bubbling up
  1227. // non-STATUS_NOT_SUPPORTED failure codes and fail the entire
  1228. // devnode if one is seen.
  1229. //
  1230. ASSERT(status == STATUS_NOT_SUPPORTED);
  1231. *Resource = resReqList;
  1232. if (resReqList) {
  1233. *Length = resReqList->ListSize;
  1234. } else {
  1235. *Length = 0;
  1236. }
  1237. }
  1238. return STATUS_SUCCESS;
  1239. }
  1240. }
  1241. NTSTATUS
  1242. IopQueryResourceHandlerInterface(
  1243. IN RESOURCE_HANDLER_TYPE HandlerType,
  1244. IN PDEVICE_OBJECT DeviceObject,
  1245. IN UCHAR ResourceType,
  1246. IN OUT PVOID *Interface
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. This routine queries the specified DeviceObject for the specified ResourceType
  1251. resource translator.
  1252. Parameters:
  1253. HandlerType - specifies Arbiter or Translator
  1254. DeviceObject - Supplies a pointer to the Device object to be queried.
  1255. ResourceType - Specifies the desired type of translator.
  1256. Interface - supplies a variable to receive the desired interface.
  1257. Return Value:
  1258. Status code that indicates whether or not the function was successful.
  1259. --*/
  1260. {
  1261. IO_STACK_LOCATION irpSp;
  1262. NTSTATUS status;
  1263. PINTERFACE interface;
  1264. USHORT size;
  1265. GUID interfaceType;
  1266. PDEVICE_NODE deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  1267. PAGED_CODE();
  1268. //
  1269. // If this device object is created by pnp mgr for legacy resource allocation,
  1270. // skip it.
  1271. //
  1272. if ((deviceNode->DuplicatePDO == (PDEVICE_OBJECT) DeviceObject->DriverObject) ||
  1273. !(DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE)) {
  1274. return STATUS_NOT_SUPPORTED;
  1275. }
  1276. switch (HandlerType) {
  1277. case ResourceTranslator:
  1278. size = sizeof(TRANSLATOR_INTERFACE) + 4; // Pnptest
  1279. //size = sizeof(TRANSLATOR_INTERFACE);
  1280. interfaceType = GUID_TRANSLATOR_INTERFACE_STANDARD;
  1281. break;
  1282. case ResourceArbiter:
  1283. size = sizeof(ARBITER_INTERFACE);
  1284. interfaceType = GUID_ARBITER_INTERFACE_STANDARD;
  1285. break;
  1286. case ResourceLegacyDeviceDetection:
  1287. size = sizeof(LEGACY_DEVICE_DETECTION_INTERFACE);
  1288. interfaceType = GUID_LEGACY_DEVICE_DETECTION_STANDARD;
  1289. break;
  1290. default:
  1291. return STATUS_INVALID_PARAMETER;
  1292. }
  1293. interface = (PINTERFACE) ExAllocatePool(PagedPool, size);
  1294. if (interface == NULL) {
  1295. return STATUS_INSUFFICIENT_RESOURCES;
  1296. }
  1297. RtlZeroMemory(interface, size);
  1298. interface->Size = size;
  1299. //
  1300. // Initialize the stack location to pass to IopSynchronousCall()
  1301. //
  1302. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1303. //
  1304. // Set the function codes.
  1305. //
  1306. irpSp.MajorFunction = IRP_MJ_PNP;
  1307. irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
  1308. //
  1309. // Set the pointer to the resource list
  1310. //
  1311. irpSp.Parameters.QueryInterface.InterfaceType = &interfaceType;
  1312. irpSp.Parameters.QueryInterface.Size = interface->Size;
  1313. irpSp.Parameters.QueryInterface.Version = interface->Version = 0;
  1314. irpSp.Parameters.QueryInterface.Interface = interface;
  1315. irpSp.Parameters.QueryInterface.InterfaceSpecificData = (PVOID) (ULONG_PTR) ResourceType;
  1316. //
  1317. // Make the call and return.
  1318. //
  1319. status = IopSynchronousCall(DeviceObject, &irpSp, NULL);
  1320. if (NT_SUCCESS(status)) {
  1321. switch (HandlerType) {
  1322. case ResourceTranslator:
  1323. if ( ((PTRANSLATOR_INTERFACE)interface)->TranslateResources == NULL ||
  1324. ((PTRANSLATOR_INTERFACE)interface)->TranslateResourceRequirements == NULL) {
  1325. IopDbgPrint((IOP_ERROR_LEVEL,
  1326. "!devstack %p returned success for IRP_MN_QUERY_INTERFACE (GUID_TRANSLATOR_INTERFACE_STANDARD) but did not fill in the required data\n",
  1327. DeviceObject));
  1328. ASSERT(!NT_SUCCESS(status));
  1329. status = STATUS_UNSUCCESSFUL;
  1330. }
  1331. break;
  1332. case ResourceArbiter:
  1333. if (((PARBITER_INTERFACE)interface)->ArbiterHandler == NULL) {
  1334. IopDbgPrint((IOP_ERROR_LEVEL,
  1335. "!devstack %p returned success for IRP_MN_QUERY_INTERFACE (GUID_ARBITER_INTERFACE_STANDARD) but did not fill in the required data\n",
  1336. DeviceObject));
  1337. ASSERT(!NT_SUCCESS(status));
  1338. status = STATUS_UNSUCCESSFUL;
  1339. }
  1340. break;
  1341. case ResourceLegacyDeviceDetection:
  1342. if (((PLEGACY_DEVICE_DETECTION_INTERFACE)interface)->LegacyDeviceDetection == NULL) {
  1343. IopDbgPrint((IOP_ERROR_LEVEL,
  1344. "!devstack %p returned success for IRP_MN_QUERY_INTERFACE (GUID_LEGACY_DEVICE_DETECTION_STANDARD) but did not fill in the required data\n",
  1345. DeviceObject));
  1346. ASSERT(!NT_SUCCESS(status));
  1347. status = STATUS_UNSUCCESSFUL;
  1348. }
  1349. break;
  1350. default:
  1351. //
  1352. // This should never happen.
  1353. //
  1354. IopDbgPrint((IOP_ERROR_LEVEL,
  1355. "IopQueryResourceHandlerInterface: Possible stack corruption\n"));
  1356. ASSERT(0);
  1357. status = STATUS_INVALID_PARAMETER;
  1358. break;
  1359. }
  1360. }
  1361. if (NT_SUCCESS(status)) {
  1362. *Interface = interface;
  1363. } else {
  1364. ExFreePool(interface);
  1365. }
  1366. return status;
  1367. }
  1368. NTSTATUS
  1369. IopQueryReconfiguration(
  1370. IN UCHAR Request,
  1371. IN PDEVICE_OBJECT DeviceObject
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This routine queries the specified DeviceObject for the specified ResourceType
  1376. resource translator.
  1377. Parameters:
  1378. HandlerType - specifies Arbiter or Translator
  1379. DeviceObject - Supplies a pointer to the Device object to be queried.
  1380. ResourceType - Specifies the desired type of translator.
  1381. Interface - supplies a variable to receive the desired interface.
  1382. Return Value:
  1383. Status code that indicates whether or not the function was successful.
  1384. --*/
  1385. {
  1386. IO_STACK_LOCATION irpSp;
  1387. NTSTATUS status;
  1388. PDEVICE_NODE deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
  1389. PAGED_CODE();
  1390. switch (Request) {
  1391. case IRP_MN_QUERY_STOP_DEVICE:
  1392. if (deviceNode->State != DeviceNodeStarted) {
  1393. IopDbgPrint(( IOP_RESOURCE_ERROR_LEVEL,
  1394. "An attempt made to send IRP_MN_QUERY_STOP_DEVICE to an unstarted device %wZ!\n",
  1395. &deviceNode->InstancePath));
  1396. ASSERT(0);
  1397. return STATUS_UNSUCCESSFUL;
  1398. }
  1399. break;
  1400. case IRP_MN_STOP_DEVICE:
  1401. //
  1402. // Fall through
  1403. //
  1404. if (deviceNode->State != DeviceNodeQueryStopped) {
  1405. IopDbgPrint(( IOP_RESOURCE_ERROR_LEVEL,
  1406. "An attempt made to send IRP_MN_STOP_DEVICE to an unqueried device %wZ!\n",
  1407. &deviceNode->InstancePath));
  1408. ASSERT(0);
  1409. return STATUS_UNSUCCESSFUL;
  1410. }
  1411. break;
  1412. case IRP_MN_CANCEL_STOP_DEVICE:
  1413. if ( deviceNode->State != DeviceNodeQueryStopped &&
  1414. deviceNode->State != DeviceNodeStarted) {
  1415. IopDbgPrint(( IOP_RESOURCE_ERROR_LEVEL,
  1416. "An attempt made to send IRP_MN_CANCEL_STOP_DEVICE to an unqueried\\unstarted device %wZ!\n",
  1417. &deviceNode->InstancePath));
  1418. ASSERT(0);
  1419. return STATUS_UNSUCCESSFUL;
  1420. }
  1421. break;
  1422. default:
  1423. ASSERT(0);
  1424. return STATUS_UNSUCCESSFUL;
  1425. }
  1426. //
  1427. // Initialize the stack location to pass to IopSynchronousCall()
  1428. //
  1429. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1430. //
  1431. // Set the function codes.
  1432. //
  1433. irpSp.MajorFunction = IRP_MJ_PNP;
  1434. irpSp.MinorFunction = Request;
  1435. //
  1436. // Make the call and return.
  1437. //
  1438. status = IopSynchronousCall(DeviceObject, &irpSp, NULL);
  1439. return status;
  1440. }
  1441. NTSTATUS
  1442. IopQueryLegacyBusInformation (
  1443. IN PDEVICE_OBJECT DeviceObject,
  1444. OUT LPGUID InterfaceGuid, OPTIONAL
  1445. OUT INTERFACE_TYPE *InterfaceType, OPTIONAL
  1446. OUT ULONG *BusNumber OPTIONAL
  1447. )
  1448. /*++
  1449. Routine Description:
  1450. This routine queries the specified DeviceObject for its legacy bus
  1451. information.
  1452. Parameters:
  1453. DeviceObject - The device object to be queried.
  1454. InterfaceGuid = Supplies a pointer to receive the device's interface type
  1455. GUID.
  1456. Interface = Supplies a pointer to receive the device's interface type.
  1457. BusNumber = Supplies a pointer to receive the device's bus number.
  1458. Return Value:
  1459. Returns NTSTATUS.
  1460. --*/
  1461. {
  1462. IO_STACK_LOCATION irpSp;
  1463. NTSTATUS status;
  1464. PLEGACY_BUS_INFORMATION busInfo;
  1465. PAGED_CODE();
  1466. //
  1467. // Initialize the stack location to pass to IopSynchronousCall()
  1468. //
  1469. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1470. //
  1471. // Set the function codes.
  1472. //
  1473. irpSp.MajorFunction = IRP_MJ_PNP;
  1474. irpSp.MinorFunction = IRP_MN_QUERY_LEGACY_BUS_INFORMATION;
  1475. //
  1476. // Make the call and return.
  1477. //
  1478. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)&busInfo);
  1479. if (NT_SUCCESS(status)) {
  1480. if (busInfo == NULL) {
  1481. //
  1482. // The device driver LIED to us. Bad, bad, bad device driver.
  1483. //
  1484. PDEVICE_NODE deviceNode;
  1485. deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode;
  1486. if (deviceNode && deviceNode->ServiceName.Buffer) {
  1487. DbgPrint("*** IopQueryLegacyBusInformation - Driver %wZ returned STATUS_SUCCESS\n", &deviceNode->ServiceName);
  1488. DbgPrint(" for IRP_MN_QUERY_LEGACY_BUS_INFORMATION, and a NULL POINTER.\n");
  1489. }
  1490. ASSERT(busInfo != NULL);
  1491. } else {
  1492. if (ARGUMENT_PRESENT(InterfaceGuid)) {
  1493. *InterfaceGuid = busInfo->BusTypeGuid;
  1494. }
  1495. if (ARGUMENT_PRESENT(InterfaceType)) {
  1496. *InterfaceType = busInfo->LegacyBusType;
  1497. }
  1498. if (ARGUMENT_PRESENT(BusNumber)) {
  1499. *BusNumber = busInfo->BusNumber;
  1500. }
  1501. ExFreePool(busInfo);
  1502. }
  1503. }
  1504. return status;
  1505. }
  1506. NTSTATUS
  1507. IopQueryPnpBusInformation (
  1508. IN PDEVICE_OBJECT DeviceObject,
  1509. OUT LPGUID InterfaceGuid, OPTIONAL
  1510. OUT INTERFACE_TYPE *InterfaceType, OPTIONAL
  1511. OUT ULONG *BusNumber OPTIONAL
  1512. )
  1513. /*++
  1514. Routine Description:
  1515. This routine queries the specified DeviceObject for the specified ResourceType
  1516. resource translator.
  1517. Parameters:
  1518. HandlerType - specifies Arbiter or Translator
  1519. DeviceObject - Supplies a pointer to the Device object to be queried.
  1520. ResourceType - Specifies the desired type of translator.
  1521. Interface - supplies a variable to receive the desired interface.
  1522. Return Value:
  1523. Status code that indicates whether or not the function was successful.
  1524. --*/
  1525. {
  1526. IO_STACK_LOCATION irpSp;
  1527. NTSTATUS status;
  1528. PPNP_BUS_INFORMATION busInfo;
  1529. PAGED_CODE();
  1530. //
  1531. // Initialize the stack location to pass to IopSynchronousCall()
  1532. //
  1533. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1534. //
  1535. // Set the function codes.
  1536. //
  1537. irpSp.MajorFunction = IRP_MJ_PNP;
  1538. irpSp.MinorFunction = IRP_MN_QUERY_BUS_INFORMATION;
  1539. //
  1540. // Make the call and return.
  1541. //
  1542. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)&busInfo);
  1543. if (NT_SUCCESS(status)) {
  1544. if (busInfo == NULL) {
  1545. //
  1546. // The device driver LIED to us. Bad, bad, bad device driver.
  1547. //
  1548. PDEVICE_NODE deviceNode;
  1549. deviceNode = DeviceObject->DeviceObjectExtension->DeviceNode;
  1550. if (deviceNode && deviceNode->ServiceName.Buffer) {
  1551. DbgPrint("*** IopQueryPnpBusInformation - Driver %wZ returned STATUS_SUCCESS\n", &deviceNode->ServiceName);
  1552. DbgPrint(" for IRP_MN_QUERY_BUS_INFORMATION, and a NULL POINTER.\n");
  1553. }
  1554. ASSERT(busInfo != NULL);
  1555. } else {
  1556. if (ARGUMENT_PRESENT(InterfaceGuid)) {
  1557. *InterfaceGuid = busInfo->BusTypeGuid;
  1558. }
  1559. if (ARGUMENT_PRESENT(InterfaceType)) {
  1560. *InterfaceType = busInfo->LegacyBusType;
  1561. }
  1562. if (ARGUMENT_PRESENT(BusNumber)) {
  1563. *BusNumber = busInfo->BusNumber;
  1564. }
  1565. ExFreePool(busInfo);
  1566. }
  1567. }
  1568. return status;
  1569. }
  1570. NTSTATUS
  1571. IopQueryDeviceState(
  1572. IN PDEVICE_OBJECT DeviceObject,
  1573. OUT PPNP_DEVICE_STATE DeviceState
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. This routine sends query device state irp to the specified device object.
  1578. Parameters:
  1579. DeviceObjet - Supplies the device object of the device being queried.
  1580. Return Value:
  1581. NTSTATUS code.
  1582. --*/
  1583. {
  1584. IO_STACK_LOCATION irpSp;
  1585. PDEVICE_NODE deviceNode;
  1586. ULONG_PTR stateValue;
  1587. NTSTATUS status;
  1588. PAGED_CODE();
  1589. //
  1590. // Initialize the stack location to pass to IopSynchronousCall()
  1591. //
  1592. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1593. //
  1594. // Set the function codes.
  1595. //
  1596. irpSp.MajorFunction = IRP_MJ_PNP;
  1597. irpSp.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
  1598. //
  1599. // Make the call.
  1600. //
  1601. status = IopSynchronousCall(DeviceObject, &irpSp, &stateValue);
  1602. //
  1603. // Now perform the appropriate action based on the returned state
  1604. //
  1605. if (NT_SUCCESS(status)) {
  1606. *DeviceState = (PNP_DEVICE_STATE)stateValue;
  1607. }
  1608. return status;
  1609. }
  1610. VOID
  1611. IopIncDisableableDepends(
  1612. IN OUT PDEVICE_NODE DeviceNode
  1613. )
  1614. /*++
  1615. Routine Description:
  1616. Increments the DisableableDepends field of this devicenode
  1617. and potentially every parent device node up the tree
  1618. A parent devicenode is only incremented if the child in question
  1619. is incremented from 0 to 1
  1620. Parameters:
  1621. DeviceNode - Supplies the device node where the depends is to be incremented
  1622. Return Value:
  1623. none.
  1624. --*/
  1625. {
  1626. while (DeviceNode != NULL) {
  1627. LONG newval;
  1628. newval = InterlockedIncrement((PLONG)&DeviceNode->DisableableDepends);
  1629. if (newval != 1) {
  1630. //
  1631. // we were already non-disableable, so we don't have to bother parent
  1632. //
  1633. break;
  1634. }
  1635. DeviceNode = DeviceNode ->Parent;
  1636. }
  1637. }
  1638. VOID
  1639. IopDecDisableableDepends(
  1640. IN OUT PDEVICE_NODE DeviceNode
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. Decrements the DisableableDepends field of this devicenode
  1645. and potentially every parent device node up the tree
  1646. A parent devicenode is only decremented if the child in question
  1647. is decremented from 1 to 0
  1648. Parameters:
  1649. DeviceNode - Supplies the device node where the depends is to be decremented
  1650. Return Value:
  1651. none.
  1652. --*/
  1653. {
  1654. while (DeviceNode != NULL) {
  1655. LONG newval;
  1656. newval = InterlockedDecrement((PLONG)&DeviceNode->DisableableDepends);
  1657. if (newval != 0) {
  1658. //
  1659. // we are still non-disableable, so we don't have to bother parent
  1660. //
  1661. break;
  1662. }
  1663. DeviceNode = DeviceNode ->Parent;
  1664. }
  1665. }
  1666. NTSTATUS
  1667. IopFilterResourceRequirementsCall(
  1668. IN PDEVICE_OBJECT DeviceObject,
  1669. IN PIO_RESOURCE_REQUIREMENTS_LIST ResReqList OPTIONAL,
  1670. OUT PVOID *Information
  1671. )
  1672. /*++
  1673. Routine Description:
  1674. This function sends a synchronous filter resource requirements irp to the
  1675. top level device object which roots on DeviceObject.
  1676. Parameters:
  1677. DeviceObject - Supplies the device object of the device being removed.
  1678. ResReqList - Supplies a pointer to the resource requirements requiring
  1679. filtering.
  1680. Information - Supplies a pointer to a variable that receives the returned
  1681. information of the irp.
  1682. Return Value:
  1683. NTSTATUS code.
  1684. --*/
  1685. {
  1686. PIRP irp;
  1687. PIO_STACK_LOCATION irpSp;
  1688. IO_STATUS_BLOCK statusBlock;
  1689. KEVENT event;
  1690. NTSTATUS status;
  1691. PULONG_PTR returnInfo = (PULONG_PTR)Information;
  1692. PDEVICE_OBJECT deviceObject;
  1693. PAGED_CODE();
  1694. //
  1695. // Get a pointer to the topmost device object in the stack of devices,
  1696. // beginning with the deviceObject.
  1697. //
  1698. deviceObject = IoGetAttachedDevice(DeviceObject);
  1699. //
  1700. // Begin by allocating the IRP for this request. Do not charge quota to
  1701. // the current process for this IRP.
  1702. //
  1703. irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
  1704. if (irp == NULL){
  1705. return STATUS_INSUFFICIENT_RESOURCES;
  1706. }
  1707. SPECIALIRP_WATERMARK_IRP(irp, IRP_SYSTEM_RESTRICTED);
  1708. //
  1709. // Initialize it to success. This is a special hack for WDM (ie 9x)
  1710. // compatibility. The driver verifier is in on this one.
  1711. //
  1712. if (ResReqList) {
  1713. irp->IoStatus.Status = statusBlock.Status = STATUS_SUCCESS;
  1714. irp->IoStatus.Information = statusBlock.Information = (ULONG_PTR) ResReqList;
  1715. } else {
  1716. irp->IoStatus.Status = statusBlock.Status = STATUS_NOT_SUPPORTED;
  1717. }
  1718. //
  1719. // Set the pointer to the status block and initialized event.
  1720. //
  1721. KeInitializeEvent( &event,
  1722. SynchronizationEvent,
  1723. FALSE );
  1724. irp->UserIosb = &statusBlock;
  1725. irp->UserEvent = &event;
  1726. //
  1727. // Set the address of the current thread
  1728. //
  1729. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1730. //
  1731. // Queue this irp onto the current thread
  1732. //
  1733. IopQueueThreadIrp(irp);
  1734. //
  1735. // Get a pointer to the stack location of the first driver which will be
  1736. // invoked. This is where the function codes and parameters are set.
  1737. //
  1738. irpSp = IoGetNextIrpStackLocation(irp);
  1739. //
  1740. // Setup the stack location contents
  1741. //
  1742. irpSp->MinorFunction = IRP_MN_FILTER_RESOURCE_REQUIREMENTS;
  1743. irpSp->MajorFunction = IRP_MJ_PNP;
  1744. irpSp->Parameters.FilterResourceRequirements.IoResourceRequirementList = ResReqList;
  1745. //
  1746. // Call the driver
  1747. //
  1748. status = IoCallDriver(deviceObject, irp);
  1749. PnpIrpStatusTracking(status, IRP_MN_FILTER_RESOURCE_REQUIREMENTS, deviceObject);
  1750. //
  1751. // If a driver returns STATUS_PENDING, we will wait for it to complete
  1752. //
  1753. if (status == STATUS_PENDING) {
  1754. (VOID) KeWaitForSingleObject( &event,
  1755. Executive,
  1756. KernelMode,
  1757. FALSE,
  1758. (PLARGE_INTEGER) NULL );
  1759. status = statusBlock.Status;
  1760. }
  1761. *returnInfo = (ULONG_PTR) statusBlock.Information;
  1762. return status;
  1763. }
  1764. NTSTATUS
  1765. IopQueryDockRemovalInterface(
  1766. IN PDEVICE_OBJECT DeviceObject,
  1767. IN OUT PDOCK_INTERFACE *DockInterface
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. This routine queries the specified DeviceObject for the dock removal
  1772. interface. We use this interface to send pseudo-remove's. We use this
  1773. to solve the removal orderings problem.
  1774. Parameters:
  1775. DeviceObject - Supplies a pointer to the Device object to be queried.
  1776. Interface - supplies a variable to receive the desired interface.
  1777. Return Value:
  1778. Status code that indicates whether or not the function was successful.
  1779. --*/
  1780. {
  1781. IO_STACK_LOCATION irpSp;
  1782. NTSTATUS status;
  1783. PINTERFACE interface;
  1784. USHORT size;
  1785. GUID interfaceType;
  1786. PAGED_CODE();
  1787. size = sizeof(DOCK_INTERFACE);
  1788. interfaceType = GUID_DOCK_INTERFACE;
  1789. interface = (PINTERFACE) ExAllocatePool(PagedPool, size);
  1790. if (interface == NULL) {
  1791. return STATUS_INSUFFICIENT_RESOURCES;
  1792. }
  1793. RtlZeroMemory(interface, size);
  1794. interface->Size = size;
  1795. //
  1796. // Initialize the stack location to pass to IopSynchronousCall()
  1797. //
  1798. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1799. //
  1800. // Set the function codes.
  1801. //
  1802. irpSp.MajorFunction = IRP_MJ_PNP;
  1803. irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
  1804. //
  1805. // Set the pointer to the resource list
  1806. //
  1807. irpSp.Parameters.QueryInterface.InterfaceType = &interfaceType;
  1808. irpSp.Parameters.QueryInterface.Size = interface->Size;
  1809. irpSp.Parameters.QueryInterface.Version = interface->Version = 0;
  1810. irpSp.Parameters.QueryInterface.Interface = interface;
  1811. irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1812. //
  1813. // Make the call and return.
  1814. //
  1815. status = IopSynchronousCall(DeviceObject, &irpSp, NULL);
  1816. if (NT_SUCCESS(status)) {
  1817. *DockInterface = (PDOCK_INTERFACE) interface;
  1818. } else {
  1819. ExFreePool(interface);
  1820. }
  1821. return status;
  1822. }
  1823. NTSTATUS
  1824. PpIrpQueryResourceRequirements(
  1825. IN PDEVICE_OBJECT DeviceObject,
  1826. OUT PIO_RESOURCE_REQUIREMENTS_LIST *Requirements
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine will issue IRP_MN_QUERY_RESOURCE_REQUIREMENTS to the
  1831. DeviceObject to retrieve its resource requirements. If this routine
  1832. failes, Requirements will be set to NULL.
  1833. Arguments:
  1834. DeviceObject - The device object the request should be sent to.
  1835. Requirements - Receives the requirements returned by the driver if any.
  1836. The caller is expected to free the storage for Requirements on success.
  1837. Return Value:
  1838. NTSTATUS.
  1839. --*/
  1840. {
  1841. IO_STACK_LOCATION irpSp;
  1842. NTSTATUS status;
  1843. PAGED_CODE();
  1844. *Requirements = NULL;
  1845. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1846. irpSp.MajorFunction = IRP_MJ_PNP;
  1847. irpSp.MinorFunction = IRP_MN_QUERY_RESOURCE_REQUIREMENTS;
  1848. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)Requirements);
  1849. ASSERT(NT_SUCCESS(status) || (*Requirements == NULL));
  1850. if (NT_SUCCESS(status)) {
  1851. if(*Requirements == NULL) {
  1852. status = STATUS_NOT_SUPPORTED;
  1853. }
  1854. } else {
  1855. *Requirements = NULL;
  1856. }
  1857. return status;
  1858. }
  1859. #if FAULT_INJECT_INVALID_ID
  1860. //
  1861. // Fault injection for invalid IDs
  1862. //
  1863. ULONG PiFailQueryID = 0;
  1864. #endif
  1865. NTSTATUS
  1866. PpIrpQueryID(
  1867. IN PDEVICE_OBJECT DeviceObject,
  1868. IN BUS_QUERY_ID_TYPE IDType,
  1869. OUT PWCHAR *ID
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. This routine will issue IRP_MN_QUERY_ID to the DeviceObject
  1874. to retrieve the specified ID. If this routine fails, ID will
  1875. be set to NULL.
  1876. Arguments:
  1877. DeviceObject - The device object the request should be sent to.
  1878. IDType - Type of ID to be queried.
  1879. ID - Receives the ID returned by the driver if any. The caller
  1880. is expected to free the storage for ID on success.
  1881. Return Value:
  1882. NTSTATUS.
  1883. --*/
  1884. {
  1885. IO_STACK_LOCATION irpSp;
  1886. NTSTATUS status;
  1887. PAGED_CODE();
  1888. ASSERT(IDType == BusQueryDeviceID || IDType == BusQueryInstanceID ||
  1889. IDType == BusQueryHardwareIDs || IDType == BusQueryCompatibleIDs ||
  1890. IDType == BusQueryDeviceSerialNumber);
  1891. *ID = NULL;
  1892. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1893. irpSp.MajorFunction = IRP_MJ_PNP;
  1894. irpSp.MinorFunction = IRP_MN_QUERY_ID;
  1895. irpSp.Parameters.QueryId.IdType = IDType;
  1896. status = IopSynchronousCall(DeviceObject, &irpSp, (PULONG_PTR)ID);
  1897. ASSERT(NT_SUCCESS(status) || (*ID == NULL));
  1898. if (NT_SUCCESS(status)) {
  1899. if(*ID == NULL) {
  1900. status = STATUS_NOT_SUPPORTED;
  1901. }
  1902. } else {
  1903. *ID = NULL;
  1904. }
  1905. #if FAULT_INJECT_INVALID_ID
  1906. //
  1907. // Fault injection for invalid IDs
  1908. //
  1909. if (*ID){
  1910. static LARGE_INTEGER seed = {0};
  1911. if(seed.LowPart == 0) {
  1912. KeQuerySystemTime(&seed);
  1913. }
  1914. if(PnPBootDriversInitialized && PiFailQueryID && RtlRandom(&seed.LowPart) % 10 > 7) {
  1915. **ID = L',';
  1916. }
  1917. }
  1918. #endif
  1919. return status;
  1920. }