Leaked source code of windows server 2003
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.

2561 lines
70 KiB

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