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 ASSERT(FALSE); 1353 1354 /* Cast the buffer to something we understand */ 1355 FileObjectExtension = FileObject->FileObjectExtension; 1356 1357 /* Check if have a replacement top level device */ 1358 if (FileObjectExtension->TopDeviceObjectHint) 1359 { 1360 /* Use this instead of returning the top level device */ 1361 return FileObjectExtension->TopDeviceObjectHint; 1362 } 1363 } 1364 } 1365 1366 /* Return the highest attached device */ 1367 DeviceObject = IoGetAttachedDevice(DeviceObject); 1368 } 1369 1370 /* Return the DO we found */ 1371 return DeviceObject; 1372 } 1373 1374 /* 1375 * @implemented 1376 */ 1377 NTSTATUS 1378 NTAPI 1379 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 1380 OUT PDEVICE_OBJECT *DeviceObject) 1381 { 1382 NTSTATUS Status; 1383 PDEVICE_NODE DeviceNode = NULL; 1384 1385 /* Call the internal helper function */ 1386 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode); 1387 if (NT_SUCCESS(Status) && DeviceNode) 1388 { 1389 *DeviceObject = DeviceNode->PhysicalDeviceObject; 1390 } 1391 return Status; 1392 } 1393 1394 /* 1395 * @implemented 1396 */ 1397 PDEVICE_OBJECT 1398 NTAPI 1399 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject) 1400 { 1401 PDEVICE_OBJECT DeviceObject; 1402 1403 /* 1404 * If the FILE_OBJECT's VPB is defined, 1405 * get the device from it. 1406 */ 1407 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1408 { 1409 /* Use the VPB's Device Object's */ 1410 DeviceObject = FileObject->Vpb->DeviceObject; 1411 } 1412 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1413 (FileObject->DeviceObject->Vpb) && 1414 (FileObject->DeviceObject->Vpb->DeviceObject)) 1415 { 1416 /* Use the VPB's File System Object */ 1417 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1418 } 1419 else 1420 { 1421 /* Use the FO's Device Object */ 1422 DeviceObject = FileObject->DeviceObject; 1423 } 1424 1425 /* Return the device object we found */ 1426 ASSERT(DeviceObject != NULL); 1427 return DeviceObject; 1428 } 1429 1430 /* 1431 * @implemented 1432 */ 1433 NTSTATUS 1434 NTAPI 1435 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject) 1436 { 1437 PSHUTDOWN_ENTRY Entry; 1438 1439 /* Allocate the shutdown entry */ 1440 Entry = ExAllocatePoolWithTag(NonPagedPool, 1441 sizeof(SHUTDOWN_ENTRY), 1442 TAG_SHUTDOWN_ENTRY); 1443 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1444 1445 /* Set the DO */ 1446 Entry->DeviceObject = DeviceObject; 1447 1448 /* Reference it so it doesn't go away */ 1449 ObReferenceObject(DeviceObject); 1450 1451 /* Insert it into the list */ 1452 ExInterlockedInsertHeadList(&LastChanceShutdownListHead, 1453 &Entry->ShutdownList, 1454 &ShutdownListLock); 1455 1456 /* Set the shutdown registered flag */ 1457 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1458 return STATUS_SUCCESS; 1459 } 1460 1461 /* 1462 * @implemented 1463 */ 1464 NTSTATUS 1465 NTAPI 1466 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1467 { 1468 PSHUTDOWN_ENTRY Entry; 1469 1470 /* Allocate the shutdown entry */ 1471 Entry = ExAllocatePoolWithTag(NonPagedPool, 1472 sizeof(SHUTDOWN_ENTRY), 1473 TAG_SHUTDOWN_ENTRY); 1474 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES; 1475 1476 /* Set the DO */ 1477 Entry->DeviceObject = DeviceObject; 1478 1479 /* Reference it so it doesn't go away */ 1480 ObReferenceObject(DeviceObject); 1481 1482 /* Insert it into the list */ 1483 ExInterlockedInsertHeadList(&ShutdownListHead, 1484 &Entry->ShutdownList, 1485 &ShutdownListLock); 1486 1487 /* Set the shutdown registered flag */ 1488 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED; 1489 return STATUS_SUCCESS; 1490 } 1491 1492 /* 1493 * @implemented 1494 */ 1495 VOID 1496 NTAPI 1497 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject) 1498 { 1499 PSHUTDOWN_ENTRY ShutdownEntry; 1500 PLIST_ENTRY NextEntry; 1501 KIRQL OldIrql; 1502 1503 /* Remove the flag */ 1504 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 1505 1506 /* Acquire the shutdown lock and loop the shutdown list */ 1507 KeAcquireSpinLock(&ShutdownListLock, &OldIrql); 1508 NextEntry = ShutdownListHead.Flink; 1509 while (NextEntry != &ShutdownListHead) 1510 { 1511 /* Get the entry */ 1512 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1513 SHUTDOWN_ENTRY, 1514 ShutdownList); 1515 1516 /* Get if the DO matches */ 1517 if (ShutdownEntry->DeviceObject == DeviceObject) 1518 { 1519 /* Remove it from the list */ 1520 RemoveEntryList(NextEntry); 1521 NextEntry = NextEntry->Blink; 1522 1523 /* Free the entry */ 1524 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1525 1526 /* Get rid of our reference to it */ 1527 ObDereferenceObject(DeviceObject); 1528 } 1529 1530 /* Go to the next entry */ 1531 NextEntry = NextEntry->Flink; 1532 } 1533 1534 /* Now loop the last chance list */ 1535 NextEntry = LastChanceShutdownListHead.Flink; 1536 while (NextEntry != &LastChanceShutdownListHead) 1537 { 1538 /* Get the entry */ 1539 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1540 SHUTDOWN_ENTRY, 1541 ShutdownList); 1542 1543 /* Get if the DO matches */ 1544 if (ShutdownEntry->DeviceObject == DeviceObject) 1545 { 1546 /* Remove it from the list */ 1547 RemoveEntryList(NextEntry); 1548 NextEntry = NextEntry->Blink; 1549 1550 /* Free the entry */ 1551 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1552 1553 /* Get rid of our reference to it */ 1554 ObDereferenceObject(DeviceObject); 1555 } 1556 1557 /* Go to the next entry */ 1558 NextEntry = NextEntry->Flink; 1559 } 1560 1561 /* Release the shutdown lock */ 1562 KeReleaseSpinLock(&ShutdownListLock, OldIrql); 1563 } 1564 1565 /* 1566 * @implemented 1567 */ 1568 VOID 1569 NTAPI 1570 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject, 1571 IN BOOLEAN DeferredStartIo, 1572 IN BOOLEAN NonCancelable) 1573 { 1574 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1575 1576 /* Get the Device Extension */ 1577 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1578 1579 /* Set the flags the caller requested */ 1580 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0; 1581 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0; 1582 } 1583 1584 /* 1585 * @implemented 1586 */ 1587 VOID 1588 NTAPI 1589 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 1590 IN BOOLEAN Cancelable, 1591 IN ULONG Key) 1592 { 1593 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1594 1595 /* Get the Device Extension */ 1596 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1597 1598 /* Check if deferred start was requested */ 1599 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1600 { 1601 /* Call our internal function to handle the defered case */ 1602 IopStartNextPacketByKeyEx(DeviceObject, 1603 Key, 1604 DOE_SIO_WITH_KEY | 1605 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1606 } 1607 else 1608 { 1609 /* Call the normal routine */ 1610 IopStartNextPacketByKey(DeviceObject, Cancelable, Key); 1611 } 1612 } 1613 1614 /* 1615 * @implemented 1616 */ 1617 VOID 1618 NTAPI 1619 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 1620 IN BOOLEAN Cancelable) 1621 { 1622 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1623 1624 /* Get the Device Extension */ 1625 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1626 1627 /* Check if deferred start was requested */ 1628 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED) 1629 { 1630 /* Call our internal function to handle the defered case */ 1631 IopStartNextPacketByKeyEx(DeviceObject, 1632 0, 1633 DOE_SIO_NO_KEY | 1634 (Cancelable ? DOE_SIO_CANCELABLE : 0)); 1635 } 1636 else 1637 { 1638 /* Call the normal routine */ 1639 IopStartNextPacket(DeviceObject, Cancelable); 1640 } 1641 } 1642 1643 /* 1644 * @implemented 1645 */ 1646 VOID 1647 NTAPI 1648 IoStartPacket(IN PDEVICE_OBJECT DeviceObject, 1649 IN PIRP Irp, 1650 IN PULONG Key, 1651 IN PDRIVER_CANCEL CancelFunction) 1652 { 1653 BOOLEAN Stat; 1654 KIRQL OldIrql, CancelIrql; 1655 1656 /* Raise to dispatch level */ 1657 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 1658 1659 /* Check if we should acquire the cancel lock */ 1660 if (CancelFunction) 1661 { 1662 /* Acquire and set it */ 1663 IoAcquireCancelSpinLock(&CancelIrql); 1664 Irp->CancelRoutine = CancelFunction; 1665 } 1666 1667 /* Check if we have a key */ 1668 if (Key) 1669 { 1670 /* Insert by key */ 1671 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue, 1672 &Irp->Tail.Overlay.DeviceQueueEntry, 1673 *Key); 1674 } 1675 else 1676 { 1677 /* Insert without a key */ 1678 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue, 1679 &Irp->Tail.Overlay.DeviceQueueEntry); 1680 } 1681 1682 /* Check if this was a first insert */ 1683 if (!Stat) 1684 { 1685 /* Set the IRP */ 1686 DeviceObject->CurrentIrp = Irp; 1687 1688 /* Check if this is a cancelable packet */ 1689 if (CancelFunction) 1690 { 1691 /* Check if the caller requested no cancellation */ 1692 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 1693 DOE_SIO_NO_CANCEL) 1694 { 1695 /* He did, so remove the cancel routine */ 1696 Irp->CancelRoutine = NULL; 1697 } 1698 1699 /* Release the cancel lock */ 1700 IoReleaseCancelSpinLock(CancelIrql); 1701 } 1702 1703 /* Call the Start I/O function */ 1704 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 1705 } 1706 else 1707 { 1708 /* The packet was inserted... check if we have a cancel function */ 1709 if (CancelFunction) 1710 { 1711 /* Check if the IRP got cancelled */ 1712 if (Irp->Cancel) 1713 { 1714 /* 1715 * Set the cancel IRQL, clear the currnet cancel routine and 1716 * call ours 1717 */ 1718 Irp->CancelIrql = CancelIrql; 1719 Irp->CancelRoutine = NULL; 1720 CancelFunction(DeviceObject, Irp); 1721 } 1722 else 1723 { 1724 /* Otherwise, release the lock */ 1725 IoReleaseCancelSpinLock(CancelIrql); 1726 } 1727 } 1728 } 1729 1730 /* Return back to previous IRQL */ 1731 KeLowerIrql(OldIrql); 1732 } 1733 1734 #if defined (_WIN64) 1735 ULONG 1736 NTAPI 1737 IoWMIDeviceObjectToProviderId( 1738 IN PDEVICE_OBJECT DeviceObject) 1739 { 1740 UNIMPLEMENTED; 1741 return 0; 1742 } 1743 #endif 1744 1745 /* EOF */ 1746