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 /* PUBLIC FUNCTIONS ***********************************************************/ 691 692 /* 693 * IoAttachDevice 694 * 695 * Layers a device over the highest device in a device stack. 696 * 697 * Parameters 698 * SourceDevice 699 * Device to be attached. 700 * 701 * TargetDevice 702 * Name of the target device. 703 * 704 * AttachedDevice 705 * Caller storage for the device attached to. 706 * 707 * Status 708 * @implemented 709 */ 710 NTSTATUS 711 NTAPI 712 IoAttachDevice(PDEVICE_OBJECT SourceDevice, 713 PUNICODE_STRING TargetDeviceName, 714 PDEVICE_OBJECT *AttachedDevice) 715 { 716 NTSTATUS Status; 717 PFILE_OBJECT FileObject = NULL; 718 PDEVICE_OBJECT TargetDevice = NULL; 719 720 /* Call the helper routine for an attach operation */ 721 Status = IopGetDeviceObjectPointer(TargetDeviceName, 722 FILE_READ_ATTRIBUTES, 723 &FileObject, 724 &TargetDevice, 725 IO_ATTACH_DEVICE_API); 726 if (!NT_SUCCESS(Status)) return Status; 727 728 /* Attach the device */ 729 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice, 730 TargetDevice, 731 AttachedDevice); 732 733 /* Dereference it */ 734 ObDereferenceObject(FileObject); 735 return Status; 736 } 737 738 /* 739 * IoAttachDeviceByPointer 740 * 741 * Status 742 * @implemented 743 */ 744 NTSTATUS 745 NTAPI 746 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice, 747 IN PDEVICE_OBJECT TargetDevice) 748 { 749 PDEVICE_OBJECT AttachedDevice; 750 NTSTATUS Status = STATUS_SUCCESS; 751 752 /* Do the Attach */ 753 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice); 754 if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE; 755 756 /* Return the status */ 757 return Status; 758 } 759 760 /* 761 * @implemented 762 */ 763 PDEVICE_OBJECT 764 NTAPI 765 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice, 766 IN PDEVICE_OBJECT TargetDevice) 767 { 768 /* Attach it safely */ 769 return IopAttachDeviceToDeviceStackSafe(SourceDevice, 770 TargetDevice, 771 NULL); 772 } 773 774 /* 775 * @implemented 776 */ 777 NTSTATUS 778 NTAPI 779 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 780 IN PDEVICE_OBJECT TargetDevice, 781 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject) 782 { 783 /* Call the internal function */ 784 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice, 785 TargetDevice, 786 AttachedToDeviceObject)) 787 { 788 /* Nothing found */ 789 return STATUS_NO_SUCH_DEVICE; 790 } 791 792 /* Success! */ 793 return STATUS_SUCCESS; 794 } 795 796 /* 797 * IoCreateDevice 798 * 799 * Allocates memory for and intializes a device object for use for 800 * a driver. 801 * 802 * Parameters 803 * DriverObject 804 * Driver object passed by IO Manager when the driver was loaded. 805 * 806 * DeviceExtensionSize 807 * Number of bytes for the device extension. 808 * 809 * DeviceName 810 * Unicode name of device. 811 * 812 * DeviceType 813 * Device type of the new device. 814 * 815 * DeviceCharacteristics 816 * Bit mask of device characteristics. 817 * 818 * Exclusive 819 * TRUE if only one thread can access the device at a time. 820 * 821 * DeviceObject 822 * On successful return this parameter is filled by pointer to 823 * allocated device object. 824 * 825 * Status 826 * @implemented 827 */ 828 NTSTATUS 829 NTAPI 830 IoCreateDevice(IN PDRIVER_OBJECT DriverObject, 831 IN ULONG DeviceExtensionSize, 832 IN PUNICODE_STRING DeviceName, 833 IN DEVICE_TYPE DeviceType, 834 IN ULONG DeviceCharacteristics, 835 IN BOOLEAN Exclusive, 836 OUT PDEVICE_OBJECT *DeviceObject) 837 { 838 WCHAR AutoNameBuffer[20]; 839 UNICODE_STRING AutoName; 840 PDEVICE_OBJECT CreatedDeviceObject; 841 PDEVOBJ_EXTENSION DeviceObjectExtension; 842 OBJECT_ATTRIBUTES ObjectAttributes; 843 NTSTATUS Status; 844 ULONG AlignedDeviceExtensionSize; 845 ULONG TotalSize; 846 HANDLE TempHandle; 847 PAGED_CODE(); 848 849 /* Check if we have to generate a name */ 850 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) 851 { 852 /* Generate it */ 853 swprintf(AutoNameBuffer, 854 L"\\Device\\%08lx", 855 InterlockedIncrementUL(&IopDeviceObjectNumber)); 856 857 /* Initialize the name */ 858 RtlInitUnicodeString(&AutoName, AutoNameBuffer); 859 DeviceName = &AutoName; 860 } 861 862 /* Initialize the Object Attributes */ 863 InitializeObjectAttributes(&ObjectAttributes, 864 DeviceName, 865 OBJ_KERNEL_HANDLE, 866 NULL, 867 SePublicOpenUnrestrictedSd); 868 869 /* Honor exclusive flag */ 870 if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE; 871 872 /* Create a permanent object for named devices */ 873 if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT; 874 875 /* Align the Extension Size to 8-bytes */ 876 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7; 877 878 /* Total Size */ 879 TotalSize = AlignedDeviceExtensionSize + 880 sizeof(DEVICE_OBJECT) + 881 sizeof(EXTENDED_DEVOBJ_EXTENSION); 882 883 /* Create the Device Object */ 884 *DeviceObject = NULL; 885 Status = ObCreateObject(KernelMode, 886 IoDeviceObjectType, 887 &ObjectAttributes, 888 KernelMode, 889 NULL, 890 TotalSize, 891 0, 892 0, 893 (PVOID*)&CreatedDeviceObject); 894 if (!NT_SUCCESS(Status)) return Status; 895 896 /* Clear the whole Object and extension so we don't null stuff manually */ 897 RtlZeroMemory(CreatedDeviceObject, TotalSize); 898 899 /* 900 * Setup the Type and Size. Note that we don't use the aligned size, 901 * because that's only padding for the DevObjExt and not part of the Object. 902 */ 903 CreatedDeviceObject->Type = IO_TYPE_DEVICE; 904 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize; 905 906 /* The kernel extension is after the driver internal extension */ 907 DeviceObjectExtension = (PDEVOBJ_EXTENSION) 908 ((ULONG_PTR)(CreatedDeviceObject + 1) + 909 AlignedDeviceExtensionSize); 910 911 /* Set the Type and Size. Question: why is Size 0 on Windows? */ 912 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION; 913 DeviceObjectExtension->Size = 0; 914 915 /* Initialize with Power Manager */ 916 PoInitializeDeviceObject(DeviceObjectExtension); 917 918 /* Link the Object and Extension */ 919 DeviceObjectExtension->DeviceObject = CreatedDeviceObject; 920 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension; 921 922 /* Set Device Object Data */ 923 CreatedDeviceObject->DeviceType = DeviceType; 924 CreatedDeviceObject->Characteristics = DeviceCharacteristics; 925 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ? 926 CreatedDeviceObject + 1 : 927 NULL; 928 CreatedDeviceObject->StackSize = 1; 929 CreatedDeviceObject->AlignmentRequirement = 0; 930 931 /* Set the Flags */ 932 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING; 933 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE; 934 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME; 935 936 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */ 937 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) || 938 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) || 939 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) || 940 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)) 941 { 942 /* Create Vpb */ 943 Status = IopCreateVpb(CreatedDeviceObject); 944 if (!NT_SUCCESS(Status)) 945 { 946 /* Dereference the device object and fail */ 947 ObDereferenceObject(CreatedDeviceObject); 948 return Status; 949 } 950 951 /* Initialize Lock Event */ 952 KeInitializeEvent(&CreatedDeviceObject->DeviceLock, 953 SynchronizationEvent, 954 TRUE); 955 } 956 957 /* Set the right Sector Size */ 958 switch (DeviceType) 959 { 960 /* All disk systems */ 961 case FILE_DEVICE_DISK_FILE_SYSTEM: 962 case FILE_DEVICE_DISK: 963 case FILE_DEVICE_VIRTUAL_DISK: 964 965 /* The default is 512 bytes */ 966 CreatedDeviceObject->SectorSize = 512; 967 break; 968 969 /* CD-ROM file systems */ 970 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 971 972 /* The default is 2048 bytes */ 973 CreatedDeviceObject->SectorSize = 2048; 974 } 975 976 /* Create the Device Queue */ 977 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || 978 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) || 979 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || 980 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) || 981 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)) 982 { 983 /* Simple FS Devices, they don't need a real Device Queue */ 984 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry); 985 } 986 else 987 { 988 /* An actual Device, initialize its DQ */ 989 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue); 990 } 991 992 /* Insert the Object */ 993 Status = ObInsertObject(CreatedDeviceObject, 994 NULL, 995 FILE_READ_DATA | FILE_WRITE_DATA, 996 1, 997 (PVOID*)&CreatedDeviceObject, 998 &TempHandle); 999 if (!NT_SUCCESS(Status)) return Status; 1000 1001 /* Now do the final linking */ 1002 ObReferenceObject(DriverObject); 1003 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0); 1004 CreatedDeviceObject->DriverObject = DriverObject; 1005 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd); 1006 1007 /* Link with the power manager */ 1008 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject); 1009 1010 /* Close the temporary handle and return to caller */ 1011 ObCloseHandle(TempHandle, KernelMode); 1012 *DeviceObject = CreatedDeviceObject; 1013 return STATUS_SUCCESS; 1014 } 1015 1016 /* 1017 * IoDeleteDevice 1018 * 1019 * Status 1020 * @implemented 1021 */ 1022 VOID 1023 NTAPI 1024 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject) 1025 { 1026 PIO_TIMER Timer; 1027 1028 /* Check if the device is registered for shutdown notifications */ 1029 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) 1030 { 1031 /* Call the shutdown notifications */ 1032 IoUnregisterShutdownNotification(DeviceObject); 1033 } 1034 1035 /* Check if it has a timer */ 1036 Timer = DeviceObject->Timer; 1037 if (Timer) 1038 { 1039 /* Remove it and free it */ 1040 IopRemoveTimerFromTimerList(Timer); 1041 ExFreePoolWithTag(Timer, TAG_IO_TIMER); 1042 } 1043 1044 /* Check if the device has a name */ 1045 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) 1046 { 1047 /* It does, make it temporary so we can remove it */ 1048 ObMakeTemporaryObject(DeviceObject); 1049 } 1050 1051 /* Set the pending delete flag */ 1052 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING; 1053 1054 /* Unlink with the power manager */ 1055 if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject); 1056 1057 /* Check if the device object can be unloaded */ 1058 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject); 1059 } 1060 1061 /* 1062 * IoDetachDevice 1063 * 1064 * Status 1065 * @implemented 1066 */ 1067 VOID 1068 NTAPI 1069 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice) 1070 { 1071 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1072 1073 /* Sanity check */ 1074 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice); 1075 ASSERT(DeviceExtension->AttachedTo == TargetDevice); 1076 1077 /* Remove the attachment */ 1078 DeviceExtension->AttachedTo = NULL; 1079 TargetDevice->AttachedDevice = NULL; 1080 1081 /* Check if it's ok to delete this device */ 1082 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) && 1083 !(TargetDevice->ReferenceCount)) 1084 { 1085 /* It is, do it */ 1086 IopUnloadDevice(TargetDevice); 1087 } 1088 } 1089 1090 /* 1091 * @implemented 1092 */ 1093 NTSTATUS 1094 NTAPI 1095 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject, 1096 IN PDEVICE_OBJECT *DeviceObjectList, 1097 IN ULONG DeviceObjectListSize, 1098 OUT PULONG ActualNumberDeviceObjects) 1099 { 1100 ULONG ActualDevices = 1; 1101 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject; 1102 KIRQL OldIrql; 1103 1104 /* Lock the Device list while we enumerate it */ 1105 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 1106 1107 /* Find out how many devices we'll enumerate */ 1108 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++; 1109 1110 /* Go back to the first */ 1111 CurrentDevice = DriverObject->DeviceObject; 1112 1113 /* Start by at least returning this */ 1114 *ActualNumberDeviceObjects = ActualDevices; 1115 1116 /* Check if we can support so many */ 1117 if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize) 1118 { 1119 /* Fail because the buffer was too small */ 1120 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 1121 return STATUS_BUFFER_TOO_SMALL; 1122 } 1123 1124 /* Check if the caller wanted the device list */ 1125 if (DeviceObjectList) 1126 { 1127 /* Loop through all the devices */ 1128 while (ActualDevices) 1129 { 1130 /* Reference each Device */ 1131 ObReferenceObject(CurrentDevice); 1132 1133 /* Add it to the list */ 1134 *DeviceObjectList = CurrentDevice; 1135 1136 /* Go to the next one */ 1137 CurrentDevice = CurrentDevice->NextDevice; 1138 ActualDevices--; 1139 DeviceObjectList++; 1140 } 1141 } 1142 1143 /* Release the device list lock */ 1144 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 1145 1146 /* Return the status */ 1147 return STATUS_SUCCESS; 1148 } 1149 1150 /* 1151 * IoGetAttachedDevice 1152 * 1153 * Status 1154 * @implemented 1155 */ 1156 PDEVICE_OBJECT 1157 NTAPI 1158 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject) 1159 { 1160 /* Get the last attached device */ 1161 while (DeviceObject->AttachedDevice) 1162 { 1163 /* Move to the next one */ 1164 DeviceObject = DeviceObject->AttachedDevice; 1165 } 1166 1167 /* Return it */ 1168 return DeviceObject; 1169 } 1170 1171 /* 1172 * IoGetAttachedDeviceReference 1173 * 1174 * Status 1175 * @implemented 1176 */ 1177 PDEVICE_OBJECT 1178 NTAPI 1179 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject) 1180 { 1181 /* Reference the Attached Device */ 1182 DeviceObject = IoGetAttachedDevice(DeviceObject); 1183 ObReferenceObject(DeviceObject); 1184 return DeviceObject; 1185 } 1186 1187 /* 1188 * @implemented 1189 */ 1190 PDEVICE_OBJECT 1191 NTAPI 1192 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject) 1193 { 1194 /* Reference the lowest attached device */ 1195 DeviceObject = IopGetLowestDevice(DeviceObject); 1196 ObReferenceObject(DeviceObject); 1197 return DeviceObject; 1198 } 1199 1200 /* 1201 * IoGetDeviceObjectPointer 1202 * 1203 * Status 1204 * @implemented 1205 */ 1206 NTSTATUS 1207 NTAPI 1208 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 1209 IN ACCESS_MASK DesiredAccess, 1210 OUT PFILE_OBJECT *FileObject, 1211 OUT PDEVICE_OBJECT *DeviceObject) 1212 { 1213 /* Call the helper routine for a normal operation */ 1214 return IopGetDeviceObjectPointer(ObjectName, 1215 DesiredAccess, 1216 FileObject, 1217 DeviceObject, 1218 0); 1219 } 1220 1221 /* 1222 * @implemented 1223 */ 1224 NTSTATUS 1225 NTAPI 1226 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject, 1227 OUT PDEVICE_OBJECT *DiskDeviceObject) 1228 { 1229 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1230 PVPB Vpb; 1231 KIRQL OldIrql; 1232 NTSTATUS Status; 1233 1234 /* Make sure there's a VPB */ 1235 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER; 1236 1237 /* Acquire it */ 1238 IoAcquireVpbSpinLock(&OldIrql); 1239 1240 /* Get the Device Extension */ 1241 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject); 1242 1243 /* Make sure this one has a VPB too */ 1244 Vpb = DeviceExtension->Vpb; 1245 if (Vpb) 1246 { 1247 /* Make sure that it's mounted */ 1248 if ((Vpb->ReferenceCount) && 1249 (Vpb->Flags & VPB_MOUNTED)) 1250 { 1251 /* Return the Disk Device Object */ 1252 *DiskDeviceObject = Vpb->RealDevice; 1253 1254 /* Reference it and return success */ 1255 ObReferenceObject(Vpb->RealDevice); 1256 Status = STATUS_SUCCESS; 1257 } 1258 else 1259 { 1260 /* It's not, so return failure */ 1261 Status = STATUS_VOLUME_DISMOUNTED; 1262 } 1263 } 1264 else 1265 { 1266 /* Fail */ 1267 Status = STATUS_INVALID_PARAMETER; 1268 } 1269 1270 /* Release the lock */ 1271 IoReleaseVpbSpinLock(OldIrql); 1272 return Status; 1273 } 1274 1275 /* 1276 * @implemented 1277 */ 1278 PDEVICE_OBJECT 1279 NTAPI 1280 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject) 1281 { 1282 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1283 PDEVICE_OBJECT LowerDeviceObject = NULL; 1284 1285 /* Make sure it's not getting deleted */ 1286 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1287 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING | 1288 DOE_DELETE_PENDING | 1289 DOE_REMOVE_PENDING | 1290 DOE_REMOVE_PROCESSED))) 1291 { 1292 /* Get the Lower Device Object */ 1293 LowerDeviceObject = DeviceExtension->AttachedTo; 1294 1295 /* Check that we got a valid device object */ 1296 if (LowerDeviceObject) 1297 { 1298 /* We did so let's reference it */ 1299 ObReferenceObject(LowerDeviceObject); 1300 } 1301 } 1302 1303 /* Return it */ 1304 return LowerDeviceObject; 1305 } 1306 1307 /* 1308 * @implemented 1309 */ 1310 PDEVICE_OBJECT 1311 NTAPI 1312 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject) 1313 { 1314 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject; 1315 1316 /* Check if we have a VPB with a device object */ 1317 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1318 { 1319 /* Then use the DO from the VPB */ 1320 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1321 DeviceObject = FileObject->Vpb->DeviceObject; 1322 } 1323 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1324 (FileObject->DeviceObject->Vpb) && 1325 (FileObject->DeviceObject->Vpb->DeviceObject)) 1326 { 1327 /* The disk device actually has a VPB, so get the DO from there */ 1328 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1329 } 1330 else 1331 { 1332 /* Otherwise, this was a direct open */ 1333 DeviceObject = FileObject->DeviceObject; 1334 } 1335 1336 /* Sanity check */ 1337 ASSERT(DeviceObject != NULL); 1338 1339 /* Check if we were attached */ 1340 if (DeviceObject->AttachedDevice) 1341 { 1342 /* Check if the file object has an extension present */ 1343 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) 1344 { 1345 /* Sanity check, direct open files can't have this */ 1346 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1347 1348 /* Check if the extension is really present */ 1349 if (FileObject->FileObjectExtension) 1350 { 1351 PFILE_OBJECT_EXTENSION FileObjectExtension; 1352 1353 /* Cast the buffer to something we understand */ 1354 FileObjectExtension = FileObject->FileObjectExtension; 1355 1356 /* Check if have a replacement top level device */ 1357 if (FileObjectExtension->TopDeviceObjectHint) 1358 { 1359 /* Use this instead of returning the top level device */ 1360 return FileObjectExtension->TopDeviceObjectHint; 1361 } 1362 } 1363 } 1364 1365 /* Return the highest attached device */ 1366 DeviceObject = IoGetAttachedDevice(DeviceObject); 1367 } 1368 1369 /* Return the DO we found */ 1370 return DeviceObject; 1371 } 1372 1373 /* 1374 * @implemented 1375 */ 1376 NTSTATUS 1377 NTAPI 1378 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 1379 OUT PDEVICE_OBJECT *DeviceObject) 1380 { 1381 NTSTATUS Status; 1382 PDEVICE_NODE DeviceNode = NULL; 1383 1384 /* Call the internal helper function */ 1385 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode); 1386 if (NT_SUCCESS(Status) && DeviceNode) 1387 { 1388 *DeviceObject = DeviceNode->PhysicalDeviceObject; 1389 } 1390 return Status; 1391 } 1392 1393 /* 1394 * @implemented 1395 */ 1396 PDEVICE_OBJECT 1397 NTAPI 1398 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject) 1399 { 1400 PDEVICE_OBJECT DeviceObject; 1401 1402 /* 1403 * If the FILE_OBJECT's VPB is defined, 1404 * get the device from it. 1405 */ 1406 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1407 { 1408 /* Use the VPB's Device Object's */ 1409 DeviceObject = FileObject->Vpb->DeviceObject; 1410 } 1411 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1412 (FileObject->DeviceObject->Vpb) && 1413 (FileObject->DeviceObject->Vpb->DeviceObject)) 1414 { 1415 /* Use the VPB's File System Object */ 1416 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1417 } 1418 else 1419 { 1420 /* Use the FO's Device Object */ 1421 DeviceObject = FileObject->DeviceObject; 1422 } 1423 1424 /* Return the device object we found */ 1425 ASSERT(DeviceObject != NULL); 1426 return DeviceObject; 1427 } 1428 1429 /* 1430 * @implemented 1431 */ 1432 NTSTATUS 1433 NTAPI 1434 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject) 1435 { 1436 PSHUTDOWN_ENTRY Entry; 1437 1438 /* Allocate the shutdown entry */ 1439 Entry = ExAllocatePoolWithTag(NonPagedPool, 1440 sizeof(SHUTDOWN_ENTRY), 1441 TAG_SHUTDOWN_ENTRY); 1442 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1443 1444 /* Set the DO */ 1445 Entry->DeviceObject = DeviceObject; 1446 1447 /* Reference it so it doesn't go away */ 1448 ObReferenceObject(DeviceObject); 1449 1450 /* Insert it into the list */ 1451 ExInterlockedInsertHeadList(&LastChanceShutdownListHead, 1452 &Entry->ShutdownList, 1453 &ShutdownListLock); 1454 1455 /* Set the shutdown registered flag */ 1456 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1457 return STATUS_SUCCESS; 1458 } 1459 1460 /* 1461 * @implemented 1462 */ 1463 NTSTATUS 1464 NTAPI 1465 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1466 { 1467 PSHUTDOWN_ENTRY Entry; 1468 1469 /* Allocate the shutdown entry */ 1470 Entry = ExAllocatePoolWithTag(NonPagedPool, 1471 sizeof(SHUTDOWN_ENTRY), 1472 TAG_SHUTDOWN_ENTRY); 1473 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1474 1475 /* Set the DO */ 1476 Entry->DeviceObject = DeviceObject; 1477 1478 /* Reference it so it doesn't go away */ 1479 ObReferenceObject(DeviceObject); 1480 1481 /* Insert it into the list */ 1482 ExInterlockedInsertHeadList(&ShutdownListHead, 1483 &Entry->ShutdownList, 1484 &ShutdownListLock); 1485 1486 /* Set the shutdown registered flag */ 1487 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1488 return STATUS_SUCCESS; 1489 } 1490 1491 /* 1492 * @implemented 1493 */ 1494 VOID 1495 NTAPI 1496 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1497 { 1498 PSHUTDOWN_ENTRY ShutdownEntry; 1499 PLIST_ENTRY NextEntry; 1500 KIRQL OldIrql; 1501 1502 /* Remove the flag */ 1503 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 1504 1505 /* Acquire the shutdown lock and loop the shutdown list */ 1506 KeAcquireSpinLock(&ShutdownListLock, &OldIrql); 1507 NextEntry = ShutdownListHead.Flink; 1508 while (NextEntry != &ShutdownListHead) 1509 { 1510 /* Get the entry */ 1511 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1512 SHUTDOWN_ENTRY, 1513 ShutdownList); 1514 1515 /* Get if the DO matches */ 1516 if (ShutdownEntry->DeviceObject == DeviceObject) 1517 { 1518 /* Remove it from the list */ 1519 RemoveEntryList(NextEntry); 1520 NextEntry = NextEntry->Blink; 1521 1522 /* Free the entry */ 1523 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1524 1525 /* Get rid of our reference to it */ 1526 ObDereferenceObject(DeviceObject); 1527 } 1528 1529 /* Go to the next entry */ 1530 NextEntry = NextEntry->Flink; 1531 } 1532 1533 /* Now loop the last chance list */ 1534 NextEntry = LastChanceShutdownListHead.Flink; 1535 while (NextEntry != &LastChanceShutdownListHead) 1536 { 1537 /* Get the entry */ 1538 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1539 SHUTDOWN_ENTRY, 1540 ShutdownList); 1541 1542 /* Get if the DO matches */ 1543 if (ShutdownEntry->DeviceObject == DeviceObject) 1544 { 1545 /* Remove it from the list */ 1546 RemoveEntryList(NextEntry); 1547 NextEntry = NextEntry->Blink; 1548 1549 /* Free the entry */ 1550 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1551 1552 /* Get rid of our reference to it */ 1553 ObDereferenceObject(DeviceObject); 1554 } 1555 1556 /* Go to the next entry */ 1557 NextEntry = NextEntry->Flink; 1558 } 1559 1560 /* Release the shutdown lock */ 1561 KeReleaseSpinLock(&ShutdownListLock, OldIrql); 1562 } 1563 1564 /* 1565 * @implemented 1566 */ 1567 VOID 1568 NTAPI 1569 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject, 1570 IN BOOLEAN DeferredStartIo, 1571 IN BOOLEAN NonCancelable) 1572 { 1573 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1574 1575 /* Get the Device Extension */ 1576 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1577 1578 /* Set the flags the caller requested */ 1579 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0; 1580 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0; 1581 } 1582 1583 /* 1584 * @implemented 1585 */ 1586 VOID 1587 NTAPI 1588 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 1589 IN BOOLEAN Cancelable, 1590 IN ULONG Key) 1591 { 1592 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1593 1594 /* Get the Device Extension */ 1595 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1596 1597 /* Check if deferred start was requested */ 1598 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1599 { 1600 /* Call our internal function to handle the defered case */ 1601 IopStartNextPacketByKeyEx(DeviceObject, 1602 Key, 1603 DOE_SIO_WITH_KEY | 1604 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1605 } 1606 else 1607 { 1608 /* Call the normal routine */ 1609 IopStartNextPacketByKey(DeviceObject, Cancelable, Key); 1610 } 1611 } 1612 1613 /* 1614 * @implemented 1615 */ 1616 VOID 1617 NTAPI 1618 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 1619 IN BOOLEAN Cancelable) 1620 { 1621 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1622 1623 /* Get the Device Extension */ 1624 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1625 1626 /* Check if deferred start was requested */ 1627 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1628 { 1629 /* Call our internal function to handle the defered case */ 1630 IopStartNextPacketByKeyEx(DeviceObject, 1631 0, 1632 DOE_SIO_NO_KEY | 1633 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1634 } 1635 else 1636 { 1637 /* Call the normal routine */ 1638 IopStartNextPacket(DeviceObject, Cancelable); 1639 } 1640 } 1641 1642 /* 1643 * @implemented 1644 */ 1645 VOID 1646 NTAPI 1647 IoStartPacket(IN PDEVICE_OBJECT DeviceObject, 1648 IN PIRP Irp, 1649 IN PULONG Key, 1650 IN PDRIVER_CANCEL CancelFunction) 1651 { 1652 BOOLEAN Stat; 1653 KIRQL OldIrql, CancelIrql; 1654 1655 /* Raise to dispatch level */ 1656 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 1657 1658 /* Check if we should acquire the cancel lock */ 1659 if (CancelFunction) 1660 { 1661 /* Acquire and set it */ 1662 IoAcquireCancelSpinLock(&CancelIrql); 1663 Irp->CancelRoutine = CancelFunction; 1664 } 1665 1666 /* Check if we have a key */ 1667 if (Key) 1668 { 1669 /* Insert by key */ 1670 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue, 1671 &Irp->Tail.Overlay.DeviceQueueEntry, 1672 *Key); 1673 } 1674 else 1675 { 1676 /* Insert without a key */ 1677 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue, 1678 &Irp->Tail.Overlay.DeviceQueueEntry); 1679 } 1680 1681 /* Check if this was a first insert */ 1682 if (!Stat) 1683 { 1684 /* Set the IRP */ 1685 DeviceObject->CurrentIrp = Irp; 1686 1687 /* Check if this is a cancelable packet */ 1688 if (CancelFunction) 1689 { 1690 /* Check if the caller requested no cancellation */ 1691 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 1692 DOE_SIO_NO_CANCEL) 1693 { 1694 /* He did, so remove the cancel routine */ 1695 Irp->CancelRoutine = NULL; 1696 } 1697 1698 /* Release the cancel lock */ 1699 IoReleaseCancelSpinLock(CancelIrql); 1700 } 1701 1702 /* Call the Start I/O function */ 1703 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 1704 } 1705 else 1706 { 1707 /* The packet was inserted... check if we have a cancel function */ 1708 if (CancelFunction) 1709 { 1710 /* Check if the IRP got cancelled */ 1711 if (Irp->Cancel) 1712 { 1713 /* 1714 * Set the cancel IRQL, clear the currnet cancel routine and 1715 * call ours 1716 */ 1717 Irp->CancelIrql = CancelIrql; 1718 Irp->CancelRoutine = NULL; 1719 CancelFunction(DeviceObject, Irp); 1720 } 1721 else 1722 { 1723 /* Otherwise, release the lock */ 1724 IoReleaseCancelSpinLock(CancelIrql); 1725 } 1726 } 1727 } 1728 1729 /* Return back to previous IRQL */ 1730 KeLowerIrql(OldIrql); 1731 } 1732 1733 #if defined (_WIN64) 1734 ULONG 1735 NTAPI 1736 IoWMIDeviceObjectToProviderId( 1737 IN PDEVICE_OBJECT DeviceObject) 1738 { 1739 UNIMPLEMENTED; 1740 return 0; 1741 } 1742 #endif 1743 1744 /* EOF */ 1745