1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/iomgr/device.c 5 * PURPOSE: Device Object Management, including Notifications and Queues. 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Filip Navara (navaraf@reactos.org) 8 * Hervé Poussineau (hpoussin@reactos.org) 9 */ 10 11 /* INCLUDES *******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* GLOBALS ********************************************************************/ 18 19 ULONG IopDeviceObjectNumber = 0; 20 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead; 21 KSPIN_LOCK ShutdownListLock; 22 extern LIST_ENTRY IopDiskFileSystemQueueHead; 23 extern LIST_ENTRY IopCdRomFileSystemQueueHead; 24 extern LIST_ENTRY IopTapeFileSystemQueueHead; 25 extern ERESOURCE IopDatabaseResource; 26 27 /* PRIVATE FUNCTIONS **********************************************************/ 28 29 VOID 30 NTAPI 31 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver) 32 { 33 PDEVICE_OBJECT DeviceObject; 34 PAGED_CODE(); 35 36 /* Set the driver as initialized */ 37 Driver->Flags |= DRVO_INITIALIZED; 38 DeviceObject = Driver->DeviceObject; 39 while (DeviceObject) 40 { 41 /* Set every device as initialized too */ 42 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 43 DeviceObject = DeviceObject->NextDevice; 44 } 45 } 46 47 VOID 48 NTAPI 49 IopDeleteDevice(IN PVOID ObjectBody) 50 { 51 PDEVICE_OBJECT DeviceObject = ObjectBody; 52 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject); 53 PAGED_CODE(); 54 55 /* Cleanup and free the device node */ 56 if (DeviceNode) 57 IopFreeDeviceNode(DeviceNode); 58 59 /* Dereference the driver object, referenced in IoCreateDevice */ 60 if (DeviceObject->DriverObject) 61 ObDereferenceObject(DeviceObject->DriverObject); 62 } 63 64 65 PDEVICE_OBJECT 66 NTAPI 67 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 68 IN PDEVICE_OBJECT TargetDevice, 69 OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL) 70 { 71 PDEVICE_OBJECT AttachedDevice; 72 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension; 73 74 /* Get the Attached Device and source extension */ 75 AttachedDevice = IoGetAttachedDevice(TargetDevice); 76 SourceDeviceExtension = IoGetDevObjExtension(SourceDevice); 77 ASSERT(SourceDeviceExtension->AttachedTo == NULL); 78 79 /* Make sure that it's in a correct state */ 80 if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) || 81 (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 82 (DOE_UNLOAD_PENDING | 83 DOE_DELETE_PENDING | 84 DOE_REMOVE_PENDING | 85 DOE_REMOVE_PROCESSED))) 86 { 87 /* Device was unloading or being removed */ 88 AttachedDevice = NULL; 89 } 90 else 91 { 92 /* Update atached device fields */ 93 AttachedDevice->AttachedDevice = SourceDevice; 94 AttachedDevice->Spare1++; 95 96 /* Update the source with the attached data */ 97 SourceDevice->StackSize = AttachedDevice->StackSize + 1; 98 SourceDevice->AlignmentRequirement = AttachedDevice-> 99 AlignmentRequirement; 100 SourceDevice->SectorSize = AttachedDevice->SectorSize; 101 102 /* Check for pending start flag */ 103 if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 104 DOE_START_PENDING) 105 { 106 /* Propagate */ 107 IoGetDevObjExtension(SourceDevice)->ExtensionFlags |= 108 DOE_START_PENDING; 109 } 110 111 /* Set the attachment in the device extension */ 112 SourceDeviceExtension->AttachedTo = AttachedDevice; 113 } 114 115 /* Return the attached device */ 116 if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice; 117 return AttachedDevice; 118 } 119 120 VOID 121 NTAPI 122 IoShutdownPnpDevices(VOID) 123 { 124 /* This routine is only used by Driver Verifier to validate shutdown */ 125 return; 126 } 127 128 VOID 129 NTAPI 130 IoShutdownSystem(IN ULONG Phase) 131 { 132 PLIST_ENTRY ListEntry; 133 PDEVICE_OBJECT DeviceObject; 134 PSHUTDOWN_ENTRY ShutdownEntry; 135 IO_STATUS_BLOCK StatusBlock; 136 PIRP Irp; 137 KEVENT Event; 138 NTSTATUS Status; 139 140 /* Initialize an event to wait on */ 141 KeInitializeEvent(&Event, NotificationEvent, FALSE); 142 143 /* What phase? */ 144 if (Phase == 0) 145 { 146 /* Shutdown PnP */ 147 IoShutdownPnpDevices(); 148 149 /* Loop first-chance shutdown notifications */ 150 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 151 &ShutdownListLock); 152 while (ListEntry) 153 { 154 /* Get the shutdown entry */ 155 ShutdownEntry = CONTAINING_RECORD(ListEntry, 156 SHUTDOWN_ENTRY, 157 ShutdownList); 158 159 /* Get the attached device */ 160 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 161 162 /* Build the shutdown IRP and call the driver */ 163 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 164 DeviceObject, 165 NULL, 166 0, 167 NULL, 168 &Event, 169 &StatusBlock); 170 if (Irp) 171 { 172 Status = IoCallDriver(DeviceObject, Irp); 173 if (Status == STATUS_PENDING) 174 { 175 /* Wait on the driver */ 176 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 177 } 178 } 179 180 /* Remove the flag */ 181 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 182 183 /* Get rid of our reference to it */ 184 ObDereferenceObject(ShutdownEntry->DeviceObject); 185 186 /* Free the shutdown entry and reset the event */ 187 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 188 KeClearEvent(&Event); 189 190 /* Go to the next entry */ 191 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 192 &ShutdownListLock); 193 } 194 } 195 else if (Phase == 1) 196 { 197 /* Acquire resource forever */ 198 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 199 200 /* Shutdown disk file systems */ 201 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead); 202 203 /* Shutdown cdrom file systems */ 204 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead); 205 206 /* Shutdown tape filesystems */ 207 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead); 208 209 /* Loop last-chance shutdown notifications */ 210 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 211 &ShutdownListLock); 212 while (ListEntry) 213 { 214 /* Get the shutdown entry */ 215 ShutdownEntry = CONTAINING_RECORD(ListEntry, 216 SHUTDOWN_ENTRY, 217 ShutdownList); 218 219 /* Get the attached device */ 220 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 221 222 /* Build the shutdown IRP and call the driver */ 223 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 224 DeviceObject, 225 NULL, 226 0, 227 NULL, 228 &Event, 229 &StatusBlock); 230 if (Irp) 231 { 232 Status = IoCallDriver(DeviceObject, Irp); 233 if (Status == STATUS_PENDING) 234 { 235 /* Wait on the driver */ 236 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 237 } 238 } 239 240 /* Remove the flag */ 241 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 242 243 /* Get rid of our reference to it */ 244 ObDereferenceObject(ShutdownEntry->DeviceObject); 245 246 /* Free the shutdown entry and reset the event */ 247 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 248 KeClearEvent(&Event); 249 250 /* Go to the next entry */ 251 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 252 &ShutdownListLock); 253 } 254 255 } 256 } 257 258 NTSTATUS 259 NTAPI 260 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 261 IN ACCESS_MASK DesiredAccess, 262 OUT PFILE_OBJECT *FileObject, 263 OUT PDEVICE_OBJECT *DeviceObject, 264 IN ULONG AttachFlag) 265 { 266 OBJECT_ATTRIBUTES ObjectAttributes; 267 IO_STATUS_BLOCK StatusBlock; 268 PFILE_OBJECT LocalFileObject; 269 HANDLE FileHandle; 270 NTSTATUS Status; 271 272 /* Open the Device */ 273 InitializeObjectAttributes(&ObjectAttributes, 274 ObjectName, 275 OBJ_KERNEL_HANDLE, 276 NULL, 277 NULL); 278 Status = ZwOpenFile(&FileHandle, 279 DesiredAccess, 280 &ObjectAttributes, 281 &StatusBlock, 282 0, 283 FILE_NON_DIRECTORY_FILE | AttachFlag); 284 if (!NT_SUCCESS(Status)) return Status; 285 286 /* Get File Object */ 287 Status = ObReferenceObjectByHandle(FileHandle, 288 0, 289 IoFileObjectType, 290 KernelMode, 291 (PVOID*)&LocalFileObject, 292 NULL); 293 if (NT_SUCCESS(Status)) 294 { 295 /* Return the requested data */ 296 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject); 297 *FileObject = LocalFileObject; 298 } 299 300 /* Close the handle */ 301 ZwClose(FileHandle); 302 303 return Status; 304 } 305 306 PDEVICE_OBJECT 307 NTAPI 308 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject) 309 { 310 PDEVICE_OBJECT LowestDevice; 311 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 312 313 /* Get the current device and its extension */ 314 LowestDevice = DeviceObject; 315 DeviceExtension = IoGetDevObjExtension(LowestDevice); 316 317 /* Keep looping as long as we're attached */ 318 while (DeviceExtension->AttachedTo) 319 { 320 /* Get the lowest device and its extension */ 321 LowestDevice = DeviceExtension->AttachedTo; 322 DeviceExtension = IoGetDevObjExtension(LowestDevice); 323 } 324 325 /* Return the lowest device */ 326 return LowestDevice; 327 } 328 329 VOID 330 NTAPI 331 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject, 332 IN PDEVICE_OBJECT DeviceObject, 333 IN IOP_DEVICE_LIST_OPERATION Type) 334 { 335 PDEVICE_OBJECT Previous; 336 KIRQL OldIrql; 337 338 /* Lock the Device list while we edit it */ 339 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 340 341 /* Check the type of operation */ 342 if (Type == IopRemove) 343 { 344 /* Get the current device and check if it's the current one */ 345 Previous = DeviceObject->DriverObject->DeviceObject; 346 if (Previous == DeviceObject) 347 { 348 /* It is, simply unlink this one directly */ 349 DeviceObject->DriverObject->DeviceObject = 350 DeviceObject->NextDevice; 351 } 352 else 353 { 354 /* It's not, so loop until we find the device */ 355 while (Previous->NextDevice != DeviceObject) 356 { 357 /* Not this one, keep moving */ 358 if (!Previous->NextDevice) 359 { 360 DPRINT1("Failed to remove PDO %p (not found)\n", 361 DeviceObject); 362 363 ASSERT(FALSE); 364 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 365 return; 366 } 367 Previous = Previous->NextDevice; 368 } 369 370 /* We found it, now unlink us */ 371 Previous->NextDevice = DeviceObject->NextDevice; 372 } 373 } 374 else 375 { 376 /* Link the device object and the driver object */ 377 DeviceObject->NextDevice = DriverObject->DeviceObject; 378 DriverObject->DeviceObject = DeviceObject; 379 } 380 381 /* Release the device list lock */ 382 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 383 } 384 385 VOID 386 NTAPI 387 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject) 388 { 389 PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject; 390 PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject); 391 392 /* Check if deletion is pending */ 393 if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING) 394 { 395 if (DeviceObject->AttachedDevice) 396 { 397 DPRINT("Device object is in the middle of a device stack\n"); 398 return; 399 } 400 401 if (DeviceObject->ReferenceCount) 402 { 403 DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount); 404 return; 405 } 406 407 /* Check if we have a Security Descriptor */ 408 if (DeviceObject->SecurityDescriptor) 409 { 410 /* Dereference it */ 411 ObDereferenceSecurityDescriptor(DeviceObject->SecurityDescriptor, 1); 412 } 413 414 /* Remove the device from the list */ 415 IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove); 416 417 /* Dereference the keep-alive */ 418 ObDereferenceObject(DeviceObject); 419 } 420 421 /* We can't unload a non-PnP driver here */ 422 if (DriverObject->Flags & DRVO_LEGACY_DRIVER) 423 { 424 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 425 return; 426 } 427 428 /* Return if we've already called unload (maybe we're in it?) */ 429 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return; 430 431 /* We can't unload unless there's an unload handler */ 432 if (!DriverObject->DriverUnload) 433 { 434 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 435 return; 436 } 437 438 /* Bail if there are still devices present */ 439 if (DriverObject->DeviceObject) 440 { 441 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName); 442 return; 443 } 444 445 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName); 446 447 /* Set the unload invoked flag */ 448 DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 449 450 /* Unload it */ 451 DriverObject->DriverUnload(DriverObject); 452 453 /* Make object temporary so it can be deleted */ 454 ObMakeTemporaryObject(DriverObject); 455 } 456 457 VOID 458 NTAPI 459 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject, 460 IN BOOLEAN ForceUnload) 461 { 462 /* Sanity check */ 463 ASSERT(DeviceObject->ReferenceCount); 464 465 /* Dereference the device */ 466 InterlockedDecrement(&DeviceObject->ReferenceCount); 467 468 /* 469 * Check if we can unload it and it's safe to unload (or if we're forcing 470 * an unload, which is OK too). 471 */ 472 ASSERT(!ForceUnload); 473 if (!(DeviceObject->ReferenceCount) && 474 (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING)) 475 { 476 /* Unload it */ 477 IopUnloadDevice(DeviceObject); 478 } 479 } 480 481 VOID 482 NTAPI 483 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 484 IN BOOLEAN Cancelable, 485 IN ULONG Key) 486 { 487 PKDEVICE_QUEUE_ENTRY Entry; 488 PIRP Irp; 489 KIRQL OldIrql; 490 491 /* Acquire the cancel lock if this is cancelable */ 492 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 493 494 /* Clear the current IRP */ 495 DeviceObject->CurrentIrp = NULL; 496 497 /* Remove an entry from the queue */ 498 Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key); 499 if (Entry) 500 { 501 /* Get the IRP and set it */ 502 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 503 DeviceObject->CurrentIrp = Irp; 504 505 /* Check if this is a cancelable packet */ 506 if (Cancelable) 507 { 508 /* Check if the caller requested no cancellation */ 509 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 510 DOE_SIO_NO_CANCEL) 511 { 512 /* He did, so remove the cancel routine */ 513 Irp->CancelRoutine = NULL; 514 } 515 516 /* Release the cancel lock */ 517 IoReleaseCancelSpinLock(OldIrql); 518 } 519 520 /* Call the Start I/O Routine */ 521 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 522 } 523 else 524 { 525 /* Otherwise, release the cancel lock if we had acquired it */ 526 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 527 } 528 } 529 530 VOID 531 NTAPI 532 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 533 IN BOOLEAN Cancelable) 534 { 535 PKDEVICE_QUEUE_ENTRY Entry; 536 PIRP Irp; 537 KIRQL OldIrql; 538 539 /* Acquire the cancel lock if this is cancelable */ 540 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 541 542 /* Clear the current IRP */ 543 DeviceObject->CurrentIrp = NULL; 544 545 /* Remove an entry from the queue */ 546 Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue); 547 if (Entry) 548 { 549 /* Get the IRP and set it */ 550 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 551 DeviceObject->CurrentIrp = Irp; 552 553 /* Check if this is a cancelable packet */ 554 if (Cancelable) 555 { 556 /* Check if the caller requested no cancellation */ 557 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 558 DOE_SIO_NO_CANCEL) 559 { 560 /* He did, so remove the cancel routine */ 561 Irp->CancelRoutine = NULL; 562 } 563 564 /* Release the cancel lock */ 565 IoReleaseCancelSpinLock(OldIrql); 566 } 567 568 /* Call the Start I/O Routine */ 569 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 570 } 571 else 572 { 573 /* Otherwise, release the cancel lock if we had acquired it */ 574 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 575 } 576 } 577 578 VOID 579 NTAPI 580 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject, 581 IN ULONG Key, 582 IN ULONG Flags) 583 { 584 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 585 ULONG CurrentKey = Key; 586 ULONG CurrentFlags = Flags; 587 588 /* Get the device extension and start the packet loop */ 589 DeviceExtension = IoGetDevObjExtension(DeviceObject); 590 while (TRUE) 591 { 592 /* Increase the count */ 593 if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1) 594 { 595 /* 596 * We've already called the routine once... 597 * All we have to do is save the key and add the new flags 598 */ 599 DeviceExtension->StartIoFlags |= CurrentFlags; 600 DeviceExtension->StartIoKey = CurrentKey; 601 } 602 else 603 { 604 /* Mask out the current packet flags and key */ 605 DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY | 606 DOE_SIO_NO_KEY | 607 DOE_SIO_CANCELABLE); 608 DeviceExtension->StartIoKey = 0; 609 610 /* Check if this is a packet start with key */ 611 if (Flags & DOE_SIO_WITH_KEY) 612 { 613 /* Start the packet with a key */ 614 IopStartNextPacketByKey(DeviceObject, 615 (Flags & DOE_SIO_CANCELABLE) ? 616 TRUE : FALSE, 617 CurrentKey); 618 } 619 else if (Flags & DOE_SIO_NO_KEY) 620 { 621 /* Start the packet */ 622 IopStartNextPacket(DeviceObject, 623 (Flags & DOE_SIO_CANCELABLE) ? 624 TRUE : FALSE); 625 } 626 } 627 628 /* Decrease the Start I/O count and check if it's 0 now */ 629 if (!InterlockedDecrement(&DeviceExtension->StartIoCount)) 630 { 631 /* Get the current active key and flags */ 632 CurrentKey = DeviceExtension->StartIoKey; 633 CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY | 634 DOE_SIO_NO_KEY | 635 DOE_SIO_CANCELABLE); 636 637 /* Check if we should still loop */ 638 if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break; 639 } 640 else 641 { 642 /* There are still Start I/Os active, so quit this loop */ 643 break; 644 } 645 } 646 } 647 648 NTSTATUS 649 NTAPI 650 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 651 OUT PDEVICE_NODE *DeviceNode) 652 { 653 NTSTATUS Status; 654 IO_STACK_LOCATION Stack = {0}; 655 PDEVICE_RELATIONS DeviceRelations; 656 PDEVICE_OBJECT DeviceObject = NULL; 657 658 ASSERT(FileObject); 659 660 /* Get DeviceObject related to given FileObject */ 661 DeviceObject = IoGetRelatedDeviceObject(FileObject); 662 if (!DeviceObject) return STATUS_NO_SUCH_DEVICE; 663 664 /* Define input parameters */ 665 Stack.MajorFunction = IRP_MJ_PNP; 666 Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; 667 Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; 668 Stack.FileObject = FileObject; 669 670 /* Call the driver to query all relations (IRP_MJ_PNP) */ 671 Status = IopSynchronousCall(DeviceObject, 672 &Stack, 673 (PVOID)&DeviceRelations); 674 if (!NT_SUCCESS(Status)) return Status; 675 676 /* Make sure it's not NULL and contains only one object */ 677 ASSERT(DeviceRelations); 678 ASSERT(DeviceRelations->Count == 1); 679 680 /* Finally get the device node */ 681 *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]); 682 if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE; 683 684 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */ 685 ExFreePool(DeviceRelations); 686 687 return Status; 688 } 689 690 BOOLEAN 691 NTAPI 692 IopVerifyDeviceObjectOnStack(IN PDEVICE_OBJECT BaseDeviceObject, 693 IN PDEVICE_OBJECT TopDeviceObjectHint) 694 { 695 KIRQL OldIrql; 696 BOOLEAN Result; 697 PDEVICE_OBJECT LoopObject; 698 699 ASSERT(BaseDeviceObject != NULL); 700 701 Result = FALSE; 702 /* Simply loop on the device stack and try to find our hint */ 703 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 704 for (LoopObject = BaseDeviceObject; ; LoopObject = LoopObject->AttachedDevice) 705 { 706 /* It was found, it's a success */ 707 if (LoopObject == TopDeviceObjectHint) 708 { 709 Result = TRUE; 710 break; 711 } 712 713 /* End of the stack, that's a failure - default */ 714 if (LoopObject == NULL) 715 { 716 break; 717 } 718 } 719 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 720 721 return Result; 722 } 723 724 /* PUBLIC FUNCTIONS ***********************************************************/ 725 726 /* 727 * IoAttachDevice 728 * 729 * Layers a device over the highest device in a device stack. 730 * 731 * Parameters 732 * SourceDevice 733 * Device to be attached. 734 * 735 * TargetDevice 736 * Name of the target device. 737 * 738 * AttachedDevice 739 * Caller storage for the device attached to. 740 * 741 * Status 742 * @implemented 743 */ 744 NTSTATUS 745 NTAPI 746 IoAttachDevice(PDEVICE_OBJECT SourceDevice, 747 PUNICODE_STRING TargetDeviceName, 748 PDEVICE_OBJECT *AttachedDevice) 749 { 750 NTSTATUS Status; 751 PFILE_OBJECT FileObject = NULL; 752 PDEVICE_OBJECT TargetDevice = NULL; 753 754 /* Call the helper routine for an attach operation */ 755 Status = IopGetDeviceObjectPointer(TargetDeviceName, 756 FILE_READ_ATTRIBUTES, 757 &FileObject, 758 &TargetDevice, 759 IO_ATTACH_DEVICE_API); 760 if (!NT_SUCCESS(Status)) return Status; 761 762 /* Attach the device */ 763 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice, 764 TargetDevice, 765 AttachedDevice); 766 767 /* Dereference it */ 768 ObDereferenceObject(FileObject); 769 return Status; 770 } 771 772 /* 773 * IoAttachDeviceByPointer 774 * 775 * Status 776 * @implemented 777 */ 778 NTSTATUS 779 NTAPI 780 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice, 781 IN PDEVICE_OBJECT TargetDevice) 782 { 783 PDEVICE_OBJECT AttachedDevice; 784 NTSTATUS Status = STATUS_SUCCESS; 785 786 /* Do the Attach */ 787 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice); 788 if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE; 789 790 /* Return the status */ 791 return Status; 792 } 793 794 /* 795 * @implemented 796 */ 797 PDEVICE_OBJECT 798 NTAPI 799 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice, 800 IN PDEVICE_OBJECT TargetDevice) 801 { 802 /* Attach it safely */ 803 return IopAttachDeviceToDeviceStackSafe(SourceDevice, 804 TargetDevice, 805 NULL); 806 } 807 808 /* 809 * @implemented 810 */ 811 NTSTATUS 812 NTAPI 813 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 814 IN PDEVICE_OBJECT TargetDevice, 815 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject) 816 { 817 /* Call the internal function */ 818 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice, 819 TargetDevice, 820 AttachedToDeviceObject)) 821 { 822 /* Nothing found */ 823 return STATUS_NO_SUCH_DEVICE; 824 } 825 826 /* Success! */ 827 return STATUS_SUCCESS; 828 } 829 830 /* 831 * IoCreateDevice 832 * 833 * Allocates memory for and intializes a device object for use for 834 * a driver. 835 * 836 * Parameters 837 * DriverObject 838 * Driver object passed by IO Manager when the driver was loaded. 839 * 840 * DeviceExtensionSize 841 * Number of bytes for the device extension. 842 * 843 * DeviceName 844 * Unicode name of device. 845 * 846 * DeviceType 847 * Device type of the new device. 848 * 849 * DeviceCharacteristics 850 * Bit mask of device characteristics. 851 * 852 * Exclusive 853 * TRUE if only one thread can access the device at a time. 854 * 855 * DeviceObject 856 * On successful return this parameter is filled by pointer to 857 * allocated device object. 858 * 859 * Status 860 * @implemented 861 */ 862 NTSTATUS 863 NTAPI 864 IoCreateDevice(IN PDRIVER_OBJECT DriverObject, 865 IN ULONG DeviceExtensionSize, 866 IN PUNICODE_STRING DeviceName, 867 IN DEVICE_TYPE DeviceType, 868 IN ULONG DeviceCharacteristics, 869 IN BOOLEAN Exclusive, 870 OUT PDEVICE_OBJECT *DeviceObject) 871 { 872 WCHAR AutoNameBuffer[20]; 873 UNICODE_STRING AutoName; 874 PDEVICE_OBJECT CreatedDeviceObject; 875 PDEVOBJ_EXTENSION DeviceObjectExtension; 876 OBJECT_ATTRIBUTES ObjectAttributes; 877 NTSTATUS Status; 878 ULONG AlignedDeviceExtensionSize; 879 ULONG TotalSize; 880 HANDLE TempHandle; 881 PAGED_CODE(); 882 883 /* Check if we have to generate a name */ 884 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) 885 { 886 /* Generate it */ 887 swprintf(AutoNameBuffer, 888 L"\\Device\\%08lx", 889 InterlockedIncrementUL(&IopDeviceObjectNumber)); 890 891 /* Initialize the name */ 892 RtlInitUnicodeString(&AutoName, AutoNameBuffer); 893 DeviceName = &AutoName; 894 } 895 896 /* Initialize the Object Attributes */ 897 InitializeObjectAttributes(&ObjectAttributes, 898 DeviceName, 899 OBJ_KERNEL_HANDLE, 900 NULL, 901 SePublicOpenUnrestrictedSd); 902 903 /* Honor exclusive flag */ 904 if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE; 905 906 /* Create a permanent object for named devices */ 907 if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT; 908 909 /* Align the Extension Size to 8-bytes */ 910 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7; 911 912 /* Total Size */ 913 TotalSize = AlignedDeviceExtensionSize + 914 sizeof(DEVICE_OBJECT) + 915 sizeof(EXTENDED_DEVOBJ_EXTENSION); 916 917 /* Create the Device Object */ 918 *DeviceObject = NULL; 919 Status = ObCreateObject(KernelMode, 920 IoDeviceObjectType, 921 &ObjectAttributes, 922 KernelMode, 923 NULL, 924 TotalSize, 925 0, 926 0, 927 (PVOID*)&CreatedDeviceObject); 928 if (!NT_SUCCESS(Status)) return Status; 929 930 /* Clear the whole Object and extension so we don't null stuff manually */ 931 RtlZeroMemory(CreatedDeviceObject, TotalSize); 932 933 /* 934 * Setup the Type and Size. Note that we don't use the aligned size, 935 * because that's only padding for the DevObjExt and not part of the Object. 936 */ 937 CreatedDeviceObject->Type = IO_TYPE_DEVICE; 938 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize; 939 940 /* The kernel extension is after the driver internal extension */ 941 DeviceObjectExtension = (PDEVOBJ_EXTENSION) 942 ((ULONG_PTR)(CreatedDeviceObject + 1) + 943 AlignedDeviceExtensionSize); 944 945 /* Set the Type and Size. Question: why is Size 0 on Windows? */ 946 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION; 947 DeviceObjectExtension->Size = 0; 948 949 /* Initialize with Power Manager */ 950 PoInitializeDeviceObject(DeviceObjectExtension); 951 952 /* Link the Object and Extension */ 953 DeviceObjectExtension->DeviceObject = CreatedDeviceObject; 954 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension; 955 956 /* Set Device Object Data */ 957 CreatedDeviceObject->DeviceType = DeviceType; 958 CreatedDeviceObject->Characteristics = DeviceCharacteristics; 959 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ? 960 CreatedDeviceObject + 1 : 961 NULL; 962 CreatedDeviceObject->StackSize = 1; 963 CreatedDeviceObject->AlignmentRequirement = 0; 964 965 /* Set the Flags */ 966 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING; 967 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE; 968 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME; 969 970 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */ 971 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) || 972 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) || 973 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) || 974 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)) 975 { 976 /* Create Vpb */ 977 Status = IopCreateVpb(CreatedDeviceObject); 978 if (!NT_SUCCESS(Status)) 979 { 980 /* Dereference the device object and fail */ 981 ObDereferenceObject(CreatedDeviceObject); 982 return Status; 983 } 984 985 /* Initialize Lock Event */ 986 KeInitializeEvent(&CreatedDeviceObject->DeviceLock, 987 SynchronizationEvent, 988 TRUE); 989 } 990 991 /* Set the right Sector Size */ 992 switch (DeviceType) 993 { 994 /* All disk systems */ 995 case FILE_DEVICE_DISK_FILE_SYSTEM: 996 case FILE_DEVICE_DISK: 997 case FILE_DEVICE_VIRTUAL_DISK: 998 999 /* The default is 512 bytes */ 1000 CreatedDeviceObject->SectorSize = 512; 1001 break; 1002 1003 /* CD-ROM file systems */ 1004 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 1005 1006 /* The default is 2048 bytes */ 1007 CreatedDeviceObject->SectorSize = 2048; 1008 } 1009 1010 /* Create the Device Queue */ 1011 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || 1012 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) || 1013 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || 1014 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) || 1015 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)) 1016 { 1017 /* Simple FS Devices, they don't need a real Device Queue */ 1018 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry); 1019 } 1020 else 1021 { 1022 /* An actual Device, initialize its DQ */ 1023 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue); 1024 } 1025 1026 /* Insert the Object */ 1027 Status = ObInsertObject(CreatedDeviceObject, 1028 NULL, 1029 FILE_READ_DATA | FILE_WRITE_DATA, 1030 1, 1031 (PVOID*)&CreatedDeviceObject, 1032 &TempHandle); 1033 if (!NT_SUCCESS(Status)) return Status; 1034 1035 /* Now do the final linking */ 1036 ObReferenceObject(DriverObject); 1037 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0); 1038 CreatedDeviceObject->DriverObject = DriverObject; 1039 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd); 1040 1041 /* Link with the power manager */ 1042 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject); 1043 1044 /* Close the temporary handle and return to caller */ 1045 ObCloseHandle(TempHandle, KernelMode); 1046 *DeviceObject = CreatedDeviceObject; 1047 return STATUS_SUCCESS; 1048 } 1049 1050 /* 1051 * IoDeleteDevice 1052 * 1053 * Status 1054 * @implemented 1055 */ 1056 VOID 1057 NTAPI 1058 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject) 1059 { 1060 PIO_TIMER Timer; 1061 1062 /* Check if the device is registered for shutdown notifications */ 1063 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) 1064 { 1065 /* Call the shutdown notifications */ 1066 IoUnregisterShutdownNotification(DeviceObject); 1067 } 1068 1069 /* Check if it has a timer */ 1070 Timer = DeviceObject->Timer; 1071 if (Timer) 1072 { 1073 /* Remove it and free it */ 1074 IopRemoveTimerFromTimerList(Timer); 1075 ExFreePoolWithTag(Timer, TAG_IO_TIMER); 1076 } 1077 1078 /* Check if the device has a name */ 1079 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) 1080 { 1081 /* It does, make it temporary so we can remove it */ 1082 ObMakeTemporaryObject(DeviceObject); 1083 } 1084 1085 /* Set the pending delete flag */ 1086 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING; 1087 1088 /* Unlink with the power manager */ 1089 if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject); 1090 1091 /* Check if the device object can be unloaded */ 1092 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject); 1093 } 1094 1095 /* 1096 * IoDetachDevice 1097 * 1098 * Status 1099 * @implemented 1100 */ 1101 VOID 1102 NTAPI 1103 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice) 1104 { 1105 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1106 1107 /* Sanity check */ 1108 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice); 1109 ASSERT(DeviceExtension->AttachedTo == TargetDevice); 1110 1111 /* Remove the attachment */ 1112 DeviceExtension->AttachedTo = NULL; 1113 TargetDevice->AttachedDevice = NULL; 1114 1115 /* Check if it's ok to delete this device */ 1116 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) && 1117 !(TargetDevice->ReferenceCount)) 1118 { 1119 /* It is, do it */ 1120 IopUnloadDevice(TargetDevice); 1121 } 1122 } 1123 1124 /* 1125 * @implemented 1126 */ 1127 NTSTATUS 1128 NTAPI 1129 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject, 1130 IN PDEVICE_OBJECT *DeviceObjectList, 1131 IN ULONG DeviceObjectListSize, 1132 OUT PULONG ActualNumberDeviceObjects) 1133 { 1134 ULONG ActualDevices = 1; 1135 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject; 1136 KIRQL OldIrql; 1137 1138 /* Lock the Device list while we enumerate it */ 1139 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 1140 1141 /* Find out how many devices we'll enumerate */ 1142 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++; 1143 1144 /* Go back to the first */ 1145 CurrentDevice = DriverObject->DeviceObject; 1146 1147 /* Start by at least returning this */ 1148 *ActualNumberDeviceObjects = ActualDevices; 1149 1150 /* Check if we can support so many */ 1151 if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize) 1152 { 1153 /* Fail because the buffer was too small */ 1154 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 1155 return STATUS_BUFFER_TOO_SMALL; 1156 } 1157 1158 /* Check if the caller wanted the device list */ 1159 if (DeviceObjectList) 1160 { 1161 /* Loop through all the devices */ 1162 while (ActualDevices) 1163 { 1164 /* Reference each Device */ 1165 ObReferenceObject(CurrentDevice); 1166 1167 /* Add it to the list */ 1168 *DeviceObjectList = CurrentDevice; 1169 1170 /* Go to the next one */ 1171 CurrentDevice = CurrentDevice->NextDevice; 1172 ActualDevices--; 1173 DeviceObjectList++; 1174 } 1175 } 1176 1177 /* Release the device list lock */ 1178 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 1179 1180 /* Return the status */ 1181 return STATUS_SUCCESS; 1182 } 1183 1184 /* 1185 * IoGetAttachedDevice 1186 * 1187 * Status 1188 * @implemented 1189 */ 1190 PDEVICE_OBJECT 1191 NTAPI 1192 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject) 1193 { 1194 /* Get the last attached device */ 1195 while (DeviceObject->AttachedDevice) 1196 { 1197 /* Move to the next one */ 1198 DeviceObject = DeviceObject->AttachedDevice; 1199 } 1200 1201 /* Return it */ 1202 return DeviceObject; 1203 } 1204 1205 /* 1206 * IoGetAttachedDeviceReference 1207 * 1208 * Status 1209 * @implemented 1210 */ 1211 PDEVICE_OBJECT 1212 NTAPI 1213 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject) 1214 { 1215 /* Reference the Attached Device */ 1216 DeviceObject = IoGetAttachedDevice(DeviceObject); 1217 ObReferenceObject(DeviceObject); 1218 return DeviceObject; 1219 } 1220 1221 /* 1222 * @implemented 1223 */ 1224 PDEVICE_OBJECT 1225 NTAPI 1226 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject) 1227 { 1228 /* Reference the lowest attached device */ 1229 DeviceObject = IopGetLowestDevice(DeviceObject); 1230 ObReferenceObject(DeviceObject); 1231 return DeviceObject; 1232 } 1233 1234 /* 1235 * IoGetDeviceObjectPointer 1236 * 1237 * Status 1238 * @implemented 1239 */ 1240 NTSTATUS 1241 NTAPI 1242 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 1243 IN ACCESS_MASK DesiredAccess, 1244 OUT PFILE_OBJECT *FileObject, 1245 OUT PDEVICE_OBJECT *DeviceObject) 1246 { 1247 /* Call the helper routine for a normal operation */ 1248 return IopGetDeviceObjectPointer(ObjectName, 1249 DesiredAccess, 1250 FileObject, 1251 DeviceObject, 1252 0); 1253 } 1254 1255 /* 1256 * @implemented 1257 */ 1258 NTSTATUS 1259 NTAPI 1260 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject, 1261 OUT PDEVICE_OBJECT *DiskDeviceObject) 1262 { 1263 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1264 PVPB Vpb; 1265 KIRQL OldIrql; 1266 NTSTATUS Status; 1267 1268 /* Make sure there's a VPB */ 1269 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER; 1270 1271 /* Acquire it */ 1272 IoAcquireVpbSpinLock(&OldIrql); 1273 1274 /* Get the Device Extension */ 1275 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject); 1276 1277 /* Make sure this one has a VPB too */ 1278 Vpb = DeviceExtension->Vpb; 1279 if (Vpb) 1280 { 1281 /* Make sure that it's mounted */ 1282 if ((Vpb->ReferenceCount) && 1283 (Vpb->Flags & VPB_MOUNTED)) 1284 { 1285 /* Return the Disk Device Object */ 1286 *DiskDeviceObject = Vpb->RealDevice; 1287 1288 /* Reference it and return success */ 1289 ObReferenceObject(Vpb->RealDevice); 1290 Status = STATUS_SUCCESS; 1291 } 1292 else 1293 { 1294 /* It's not, so return failure */ 1295 Status = STATUS_VOLUME_DISMOUNTED; 1296 } 1297 } 1298 else 1299 { 1300 /* Fail */ 1301 Status = STATUS_INVALID_PARAMETER; 1302 } 1303 1304 /* Release the lock */ 1305 IoReleaseVpbSpinLock(OldIrql); 1306 return Status; 1307 } 1308 1309 /* 1310 * @implemented 1311 */ 1312 PDEVICE_OBJECT 1313 NTAPI 1314 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject) 1315 { 1316 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1317 PDEVICE_OBJECT LowerDeviceObject = NULL; 1318 1319 /* Make sure it's not getting deleted */ 1320 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1321 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING | 1322 DOE_DELETE_PENDING | 1323 DOE_REMOVE_PENDING | 1324 DOE_REMOVE_PROCESSED))) 1325 { 1326 /* Get the Lower Device Object */ 1327 LowerDeviceObject = DeviceExtension->AttachedTo; 1328 1329 /* Check that we got a valid device object */ 1330 if (LowerDeviceObject) 1331 { 1332 /* We did so let's reference it */ 1333 ObReferenceObject(LowerDeviceObject); 1334 } 1335 } 1336 1337 /* Return it */ 1338 return LowerDeviceObject; 1339 } 1340 1341 /* 1342 * @implemented 1343 */ 1344 PDEVICE_OBJECT 1345 NTAPI 1346 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject) 1347 { 1348 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject; 1349 1350 /* Check if we have a VPB with a device object */ 1351 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1352 { 1353 /* Then use the DO from the VPB */ 1354 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1355 DeviceObject = FileObject->Vpb->DeviceObject; 1356 } 1357 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1358 (FileObject->DeviceObject->Vpb) && 1359 (FileObject->DeviceObject->Vpb->DeviceObject)) 1360 { 1361 /* The disk device actually has a VPB, so get the DO from there */ 1362 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1363 } 1364 else 1365 { 1366 /* Otherwise, this was a direct open */ 1367 DeviceObject = FileObject->DeviceObject; 1368 } 1369 1370 /* Sanity check */ 1371 ASSERT(DeviceObject != NULL); 1372 1373 /* Check if we were attached */ 1374 if (DeviceObject->AttachedDevice) 1375 { 1376 /* Check if the file object has an extension present */ 1377 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) 1378 { 1379 /* Sanity check, direct open files can't have this */ 1380 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1381 1382 /* Check if the extension is really present */ 1383 if (FileObject->FileObjectExtension) 1384 { 1385 PFILE_OBJECT_EXTENSION FileObjectExtension; 1386 1387 /* Cast the buffer to something we understand */ 1388 FileObjectExtension = FileObject->FileObjectExtension; 1389 1390 /* Check if have a replacement top level device */ 1391 if (FileObjectExtension->TopDeviceObjectHint) 1392 { 1393 /* Use this instead of returning the top level device */ 1394 return FileObjectExtension->TopDeviceObjectHint; 1395 } 1396 } 1397 } 1398 1399 /* Return the highest attached device */ 1400 DeviceObject = IoGetAttachedDevice(DeviceObject); 1401 } 1402 1403 /* Return the DO we found */ 1404 return DeviceObject; 1405 } 1406 1407 /* 1408 * @implemented 1409 */ 1410 NTSTATUS 1411 NTAPI 1412 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 1413 OUT PDEVICE_OBJECT *DeviceObject) 1414 { 1415 NTSTATUS Status; 1416 PDEVICE_NODE DeviceNode = NULL; 1417 1418 /* Call the internal helper function */ 1419 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode); 1420 if (NT_SUCCESS(Status) && DeviceNode) 1421 { 1422 *DeviceObject = DeviceNode->PhysicalDeviceObject; 1423 } 1424 return Status; 1425 } 1426 1427 /* 1428 * @implemented 1429 */ 1430 PDEVICE_OBJECT 1431 NTAPI 1432 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject) 1433 { 1434 PDEVICE_OBJECT DeviceObject; 1435 1436 /* 1437 * If the FILE_OBJECT's VPB is defined, 1438 * get the device from it. 1439 */ 1440 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1441 { 1442 /* Use the VPB's Device Object's */ 1443 DeviceObject = FileObject->Vpb->DeviceObject; 1444 } 1445 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1446 (FileObject->DeviceObject->Vpb) && 1447 (FileObject->DeviceObject->Vpb->DeviceObject)) 1448 { 1449 /* Use the VPB's File System Object */ 1450 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1451 } 1452 else 1453 { 1454 /* Use the FO's Device Object */ 1455 DeviceObject = FileObject->DeviceObject; 1456 } 1457 1458 /* Return the device object we found */ 1459 ASSERT(DeviceObject != NULL); 1460 return DeviceObject; 1461 } 1462 1463 /* 1464 * @implemented 1465 */ 1466 NTSTATUS 1467 NTAPI 1468 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject) 1469 { 1470 PSHUTDOWN_ENTRY Entry; 1471 1472 /* Allocate the shutdown entry */ 1473 Entry = ExAllocatePoolWithTag(NonPagedPool, 1474 sizeof(SHUTDOWN_ENTRY), 1475 TAG_SHUTDOWN_ENTRY); 1476 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1477 1478 /* Set the DO */ 1479 Entry->DeviceObject = DeviceObject; 1480 1481 /* Reference it so it doesn't go away */ 1482 ObReferenceObject(DeviceObject); 1483 1484 /* Insert it into the list */ 1485 ExInterlockedInsertHeadList(&LastChanceShutdownListHead, 1486 &Entry->ShutdownList, 1487 &ShutdownListLock); 1488 1489 /* Set the shutdown registered flag */ 1490 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1491 return STATUS_SUCCESS; 1492 } 1493 1494 /* 1495 * @implemented 1496 */ 1497 NTSTATUS 1498 NTAPI 1499 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1500 { 1501 PSHUTDOWN_ENTRY Entry; 1502 1503 /* Allocate the shutdown entry */ 1504 Entry = ExAllocatePoolWithTag(NonPagedPool, 1505 sizeof(SHUTDOWN_ENTRY), 1506 TAG_SHUTDOWN_ENTRY); 1507 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1508 1509 /* Set the DO */ 1510 Entry->DeviceObject = DeviceObject; 1511 1512 /* Reference it so it doesn't go away */ 1513 ObReferenceObject(DeviceObject); 1514 1515 /* Insert it into the list */ 1516 ExInterlockedInsertHeadList(&ShutdownListHead, 1517 &Entry->ShutdownList, 1518 &ShutdownListLock); 1519 1520 /* Set the shutdown registered flag */ 1521 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1522 return STATUS_SUCCESS; 1523 } 1524 1525 /* 1526 * @implemented 1527 */ 1528 VOID 1529 NTAPI 1530 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1531 { 1532 PSHUTDOWN_ENTRY ShutdownEntry; 1533 PLIST_ENTRY NextEntry; 1534 KIRQL OldIrql; 1535 1536 /* Remove the flag */ 1537 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 1538 1539 /* Acquire the shutdown lock and loop the shutdown list */ 1540 KeAcquireSpinLock(&ShutdownListLock, &OldIrql); 1541 NextEntry = ShutdownListHead.Flink; 1542 while (NextEntry != &ShutdownListHead) 1543 { 1544 /* Get the entry */ 1545 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1546 SHUTDOWN_ENTRY, 1547 ShutdownList); 1548 1549 /* Get if the DO matches */ 1550 if (ShutdownEntry->DeviceObject == DeviceObject) 1551 { 1552 /* Remove it from the list */ 1553 RemoveEntryList(NextEntry); 1554 NextEntry = NextEntry->Blink; 1555 1556 /* Free the entry */ 1557 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1558 1559 /* Get rid of our reference to it */ 1560 ObDereferenceObject(DeviceObject); 1561 } 1562 1563 /* Go to the next entry */ 1564 NextEntry = NextEntry->Flink; 1565 } 1566 1567 /* Now loop the last chance list */ 1568 NextEntry = LastChanceShutdownListHead.Flink; 1569 while (NextEntry != &LastChanceShutdownListHead) 1570 { 1571 /* Get the entry */ 1572 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1573 SHUTDOWN_ENTRY, 1574 ShutdownList); 1575 1576 /* Get if the DO matches */ 1577 if (ShutdownEntry->DeviceObject == DeviceObject) 1578 { 1579 /* Remove it from the list */ 1580 RemoveEntryList(NextEntry); 1581 NextEntry = NextEntry->Blink; 1582 1583 /* Free the entry */ 1584 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1585 1586 /* Get rid of our reference to it */ 1587 ObDereferenceObject(DeviceObject); 1588 } 1589 1590 /* Go to the next entry */ 1591 NextEntry = NextEntry->Flink; 1592 } 1593 1594 /* Release the shutdown lock */ 1595 KeReleaseSpinLock(&ShutdownListLock, OldIrql); 1596 } 1597 1598 /* 1599 * @implemented 1600 */ 1601 VOID 1602 NTAPI 1603 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject, 1604 IN BOOLEAN DeferredStartIo, 1605 IN BOOLEAN NonCancelable) 1606 { 1607 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1608 1609 /* Get the Device Extension */ 1610 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1611 1612 /* Set the flags the caller requested */ 1613 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0; 1614 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0; 1615 } 1616 1617 /* 1618 * @implemented 1619 */ 1620 VOID 1621 NTAPI 1622 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 1623 IN BOOLEAN Cancelable, 1624 IN ULONG Key) 1625 { 1626 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1627 1628 /* Get the Device Extension */ 1629 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1630 1631 /* Check if deferred start was requested */ 1632 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1633 { 1634 /* Call our internal function to handle the defered case */ 1635 IopStartNextPacketByKeyEx(DeviceObject, 1636 Key, 1637 DOE_SIO_WITH_KEY | 1638 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1639 } 1640 else 1641 { 1642 /* Call the normal routine */ 1643 IopStartNextPacketByKey(DeviceObject, Cancelable, Key); 1644 } 1645 } 1646 1647 /* 1648 * @implemented 1649 */ 1650 VOID 1651 NTAPI 1652 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 1653 IN BOOLEAN Cancelable) 1654 { 1655 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1656 1657 /* Get the Device Extension */ 1658 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1659 1660 /* Check if deferred start was requested */ 1661 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1662 { 1663 /* Call our internal function to handle the defered case */ 1664 IopStartNextPacketByKeyEx(DeviceObject, 1665 0, 1666 DOE_SIO_NO_KEY | 1667 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1668 } 1669 else 1670 { 1671 /* Call the normal routine */ 1672 IopStartNextPacket(DeviceObject, Cancelable); 1673 } 1674 } 1675 1676 /* 1677 * @implemented 1678 */ 1679 VOID 1680 NTAPI 1681 IoStartPacket(IN PDEVICE_OBJECT DeviceObject, 1682 IN PIRP Irp, 1683 IN PULONG Key, 1684 IN PDRIVER_CANCEL CancelFunction) 1685 { 1686 BOOLEAN Stat; 1687 KIRQL OldIrql, CancelIrql; 1688 1689 /* Raise to dispatch level */ 1690 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 1691 1692 /* Check if we should acquire the cancel lock */ 1693 if (CancelFunction) 1694 { 1695 /* Acquire and set it */ 1696 IoAcquireCancelSpinLock(&CancelIrql); 1697 Irp->CancelRoutine = CancelFunction; 1698 } 1699 1700 /* Check if we have a key */ 1701 if (Key) 1702 { 1703 /* Insert by key */ 1704 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue, 1705 &Irp->Tail.Overlay.DeviceQueueEntry, 1706 *Key); 1707 } 1708 else 1709 { 1710 /* Insert without a key */ 1711 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue, 1712 &Irp->Tail.Overlay.DeviceQueueEntry); 1713 } 1714 1715 /* Check if this was a first insert */ 1716 if (!Stat) 1717 { 1718 /* Set the IRP */ 1719 DeviceObject->CurrentIrp = Irp; 1720 1721 /* Check if this is a cancelable packet */ 1722 if (CancelFunction) 1723 { 1724 /* Check if the caller requested no cancellation */ 1725 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 1726 DOE_SIO_NO_CANCEL) 1727 { 1728 /* He did, so remove the cancel routine */ 1729 Irp->CancelRoutine = NULL; 1730 } 1731 1732 /* Release the cancel lock */ 1733 IoReleaseCancelSpinLock(CancelIrql); 1734 } 1735 1736 /* Call the Start I/O function */ 1737 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 1738 } 1739 else 1740 { 1741 /* The packet was inserted... check if we have a cancel function */ 1742 if (CancelFunction) 1743 { 1744 /* Check if the IRP got cancelled */ 1745 if (Irp->Cancel) 1746 { 1747 /* 1748 * Set the cancel IRQL, clear the currnet cancel routine and 1749 * call ours 1750 */ 1751 Irp->CancelIrql = CancelIrql; 1752 Irp->CancelRoutine = NULL; 1753 CancelFunction(DeviceObject, Irp); 1754 } 1755 else 1756 { 1757 /* Otherwise, release the lock */ 1758 IoReleaseCancelSpinLock(CancelIrql); 1759 } 1760 } 1761 } 1762 1763 /* Return back to previous IRQL */ 1764 KeLowerIrql(OldIrql); 1765 } 1766 1767 #if defined (_WIN64) 1768 ULONG 1769 NTAPI 1770 IoWMIDeviceObjectToProviderId( 1771 IN PDEVICE_OBJECT DeviceObject) 1772 { 1773 UNIMPLEMENTED; 1774 return 0; 1775 } 1776 #endif 1777 1778 /* EOF */ 1779