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