2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/device.c
5 * PURPOSE: Device Object Management, including Notifications and Queues.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
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
;
27 /* PRIVATE FUNCTIONS **********************************************************/
31 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver
)
33 PDEVICE_OBJECT DeviceObject
;
36 /* Set the driver as initialized */
37 Driver
->Flags
|= DRVO_INITIALIZED
;
38 DeviceObject
= Driver
->DeviceObject
;
41 /* Set every device as initialized too */
42 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
43 DeviceObject
= DeviceObject
->NextDevice
;
49 IopDeleteDevice(IN PVOID ObjectBody
)
51 PDEVICE_OBJECT DeviceObject
= ObjectBody
;
52 PDEVICE_NODE DeviceNode
= IopGetDeviceNode(DeviceObject
);
55 /* Cleanup and free the device node */
57 IopFreeDeviceNode(DeviceNode
);
59 /* Dereference the driver object, referenced in IoCreateDevice */
60 if (DeviceObject
->DriverObject
)
61 ObDereferenceObject(DeviceObject
->DriverObject
);
67 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
68 IN PDEVICE_OBJECT TargetDevice
,
69 OUT PDEVICE_OBJECT
*AttachedToDeviceObject OPTIONAL
)
71 PDEVICE_OBJECT AttachedDevice
;
72 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension
;
74 /* Get the Attached Device and source extension */
75 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
76 SourceDeviceExtension
= IoGetDevObjExtension(SourceDevice
);
77 ASSERT(SourceDeviceExtension
->AttachedTo
== NULL
);
79 /* Make sure that it's in a correct state */
80 if ((AttachedDevice
->Flags
& DO_DEVICE_INITIALIZING
) ||
81 (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
85 DOE_REMOVE_PROCESSED
)))
87 /* Device was unloading or being removed */
88 AttachedDevice
= NULL
;
92 /* Update atached device fields */
93 AttachedDevice
->AttachedDevice
= SourceDevice
;
94 AttachedDevice
->Spare1
++;
96 /* Update the source with the attached data */
97 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
98 SourceDevice
->AlignmentRequirement
= AttachedDevice
->
100 SourceDevice
->SectorSize
= AttachedDevice
->SectorSize
;
102 /* Check for pending start flag */
103 if (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
107 IoGetDevObjExtension(SourceDevice
)->ExtensionFlags
|=
111 /* Set the attachment in the device extension */
112 SourceDeviceExtension
->AttachedTo
= AttachedDevice
;
115 /* Return the attached device */
116 if (AttachedToDeviceObject
) *AttachedToDeviceObject
= AttachedDevice
;
117 return AttachedDevice
;
122 IoShutdownPnpDevices(VOID
)
124 /* This routine is only used by Driver Verifier to validate shutdown */
130 IoShutdownSystem(IN ULONG Phase
)
132 PLIST_ENTRY ListEntry
;
133 PDEVICE_OBJECT DeviceObject
;
134 PSHUTDOWN_ENTRY ShutdownEntry
;
135 IO_STATUS_BLOCK StatusBlock
;
140 /* Initialize an event to wait on */
141 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
147 IoShutdownPnpDevices();
149 /* Loop first-chance shutdown notifications */
150 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
154 /* Get the shutdown entry */
155 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
159 /* Get the attached device */
160 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
162 /* Build the shutdown IRP and call the driver */
163 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
172 Status
= IoCallDriver(DeviceObject
, Irp
);
173 if (Status
== STATUS_PENDING
)
175 /* Wait on the driver */
176 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
180 /* Remove the flag */
181 ShutdownEntry
->DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
183 /* Get rid of our reference to it */
184 ObDereferenceObject(ShutdownEntry
->DeviceObject
);
186 /* Free the shutdown entry and reset the event */
187 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
188 KeClearEvent(&Event
);
190 /* Go to the next entry */
191 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
197 /* Acquire resource forever */
198 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
200 /* Shutdown disk file systems */
201 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead
);
203 /* Shutdown cdrom file systems */
204 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead
);
206 /* Shutdown tape filesystems */
207 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead
);
209 /* Loop last-chance shutdown notifications */
210 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
214 /* Get the shutdown entry */
215 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
219 /* Get the attached device */
220 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
222 /* Build the shutdown IRP and call the driver */
223 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
232 Status
= IoCallDriver(DeviceObject
, Irp
);
233 if (Status
== STATUS_PENDING
)
235 /* Wait on the driver */
236 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
240 /* Remove the flag */
241 ShutdownEntry
->DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
243 /* Get rid of our reference to it */
244 ObDereferenceObject(ShutdownEntry
->DeviceObject
);
246 /* Free the shutdown entry and reset the event */
247 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
248 KeClearEvent(&Event
);
250 /* Go to the next entry */
251 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
260 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
261 IN ACCESS_MASK DesiredAccess
,
262 OUT PFILE_OBJECT
*FileObject
,
263 OUT PDEVICE_OBJECT
*DeviceObject
,
266 OBJECT_ATTRIBUTES ObjectAttributes
;
267 IO_STATUS_BLOCK StatusBlock
;
268 PFILE_OBJECT LocalFileObject
;
272 /* Open the Device */
273 InitializeObjectAttributes(&ObjectAttributes
,
278 Status
= ZwOpenFile(&FileHandle
,
283 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
284 if (!NT_SUCCESS(Status
)) return Status
;
286 /* Get File Object */
287 Status
= ObReferenceObjectByHandle(FileHandle
,
291 (PVOID
*)&LocalFileObject
,
293 if (NT_SUCCESS(Status
))
295 /* Return the requested data */
296 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
297 *FileObject
= LocalFileObject
;
300 /* Close the handle */
308 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
310 PDEVICE_OBJECT LowestDevice
;
311 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
313 /* Get the current device and its extension */
314 LowestDevice
= DeviceObject
;
315 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
317 /* Keep looping as long as we're attached */
318 while (DeviceExtension
->AttachedTo
)
320 /* Get the lowest device and its extension */
321 LowestDevice
= DeviceExtension
->AttachedTo
;
322 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
325 /* Return the lowest device */
331 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
332 IN PDEVICE_OBJECT DeviceObject
,
333 IN IOP_DEVICE_LIST_OPERATION Type
)
335 PDEVICE_OBJECT Previous
;
338 /* Lock the Device list while we edit it */
339 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
341 /* Check the type of operation */
342 if (Type
== IopRemove
)
344 /* Get the current device and check if it's the current one */
345 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
346 if (Previous
== DeviceObject
)
348 /* It is, simply unlink this one directly */
349 DeviceObject
->DriverObject
->DeviceObject
=
350 DeviceObject
->NextDevice
;
354 /* It's not, so loop until we find the device */
355 while (Previous
->NextDevice
!= DeviceObject
)
357 /* Not this one, keep moving */
358 if (!Previous
->NextDevice
)
360 DPRINT1("Failed to remove PDO %p (not found)\n",
364 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
367 Previous
= Previous
->NextDevice
;
370 /* We found it, now unlink us */
371 Previous
->NextDevice
= DeviceObject
->NextDevice
;
376 /* Link the device object and the driver object */
377 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
378 DriverObject
->DeviceObject
= DeviceObject
;
381 /* Release the device list lock */
382 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
387 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
389 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
390 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
= IoGetDevObjExtension(DeviceObject
);
392 /* Check if deletion is pending */
393 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
395 if (DeviceObject
->AttachedDevice
)
397 DPRINT("Device object is in the middle of a device stack\n");
401 if (DeviceObject
->ReferenceCount
)
403 DPRINT("Device object still has %d references\n", DeviceObject
->ReferenceCount
);
407 /* Check if we have a Security Descriptor */
408 if (DeviceObject
->SecurityDescriptor
)
411 ObDereferenceSecurityDescriptor(DeviceObject
->SecurityDescriptor
, 1);
414 /* Remove the device from the list */
415 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
417 /* Dereference the keep-alive */
418 ObDereferenceObject(DeviceObject
);
421 /* We can't unload a non-PnP driver here */
422 if (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)
424 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
428 /* Return if we've already called unload (maybe we're in it?) */
429 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) return;
431 /* We can't unload unless there's an unload handler */
432 if (!DriverObject
->DriverUnload
)
434 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
438 /* Bail if there are still devices present */
439 if (DriverObject
->DeviceObject
)
441 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
445 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject
->DriverName
);
447 /* Set the unload invoked flag */
448 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
451 DriverObject
->DriverUnload(DriverObject
);
453 /* Make object temporary so it can be deleted */
454 ObMakeTemporaryObject(DriverObject
);
459 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
460 IN BOOLEAN ForceUnload
)
463 ASSERT(DeviceObject
->ReferenceCount
);
465 /* Dereference the device */
466 InterlockedDecrement(&DeviceObject
->ReferenceCount
);
469 * Check if we can unload it and it's safe to unload (or if we're forcing
470 * an unload, which is OK too).
472 ASSERT(!ForceUnload
);
473 if (!(DeviceObject
->ReferenceCount
) &&
474 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
& DOE_DELETE_PENDING
))
477 IopUnloadDevice(DeviceObject
);
483 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
484 IN BOOLEAN Cancelable
,
487 PKDEVICE_QUEUE_ENTRY Entry
;
491 /* Acquire the cancel lock if this is cancelable */
492 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
494 /* Clear the current IRP */
495 DeviceObject
->CurrentIrp
= NULL
;
497 /* Remove an entry from the queue */
498 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
501 /* Get the IRP and set it */
502 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
503 DeviceObject
->CurrentIrp
= Irp
;
505 /* Check if this is a cancelable packet */
508 /* Check if the caller requested no cancellation */
509 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
512 /* He did, so remove the cancel routine */
513 Irp
->CancelRoutine
= NULL
;
516 /* Release the cancel lock */
517 IoReleaseCancelSpinLock(OldIrql
);
520 /* Call the Start I/O Routine */
521 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
525 /* Otherwise, release the cancel lock if we had acquired it */
526 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
532 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
533 IN BOOLEAN Cancelable
)
535 PKDEVICE_QUEUE_ENTRY Entry
;
539 /* Acquire the cancel lock if this is cancelable */
540 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
542 /* Clear the current IRP */
543 DeviceObject
->CurrentIrp
= NULL
;
545 /* Remove an entry from the queue */
546 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
549 /* Get the IRP and set it */
550 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
551 DeviceObject
->CurrentIrp
= Irp
;
553 /* Check if this is a cancelable packet */
556 /* Check if the caller requested no cancellation */
557 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
560 /* He did, so remove the cancel routine */
561 Irp
->CancelRoutine
= NULL
;
564 /* Release the cancel lock */
565 IoReleaseCancelSpinLock(OldIrql
);
568 /* Call the Start I/O Routine */
569 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
573 /* Otherwise, release the cancel lock if we had acquired it */
574 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
580 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
584 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
585 ULONG CurrentKey
= Key
;
586 ULONG CurrentFlags
= Flags
;
588 /* Get the device extension and start the packet loop */
589 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
592 /* Increase the count */
593 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
596 * We've already called the routine once...
597 * All we have to do is save the key and add the new flags
599 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
600 DeviceExtension
->StartIoKey
= CurrentKey
;
604 /* Mask out the current packet flags and key */
605 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
608 DeviceExtension
->StartIoKey
= 0;
610 /* Check if this is a packet start with key */
611 if (Flags
& DOE_SIO_WITH_KEY
)
613 /* Start the packet with a key */
614 IopStartNextPacketByKey(DeviceObject
,
615 (Flags
& DOE_SIO_CANCELABLE
) ?
619 else if (Flags
& DOE_SIO_NO_KEY
)
621 /* Start the packet */
622 IopStartNextPacket(DeviceObject
,
623 (Flags
& DOE_SIO_CANCELABLE
) ?
628 /* Decrease the Start I/O count and check if it's 0 now */
629 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
631 /* Get the current active key and flags */
632 CurrentKey
= DeviceExtension
->StartIoKey
;
633 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
637 /* Check if we should still loop */
638 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
642 /* There are still Start I/Os active, so quit this loop */
650 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
651 OUT PDEVICE_NODE
*DeviceNode
)
654 IO_STACK_LOCATION Stack
= {0};
655 PDEVICE_RELATIONS DeviceRelations
;
656 PDEVICE_OBJECT DeviceObject
= NULL
;
660 /* Get DeviceObject related to given FileObject */
661 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
662 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
664 /* Define input parameters */
665 Stack
.MajorFunction
= IRP_MJ_PNP
;
666 Stack
.MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
667 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
668 Stack
.FileObject
= FileObject
;
670 /* Call the driver to query all relations (IRP_MJ_PNP) */
671 Status
= IopSynchronousCall(DeviceObject
,
673 (PVOID
)&DeviceRelations
);
674 if (!NT_SUCCESS(Status
)) return Status
;
676 /* Make sure it's not NULL and contains only one object */
677 ASSERT(DeviceRelations
);
678 ASSERT(DeviceRelations
->Count
== 1);
680 /* Finally get the device node */
681 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
682 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
684 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
685 ExFreePool(DeviceRelations
);
692 IopVerifyDeviceObjectOnStack(IN PDEVICE_OBJECT BaseDeviceObject
,
693 IN PDEVICE_OBJECT TopDeviceObjectHint
)
697 PDEVICE_OBJECT LoopObject
;
699 ASSERT(BaseDeviceObject
!= NULL
);
702 /* Simply loop on the device stack and try to find our hint */
703 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
704 for (LoopObject
= BaseDeviceObject
; ; LoopObject
= LoopObject
->AttachedDevice
)
706 /* It was found, it's a success */
707 if (LoopObject
== TopDeviceObjectHint
)
713 /* End of the stack, that's a failure - default */
714 if (LoopObject
== NULL
)
719 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
724 /* PUBLIC FUNCTIONS ***********************************************************/
729 * Layers a device over the highest device in a device stack.
733 * Device to be attached.
736 * Name of the target device.
739 * Caller storage for the device attached to.
746 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
747 PUNICODE_STRING TargetDeviceName
,
748 PDEVICE_OBJECT
*AttachedDevice
)
751 PFILE_OBJECT FileObject
= NULL
;
752 PDEVICE_OBJECT TargetDevice
= NULL
;
754 /* Call the helper routine for an attach operation */
755 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
756 FILE_READ_ATTRIBUTES
,
759 IO_ATTACH_DEVICE_API
);
760 if (!NT_SUCCESS(Status
)) return Status
;
762 /* Attach the device */
763 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
768 ObDereferenceObject(FileObject
);
773 * IoAttachDeviceByPointer
780 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
781 IN PDEVICE_OBJECT TargetDevice
)
783 PDEVICE_OBJECT AttachedDevice
;
784 NTSTATUS Status
= STATUS_SUCCESS
;
787 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
788 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
790 /* Return the status */
799 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
800 IN PDEVICE_OBJECT TargetDevice
)
802 /* Attach it safely */
803 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
813 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
814 IN PDEVICE_OBJECT TargetDevice
,
815 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
817 /* Call the internal function */
818 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
820 AttachedToDeviceObject
))
823 return STATUS_NO_SUCH_DEVICE
;
827 return STATUS_SUCCESS
;
833 * Allocates memory for and intializes a device object for use for
838 * Driver object passed by IO Manager when the driver was loaded.
840 * DeviceExtensionSize
841 * Number of bytes for the device extension.
844 * Unicode name of device.
847 * Device type of the new device.
849 * DeviceCharacteristics
850 * Bit mask of device characteristics.
853 * TRUE if only one thread can access the device at a time.
856 * On successful return this parameter is filled by pointer to
857 * allocated device object.
864 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
865 IN ULONG DeviceExtensionSize
,
866 IN PUNICODE_STRING DeviceName
,
867 IN DEVICE_TYPE DeviceType
,
868 IN ULONG DeviceCharacteristics
,
869 IN BOOLEAN Exclusive
,
870 OUT PDEVICE_OBJECT
*DeviceObject
)
872 WCHAR AutoNameBuffer
[20];
873 UNICODE_STRING AutoName
;
874 PDEVICE_OBJECT CreatedDeviceObject
;
875 PDEVOBJ_EXTENSION DeviceObjectExtension
;
876 OBJECT_ATTRIBUTES ObjectAttributes
;
878 ULONG AlignedDeviceExtensionSize
;
883 /* Check if we have to generate a name */
884 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
887 swprintf(AutoNameBuffer
,
889 InterlockedIncrementUL(&IopDeviceObjectNumber
));
891 /* Initialize the name */
892 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
893 DeviceName
= &AutoName
;
896 /* Initialize the Object Attributes */
897 InitializeObjectAttributes(&ObjectAttributes
,
901 SePublicOpenUnrestrictedSd
);
903 /* Honor exclusive flag */
904 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
906 /* Create a permanent object for named devices */
907 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
909 /* Align the Extension Size to 8-bytes */
910 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
913 TotalSize
= AlignedDeviceExtensionSize
+
914 sizeof(DEVICE_OBJECT
) +
915 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
917 /* Create the Device Object */
918 *DeviceObject
= NULL
;
919 Status
= ObCreateObject(KernelMode
,
927 (PVOID
*)&CreatedDeviceObject
);
928 if (!NT_SUCCESS(Status
)) return Status
;
930 /* Clear the whole Object and extension so we don't null stuff manually */
931 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
934 * Setup the Type and Size. Note that we don't use the aligned size,
935 * because that's only padding for the DevObjExt and not part of the Object.
937 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
938 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
940 /* The kernel extension is after the driver internal extension */
941 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
942 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
943 AlignedDeviceExtensionSize
);
945 /* Set the Type and Size. Question: why is Size 0 on Windows? */
946 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
947 DeviceObjectExtension
->Size
= 0;
949 /* Initialize with Power Manager */
950 PoInitializeDeviceObject(DeviceObjectExtension
);
952 /* Link the Object and Extension */
953 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
954 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
956 /* Set Device Object Data */
957 CreatedDeviceObject
->DeviceType
= DeviceType
;
958 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
959 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
960 CreatedDeviceObject
+ 1 :
962 CreatedDeviceObject
->StackSize
= 1;
963 CreatedDeviceObject
->AlignmentRequirement
= 0;
966 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
967 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
968 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
970 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
971 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
972 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
973 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
974 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
977 Status
= IopCreateVpb(CreatedDeviceObject
);
978 if (!NT_SUCCESS(Status
))
980 /* Dereference the device object and fail */
981 ObDereferenceObject(CreatedDeviceObject
);
985 /* Initialize Lock Event */
986 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
987 SynchronizationEvent
,
991 /* Set the right Sector Size */
994 /* All disk systems */
995 case FILE_DEVICE_DISK_FILE_SYSTEM
:
996 case FILE_DEVICE_DISK
:
997 case FILE_DEVICE_VIRTUAL_DISK
:
999 /* The default is 512 bytes */
1000 CreatedDeviceObject
->SectorSize
= 512;
1003 /* CD-ROM file systems */
1004 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
1006 /* The default is 2048 bytes */
1007 CreatedDeviceObject
->SectorSize
= 2048;
1010 /* Create the Device Queue */
1011 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1012 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
1013 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1014 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
1015 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
1017 /* Simple FS Devices, they don't need a real Device Queue */
1018 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
1022 /* An actual Device, initialize its DQ */
1023 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
1026 /* Insert the Object */
1027 Status
= ObInsertObject(CreatedDeviceObject
,
1029 FILE_READ_DATA
| FILE_WRITE_DATA
,
1031 (PVOID
*)&CreatedDeviceObject
,
1033 if (!NT_SUCCESS(Status
)) return Status
;
1035 /* Now do the final linking */
1036 ObReferenceObject(DriverObject
);
1037 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
1038 CreatedDeviceObject
->DriverObject
= DriverObject
;
1039 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
1041 /* Link with the power manager */
1042 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
1044 /* Close the temporary handle and return to caller */
1045 ObCloseHandle(TempHandle
, KernelMode
);
1046 *DeviceObject
= CreatedDeviceObject
;
1047 return STATUS_SUCCESS
;
1058 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1062 /* Check if the device is registered for shutdown notifications */
1063 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1065 /* Call the shutdown notifications */
1066 IoUnregisterShutdownNotification(DeviceObject
);
1069 /* Check if it has a timer */
1070 Timer
= DeviceObject
->Timer
;
1073 /* Remove it and free it */
1074 IopRemoveTimerFromTimerList(Timer
);
1075 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1078 /* Check if the device has a name */
1079 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1081 /* It does, make it temporary so we can remove it */
1082 ObMakeTemporaryObject(DeviceObject
);
1085 /* Set the pending delete flag */
1086 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1088 /* Unlink with the power manager */
1089 if (DeviceObject
->Vpb
) PoRemoveVolumeDevice(DeviceObject
);
1091 /* Check if the device object can be unloaded */
1092 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1103 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1105 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1108 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1109 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1111 /* Remove the attachment */
1112 DeviceExtension
->AttachedTo
= NULL
;
1113 TargetDevice
->AttachedDevice
= NULL
;
1115 /* Check if it's ok to delete this device */
1116 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
& DOE_DELETE_PENDING
) &&
1117 !(TargetDevice
->ReferenceCount
))
1120 IopUnloadDevice(TargetDevice
);
1129 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1130 IN PDEVICE_OBJECT
*DeviceObjectList
,
1131 IN ULONG DeviceObjectListSize
,
1132 OUT PULONG ActualNumberDeviceObjects
)
1134 ULONG ActualDevices
= 1;
1135 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1138 /* Lock the Device list while we enumerate it */
1139 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
1141 /* Find out how many devices we'll enumerate */
1142 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1144 /* Go back to the first */
1145 CurrentDevice
= DriverObject
->DeviceObject
;
1147 /* Start by at least returning this */
1148 *ActualNumberDeviceObjects
= ActualDevices
;
1150 /* Check if we can support so many */
1151 if ((ActualDevices
* sizeof(PDEVICE_OBJECT
)) > DeviceObjectListSize
)
1153 /* Fail because the buffer was too small */
1154 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1155 return STATUS_BUFFER_TOO_SMALL
;
1158 /* Check if the caller wanted the device list */
1159 if (DeviceObjectList
)
1161 /* Loop through all the devices */
1162 while (ActualDevices
)
1164 /* Reference each Device */
1165 ObReferenceObject(CurrentDevice
);
1167 /* Add it to the list */
1168 *DeviceObjectList
= CurrentDevice
;
1170 /* Go to the next one */
1171 CurrentDevice
= CurrentDevice
->NextDevice
;
1177 /* Release the device list lock */
1178 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1180 /* Return the status */
1181 return STATUS_SUCCESS
;
1185 * IoGetAttachedDevice
1192 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1194 /* Get the last attached device */
1195 while (DeviceObject
->AttachedDevice
)
1197 /* Move to the next one */
1198 DeviceObject
= DeviceObject
->AttachedDevice
;
1202 return DeviceObject
;
1206 * IoGetAttachedDeviceReference
1213 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1215 /* Reference the Attached Device */
1216 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1217 ObReferenceObject(DeviceObject
);
1218 return DeviceObject
;
1226 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1228 /* Reference the lowest attached device */
1229 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1230 ObReferenceObject(DeviceObject
);
1231 return DeviceObject
;
1235 * IoGetDeviceObjectPointer
1242 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1243 IN ACCESS_MASK DesiredAccess
,
1244 OUT PFILE_OBJECT
*FileObject
,
1245 OUT PDEVICE_OBJECT
*DeviceObject
)
1247 /* Call the helper routine for a normal operation */
1248 return IopGetDeviceObjectPointer(ObjectName
,
1260 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1261 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1263 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1268 /* Make sure there's a VPB */
1269 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1272 IoAcquireVpbSpinLock(&OldIrql
);
1274 /* Get the Device Extension */
1275 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1277 /* Make sure this one has a VPB too */
1278 Vpb
= DeviceExtension
->Vpb
;
1281 /* Make sure that it's mounted */
1282 if ((Vpb
->ReferenceCount
) &&
1283 (Vpb
->Flags
& VPB_MOUNTED
))
1285 /* Return the Disk Device Object */
1286 *DiskDeviceObject
= Vpb
->RealDevice
;
1288 /* Reference it and return success */
1289 ObReferenceObject(Vpb
->RealDevice
);
1290 Status
= STATUS_SUCCESS
;
1294 /* It's not, so return failure */
1295 Status
= STATUS_VOLUME_DISMOUNTED
;
1301 Status
= STATUS_INVALID_PARAMETER
;
1304 /* Release the lock */
1305 IoReleaseVpbSpinLock(OldIrql
);
1314 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1316 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1317 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1319 /* Make sure it's not getting deleted */
1320 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1321 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1322 DOE_DELETE_PENDING
|
1323 DOE_REMOVE_PENDING
|
1324 DOE_REMOVE_PROCESSED
)))
1326 /* Get the Lower Device Object */
1327 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1329 /* Check that we got a valid device object */
1330 if (LowerDeviceObject
)
1332 /* We did so let's reference it */
1333 ObReferenceObject(LowerDeviceObject
);
1338 return LowerDeviceObject
;
1346 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1348 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1350 /* Check if we have a VPB with a device object */
1351 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1353 /* Then use the DO from the VPB */
1354 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1355 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1357 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1358 (FileObject
->DeviceObject
->Vpb
) &&
1359 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1361 /* The disk device actually has a VPB, so get the DO from there */
1362 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1366 /* Otherwise, this was a direct open */
1367 DeviceObject
= FileObject
->DeviceObject
;
1371 ASSERT(DeviceObject
!= NULL
);
1373 /* Check if we were attached */
1374 if (DeviceObject
->AttachedDevice
)
1376 /* Check if the file object has an extension present */
1377 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1379 /* Sanity check, direct open files can't have this */
1380 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1382 /* Check if the extension is really present */
1383 if (FileObject
->FileObjectExtension
)
1385 PFILE_OBJECT_EXTENSION FileObjectExtension
;
1387 /* Cast the buffer to something we understand */
1388 FileObjectExtension
= FileObject
->FileObjectExtension
;
1390 /* Check if have a replacement top level device */
1391 if (FileObjectExtension
->TopDeviceObjectHint
)
1393 /* Use this instead of returning the top level device */
1394 return FileObjectExtension
->TopDeviceObjectHint
;
1399 /* Return the highest attached device */
1400 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1403 /* Return the DO we found */
1404 return DeviceObject
;
1412 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1413 OUT PDEVICE_OBJECT
*DeviceObject
)
1416 PDEVICE_NODE DeviceNode
= NULL
;
1418 /* Call the internal helper function */
1419 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1420 if (NT_SUCCESS(Status
) && DeviceNode
)
1422 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1432 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1434 PDEVICE_OBJECT DeviceObject
;
1437 * If the FILE_OBJECT's VPB is defined,
1438 * get the device from it.
1440 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1442 /* Use the VPB's Device Object's */
1443 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1445 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1446 (FileObject
->DeviceObject
->Vpb
) &&
1447 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1449 /* Use the VPB's File System Object */
1450 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1454 /* Use the FO's Device Object */
1455 DeviceObject
= FileObject
->DeviceObject
;
1458 /* Return the device object we found */
1459 ASSERT(DeviceObject
!= NULL
);
1460 return DeviceObject
;
1468 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1470 PSHUTDOWN_ENTRY Entry
;
1472 /* Allocate the shutdown entry */
1473 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1474 sizeof(SHUTDOWN_ENTRY
),
1475 TAG_SHUTDOWN_ENTRY
);
1476 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1479 Entry
->DeviceObject
= DeviceObject
;
1481 /* Reference it so it doesn't go away */
1482 ObReferenceObject(DeviceObject
);
1484 /* Insert it into the list */
1485 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1486 &Entry
->ShutdownList
,
1489 /* Set the shutdown registered flag */
1490 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1491 return STATUS_SUCCESS
;
1499 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1501 PSHUTDOWN_ENTRY Entry
;
1503 /* Allocate the shutdown entry */
1504 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1505 sizeof(SHUTDOWN_ENTRY
),
1506 TAG_SHUTDOWN_ENTRY
);
1507 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1510 Entry
->DeviceObject
= DeviceObject
;
1512 /* Reference it so it doesn't go away */
1513 ObReferenceObject(DeviceObject
);
1515 /* Insert it into the list */
1516 ExInterlockedInsertHeadList(&ShutdownListHead
,
1517 &Entry
->ShutdownList
,
1520 /* Set the shutdown registered flag */
1521 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1522 return STATUS_SUCCESS
;
1530 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1532 PSHUTDOWN_ENTRY ShutdownEntry
;
1533 PLIST_ENTRY NextEntry
;
1536 /* Remove the flag */
1537 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1539 /* Acquire the shutdown lock and loop the shutdown list */
1540 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1541 NextEntry
= ShutdownListHead
.Flink
;
1542 while (NextEntry
!= &ShutdownListHead
)
1545 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1549 /* Get if the DO matches */
1550 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1552 /* Remove it from the list */
1553 RemoveEntryList(NextEntry
);
1554 NextEntry
= NextEntry
->Blink
;
1556 /* Free the entry */
1557 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1559 /* Get rid of our reference to it */
1560 ObDereferenceObject(DeviceObject
);
1563 /* Go to the next entry */
1564 NextEntry
= NextEntry
->Flink
;
1567 /* Now loop the last chance list */
1568 NextEntry
= LastChanceShutdownListHead
.Flink
;
1569 while (NextEntry
!= &LastChanceShutdownListHead
)
1572 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1576 /* Get if the DO matches */
1577 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1579 /* Remove it from the list */
1580 RemoveEntryList(NextEntry
);
1581 NextEntry
= NextEntry
->Blink
;
1583 /* Free the entry */
1584 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1586 /* Get rid of our reference to it */
1587 ObDereferenceObject(DeviceObject
);
1590 /* Go to the next entry */
1591 NextEntry
= NextEntry
->Flink
;
1594 /* Release the shutdown lock */
1595 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1603 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1604 IN BOOLEAN DeferredStartIo
,
1605 IN BOOLEAN NonCancelable
)
1607 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1609 /* Get the Device Extension */
1610 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1612 /* Set the flags the caller requested */
1613 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1614 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1622 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1623 IN BOOLEAN Cancelable
,
1626 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1628 /* Get the Device Extension */
1629 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1631 /* Check if deferred start was requested */
1632 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1634 /* Call our internal function to handle the defered case */
1635 IopStartNextPacketByKeyEx(DeviceObject
,
1638 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1642 /* Call the normal routine */
1643 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1652 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1653 IN BOOLEAN Cancelable
)
1655 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1657 /* Get the Device Extension */
1658 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1660 /* Check if deferred start was requested */
1661 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1663 /* Call our internal function to handle the defered case */
1664 IopStartNextPacketByKeyEx(DeviceObject
,
1667 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1671 /* Call the normal routine */
1672 IopStartNextPacket(DeviceObject
, Cancelable
);
1681 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1684 IN PDRIVER_CANCEL CancelFunction
)
1687 KIRQL OldIrql
, CancelIrql
;
1689 /* Raise to dispatch level */
1690 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1692 /* Check if we should acquire the cancel lock */
1695 /* Acquire and set it */
1696 IoAcquireCancelSpinLock(&CancelIrql
);
1697 Irp
->CancelRoutine
= CancelFunction
;
1700 /* Check if we have a key */
1704 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1705 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1710 /* Insert without a key */
1711 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1712 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1715 /* Check if this was a first insert */
1719 DeviceObject
->CurrentIrp
= Irp
;
1721 /* Check if this is a cancelable packet */
1724 /* Check if the caller requested no cancellation */
1725 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1728 /* He did, so remove the cancel routine */
1729 Irp
->CancelRoutine
= NULL
;
1732 /* Release the cancel lock */
1733 IoReleaseCancelSpinLock(CancelIrql
);
1736 /* Call the Start I/O function */
1737 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1741 /* The packet was inserted... check if we have a cancel function */
1744 /* Check if the IRP got cancelled */
1748 * Set the cancel IRQL, clear the currnet cancel routine and
1751 Irp
->CancelIrql
= CancelIrql
;
1752 Irp
->CancelRoutine
= NULL
;
1753 CancelFunction(DeviceObject
, Irp
);
1757 /* Otherwise, release the lock */
1758 IoReleaseCancelSpinLock(CancelIrql
);
1763 /* Return back to previous IRQL */
1764 KeLowerIrql(OldIrql
);
1767 #if defined (_WIN64)
1770 IoWMIDeviceObjectToProviderId(
1771 IN PDEVICE_OBJECT DeviceObject
)