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 IopDiskFsListHead; 23 extern LIST_ENTRY IopCdRomFsListHead; 24 extern LIST_ENTRY IopTapeFsListHead; 25 26 /* PRIVATE FUNCTIONS **********************************************************/ 27 28 VOID 29 NTAPI 30 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver) 31 { 32 PDEVICE_OBJECT DeviceObject; 33 PAGED_CODE(); 34 35 /* Set the driver as initialized */ 36 Driver->Flags |= DRVO_INITIALIZED; 37 DeviceObject = Driver->DeviceObject; 38 while (DeviceObject) 39 { 40 /* Set every device as initialized too */ 41 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 42 DeviceObject = DeviceObject->NextDevice; 43 } 44 } 45 46 VOID 47 NTAPI 48 IopDeleteDevice(IN PVOID ObjectBody) 49 { 50 PDEVICE_OBJECT DeviceObject = ObjectBody; 51 PAGED_CODE(); 52 53 /* TODO: Delete Device Node */ 54 55 /* Dereference the driver object, referenced in IoCreateDevice */ 56 if (DeviceObject->DriverObject) 57 ObDereferenceObject(DeviceObject->DriverObject); 58 } 59 60 61 PDEVICE_OBJECT 62 NTAPI 63 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 64 IN PDEVICE_OBJECT TargetDevice, 65 OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL) 66 { 67 PDEVICE_OBJECT AttachedDevice; 68 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension; 69 70 /* Get the Attached Device and source extension */ 71 AttachedDevice = IoGetAttachedDevice(TargetDevice); 72 SourceDeviceExtension = IoGetDevObjExtension(SourceDevice); 73 ASSERT(SourceDeviceExtension->AttachedTo == NULL); 74 75 /* Make sure that it's in a correct state */ 76 if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) || 77 (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 78 (DOE_UNLOAD_PENDING | 79 DOE_DELETE_PENDING | 80 DOE_REMOVE_PENDING | 81 DOE_REMOVE_PROCESSED))) 82 { 83 /* Device was unloading or being removed */ 84 AttachedDevice = NULL; 85 } 86 else 87 { 88 /* Update atached device fields */ 89 AttachedDevice->AttachedDevice = SourceDevice; 90 AttachedDevice->Spare1++; 91 92 /* Update the source with the attached data */ 93 SourceDevice->StackSize = AttachedDevice->StackSize + 1; 94 SourceDevice->AlignmentRequirement = AttachedDevice-> 95 AlignmentRequirement; 96 SourceDevice->SectorSize = AttachedDevice->SectorSize; 97 98 /* Check for pending start flag */ 99 if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags & 100 DOE_START_PENDING) 101 { 102 /* Propagate */ 103 IoGetDevObjExtension(SourceDevice)->ExtensionFlags |= 104 DOE_START_PENDING; 105 } 106 107 /* Set the attachment in the device extension */ 108 SourceDeviceExtension->AttachedTo = AttachedDevice; 109 } 110 111 /* Return the attached device */ 112 if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice; 113 return AttachedDevice; 114 } 115 116 VOID 117 NTAPI 118 IoShutdownPnpDevices(VOID) 119 { 120 /* This routine is only used by Driver Verifier to validate shutdown */ 121 return; 122 } 123 124 VOID 125 NTAPI 126 IoShutdownSystem(IN ULONG Phase) 127 { 128 PLIST_ENTRY ListEntry; 129 PDEVICE_OBJECT DeviceObject; 130 PSHUTDOWN_ENTRY ShutdownEntry; 131 IO_STATUS_BLOCK StatusBlock; 132 PIRP Irp; 133 KEVENT Event; 134 NTSTATUS Status; 135 136 /* Initialize an event to wait on */ 137 KeInitializeEvent(&Event, NotificationEvent, FALSE); 138 139 /* What phase? */ 140 if (Phase == 0) 141 { 142 /* Shutdown PnP */ 143 IoShutdownPnpDevices(); 144 145 /* Loop first-chance shutdown notifications */ 146 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 147 &ShutdownListLock); 148 while (ListEntry) 149 { 150 /* Get the shutdown entry */ 151 ShutdownEntry = CONTAINING_RECORD(ListEntry, 152 SHUTDOWN_ENTRY, 153 ShutdownList); 154 155 /* Get the attached device */ 156 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 157 158 /* Build the shutdown IRP and call the driver */ 159 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 160 DeviceObject, 161 NULL, 162 0, 163 NULL, 164 &Event, 165 &StatusBlock); 166 Status = IoCallDriver(DeviceObject, Irp); 167 if (Status == STATUS_PENDING) 168 { 169 /* Wait on the driver */ 170 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 171 } 172 173 /* Get rid of our reference to it */ 174 ObDereferenceObject(DeviceObject); 175 176 /* Free the shutdown entry and reset the event */ 177 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 178 KeClearEvent(&Event); 179 180 /* Go to the next entry */ 181 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead, 182 &ShutdownListLock); 183 } 184 } 185 else if (Phase == 1) 186 { 187 /* Shutdown disk file systems */ 188 IopShutdownBaseFileSystems(&IopDiskFsListHead); 189 190 /* Shutdown cdrom file systems */ 191 IopShutdownBaseFileSystems(&IopCdRomFsListHead); 192 193 /* Shutdown tape filesystems */ 194 IopShutdownBaseFileSystems(&IopTapeFsListHead); 195 196 /* Loop last-chance shutdown notifications */ 197 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 198 &ShutdownListLock); 199 while (ListEntry) 200 { 201 /* Get the shutdown entry */ 202 ShutdownEntry = CONTAINING_RECORD(ListEntry, 203 SHUTDOWN_ENTRY, 204 ShutdownList); 205 206 /* Get the attached device */ 207 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject); 208 209 /* Build the shutdown IRP and call the driver */ 210 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 211 DeviceObject, 212 NULL, 213 0, 214 NULL, 215 &Event, 216 &StatusBlock); 217 Status = IoCallDriver(DeviceObject, Irp); 218 if (Status == STATUS_PENDING) 219 { 220 /* Wait on the driver */ 221 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 222 } 223 224 /* Get rid of our reference to it */ 225 ObDereferenceObject(DeviceObject); 226 227 /* Free the shutdown entry and reset the event */ 228 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 229 KeClearEvent(&Event); 230 231 /* Go to the next entry */ 232 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead, 233 &ShutdownListLock); 234 } 235 236 } 237 } 238 239 NTSTATUS 240 NTAPI 241 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 242 IN ACCESS_MASK DesiredAccess, 243 OUT PFILE_OBJECT *FileObject, 244 OUT PDEVICE_OBJECT *DeviceObject, 245 IN ULONG AttachFlag) 246 { 247 OBJECT_ATTRIBUTES ObjectAttributes; 248 IO_STATUS_BLOCK StatusBlock; 249 PFILE_OBJECT LocalFileObject; 250 HANDLE FileHandle; 251 NTSTATUS Status; 252 253 /* Open the Device */ 254 InitializeObjectAttributes(&ObjectAttributes, 255 ObjectName, 256 OBJ_KERNEL_HANDLE, 257 NULL, 258 NULL); 259 Status = ZwOpenFile(&FileHandle, 260 DesiredAccess, 261 &ObjectAttributes, 262 &StatusBlock, 263 0, 264 FILE_NON_DIRECTORY_FILE | AttachFlag); 265 if (!NT_SUCCESS(Status)) return Status; 266 267 /* Get File Object */ 268 Status = ObReferenceObjectByHandle(FileHandle, 269 0, 270 IoFileObjectType, 271 KernelMode, 272 (PVOID*)&LocalFileObject, 273 NULL); 274 if (NT_SUCCESS(Status)) 275 { 276 /* Return the requested data */ 277 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject); 278 *FileObject = LocalFileObject; 279 } 280 281 /* Close the handle */ 282 ZwClose(FileHandle); 283 284 return Status; 285 } 286 287 PDEVICE_OBJECT 288 NTAPI 289 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject) 290 { 291 PDEVICE_OBJECT LowestDevice; 292 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 293 294 /* Get the current device and its extension */ 295 LowestDevice = DeviceObject; 296 DeviceExtension = IoGetDevObjExtension(LowestDevice); 297 298 /* Keep looping as long as we're attached */ 299 while (DeviceExtension->AttachedTo) 300 { 301 /* Get the lowest device and its extension */ 302 LowestDevice = DeviceExtension->AttachedTo; 303 DeviceExtension = IoGetDevObjExtension(LowestDevice); 304 } 305 306 /* Return the lowest device */ 307 return LowestDevice; 308 } 309 310 VOID 311 NTAPI 312 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject, 313 IN PDEVICE_OBJECT DeviceObject, 314 IN IOP_DEVICE_LIST_OPERATION Type) 315 { 316 PDEVICE_OBJECT Previous; 317 318 /* Check the type of operation */ 319 if (Type == IopRemove) 320 { 321 /* Get the current device and check if it's the current one */ 322 Previous = DeviceObject->DriverObject->DeviceObject; 323 if (Previous == DeviceObject) 324 { 325 /* It is, simply unlink this one directly */ 326 DeviceObject->DriverObject->DeviceObject = 327 DeviceObject->NextDevice; 328 } 329 else 330 { 331 /* It's not, so loop until we find the device */ 332 while (Previous->NextDevice != DeviceObject) 333 { 334 /* Not this one, keep moving */ 335 Previous = Previous->NextDevice; 336 } 337 338 /* We found it, now unlink us */ 339 Previous->NextDevice = DeviceObject->NextDevice; 340 } 341 } 342 else 343 { 344 /* Link the device object and the driver object */ 345 DeviceObject->NextDevice = DriverObject->DeviceObject; 346 DriverObject->DeviceObject = DeviceObject; 347 } 348 } 349 350 VOID 351 NTAPI 352 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject) 353 { 354 PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject; 355 PDEVICE_OBJECT AttachedDeviceObject, LowestDeviceObject; 356 PEXTENDED_DEVOBJ_EXTENSION ThisExtension, DeviceExtension; 357 PDEVICE_NODE DeviceNode; 358 BOOLEAN SafeToUnload = TRUE; 359 360 /* Check if removal is pending */ 361 ThisExtension = IoGetDevObjExtension(DeviceObject); 362 if (ThisExtension->ExtensionFlags & DOE_REMOVE_PENDING) 363 { 364 /* Get the PDO, extension, and node */ 365 LowestDeviceObject = IopGetLowestDevice(DeviceObject); 366 DeviceExtension = IoGetDevObjExtension(LowestDeviceObject); 367 DeviceNode = DeviceExtension->DeviceNode; 368 369 /* The PDO needs a device node */ 370 ASSERT(DeviceNode != NULL); 371 372 /* Loop all attached objects */ 373 AttachedDeviceObject = LowestDeviceObject; 374 while (AttachedDeviceObject) 375 { 376 /* Make sure they're dereferenced */ 377 if (AttachedDeviceObject->ReferenceCount) return; 378 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 379 } 380 381 /* Loop all attached objects */ 382 AttachedDeviceObject = LowestDeviceObject; 383 while (AttachedDeviceObject) 384 { 385 /* Get the device extension */ 386 DeviceExtension = IoGetDevObjExtension(AttachedDeviceObject); 387 388 /* Remove the pending flag and set processed */ 389 DeviceExtension->ExtensionFlags &= ~DOE_REMOVE_PENDING; 390 DeviceExtension->ExtensionFlags |= DOE_REMOVE_PROCESSED; 391 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 392 } 393 394 /* 395 * FIXME: TODO HPOUSSIN 396 * We need to parse/lock the device node, and if we have any pending 397 * surprise removals, query all relationships and send IRP_MN_REMOVE_ 398 * _DEVICE to the devices related... 399 */ 400 return; 401 } 402 403 /* Check if deletion is pending */ 404 if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING) 405 { 406 /* Make sure unload is pending */ 407 if (!(ThisExtension->ExtensionFlags & DOE_UNLOAD_PENDING) || 408 (DriverObject->Flags & DRVO_UNLOAD_INVOKED)) 409 { 410 /* We can't unload anymore */ 411 SafeToUnload = FALSE; 412 } 413 414 /* 415 * Check if we have an attached device and fail if we're attached 416 * and still have a reference count. 417 */ 418 AttachedDeviceObject = DeviceObject->AttachedDevice; 419 if ((AttachedDeviceObject) && (DeviceObject->ReferenceCount)) return; 420 421 /* Check if we have a Security Descriptor */ 422 if (DeviceObject->SecurityDescriptor) 423 { 424 /* Free it */ 425 ExFreePoolWithTag(DeviceObject->SecurityDescriptor, TAG_SD); 426 } 427 428 /* Remove the device from the list */ 429 IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove); 430 431 /* Dereference the keep-alive */ 432 ObDereferenceObject(DeviceObject); 433 434 /* If we're not unloading, stop here */ 435 if (!SafeToUnload) return; 436 } 437 438 /* Loop all the device objects */ 439 DeviceObject = DriverObject->DeviceObject; 440 while (DeviceObject) 441 { 442 /* 443 * Make sure we're not attached, having a reference count 444 * or already deleting 445 */ 446 if ((DeviceObject->ReferenceCount) || 447 (DeviceObject->AttachedDevice) || 448 (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & 449 (DOE_DELETE_PENDING | DOE_REMOVE_PENDING))) 450 { 451 /* We're not safe to unload, quit */ 452 return; 453 } 454 455 /* Check the next device */ 456 DeviceObject = DeviceObject->NextDevice; 457 } 458 459 /* Set the unload invoked flag */ 460 DriverObject->Flags |= DRVO_UNLOAD_INVOKED; 461 462 /* Unload it */ 463 if (DriverObject->DriverUnload) DriverObject->DriverUnload(DriverObject); 464 465 /* Make object temporary so it can be deleted */ 466 ObMakeTemporaryObject(DriverObject); 467 468 /* Dereference once more, referenced at driver object creation */ 469 ObDereferenceObject(DriverObject); 470 471 } 472 473 VOID 474 NTAPI 475 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject, 476 IN BOOLEAN ForceUnload) 477 { 478 /* Sanity check */ 479 ASSERT(DeviceObject->ReferenceCount); 480 481 /* Dereference the device */ 482 DeviceObject->ReferenceCount--; 483 484 /* 485 * Check if we can unload it and it's safe to unload (or if we're forcing 486 * an unload, which is OK too). 487 */ 488 if (!(DeviceObject->ReferenceCount) && 489 ((ForceUnload) || (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & 490 (DOE_UNLOAD_PENDING | 491 DOE_DELETE_PENDING | 492 DOE_REMOVE_PENDING | 493 DOE_REMOVE_PROCESSED)))) 494 { 495 /* Unload it */ 496 IopUnloadDevice(DeviceObject); 497 } 498 } 499 500 VOID 501 NTAPI 502 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject, 503 IN BOOLEAN Cancelable, 504 IN ULONG Key) 505 { 506 PKDEVICE_QUEUE_ENTRY Entry; 507 PIRP Irp; 508 KIRQL OldIrql; 509 510 /* Acquire the cancel lock if this is cancelable */ 511 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 512 513 /* Clear the current IRP */ 514 DeviceObject->CurrentIrp = NULL; 515 516 /* Remove an entry from the queue */ 517 Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key); 518 if (Entry) 519 { 520 /* Get the IRP and set it */ 521 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 522 DeviceObject->CurrentIrp = Irp; 523 524 /* Check if this is a cancelable packet */ 525 if (Cancelable) 526 { 527 /* Check if the caller requested no cancellation */ 528 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 529 DOE_SIO_NO_CANCEL) 530 { 531 /* He did, so remove the cancel routine */ 532 Irp->CancelRoutine = NULL; 533 } 534 535 /* Release the cancel lock */ 536 IoReleaseCancelSpinLock(OldIrql); 537 } 538 539 /* Call the Start I/O Routine */ 540 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 541 } 542 else 543 { 544 /* Otherwise, release the cancel lock if we had acquired it */ 545 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 546 } 547 } 548 549 VOID 550 NTAPI 551 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject, 552 IN BOOLEAN Cancelable) 553 { 554 PKDEVICE_QUEUE_ENTRY Entry; 555 PIRP Irp; 556 KIRQL OldIrql; 557 558 /* Acquire the cancel lock if this is cancelable */ 559 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql); 560 561 /* Clear the current IRP */ 562 DeviceObject->CurrentIrp = NULL; 563 564 /* Remove an entry from the queue */ 565 Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue); 566 if (Entry) 567 { 568 /* Get the IRP and set it */ 569 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 570 DeviceObject->CurrentIrp = Irp; 571 572 /* Check if this is a cancelable packet */ 573 if (Cancelable) 574 { 575 /* Check if the caller requested no cancellation */ 576 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags & 577 DOE_SIO_NO_CANCEL) 578 { 579 /* He did, so remove the cancel routine */ 580 Irp->CancelRoutine = NULL; 581 } 582 583 /* Release the cancel lock */ 584 IoReleaseCancelSpinLock(OldIrql); 585 } 586 587 /* Call the Start I/O Routine */ 588 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp); 589 } 590 else 591 { 592 /* Otherwise, release the cancel lock if we had acquired it */ 593 if (Cancelable) IoReleaseCancelSpinLock(OldIrql); 594 } 595 } 596 597 VOID 598 NTAPI 599 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject, 600 IN ULONG Key, 601 IN ULONG Flags) 602 { 603 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 604 ULONG CurrentKey = Key; 605 ULONG CurrentFlags = Flags; 606 607 /* Get the device extension and start the packet loop */ 608 DeviceExtension = IoGetDevObjExtension(DeviceObject); 609 while (TRUE) 610 { 611 /* Increase the count */ 612 if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1) 613 { 614 /* 615 * We've already called the routine once... 616 * All we have to do is save the key and add the new flags 617 */ 618 DeviceExtension->StartIoFlags |= CurrentFlags; 619 DeviceExtension->StartIoKey = CurrentKey; 620 } 621 else 622 { 623 /* Mask out the current packet flags and key */ 624 DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY | 625 DOE_SIO_NO_KEY | 626 DOE_SIO_CANCELABLE); 627 DeviceExtension->StartIoKey = 0; 628 629 /* Check if this is a packet start with key */ 630 if (Flags & DOE_SIO_WITH_KEY) 631 { 632 /* Start the packet with a key */ 633 IopStartNextPacketByKey(DeviceObject, 634 (Flags & DOE_SIO_CANCELABLE) ? 635 TRUE : FALSE, 636 CurrentKey); 637 } 638 else if (Flags & DOE_SIO_NO_KEY) 639 { 640 /* Start the packet */ 641 IopStartNextPacket(DeviceObject, 642 (Flags & DOE_SIO_CANCELABLE) ? 643 TRUE : FALSE); 644 } 645 } 646 647 /* Decrease the Start I/O count and check if it's 0 now */ 648 if (!InterlockedDecrement(&DeviceExtension->StartIoCount)) 649 { 650 /* Get the current active key and flags */ 651 CurrentKey = DeviceExtension->StartIoKey; 652 CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY | 653 DOE_SIO_NO_KEY | 654 DOE_SIO_CANCELABLE); 655 656 /* Check if we should still loop */ 657 if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break; 658 } 659 else 660 { 661 /* There are still Start I/Os active, so quit this loop */ 662 break; 663 } 664 } 665 } 666 667 NTSTATUS 668 NTAPI 669 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject, 670 OUT PDEVICE_NODE *DeviceNode) 671 { 672 NTSTATUS Status; 673 IO_STACK_LOCATION Stack = {0}; 674 PDEVICE_RELATIONS DeviceRelations; 675 PDEVICE_OBJECT DeviceObject = NULL; 676 677 ASSERT(FileObject); 678 679 /* Get DeviceObject related to given FileObject */ 680 DeviceObject = IoGetRelatedDeviceObject(FileObject); 681 if (!DeviceObject) return STATUS_NO_SUCH_DEVICE; 682 683 /* Define input parameters */ 684 Stack.MajorFunction = IRP_MJ_PNP; 685 Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; 686 Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; 687 Stack.FileObject = FileObject; 688 689 /* Call the driver to query all relations (IRP_MJ_PNP) */ 690 Status = IopSynchronousCall(DeviceObject, 691 &Stack, 692 (PVOID)&DeviceRelations); 693 if (!NT_SUCCESS(Status)) return Status; 694 695 /* Make sure it's not NULL and contains only one object */ 696 ASSERT(DeviceRelations); 697 ASSERT(DeviceRelations->Count == 1); 698 699 /* Finally get the device node */ 700 *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]); 701 if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE; 702 703 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */ 704 ExFreePool(DeviceRelations); 705 706 return Status; 707 } 708 709 /* PUBLIC FUNCTIONS ***********************************************************/ 710 711 /* 712 * IoAttachDevice 713 * 714 * Layers a device over the highest device in a device stack. 715 * 716 * Parameters 717 * SourceDevice 718 * Device to be attached. 719 * 720 * TargetDevice 721 * Name of the target device. 722 * 723 * AttachedDevice 724 * Caller storage for the device attached to. 725 * 726 * Status 727 * @implemented 728 */ 729 NTSTATUS 730 NTAPI 731 IoAttachDevice(PDEVICE_OBJECT SourceDevice, 732 PUNICODE_STRING TargetDeviceName, 733 PDEVICE_OBJECT *AttachedDevice) 734 { 735 NTSTATUS Status; 736 PFILE_OBJECT FileObject = NULL; 737 PDEVICE_OBJECT TargetDevice = NULL; 738 739 /* Call the helper routine for an attach operation */ 740 Status = IopGetDeviceObjectPointer(TargetDeviceName, 741 FILE_READ_ATTRIBUTES, 742 &FileObject, 743 &TargetDevice, 744 IO_ATTACH_DEVICE_API); 745 if (!NT_SUCCESS(Status)) return Status; 746 747 /* Attach the device */ 748 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice, 749 TargetDevice, 750 AttachedDevice); 751 752 /* Dereference it */ 753 ObDereferenceObject(FileObject); 754 return Status; 755 } 756 757 /* 758 * IoAttachDeviceByPointer 759 * 760 * Status 761 * @implemented 762 */ 763 NTSTATUS 764 NTAPI 765 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice, 766 IN PDEVICE_OBJECT TargetDevice) 767 { 768 PDEVICE_OBJECT AttachedDevice; 769 NTSTATUS Status = STATUS_SUCCESS; 770 771 /* Do the Attach */ 772 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice); 773 if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE; 774 775 /* Return the status */ 776 return Status; 777 } 778 779 /* 780 * @implemented 781 */ 782 PDEVICE_OBJECT 783 NTAPI 784 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice, 785 IN PDEVICE_OBJECT TargetDevice) 786 { 787 /* Attach it safely */ 788 return IopAttachDeviceToDeviceStackSafe(SourceDevice, 789 TargetDevice, 790 NULL); 791 } 792 793 /* 794 * @implemented 795 */ 796 NTSTATUS 797 NTAPI 798 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice, 799 IN PDEVICE_OBJECT TargetDevice, 800 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject) 801 { 802 /* Call the internal function */ 803 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice, 804 TargetDevice, 805 AttachedToDeviceObject)) 806 { 807 /* Nothing found */ 808 return STATUS_NO_SUCH_DEVICE; 809 } 810 811 /* Success! */ 812 return STATUS_SUCCESS; 813 } 814 815 /* 816 * IoCreateDevice 817 * 818 * Allocates memory for and intializes a device object for use for 819 * a driver. 820 * 821 * Parameters 822 * DriverObject 823 * Driver object passed by IO Manager when the driver was loaded. 824 * 825 * DeviceExtensionSize 826 * Number of bytes for the device extension. 827 * 828 * DeviceName 829 * Unicode name of device. 830 * 831 * DeviceType 832 * Device type of the new device. 833 * 834 * DeviceCharacteristics 835 * Bit mask of device characteristics. 836 * 837 * Exclusive 838 * TRUE if only one thread can access the device at a time. 839 * 840 * DeviceObject 841 * On successful return this parameter is filled by pointer to 842 * allocated device object. 843 * 844 * Status 845 * @implemented 846 */ 847 NTSTATUS 848 NTAPI 849 IoCreateDevice(IN PDRIVER_OBJECT DriverObject, 850 IN ULONG DeviceExtensionSize, 851 IN PUNICODE_STRING DeviceName, 852 IN DEVICE_TYPE DeviceType, 853 IN ULONG DeviceCharacteristics, 854 IN BOOLEAN Exclusive, 855 OUT PDEVICE_OBJECT *DeviceObject) 856 { 857 WCHAR AutoNameBuffer[20]; 858 UNICODE_STRING AutoName; 859 PDEVICE_OBJECT CreatedDeviceObject; 860 PDEVOBJ_EXTENSION DeviceObjectExtension; 861 OBJECT_ATTRIBUTES ObjectAttributes; 862 NTSTATUS Status; 863 ULONG AlignedDeviceExtensionSize; 864 ULONG TotalSize; 865 HANDLE TempHandle; 866 PAGED_CODE(); 867 868 /* Check if we have to generate a name */ 869 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) 870 { 871 /* Generate it */ 872 swprintf(AutoNameBuffer, 873 L"\\Device\\%08lx", 874 InterlockedIncrementUL(&IopDeviceObjectNumber)); 875 876 /* Initialize the name */ 877 RtlInitUnicodeString(&AutoName, AutoNameBuffer); 878 DeviceName = &AutoName; 879 } 880 881 /* Initialize the Object Attributes */ 882 InitializeObjectAttributes(&ObjectAttributes, 883 DeviceName, 884 OBJ_KERNEL_HANDLE, 885 NULL, 886 NULL); 887 888 /* Honor exclusive flag */ 889 if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE; 890 891 /* Create a permanent object for named devices */ 892 if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT; 893 894 /* Align the Extension Size to 8-bytes */ 895 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7; 896 897 /* Total Size */ 898 TotalSize = AlignedDeviceExtensionSize + 899 sizeof(DEVICE_OBJECT) + 900 sizeof(EXTENDED_DEVOBJ_EXTENSION); 901 902 /* Create the Device Object */ 903 *DeviceObject = NULL; 904 Status = ObCreateObject(KernelMode, 905 IoDeviceObjectType, 906 &ObjectAttributes, 907 KernelMode, 908 NULL, 909 TotalSize, 910 0, 911 0, 912 (PVOID*)&CreatedDeviceObject); 913 if (!NT_SUCCESS(Status)) return Status; 914 915 /* Clear the whole Object and extension so we don't null stuff manually */ 916 RtlZeroMemory(CreatedDeviceObject, TotalSize); 917 918 /* 919 * Setup the Type and Size. Note that we don't use the aligned size, 920 * because that's only padding for the DevObjExt and not part of the Object. 921 */ 922 CreatedDeviceObject->Type = IO_TYPE_DEVICE; 923 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize; 924 925 /* The kernel extension is after the driver internal extension */ 926 DeviceObjectExtension = (PDEVOBJ_EXTENSION) 927 ((ULONG_PTR)(CreatedDeviceObject + 1) + 928 AlignedDeviceExtensionSize); 929 930 /* Set the Type and Size. Question: why is Size 0 on Windows? */ 931 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION; 932 DeviceObjectExtension->Size = 0; 933 934 /* Initialize with Power Manager */ 935 PoInitializeDeviceObject(DeviceObjectExtension); 936 937 /* Link the Object and Extension */ 938 DeviceObjectExtension->DeviceObject = CreatedDeviceObject; 939 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension; 940 941 /* Set Device Object Data */ 942 CreatedDeviceObject->DeviceType = DeviceType; 943 CreatedDeviceObject->Characteristics = DeviceCharacteristics; 944 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ? 945 CreatedDeviceObject + 1 : 946 NULL; 947 CreatedDeviceObject->StackSize = 1; 948 CreatedDeviceObject->AlignmentRequirement = 0; 949 950 /* Set the Flags */ 951 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING; 952 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE; 953 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME; 954 955 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */ 956 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) || 957 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) || 958 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) || 959 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)) 960 { 961 /* Create Vpb */ 962 Status = IopCreateVpb(CreatedDeviceObject); 963 if (!NT_SUCCESS(Status)) 964 { 965 /* Reference the device object and fail */ 966 ObDereferenceObject(DeviceObject); 967 return Status; 968 } 969 970 /* Initialize Lock Event */ 971 KeInitializeEvent(&CreatedDeviceObject->DeviceLock, 972 SynchronizationEvent, 973 TRUE); 974 } 975 976 /* Set the right Sector Size */ 977 switch (DeviceType) 978 { 979 /* All disk systems */ 980 case FILE_DEVICE_DISK_FILE_SYSTEM: 981 case FILE_DEVICE_DISK: 982 case FILE_DEVICE_VIRTUAL_DISK: 983 984 /* The default is 512 bytes */ 985 CreatedDeviceObject->SectorSize = 512; 986 break; 987 988 /* CD-ROM file systems */ 989 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 990 991 /* The default is 2048 bytes */ 992 CreatedDeviceObject->SectorSize = 2048; 993 } 994 995 /* Create the Device Queue */ 996 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) || 997 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) || 998 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || 999 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) || 1000 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM)) 1001 { 1002 /* Simple FS Devices, they don't need a real Device Queue */ 1003 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry); 1004 } 1005 else 1006 { 1007 /* An actual Device, initialize its DQ */ 1008 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue); 1009 } 1010 1011 /* Insert the Object */ 1012 Status = ObInsertObject(CreatedDeviceObject, 1013 NULL, 1014 FILE_READ_DATA | FILE_WRITE_DATA, 1015 1, 1016 (PVOID*)&CreatedDeviceObject, 1017 &TempHandle); 1018 if (!NT_SUCCESS(Status)) return Status; 1019 1020 /* Now do the final linking */ 1021 ObReferenceObject(DriverObject); 1022 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0); 1023 CreatedDeviceObject->DriverObject = DriverObject; 1024 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd); 1025 1026 /* Link with the power manager */ 1027 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject); 1028 1029 /* Close the temporary handle and return to caller */ 1030 ObCloseHandle(TempHandle, KernelMode); 1031 *DeviceObject = CreatedDeviceObject; 1032 return STATUS_SUCCESS; 1033 } 1034 1035 /* 1036 * IoDeleteDevice 1037 * 1038 * Status 1039 * @implemented 1040 */ 1041 VOID 1042 NTAPI 1043 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject) 1044 { 1045 PIO_TIMER Timer; 1046 1047 /* Check if the device is registered for shutdown notifications */ 1048 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED) 1049 { 1050 /* Call the shutdown notifications */ 1051 IoUnregisterShutdownNotification(DeviceObject); 1052 } 1053 1054 /* Check if it has a timer */ 1055 Timer = DeviceObject->Timer; 1056 if (Timer) 1057 { 1058 /* Remove it and free it */ 1059 IopRemoveTimerFromTimerList(Timer); 1060 ExFreePoolWithTag(Timer, TAG_IO_TIMER); 1061 } 1062 1063 /* Check if the device has a name */ 1064 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME) 1065 { 1066 /* It does, make it temporary so we can remove it */ 1067 ObMakeTemporaryObject(DeviceObject); 1068 } 1069 1070 /* Set the pending delete flag */ 1071 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING; 1072 1073 /* Check if the device object can be unloaded */ 1074 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject); 1075 } 1076 1077 /* 1078 * IoDetachDevice 1079 * 1080 * Status 1081 * @implemented 1082 */ 1083 VOID 1084 NTAPI 1085 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice) 1086 { 1087 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1088 1089 /* Sanity check */ 1090 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice); 1091 ASSERT(DeviceExtension->AttachedTo == TargetDevice); 1092 1093 /* Remove the attachment */ 1094 DeviceExtension->AttachedTo = NULL; 1095 TargetDevice->AttachedDevice = NULL; 1096 1097 /* Check if it's ok to delete this device */ 1098 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & 1099 (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) && 1100 !(TargetDevice->ReferenceCount)) 1101 { 1102 /* It is, do it */ 1103 IopUnloadDevice(TargetDevice); 1104 } 1105 } 1106 1107 /* 1108 * @implemented 1109 */ 1110 NTSTATUS 1111 NTAPI 1112 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject, 1113 IN PDEVICE_OBJECT *DeviceObjectList, 1114 IN ULONG DeviceObjectListSize, 1115 OUT PULONG ActualNumberDeviceObjects) 1116 { 1117 ULONG ActualDevices = 1; 1118 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject; 1119 1120 /* Find out how many devices we'll enumerate */ 1121 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++; 1122 1123 /* Go back to the first */ 1124 CurrentDevice = DriverObject->DeviceObject; 1125 1126 /* Start by at least returning this */ 1127 *ActualNumberDeviceObjects = ActualDevices; 1128 1129 /* Check if we can support so many */ 1130 if ((ActualDevices * 4) > DeviceObjectListSize) 1131 { 1132 /* Fail because the buffer was too small */ 1133 return STATUS_BUFFER_TOO_SMALL; 1134 } 1135 1136 /* Check if the caller only wanted the size */ 1137 if (DeviceObjectList) 1138 { 1139 /* Loop through all the devices */ 1140 while (ActualDevices) 1141 { 1142 /* Reference each Device */ 1143 ObReferenceObject(CurrentDevice); 1144 1145 /* Add it to the list */ 1146 *DeviceObjectList = CurrentDevice; 1147 1148 /* Go to the next one */ 1149 CurrentDevice = CurrentDevice->NextDevice; 1150 ActualDevices--; 1151 DeviceObjectList++; 1152 } 1153 } 1154 1155 /* Return the status */ 1156 return STATUS_SUCCESS; 1157 } 1158 1159 /* 1160 * IoGetAttachedDevice 1161 * 1162 * Status 1163 * @implemented 1164 */ 1165 PDEVICE_OBJECT 1166 NTAPI 1167 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject) 1168 { 1169 /* Get the last attached device */ 1170 while (DeviceObject->AttachedDevice) 1171 { 1172 /* Move to the next one */ 1173 DeviceObject = DeviceObject->AttachedDevice; 1174 } 1175 1176 /* Return it */ 1177 return DeviceObject; 1178 } 1179 1180 /* 1181 * IoGetAttachedDeviceReference 1182 * 1183 * Status 1184 * @implemented 1185 */ 1186 PDEVICE_OBJECT 1187 NTAPI 1188 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject) 1189 { 1190 /* Reference the Attached Device */ 1191 DeviceObject = IoGetAttachedDevice(DeviceObject); 1192 ObReferenceObject(DeviceObject); 1193 return DeviceObject; 1194 } 1195 1196 /* 1197 * @implemented 1198 */ 1199 PDEVICE_OBJECT 1200 NTAPI 1201 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject) 1202 { 1203 /* Reference the lowest attached device */ 1204 DeviceObject = IopGetLowestDevice(DeviceObject); 1205 ObReferenceObject(DeviceObject); 1206 return DeviceObject; 1207 } 1208 1209 /* 1210 * IoGetDeviceObjectPointer 1211 * 1212 * Status 1213 * @implemented 1214 */ 1215 NTSTATUS 1216 NTAPI 1217 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, 1218 IN ACCESS_MASK DesiredAccess, 1219 OUT PFILE_OBJECT *FileObject, 1220 OUT PDEVICE_OBJECT *DeviceObject) 1221 { 1222 /* Call the helper routine for a normal operation */ 1223 return IopGetDeviceObjectPointer(ObjectName, 1224 DesiredAccess, 1225 FileObject, 1226 DeviceObject, 1227 0); 1228 } 1229 1230 /* 1231 * @implemented 1232 */ 1233 NTSTATUS 1234 NTAPI 1235 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject, 1236 OUT PDEVICE_OBJECT *DiskDeviceObject) 1237 { 1238 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1239 PVPB Vpb; 1240 KIRQL OldIrql; 1241 NTSTATUS Status; 1242 1243 /* Make sure there's a VPB */ 1244 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER; 1245 1246 /* Acquire it */ 1247 IoAcquireVpbSpinLock(&OldIrql); 1248 1249 /* Get the Device Extension */ 1250 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject); 1251 1252 /* Make sure this one has a VPB too */ 1253 Vpb = DeviceExtension->Vpb; 1254 if (Vpb) 1255 { 1256 /* Make sure that it's mounted */ 1257 if ((Vpb->ReferenceCount) && 1258 (Vpb->Flags & VPB_MOUNTED)) 1259 { 1260 /* Return the Disk Device Object */ 1261 *DiskDeviceObject = Vpb->RealDevice; 1262 1263 /* Reference it and return success */ 1264 ObReferenceObject(Vpb->RealDevice); 1265 Status = STATUS_SUCCESS; 1266 } 1267 else 1268 { 1269 /* It's not, so return failure */ 1270 Status = STATUS_VOLUME_DISMOUNTED; 1271 } 1272 } 1273 else 1274 { 1275 /* Fail */ 1276 Status = STATUS_INVALID_PARAMETER; 1277 } 1278 1279 /* Release the lock */ 1280 IoReleaseVpbSpinLock(OldIrql); 1281 return Status; 1282 } 1283 1284 /* 1285 * @implemented 1286 */ 1287 PDEVICE_OBJECT 1288 NTAPI 1289 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject) 1290 { 1291 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 1292 PDEVICE_OBJECT LowerDeviceObject = NULL; 1293 1294 /* Make sure it's not getting deleted */ 1295 DeviceExtension = IoGetDevObjExtension(DeviceObject); 1296 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING | 1297 DOE_DELETE_PENDING | 1298 DOE_REMOVE_PENDING | 1299 DOE_REMOVE_PROCESSED))) 1300 { 1301 /* Get the Lower Device Object */ 1302 LowerDeviceObject = DeviceExtension->AttachedTo; 1303 1304 /* Check that we got a valid device object */ 1305 if (LowerDeviceObject) 1306 { 1307 /* We did so let's reference it */ 1308 ObReferenceObject(LowerDeviceObject); 1309 } 1310 } 1311 1312 /* Return it */ 1313 return LowerDeviceObject; 1314 } 1315 1316 /* 1317 * @implemented 1318 */ 1319 PDEVICE_OBJECT 1320 NTAPI 1321 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject) 1322 { 1323 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject; 1324 1325 /* Check if we have a VPB with a device object */ 1326 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject)) 1327 { 1328 /* Then use the DO from the VPB */ 1329 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1330 DeviceObject = FileObject->Vpb->DeviceObject; 1331 } 1332 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) && 1333 (FileObject->DeviceObject->Vpb) && 1334 (FileObject->DeviceObject->Vpb->DeviceObject)) 1335 { 1336 /* The disk device actually has a VPB, so get the DO from there */ 1337 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; 1338 } 1339 else 1340 { 1341 /* Otherwise, this was a direct open */ 1342 DeviceObject = FileObject->DeviceObject; 1343 } 1344 1345 /* Sanity check */ 1346 ASSERT(DeviceObject != NULL); 1347 1348 /* Check if we were attached */ 1349 if (DeviceObject->AttachedDevice) 1350 { 1351 /* Check if the file object has an extension present */ 1352 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION) 1353 { 1354 /* Sanity check, direct open files can't have this */ 1355 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)); 1356 1357 /* Check if the extension is really present */ 1358 if (FileObject->FileObjectExtension) 1359 { 1360 /* FIXME: Unhandled yet */ 1361 DPRINT1("FOEs not supported\n"); 1362 ASSERT(FALSE); 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 /* Acquire the shutdown lock and loop the shutdown list */ 1504 KeAcquireSpinLock(&ShutdownListLock, &OldIrql); 1505 NextEntry = ShutdownListHead.Flink; 1506 while (NextEntry != &ShutdownListHead) 1507 { 1508 /* Get the entry */ 1509 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1510 SHUTDOWN_ENTRY, 1511 ShutdownList); 1512 1513 /* Get if the DO matches */ 1514 if (ShutdownEntry->DeviceObject == DeviceObject) 1515 { 1516 /* Remove it from the list */ 1517 RemoveEntryList(NextEntry); 1518 NextEntry = NextEntry->Blink; 1519 1520 /* Free the entry */ 1521 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1522 1523 /* Get rid of our reference to it */ 1524 ObDereferenceObject(DeviceObject); 1525 } 1526 1527 /* Go to the next entry */ 1528 NextEntry = NextEntry->Flink; 1529 } 1530 1531 /* Now loop the last chance list */ 1532 NextEntry = LastChanceShutdownListHead.Flink; 1533 while (NextEntry != &LastChanceShutdownListHead) 1534 { 1535 /* Get the entry */ 1536 ShutdownEntry = CONTAINING_RECORD(NextEntry, 1537 SHUTDOWN_ENTRY, 1538 ShutdownList); 1539 1540 /* Get if the DO matches */ 1541 if (ShutdownEntry->DeviceObject == DeviceObject) 1542 { 1543 /* Remove it from the list */ 1544 RemoveEntryList(NextEntry); 1545 NextEntry = NextEntry->Blink; 1546 1547 /* Free the entry */ 1548 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY); 1549 1550 /* Get rid of our reference to it */ 1551 ObDereferenceObject(DeviceObject); 1552 } 1553 1554 /* Go to the next entry */ 1555 NextEntry = NextEntry->Flink; 1556 } 1557 1558 /* Release the shutdown lock */ 1559 KeReleaseSpinLock(&ShutdownListLock, OldIrql); 1560 1561 /* Now remove the flag */ 1562 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED; 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