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
,
170 Status
= IoCallDriver(DeviceObject
, Irp
);
171 if (Status
== STATUS_PENDING
)
173 /* Wait on the driver */
174 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
177 /* Get rid of our reference to it */
178 ObDereferenceObject(DeviceObject
);
180 /* Free the shutdown entry and reset the event */
181 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
182 KeClearEvent(&Event
);
184 /* Go to the next entry */
185 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
191 /* Acquire resource forever */
192 ExAcquireResourceExclusiveLite(&IopDatabaseResource
, TRUE
);
194 /* Shutdown disk file systems */
195 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead
);
197 /* Shutdown cdrom file systems */
198 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead
);
200 /* Shutdown tape filesystems */
201 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead
);
203 /* Loop last-chance shutdown notifications */
204 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
208 /* Get the shutdown entry */
209 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
213 /* Get the attached device */
214 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
216 /* Build the shutdown IRP and call the driver */
217 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
224 Status
= IoCallDriver(DeviceObject
, Irp
);
225 if (Status
== STATUS_PENDING
)
227 /* Wait on the driver */
228 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
231 /* Get rid of our reference to it */
232 ObDereferenceObject(DeviceObject
);
234 /* Free the shutdown entry and reset the event */
235 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
236 KeClearEvent(&Event
);
238 /* Go to the next entry */
239 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
248 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
249 IN ACCESS_MASK DesiredAccess
,
250 OUT PFILE_OBJECT
*FileObject
,
251 OUT PDEVICE_OBJECT
*DeviceObject
,
254 OBJECT_ATTRIBUTES ObjectAttributes
;
255 IO_STATUS_BLOCK StatusBlock
;
256 PFILE_OBJECT LocalFileObject
;
260 /* Open the Device */
261 InitializeObjectAttributes(&ObjectAttributes
,
266 Status
= ZwOpenFile(&FileHandle
,
271 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
272 if (!NT_SUCCESS(Status
)) return Status
;
274 /* Get File Object */
275 Status
= ObReferenceObjectByHandle(FileHandle
,
279 (PVOID
*)&LocalFileObject
,
281 if (NT_SUCCESS(Status
))
283 /* Return the requested data */
284 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
285 *FileObject
= LocalFileObject
;
288 /* Close the handle */
296 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
298 PDEVICE_OBJECT LowestDevice
;
299 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
301 /* Get the current device and its extension */
302 LowestDevice
= DeviceObject
;
303 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
305 /* Keep looping as long as we're attached */
306 while (DeviceExtension
->AttachedTo
)
308 /* Get the lowest device and its extension */
309 LowestDevice
= DeviceExtension
->AttachedTo
;
310 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
313 /* Return the lowest device */
319 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
320 IN PDEVICE_OBJECT DeviceObject
,
321 IN IOP_DEVICE_LIST_OPERATION Type
)
323 PDEVICE_OBJECT Previous
;
325 /* Check the type of operation */
326 if (Type
== IopRemove
)
328 /* Get the current device and check if it's the current one */
329 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
330 if (Previous
== DeviceObject
)
332 /* It is, simply unlink this one directly */
333 DeviceObject
->DriverObject
->DeviceObject
=
334 DeviceObject
->NextDevice
;
338 /* It's not, so loop until we find the device */
339 while (Previous
->NextDevice
!= DeviceObject
)
341 /* Not this one, keep moving */
342 Previous
= Previous
->NextDevice
;
345 /* We found it, now unlink us */
346 Previous
->NextDevice
= DeviceObject
->NextDevice
;
351 /* Link the device object and the driver object */
352 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
353 DriverObject
->DeviceObject
= DeviceObject
;
359 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
361 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
362 PDEVICE_OBJECT AttachedDeviceObject
, LowestDeviceObject
;
363 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
, DeviceExtension
;
364 PDEVICE_NODE DeviceNode
;
365 BOOLEAN SafeToUnload
= TRUE
;
367 /* Check if removal is pending */
368 ThisExtension
= IoGetDevObjExtension(DeviceObject
);
369 if (ThisExtension
->ExtensionFlags
& DOE_REMOVE_PENDING
)
371 /* Get the PDO, extension, and node */
372 LowestDeviceObject
= IopGetLowestDevice(DeviceObject
);
373 DeviceExtension
= IoGetDevObjExtension(LowestDeviceObject
);
374 DeviceNode
= DeviceExtension
->DeviceNode
;
376 /* The PDO needs a device node */
377 ASSERT(DeviceNode
!= NULL
);
379 /* Loop all attached objects */
380 AttachedDeviceObject
= LowestDeviceObject
;
381 while (AttachedDeviceObject
)
383 /* Make sure they're dereferenced */
384 if (AttachedDeviceObject
->ReferenceCount
) return;
385 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
388 /* Loop all attached objects */
389 AttachedDeviceObject
= LowestDeviceObject
;
390 while (AttachedDeviceObject
)
392 /* Get the device extension */
393 DeviceExtension
= IoGetDevObjExtension(AttachedDeviceObject
);
395 /* Remove the pending flag and set processed */
396 DeviceExtension
->ExtensionFlags
&= ~DOE_REMOVE_PENDING
;
397 DeviceExtension
->ExtensionFlags
|= DOE_REMOVE_PROCESSED
;
398 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
402 * FIXME: TODO HPOUSSIN
403 * We need to parse/lock the device node, and if we have any pending
404 * surprise removals, query all relationships and send IRP_MN_REMOVE_
405 * _DEVICE to the devices related...
410 /* Check if deletion is pending */
411 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
413 /* Make sure unload is pending */
414 if (!(ThisExtension
->ExtensionFlags
& DOE_UNLOAD_PENDING
) ||
415 (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
))
417 /* We can't unload anymore */
418 SafeToUnload
= FALSE
;
422 * Check if we have an attached device and fail if we're attached
423 * and still have a reference count.
425 AttachedDeviceObject
= DeviceObject
->AttachedDevice
;
426 if ((AttachedDeviceObject
) && (DeviceObject
->ReferenceCount
)) return;
428 /* Check if we have a Security Descriptor */
429 if (DeviceObject
->SecurityDescriptor
)
432 ExFreePoolWithTag(DeviceObject
->SecurityDescriptor
, TAG_SD
);
435 /* Remove the device from the list */
436 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
438 /* Dereference the keep-alive */
439 ObDereferenceObject(DeviceObject
);
441 /* If we're not unloading, stop here */
442 if (!SafeToUnload
) return;
445 /* Loop all the device objects */
446 DeviceObject
= DriverObject
->DeviceObject
;
450 * Make sure we're not attached, having a reference count
451 * or already deleting
453 if ((DeviceObject
->ReferenceCount
) ||
454 (DeviceObject
->AttachedDevice
) ||
455 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
456 (DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)))
458 /* We're not safe to unload, quit */
462 /* Check the next device */
463 DeviceObject
= DeviceObject
->NextDevice
;
466 /* Set the unload invoked flag */
467 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
470 if (DriverObject
->DriverUnload
) DriverObject
->DriverUnload(DriverObject
);
472 /* Make object temporary so it can be deleted */
473 ObMakeTemporaryObject(DriverObject
);
475 /* Dereference once more, referenced at driver object creation */
476 ObDereferenceObject(DriverObject
);
482 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
483 IN BOOLEAN ForceUnload
)
486 ASSERT(DeviceObject
->ReferenceCount
);
488 /* Dereference the device */
489 DeviceObject
->ReferenceCount
--;
492 * Check if we can unload it and it's safe to unload (or if we're forcing
493 * an unload, which is OK too).
495 if (!(DeviceObject
->ReferenceCount
) &&
496 ((ForceUnload
) || (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
497 (DOE_UNLOAD_PENDING
|
500 DOE_REMOVE_PROCESSED
))))
503 IopUnloadDevice(DeviceObject
);
509 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
510 IN BOOLEAN Cancelable
,
513 PKDEVICE_QUEUE_ENTRY Entry
;
517 /* Acquire the cancel lock if this is cancelable */
518 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
520 /* Clear the current IRP */
521 DeviceObject
->CurrentIrp
= NULL
;
523 /* Remove an entry from the queue */
524 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
527 /* Get the IRP and set it */
528 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
529 DeviceObject
->CurrentIrp
= Irp
;
531 /* Check if this is a cancelable packet */
534 /* Check if the caller requested no cancellation */
535 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
538 /* He did, so remove the cancel routine */
539 Irp
->CancelRoutine
= NULL
;
542 /* Release the cancel lock */
543 IoReleaseCancelSpinLock(OldIrql
);
546 /* Call the Start I/O Routine */
547 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
551 /* Otherwise, release the cancel lock if we had acquired it */
552 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
558 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
559 IN BOOLEAN Cancelable
)
561 PKDEVICE_QUEUE_ENTRY Entry
;
565 /* Acquire the cancel lock if this is cancelable */
566 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
568 /* Clear the current IRP */
569 DeviceObject
->CurrentIrp
= NULL
;
571 /* Remove an entry from the queue */
572 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
575 /* Get the IRP and set it */
576 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
577 DeviceObject
->CurrentIrp
= Irp
;
579 /* Check if this is a cancelable packet */
582 /* Check if the caller requested no cancellation */
583 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
586 /* He did, so remove the cancel routine */
587 Irp
->CancelRoutine
= NULL
;
590 /* Release the cancel lock */
591 IoReleaseCancelSpinLock(OldIrql
);
594 /* Call the Start I/O Routine */
595 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
599 /* Otherwise, release the cancel lock if we had acquired it */
600 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
606 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
610 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
611 ULONG CurrentKey
= Key
;
612 ULONG CurrentFlags
= Flags
;
614 /* Get the device extension and start the packet loop */
615 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
618 /* Increase the count */
619 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
622 * We've already called the routine once...
623 * All we have to do is save the key and add the new flags
625 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
626 DeviceExtension
->StartIoKey
= CurrentKey
;
630 /* Mask out the current packet flags and key */
631 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
634 DeviceExtension
->StartIoKey
= 0;
636 /* Check if this is a packet start with key */
637 if (Flags
& DOE_SIO_WITH_KEY
)
639 /* Start the packet with a key */
640 IopStartNextPacketByKey(DeviceObject
,
641 (Flags
& DOE_SIO_CANCELABLE
) ?
645 else if (Flags
& DOE_SIO_NO_KEY
)
647 /* Start the packet */
648 IopStartNextPacket(DeviceObject
,
649 (Flags
& DOE_SIO_CANCELABLE
) ?
654 /* Decrease the Start I/O count and check if it's 0 now */
655 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
657 /* Get the current active key and flags */
658 CurrentKey
= DeviceExtension
->StartIoKey
;
659 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
663 /* Check if we should still loop */
664 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
668 /* There are still Start I/Os active, so quit this loop */
676 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
677 OUT PDEVICE_NODE
*DeviceNode
)
680 IO_STACK_LOCATION Stack
= {0};
681 PDEVICE_RELATIONS DeviceRelations
;
682 PDEVICE_OBJECT DeviceObject
= NULL
;
686 /* Get DeviceObject related to given FileObject */
687 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
688 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
690 /* Define input parameters */
691 Stack
.MajorFunction
= IRP_MJ_PNP
;
692 Stack
.MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
693 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
694 Stack
.FileObject
= FileObject
;
696 /* Call the driver to query all relations (IRP_MJ_PNP) */
697 Status
= IopSynchronousCall(DeviceObject
,
699 (PVOID
)&DeviceRelations
);
700 if (!NT_SUCCESS(Status
)) return Status
;
702 /* Make sure it's not NULL and contains only one object */
703 ASSERT(DeviceRelations
);
704 ASSERT(DeviceRelations
->Count
== 1);
706 /* Finally get the device node */
707 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
708 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
710 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
711 ExFreePool(DeviceRelations
);
716 /* PUBLIC FUNCTIONS ***********************************************************/
721 * Layers a device over the highest device in a device stack.
725 * Device to be attached.
728 * Name of the target device.
731 * Caller storage for the device attached to.
738 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
739 PUNICODE_STRING TargetDeviceName
,
740 PDEVICE_OBJECT
*AttachedDevice
)
743 PFILE_OBJECT FileObject
= NULL
;
744 PDEVICE_OBJECT TargetDevice
= NULL
;
746 /* Call the helper routine for an attach operation */
747 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
748 FILE_READ_ATTRIBUTES
,
751 IO_ATTACH_DEVICE_API
);
752 if (!NT_SUCCESS(Status
)) return Status
;
754 /* Attach the device */
755 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
760 ObDereferenceObject(FileObject
);
765 * IoAttachDeviceByPointer
772 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
773 IN PDEVICE_OBJECT TargetDevice
)
775 PDEVICE_OBJECT AttachedDevice
;
776 NTSTATUS Status
= STATUS_SUCCESS
;
779 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
780 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
782 /* Return the status */
791 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
792 IN PDEVICE_OBJECT TargetDevice
)
794 /* Attach it safely */
795 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
805 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
806 IN PDEVICE_OBJECT TargetDevice
,
807 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
809 /* Call the internal function */
810 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
812 AttachedToDeviceObject
))
815 return STATUS_NO_SUCH_DEVICE
;
819 return STATUS_SUCCESS
;
825 * Allocates memory for and intializes a device object for use for
830 * Driver object passed by IO Manager when the driver was loaded.
832 * DeviceExtensionSize
833 * Number of bytes for the device extension.
836 * Unicode name of device.
839 * Device type of the new device.
841 * DeviceCharacteristics
842 * Bit mask of device characteristics.
845 * TRUE if only one thread can access the device at a time.
848 * On successful return this parameter is filled by pointer to
849 * allocated device object.
856 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
857 IN ULONG DeviceExtensionSize
,
858 IN PUNICODE_STRING DeviceName
,
859 IN DEVICE_TYPE DeviceType
,
860 IN ULONG DeviceCharacteristics
,
861 IN BOOLEAN Exclusive
,
862 OUT PDEVICE_OBJECT
*DeviceObject
)
864 WCHAR AutoNameBuffer
[20];
865 UNICODE_STRING AutoName
;
866 PDEVICE_OBJECT CreatedDeviceObject
;
867 PDEVOBJ_EXTENSION DeviceObjectExtension
;
868 OBJECT_ATTRIBUTES ObjectAttributes
;
870 ULONG AlignedDeviceExtensionSize
;
875 /* Check if we have to generate a name */
876 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
879 swprintf(AutoNameBuffer
,
881 InterlockedIncrementUL(&IopDeviceObjectNumber
));
883 /* Initialize the name */
884 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
885 DeviceName
= &AutoName
;
888 /* Initialize the Object Attributes */
889 InitializeObjectAttributes(&ObjectAttributes
,
895 /* Honor exclusive flag */
896 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
898 /* Create a permanent object for named devices */
899 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
901 /* Align the Extension Size to 8-bytes */
902 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
905 TotalSize
= AlignedDeviceExtensionSize
+
906 sizeof(DEVICE_OBJECT
) +
907 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
909 /* Create the Device Object */
910 *DeviceObject
= NULL
;
911 Status
= ObCreateObject(KernelMode
,
919 (PVOID
*)&CreatedDeviceObject
);
920 if (!NT_SUCCESS(Status
)) return Status
;
922 /* Clear the whole Object and extension so we don't null stuff manually */
923 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
926 * Setup the Type and Size. Note that we don't use the aligned size,
927 * because that's only padding for the DevObjExt and not part of the Object.
929 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
930 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
932 /* The kernel extension is after the driver internal extension */
933 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
934 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
935 AlignedDeviceExtensionSize
);
937 /* Set the Type and Size. Question: why is Size 0 on Windows? */
938 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
939 DeviceObjectExtension
->Size
= 0;
941 /* Initialize with Power Manager */
942 PoInitializeDeviceObject(DeviceObjectExtension
);
944 /* Link the Object and Extension */
945 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
946 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
948 /* Set Device Object Data */
949 CreatedDeviceObject
->DeviceType
= DeviceType
;
950 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
951 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
952 CreatedDeviceObject
+ 1 :
954 CreatedDeviceObject
->StackSize
= 1;
955 CreatedDeviceObject
->AlignmentRequirement
= 0;
958 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
959 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
960 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
962 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
963 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
964 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
965 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
966 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
969 Status
= IopCreateVpb(CreatedDeviceObject
);
970 if (!NT_SUCCESS(Status
))
972 /* Reference the device object and fail */
973 ObDereferenceObject(DeviceObject
);
977 /* Initialize Lock Event */
978 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
979 SynchronizationEvent
,
983 /* Set the right Sector Size */
986 /* All disk systems */
987 case FILE_DEVICE_DISK_FILE_SYSTEM
:
988 case FILE_DEVICE_DISK
:
989 case FILE_DEVICE_VIRTUAL_DISK
:
991 /* The default is 512 bytes */
992 CreatedDeviceObject
->SectorSize
= 512;
995 /* CD-ROM file systems */
996 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
998 /* The default is 2048 bytes */
999 CreatedDeviceObject
->SectorSize
= 2048;
1002 /* Create the Device Queue */
1003 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1004 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
1005 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1006 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
1007 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
1009 /* Simple FS Devices, they don't need a real Device Queue */
1010 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
1014 /* An actual Device, initialize its DQ */
1015 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
1018 /* Insert the Object */
1019 Status
= ObInsertObject(CreatedDeviceObject
,
1021 FILE_READ_DATA
| FILE_WRITE_DATA
,
1023 (PVOID
*)&CreatedDeviceObject
,
1025 if (!NT_SUCCESS(Status
)) return Status
;
1027 /* Now do the final linking */
1028 ObReferenceObject(DriverObject
);
1029 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
1030 CreatedDeviceObject
->DriverObject
= DriverObject
;
1031 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
1033 /* Link with the power manager */
1034 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
1036 /* Close the temporary handle and return to caller */
1037 ObCloseHandle(TempHandle
, KernelMode
);
1038 *DeviceObject
= CreatedDeviceObject
;
1039 return STATUS_SUCCESS
;
1050 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1054 /* Check if the device is registered for shutdown notifications */
1055 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1057 /* Call the shutdown notifications */
1058 IoUnregisterShutdownNotification(DeviceObject
);
1061 /* Check if it has a timer */
1062 Timer
= DeviceObject
->Timer
;
1065 /* Remove it and free it */
1066 IopRemoveTimerFromTimerList(Timer
);
1067 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1070 /* Check if the device has a name */
1071 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1073 /* It does, make it temporary so we can remove it */
1074 ObMakeTemporaryObject(DeviceObject
);
1077 /* Set the pending delete flag */
1078 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1080 /* Check if the device object can be unloaded */
1081 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1092 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1094 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1097 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1098 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1100 /* Remove the attachment */
1101 DeviceExtension
->AttachedTo
= NULL
;
1102 TargetDevice
->AttachedDevice
= NULL
;
1104 /* Check if it's ok to delete this device */
1105 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
&
1106 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)) &&
1107 !(TargetDevice
->ReferenceCount
))
1110 IopUnloadDevice(TargetDevice
);
1119 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1120 IN PDEVICE_OBJECT
*DeviceObjectList
,
1121 IN ULONG DeviceObjectListSize
,
1122 OUT PULONG ActualNumberDeviceObjects
)
1124 ULONG ActualDevices
= 1;
1125 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1127 /* Find out how many devices we'll enumerate */
1128 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1130 /* Go back to the first */
1131 CurrentDevice
= DriverObject
->DeviceObject
;
1133 /* Start by at least returning this */
1134 *ActualNumberDeviceObjects
= ActualDevices
;
1136 /* Check if we can support so many */
1137 if ((ActualDevices
* 4) > DeviceObjectListSize
)
1139 /* Fail because the buffer was too small */
1140 return STATUS_BUFFER_TOO_SMALL
;
1143 /* Check if the caller only wanted the size */
1144 if (DeviceObjectList
)
1146 /* Loop through all the devices */
1147 while (ActualDevices
)
1149 /* Reference each Device */
1150 ObReferenceObject(CurrentDevice
);
1152 /* Add it to the list */
1153 *DeviceObjectList
= CurrentDevice
;
1155 /* Go to the next one */
1156 CurrentDevice
= CurrentDevice
->NextDevice
;
1162 /* Return the status */
1163 return STATUS_SUCCESS
;
1167 * IoGetAttachedDevice
1174 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1176 /* Get the last attached device */
1177 while (DeviceObject
->AttachedDevice
)
1179 /* Move to the next one */
1180 DeviceObject
= DeviceObject
->AttachedDevice
;
1184 return DeviceObject
;
1188 * IoGetAttachedDeviceReference
1195 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1197 /* Reference the Attached Device */
1198 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1199 ObReferenceObject(DeviceObject
);
1200 return DeviceObject
;
1208 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1210 /* Reference the lowest attached device */
1211 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1212 ObReferenceObject(DeviceObject
);
1213 return DeviceObject
;
1217 * IoGetDeviceObjectPointer
1224 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1225 IN ACCESS_MASK DesiredAccess
,
1226 OUT PFILE_OBJECT
*FileObject
,
1227 OUT PDEVICE_OBJECT
*DeviceObject
)
1229 /* Call the helper routine for a normal operation */
1230 return IopGetDeviceObjectPointer(ObjectName
,
1242 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1243 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1245 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1250 /* Make sure there's a VPB */
1251 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1254 IoAcquireVpbSpinLock(&OldIrql
);
1256 /* Get the Device Extension */
1257 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1259 /* Make sure this one has a VPB too */
1260 Vpb
= DeviceExtension
->Vpb
;
1263 /* Make sure that it's mounted */
1264 if ((Vpb
->ReferenceCount
) &&
1265 (Vpb
->Flags
& VPB_MOUNTED
))
1267 /* Return the Disk Device Object */
1268 *DiskDeviceObject
= Vpb
->RealDevice
;
1270 /* Reference it and return success */
1271 ObReferenceObject(Vpb
->RealDevice
);
1272 Status
= STATUS_SUCCESS
;
1276 /* It's not, so return failure */
1277 Status
= STATUS_VOLUME_DISMOUNTED
;
1283 Status
= STATUS_INVALID_PARAMETER
;
1286 /* Release the lock */
1287 IoReleaseVpbSpinLock(OldIrql
);
1296 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1298 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1299 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1301 /* Make sure it's not getting deleted */
1302 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1303 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1304 DOE_DELETE_PENDING
|
1305 DOE_REMOVE_PENDING
|
1306 DOE_REMOVE_PROCESSED
)))
1308 /* Get the Lower Device Object */
1309 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1311 /* Check that we got a valid device object */
1312 if (LowerDeviceObject
)
1314 /* We did so let's reference it */
1315 ObReferenceObject(LowerDeviceObject
);
1320 return LowerDeviceObject
;
1328 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1330 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1332 /* Check if we have a VPB with a device object */
1333 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1335 /* Then use the DO from the VPB */
1336 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1337 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1339 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1340 (FileObject
->DeviceObject
->Vpb
) &&
1341 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1343 /* The disk device actually has a VPB, so get the DO from there */
1344 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1348 /* Otherwise, this was a direct open */
1349 DeviceObject
= FileObject
->DeviceObject
;
1353 ASSERT(DeviceObject
!= NULL
);
1355 /* Check if we were attached */
1356 if (DeviceObject
->AttachedDevice
)
1358 /* Check if the file object has an extension present */
1359 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1361 /* Sanity check, direct open files can't have this */
1362 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1364 /* Check if the extension is really present */
1365 if (FileObject
->FileObjectExtension
)
1367 /* FIXME: Unhandled yet */
1368 DPRINT1("FOEs not supported\n");
1373 /* Return the highest attached device */
1374 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1377 /* Return the DO we found */
1378 return DeviceObject
;
1386 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1387 OUT PDEVICE_OBJECT
*DeviceObject
)
1390 PDEVICE_NODE DeviceNode
= NULL
;
1392 /* Call the internal helper function */
1393 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1394 if (NT_SUCCESS(Status
) && DeviceNode
)
1396 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1406 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1408 PDEVICE_OBJECT DeviceObject
;
1411 * If the FILE_OBJECT's VPB is defined,
1412 * get the device from it.
1414 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1416 /* Use the VPB's Device Object's */
1417 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1419 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1420 (FileObject
->DeviceObject
->Vpb
) &&
1421 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1423 /* Use the VPB's File System Object */
1424 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1428 /* Use the FO's Device Object */
1429 DeviceObject
= FileObject
->DeviceObject
;
1432 /* Return the device object we found */
1433 ASSERT(DeviceObject
!= NULL
);
1434 return DeviceObject
;
1442 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1444 PSHUTDOWN_ENTRY Entry
;
1446 /* Allocate the shutdown entry */
1447 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1448 sizeof(SHUTDOWN_ENTRY
),
1449 TAG_SHUTDOWN_ENTRY
);
1450 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1453 Entry
->DeviceObject
= DeviceObject
;
1455 /* Reference it so it doesn't go away */
1456 ObReferenceObject(DeviceObject
);
1458 /* Insert it into the list */
1459 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1460 &Entry
->ShutdownList
,
1463 /* Set the shutdown registered flag */
1464 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1465 return STATUS_SUCCESS
;
1473 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1475 PSHUTDOWN_ENTRY Entry
;
1477 /* Allocate the shutdown entry */
1478 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1479 sizeof(SHUTDOWN_ENTRY
),
1480 TAG_SHUTDOWN_ENTRY
);
1481 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1484 Entry
->DeviceObject
= DeviceObject
;
1486 /* Reference it so it doesn't go away */
1487 ObReferenceObject(DeviceObject
);
1489 /* Insert it into the list */
1490 ExInterlockedInsertHeadList(&ShutdownListHead
,
1491 &Entry
->ShutdownList
,
1494 /* Set the shutdown registered flag */
1495 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1496 return STATUS_SUCCESS
;
1504 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1506 PSHUTDOWN_ENTRY ShutdownEntry
;
1507 PLIST_ENTRY NextEntry
;
1510 /* Acquire the shutdown lock and loop the shutdown list */
1511 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1512 NextEntry
= ShutdownListHead
.Flink
;
1513 while (NextEntry
!= &ShutdownListHead
)
1516 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1520 /* Get if the DO matches */
1521 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1523 /* Remove it from the list */
1524 RemoveEntryList(NextEntry
);
1525 NextEntry
= NextEntry
->Blink
;
1527 /* Free the entry */
1528 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1530 /* Get rid of our reference to it */
1531 ObDereferenceObject(DeviceObject
);
1534 /* Go to the next entry */
1535 NextEntry
= NextEntry
->Flink
;
1538 /* Now loop the last chance list */
1539 NextEntry
= LastChanceShutdownListHead
.Flink
;
1540 while (NextEntry
!= &LastChanceShutdownListHead
)
1543 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1547 /* Get if the DO matches */
1548 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1550 /* Remove it from the list */
1551 RemoveEntryList(NextEntry
);
1552 NextEntry
= NextEntry
->Blink
;
1554 /* Free the entry */
1555 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1557 /* Get rid of our reference to it */
1558 ObDereferenceObject(DeviceObject
);
1561 /* Go to the next entry */
1562 NextEntry
= NextEntry
->Flink
;
1565 /* Release the shutdown lock */
1566 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1568 /* Now remove the flag */
1569 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1577 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1578 IN BOOLEAN DeferredStartIo
,
1579 IN BOOLEAN NonCancelable
)
1581 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1583 /* Get the Device Extension */
1584 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1586 /* Set the flags the caller requested */
1587 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1588 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1596 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1597 IN BOOLEAN Cancelable
,
1600 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1602 /* Get the Device Extension */
1603 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1605 /* Check if deferred start was requested */
1606 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1608 /* Call our internal function to handle the defered case */
1609 IopStartNextPacketByKeyEx(DeviceObject
,
1612 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1616 /* Call the normal routine */
1617 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1626 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1627 IN BOOLEAN Cancelable
)
1629 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1631 /* Get the Device Extension */
1632 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1634 /* Check if deferred start was requested */
1635 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1637 /* Call our internal function to handle the defered case */
1638 IopStartNextPacketByKeyEx(DeviceObject
,
1641 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1645 /* Call the normal routine */
1646 IopStartNextPacket(DeviceObject
, Cancelable
);
1655 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1658 IN PDRIVER_CANCEL CancelFunction
)
1661 KIRQL OldIrql
, CancelIrql
;
1663 /* Raise to dispatch level */
1664 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1666 /* Check if we should acquire the cancel lock */
1669 /* Acquire and set it */
1670 IoAcquireCancelSpinLock(&CancelIrql
);
1671 Irp
->CancelRoutine
= CancelFunction
;
1674 /* Check if we have a key */
1678 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1679 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1684 /* Insert without a key */
1685 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1686 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1689 /* Check if this was a first insert */
1693 DeviceObject
->CurrentIrp
= Irp
;
1695 /* Check if this is a cancelable packet */
1698 /* Check if the caller requested no cancellation */
1699 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1702 /* He did, so remove the cancel routine */
1703 Irp
->CancelRoutine
= NULL
;
1706 /* Release the cancel lock */
1707 IoReleaseCancelSpinLock(CancelIrql
);
1710 /* Call the Start I/O function */
1711 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1715 /* The packet was inserted... check if we have a cancel function */
1718 /* Check if the IRP got cancelled */
1722 * Set the cancel IRQL, clear the currnet cancel routine and
1725 Irp
->CancelIrql
= CancelIrql
;
1726 Irp
->CancelRoutine
= NULL
;
1727 CancelFunction(DeviceObject
, Irp
);
1731 /* Otherwise, release the lock */
1732 IoReleaseCancelSpinLock(CancelIrql
);
1737 /* Return back to previous IRQL */
1738 KeLowerIrql(OldIrql
);
1741 #if defined (_WIN64)
1744 IoWMIDeviceObjectToProviderId(
1745 IN PDEVICE_OBJECT DeviceObject
)