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)
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
,
230 Status
= IoCallDriver(DeviceObject
, Irp
);
231 if (Status
== STATUS_PENDING
)
233 /* Wait on the driver */
234 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
237 /* Remove the flag */
238 ShutdownEntry
->DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
240 /* Get rid of our reference to it */
241 ObDereferenceObject(ShutdownEntry
->DeviceObject
);
243 /* Free the shutdown entry and reset the event */
244 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
245 KeClearEvent(&Event
);
247 /* Go to the next entry */
248 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
257 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
258 IN ACCESS_MASK DesiredAccess
,
259 OUT PFILE_OBJECT
*FileObject
,
260 OUT PDEVICE_OBJECT
*DeviceObject
,
263 OBJECT_ATTRIBUTES ObjectAttributes
;
264 IO_STATUS_BLOCK StatusBlock
;
265 PFILE_OBJECT LocalFileObject
;
269 /* Open the Device */
270 InitializeObjectAttributes(&ObjectAttributes
,
275 Status
= ZwOpenFile(&FileHandle
,
280 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
281 if (!NT_SUCCESS(Status
)) return Status
;
283 /* Get File Object */
284 Status
= ObReferenceObjectByHandle(FileHandle
,
288 (PVOID
*)&LocalFileObject
,
290 if (NT_SUCCESS(Status
))
292 /* Return the requested data */
293 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
294 *FileObject
= LocalFileObject
;
297 /* Close the handle */
305 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
307 PDEVICE_OBJECT LowestDevice
;
308 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
310 /* Get the current device and its extension */
311 LowestDevice
= DeviceObject
;
312 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
314 /* Keep looping as long as we're attached */
315 while (DeviceExtension
->AttachedTo
)
317 /* Get the lowest device and its extension */
318 LowestDevice
= DeviceExtension
->AttachedTo
;
319 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
322 /* Return the lowest device */
328 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
329 IN PDEVICE_OBJECT DeviceObject
,
330 IN IOP_DEVICE_LIST_OPERATION Type
)
332 PDEVICE_OBJECT Previous
;
334 /* Check the type of operation */
335 if (Type
== IopRemove
)
337 /* Get the current device and check if it's the current one */
338 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
339 if (Previous
== DeviceObject
)
341 /* It is, simply unlink this one directly */
342 DeviceObject
->DriverObject
->DeviceObject
=
343 DeviceObject
->NextDevice
;
347 /* It's not, so loop until we find the device */
348 while (Previous
->NextDevice
!= DeviceObject
)
350 /* Not this one, keep moving */
351 Previous
= Previous
->NextDevice
;
354 /* We found it, now unlink us */
355 Previous
->NextDevice
= DeviceObject
->NextDevice
;
360 /* Link the device object and the driver object */
361 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
362 DriverObject
->DeviceObject
= DeviceObject
;
368 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
370 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
371 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
= IoGetDevObjExtension(DeviceObject
);
373 /* Check if deletion is pending */
374 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
376 if (DeviceObject
->AttachedDevice
)
378 DPRINT("Device object is in the middle of a device stack\n");
382 if (DeviceObject
->ReferenceCount
)
384 DPRINT("Device object still has %d references\n", DeviceObject
->ReferenceCount
);
388 /* Check if we have a Security Descriptor */
389 if (DeviceObject
->SecurityDescriptor
)
392 ExFreePoolWithTag(DeviceObject
->SecurityDescriptor
, TAG_SD
);
395 /* Remove the device from the list */
396 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
398 /* Dereference the keep-alive */
399 ObDereferenceObject(DeviceObject
);
402 /* We can't unload a non-PnP driver here */
403 if (DriverObject
->Flags
& DRVO_LEGACY_DRIVER
)
405 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
409 /* Return if we've already called unload (maybe we're in it?) */
410 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) return;
412 /* We can't unload unless there's an unload handler */
413 if (!DriverObject
->DriverUnload
)
415 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
419 /* Bail if there are still devices present */
420 if (DriverObject
->DeviceObject
)
422 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
426 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject
->DriverName
);
428 /* Set the unload invoked flag */
429 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
432 DriverObject
->DriverUnload(DriverObject
);
434 /* Make object temporary so it can be deleted */
435 ObMakeTemporaryObject(DriverObject
);
440 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
441 IN BOOLEAN ForceUnload
)
444 ASSERT(DeviceObject
->ReferenceCount
);
446 /* Dereference the device */
447 InterlockedDecrement(&DeviceObject
->ReferenceCount
);
450 * Check if we can unload it and it's safe to unload (or if we're forcing
451 * an unload, which is OK too).
453 ASSERT(!ForceUnload
);
454 if (!(DeviceObject
->ReferenceCount
) &&
455 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
& DOE_DELETE_PENDING
))
458 IopUnloadDevice(DeviceObject
);
464 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
465 IN BOOLEAN Cancelable
,
468 PKDEVICE_QUEUE_ENTRY Entry
;
472 /* Acquire the cancel lock if this is cancelable */
473 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
475 /* Clear the current IRP */
476 DeviceObject
->CurrentIrp
= NULL
;
478 /* Remove an entry from the queue */
479 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
482 /* Get the IRP and set it */
483 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
484 DeviceObject
->CurrentIrp
= Irp
;
486 /* Check if this is a cancelable packet */
489 /* Check if the caller requested no cancellation */
490 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
493 /* He did, so remove the cancel routine */
494 Irp
->CancelRoutine
= NULL
;
497 /* Release the cancel lock */
498 IoReleaseCancelSpinLock(OldIrql
);
501 /* Call the Start I/O Routine */
502 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
506 /* Otherwise, release the cancel lock if we had acquired it */
507 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
513 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
514 IN BOOLEAN Cancelable
)
516 PKDEVICE_QUEUE_ENTRY Entry
;
520 /* Acquire the cancel lock if this is cancelable */
521 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
523 /* Clear the current IRP */
524 DeviceObject
->CurrentIrp
= NULL
;
526 /* Remove an entry from the queue */
527 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
530 /* Get the IRP and set it */
531 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
532 DeviceObject
->CurrentIrp
= Irp
;
534 /* Check if this is a cancelable packet */
537 /* Check if the caller requested no cancellation */
538 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
541 /* He did, so remove the cancel routine */
542 Irp
->CancelRoutine
= NULL
;
545 /* Release the cancel lock */
546 IoReleaseCancelSpinLock(OldIrql
);
549 /* Call the Start I/O Routine */
550 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
554 /* Otherwise, release the cancel lock if we had acquired it */
555 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
561 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
565 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
566 ULONG CurrentKey
= Key
;
567 ULONG CurrentFlags
= Flags
;
569 /* Get the device extension and start the packet loop */
570 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
573 /* Increase the count */
574 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
577 * We've already called the routine once...
578 * All we have to do is save the key and add the new flags
580 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
581 DeviceExtension
->StartIoKey
= CurrentKey
;
585 /* Mask out the current packet flags and key */
586 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
589 DeviceExtension
->StartIoKey
= 0;
591 /* Check if this is a packet start with key */
592 if (Flags
& DOE_SIO_WITH_KEY
)
594 /* Start the packet with a key */
595 IopStartNextPacketByKey(DeviceObject
,
596 (Flags
& DOE_SIO_CANCELABLE
) ?
600 else if (Flags
& DOE_SIO_NO_KEY
)
602 /* Start the packet */
603 IopStartNextPacket(DeviceObject
,
604 (Flags
& DOE_SIO_CANCELABLE
) ?
609 /* Decrease the Start I/O count and check if it's 0 now */
610 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
612 /* Get the current active key and flags */
613 CurrentKey
= DeviceExtension
->StartIoKey
;
614 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
618 /* Check if we should still loop */
619 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
623 /* There are still Start I/Os active, so quit this loop */
631 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
632 OUT PDEVICE_NODE
*DeviceNode
)
635 IO_STACK_LOCATION Stack
= {0};
636 PDEVICE_RELATIONS DeviceRelations
;
637 PDEVICE_OBJECT DeviceObject
= NULL
;
641 /* Get DeviceObject related to given FileObject */
642 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
643 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
645 /* Define input parameters */
646 Stack
.MajorFunction
= IRP_MJ_PNP
;
647 Stack
.MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
648 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
649 Stack
.FileObject
= FileObject
;
651 /* Call the driver to query all relations (IRP_MJ_PNP) */
652 Status
= IopSynchronousCall(DeviceObject
,
654 (PVOID
)&DeviceRelations
);
655 if (!NT_SUCCESS(Status
)) return Status
;
657 /* Make sure it's not NULL and contains only one object */
658 ASSERT(DeviceRelations
);
659 ASSERT(DeviceRelations
->Count
== 1);
661 /* Finally get the device node */
662 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
663 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
665 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
666 ExFreePool(DeviceRelations
);
671 /* PUBLIC FUNCTIONS ***********************************************************/
676 * Layers a device over the highest device in a device stack.
680 * Device to be attached.
683 * Name of the target device.
686 * Caller storage for the device attached to.
693 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
694 PUNICODE_STRING TargetDeviceName
,
695 PDEVICE_OBJECT
*AttachedDevice
)
698 PFILE_OBJECT FileObject
= NULL
;
699 PDEVICE_OBJECT TargetDevice
= NULL
;
701 /* Call the helper routine for an attach operation */
702 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
703 FILE_READ_ATTRIBUTES
,
706 IO_ATTACH_DEVICE_API
);
707 if (!NT_SUCCESS(Status
)) return Status
;
709 /* Attach the device */
710 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
715 ObDereferenceObject(FileObject
);
720 * IoAttachDeviceByPointer
727 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
728 IN PDEVICE_OBJECT TargetDevice
)
730 PDEVICE_OBJECT AttachedDevice
;
731 NTSTATUS Status
= STATUS_SUCCESS
;
734 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
735 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
737 /* Return the status */
746 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
747 IN PDEVICE_OBJECT TargetDevice
)
749 /* Attach it safely */
750 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
760 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
761 IN PDEVICE_OBJECT TargetDevice
,
762 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
764 /* Call the internal function */
765 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
767 AttachedToDeviceObject
))
770 return STATUS_NO_SUCH_DEVICE
;
774 return STATUS_SUCCESS
;
780 * Allocates memory for and intializes a device object for use for
785 * Driver object passed by IO Manager when the driver was loaded.
787 * DeviceExtensionSize
788 * Number of bytes for the device extension.
791 * Unicode name of device.
794 * Device type of the new device.
796 * DeviceCharacteristics
797 * Bit mask of device characteristics.
800 * TRUE if only one thread can access the device at a time.
803 * On successful return this parameter is filled by pointer to
804 * allocated device object.
811 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
812 IN ULONG DeviceExtensionSize
,
813 IN PUNICODE_STRING DeviceName
,
814 IN DEVICE_TYPE DeviceType
,
815 IN ULONG DeviceCharacteristics
,
816 IN BOOLEAN Exclusive
,
817 OUT PDEVICE_OBJECT
*DeviceObject
)
819 WCHAR AutoNameBuffer
[20];
820 UNICODE_STRING AutoName
;
821 PDEVICE_OBJECT CreatedDeviceObject
;
822 PDEVOBJ_EXTENSION DeviceObjectExtension
;
823 OBJECT_ATTRIBUTES ObjectAttributes
;
825 ULONG AlignedDeviceExtensionSize
;
830 /* Check if we have to generate a name */
831 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
834 swprintf(AutoNameBuffer
,
836 InterlockedIncrementUL(&IopDeviceObjectNumber
));
838 /* Initialize the name */
839 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
840 DeviceName
= &AutoName
;
843 /* Initialize the Object Attributes */
844 InitializeObjectAttributes(&ObjectAttributes
,
850 /* Honor exclusive flag */
851 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
853 /* Create a permanent object for named devices */
854 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
856 /* Align the Extension Size to 8-bytes */
857 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
860 TotalSize
= AlignedDeviceExtensionSize
+
861 sizeof(DEVICE_OBJECT
) +
862 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
864 /* Create the Device Object */
865 *DeviceObject
= NULL
;
866 Status
= ObCreateObject(KernelMode
,
874 (PVOID
*)&CreatedDeviceObject
);
875 if (!NT_SUCCESS(Status
)) return Status
;
877 /* Clear the whole Object and extension so we don't null stuff manually */
878 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
881 * Setup the Type and Size. Note that we don't use the aligned size,
882 * because that's only padding for the DevObjExt and not part of the Object.
884 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
885 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
887 /* The kernel extension is after the driver internal extension */
888 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
889 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
890 AlignedDeviceExtensionSize
);
892 /* Set the Type and Size. Question: why is Size 0 on Windows? */
893 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
894 DeviceObjectExtension
->Size
= 0;
896 /* Initialize with Power Manager */
897 PoInitializeDeviceObject(DeviceObjectExtension
);
899 /* Link the Object and Extension */
900 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
901 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
903 /* Set Device Object Data */
904 CreatedDeviceObject
->DeviceType
= DeviceType
;
905 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
906 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
907 CreatedDeviceObject
+ 1 :
909 CreatedDeviceObject
->StackSize
= 1;
910 CreatedDeviceObject
->AlignmentRequirement
= 0;
913 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
914 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
915 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
917 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
918 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
919 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
920 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
921 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
924 Status
= IopCreateVpb(CreatedDeviceObject
);
925 if (!NT_SUCCESS(Status
))
927 /* Dereference the device object and fail */
928 ObDereferenceObject(CreatedDeviceObject
);
932 /* Initialize Lock Event */
933 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
934 SynchronizationEvent
,
938 /* Set the right Sector Size */
941 /* All disk systems */
942 case FILE_DEVICE_DISK_FILE_SYSTEM
:
943 case FILE_DEVICE_DISK
:
944 case FILE_DEVICE_VIRTUAL_DISK
:
946 /* The default is 512 bytes */
947 CreatedDeviceObject
->SectorSize
= 512;
950 /* CD-ROM file systems */
951 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
953 /* The default is 2048 bytes */
954 CreatedDeviceObject
->SectorSize
= 2048;
957 /* Create the Device Queue */
958 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
959 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
960 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
961 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
962 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
964 /* Simple FS Devices, they don't need a real Device Queue */
965 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
969 /* An actual Device, initialize its DQ */
970 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
973 /* Insert the Object */
974 Status
= ObInsertObject(CreatedDeviceObject
,
976 FILE_READ_DATA
| FILE_WRITE_DATA
,
978 (PVOID
*)&CreatedDeviceObject
,
980 if (!NT_SUCCESS(Status
)) return Status
;
982 /* Now do the final linking */
983 ObReferenceObject(DriverObject
);
984 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
985 CreatedDeviceObject
->DriverObject
= DriverObject
;
986 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
988 /* Link with the power manager */
989 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
991 /* Close the temporary handle and return to caller */
992 ObCloseHandle(TempHandle
, KernelMode
);
993 *DeviceObject
= CreatedDeviceObject
;
994 return STATUS_SUCCESS
;
1005 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1009 /* Check if the device is registered for shutdown notifications */
1010 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1012 /* Call the shutdown notifications */
1013 IoUnregisterShutdownNotification(DeviceObject
);
1016 /* Check if it has a timer */
1017 Timer
= DeviceObject
->Timer
;
1020 /* Remove it and free it */
1021 IopRemoveTimerFromTimerList(Timer
);
1022 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1025 /* Check if the device has a name */
1026 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1028 /* It does, make it temporary so we can remove it */
1029 ObMakeTemporaryObject(DeviceObject
);
1032 /* Set the pending delete flag */
1033 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1035 /* Check if the device object can be unloaded */
1036 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1047 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1049 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1052 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1053 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1055 /* Remove the attachment */
1056 DeviceExtension
->AttachedTo
= NULL
;
1057 TargetDevice
->AttachedDevice
= NULL
;
1059 /* Check if it's ok to delete this device */
1060 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
& DOE_DELETE_PENDING
) &&
1061 !(TargetDevice
->ReferenceCount
))
1064 IopUnloadDevice(TargetDevice
);
1073 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1074 IN PDEVICE_OBJECT
*DeviceObjectList
,
1075 IN ULONG DeviceObjectListSize
,
1076 OUT PULONG ActualNumberDeviceObjects
)
1078 ULONG ActualDevices
= 1;
1079 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1081 /* Find out how many devices we'll enumerate */
1082 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1084 /* Go back to the first */
1085 CurrentDevice
= DriverObject
->DeviceObject
;
1087 /* Start by at least returning this */
1088 *ActualNumberDeviceObjects
= ActualDevices
;
1090 /* Check if we can support so many */
1091 if ((ActualDevices
* 4) > DeviceObjectListSize
)
1093 /* Fail because the buffer was too small */
1094 return STATUS_BUFFER_TOO_SMALL
;
1097 /* Check if the caller only wanted the size */
1098 if (DeviceObjectList
)
1100 /* Loop through all the devices */
1101 while (ActualDevices
)
1103 /* Reference each Device */
1104 ObReferenceObject(CurrentDevice
);
1106 /* Add it to the list */
1107 *DeviceObjectList
= CurrentDevice
;
1109 /* Go to the next one */
1110 CurrentDevice
= CurrentDevice
->NextDevice
;
1116 /* Return the status */
1117 return STATUS_SUCCESS
;
1121 * IoGetAttachedDevice
1128 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1130 /* Get the last attached device */
1131 while (DeviceObject
->AttachedDevice
)
1133 /* Move to the next one */
1134 DeviceObject
= DeviceObject
->AttachedDevice
;
1138 return DeviceObject
;
1142 * IoGetAttachedDeviceReference
1149 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1151 /* Reference the Attached Device */
1152 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1153 ObReferenceObject(DeviceObject
);
1154 return DeviceObject
;
1162 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1164 /* Reference the lowest attached device */
1165 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1166 ObReferenceObject(DeviceObject
);
1167 return DeviceObject
;
1171 * IoGetDeviceObjectPointer
1178 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1179 IN ACCESS_MASK DesiredAccess
,
1180 OUT PFILE_OBJECT
*FileObject
,
1181 OUT PDEVICE_OBJECT
*DeviceObject
)
1183 /* Call the helper routine for a normal operation */
1184 return IopGetDeviceObjectPointer(ObjectName
,
1196 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1197 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1199 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1204 /* Make sure there's a VPB */
1205 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1208 IoAcquireVpbSpinLock(&OldIrql
);
1210 /* Get the Device Extension */
1211 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1213 /* Make sure this one has a VPB too */
1214 Vpb
= DeviceExtension
->Vpb
;
1217 /* Make sure that it's mounted */
1218 if ((Vpb
->ReferenceCount
) &&
1219 (Vpb
->Flags
& VPB_MOUNTED
))
1221 /* Return the Disk Device Object */
1222 *DiskDeviceObject
= Vpb
->RealDevice
;
1224 /* Reference it and return success */
1225 ObReferenceObject(Vpb
->RealDevice
);
1226 Status
= STATUS_SUCCESS
;
1230 /* It's not, so return failure */
1231 Status
= STATUS_VOLUME_DISMOUNTED
;
1237 Status
= STATUS_INVALID_PARAMETER
;
1240 /* Release the lock */
1241 IoReleaseVpbSpinLock(OldIrql
);
1250 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1252 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1253 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1255 /* Make sure it's not getting deleted */
1256 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1257 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1258 DOE_DELETE_PENDING
|
1259 DOE_REMOVE_PENDING
|
1260 DOE_REMOVE_PROCESSED
)))
1262 /* Get the Lower Device Object */
1263 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1265 /* Check that we got a valid device object */
1266 if (LowerDeviceObject
)
1268 /* We did so let's reference it */
1269 ObReferenceObject(LowerDeviceObject
);
1274 return LowerDeviceObject
;
1282 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1284 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1286 /* Check if we have a VPB with a device object */
1287 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1289 /* Then use the DO from the VPB */
1290 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1291 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1293 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1294 (FileObject
->DeviceObject
->Vpb
) &&
1295 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1297 /* The disk device actually has a VPB, so get the DO from there */
1298 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1302 /* Otherwise, this was a direct open */
1303 DeviceObject
= FileObject
->DeviceObject
;
1307 ASSERT(DeviceObject
!= NULL
);
1309 /* Check if we were attached */
1310 if (DeviceObject
->AttachedDevice
)
1312 /* Check if the file object has an extension present */
1313 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1315 /* Sanity check, direct open files can't have this */
1316 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1318 /* Check if the extension is really present */
1319 if (FileObject
->FileObjectExtension
)
1321 /* FIXME: Unhandled yet */
1322 DPRINT1("FOEs not supported\n");
1327 /* Return the highest attached device */
1328 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1331 /* Return the DO we found */
1332 return DeviceObject
;
1340 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1341 OUT PDEVICE_OBJECT
*DeviceObject
)
1344 PDEVICE_NODE DeviceNode
= NULL
;
1346 /* Call the internal helper function */
1347 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1348 if (NT_SUCCESS(Status
) && DeviceNode
)
1350 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1360 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1362 PDEVICE_OBJECT DeviceObject
;
1365 * If the FILE_OBJECT's VPB is defined,
1366 * get the device from it.
1368 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1370 /* Use the VPB's Device Object's */
1371 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1373 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1374 (FileObject
->DeviceObject
->Vpb
) &&
1375 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1377 /* Use the VPB's File System Object */
1378 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1382 /* Use the FO's Device Object */
1383 DeviceObject
= FileObject
->DeviceObject
;
1386 /* Return the device object we found */
1387 ASSERT(DeviceObject
!= NULL
);
1388 return DeviceObject
;
1396 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1398 PSHUTDOWN_ENTRY Entry
;
1400 /* Allocate the shutdown entry */
1401 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1402 sizeof(SHUTDOWN_ENTRY
),
1403 TAG_SHUTDOWN_ENTRY
);
1404 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1407 Entry
->DeviceObject
= DeviceObject
;
1409 /* Reference it so it doesn't go away */
1410 ObReferenceObject(DeviceObject
);
1412 /* Insert it into the list */
1413 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1414 &Entry
->ShutdownList
,
1417 /* Set the shutdown registered flag */
1418 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1419 return STATUS_SUCCESS
;
1427 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1429 PSHUTDOWN_ENTRY Entry
;
1431 /* Allocate the shutdown entry */
1432 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1433 sizeof(SHUTDOWN_ENTRY
),
1434 TAG_SHUTDOWN_ENTRY
);
1435 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1438 Entry
->DeviceObject
= DeviceObject
;
1440 /* Reference it so it doesn't go away */
1441 ObReferenceObject(DeviceObject
);
1443 /* Insert it into the list */
1444 ExInterlockedInsertHeadList(&ShutdownListHead
,
1445 &Entry
->ShutdownList
,
1448 /* Set the shutdown registered flag */
1449 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1450 return STATUS_SUCCESS
;
1458 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1460 PSHUTDOWN_ENTRY ShutdownEntry
;
1461 PLIST_ENTRY NextEntry
;
1464 /* Remove the flag */
1465 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1467 /* Acquire the shutdown lock and loop the shutdown list */
1468 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1469 NextEntry
= ShutdownListHead
.Flink
;
1470 while (NextEntry
!= &ShutdownListHead
)
1473 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1477 /* Get if the DO matches */
1478 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1480 /* Remove it from the list */
1481 RemoveEntryList(NextEntry
);
1482 NextEntry
= NextEntry
->Blink
;
1484 /* Free the entry */
1485 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1487 /* Get rid of our reference to it */
1488 ObDereferenceObject(DeviceObject
);
1491 /* Go to the next entry */
1492 NextEntry
= NextEntry
->Flink
;
1495 /* Now loop the last chance list */
1496 NextEntry
= LastChanceShutdownListHead
.Flink
;
1497 while (NextEntry
!= &LastChanceShutdownListHead
)
1500 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1504 /* Get if the DO matches */
1505 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1507 /* Remove it from the list */
1508 RemoveEntryList(NextEntry
);
1509 NextEntry
= NextEntry
->Blink
;
1511 /* Free the entry */
1512 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1514 /* Get rid of our reference to it */
1515 ObDereferenceObject(DeviceObject
);
1518 /* Go to the next entry */
1519 NextEntry
= NextEntry
->Flink
;
1522 /* Release the shutdown lock */
1523 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1531 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1532 IN BOOLEAN DeferredStartIo
,
1533 IN BOOLEAN NonCancelable
)
1535 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1537 /* Get the Device Extension */
1538 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1540 /* Set the flags the caller requested */
1541 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1542 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1550 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1551 IN BOOLEAN Cancelable
,
1554 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1556 /* Get the Device Extension */
1557 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1559 /* Check if deferred start was requested */
1560 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1562 /* Call our internal function to handle the defered case */
1563 IopStartNextPacketByKeyEx(DeviceObject
,
1566 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1570 /* Call the normal routine */
1571 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1580 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1581 IN BOOLEAN Cancelable
)
1583 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1585 /* Get the Device Extension */
1586 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1588 /* Check if deferred start was requested */
1589 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1591 /* Call our internal function to handle the defered case */
1592 IopStartNextPacketByKeyEx(DeviceObject
,
1595 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1599 /* Call the normal routine */
1600 IopStartNextPacket(DeviceObject
, Cancelable
);
1609 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1612 IN PDRIVER_CANCEL CancelFunction
)
1615 KIRQL OldIrql
, CancelIrql
;
1617 /* Raise to dispatch level */
1618 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1620 /* Check if we should acquire the cancel lock */
1623 /* Acquire and set it */
1624 IoAcquireCancelSpinLock(&CancelIrql
);
1625 Irp
->CancelRoutine
= CancelFunction
;
1628 /* Check if we have a key */
1632 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1633 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1638 /* Insert without a key */
1639 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1640 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1643 /* Check if this was a first insert */
1647 DeviceObject
->CurrentIrp
= Irp
;
1649 /* Check if this is a cancelable packet */
1652 /* Check if the caller requested no cancellation */
1653 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1656 /* He did, so remove the cancel routine */
1657 Irp
->CancelRoutine
= NULL
;
1660 /* Release the cancel lock */
1661 IoReleaseCancelSpinLock(CancelIrql
);
1664 /* Call the Start I/O function */
1665 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1669 /* The packet was inserted... check if we have a cancel function */
1672 /* Check if the IRP got cancelled */
1676 * Set the cancel IRQL, clear the currnet cancel routine and
1679 Irp
->CancelIrql
= CancelIrql
;
1680 Irp
->CancelRoutine
= NULL
;
1681 CancelFunction(DeviceObject
, Irp
);
1685 /* Otherwise, release the lock */
1686 IoReleaseCancelSpinLock(CancelIrql
);
1691 /* Return back to previous IRQL */
1692 KeLowerIrql(OldIrql
);
1695 #if defined (_WIN64)
1698 IoWMIDeviceObjectToProviderId(
1699 IN PDEVICE_OBJECT DeviceObject
)