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 /* We can't unload unless there's an unload handler */
368 if (!DriverObject
->DriverUnload
)
370 DPRINT("No DriverUnload function! '%wZ' will not be unloaded!\n", &DriverObject
->DriverName
);
374 /* Check if removal is pending */
375 ThisExtension
= IoGetDevObjExtension(DeviceObject
);
376 if (ThisExtension
->ExtensionFlags
& DOE_REMOVE_PENDING
)
378 /* Get the PDO, extension, and node */
379 LowestDeviceObject
= IopGetLowestDevice(DeviceObject
);
380 DeviceExtension
= IoGetDevObjExtension(LowestDeviceObject
);
381 DeviceNode
= DeviceExtension
->DeviceNode
;
383 /* The PDO needs a device node */
384 ASSERT(DeviceNode
!= NULL
);
386 /* Loop all attached objects */
387 AttachedDeviceObject
= LowestDeviceObject
;
388 while (AttachedDeviceObject
)
390 /* Make sure they're dereferenced */
391 if (AttachedDeviceObject
->ReferenceCount
) return;
392 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
395 /* Loop all attached objects */
396 AttachedDeviceObject
= LowestDeviceObject
;
397 while (AttachedDeviceObject
)
399 /* Get the device extension */
400 DeviceExtension
= IoGetDevObjExtension(AttachedDeviceObject
);
402 /* Remove the pending flag and set processed */
403 DeviceExtension
->ExtensionFlags
&= ~DOE_REMOVE_PENDING
;
404 DeviceExtension
->ExtensionFlags
|= DOE_REMOVE_PROCESSED
;
405 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
409 * FIXME: TODO HPOUSSIN
410 * We need to parse/lock the device node, and if we have any pending
411 * surprise removals, query all relationships and send IRP_MN_REMOVE_
412 * _DEVICE to the devices related...
417 /* Check if deletion is pending */
418 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
420 /* Make sure unload is pending */
421 if (!(ThisExtension
->ExtensionFlags
& DOE_UNLOAD_PENDING
) ||
422 (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
))
424 /* We can't unload anymore */
425 SafeToUnload
= FALSE
;
429 * Check if we have an attached device and fail if we're attached
430 * or still have a reference count.
432 AttachedDeviceObject
= DeviceObject
->AttachedDevice
;
433 if ((AttachedDeviceObject
) || (DeviceObject
->ReferenceCount
)) return;
435 /* Check if we have a Security Descriptor */
436 if (DeviceObject
->SecurityDescriptor
)
439 ExFreePoolWithTag(DeviceObject
->SecurityDescriptor
, TAG_SD
);
442 /* Remove the device from the list */
443 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
445 /* Dereference the keep-alive */
446 ObDereferenceObject(DeviceObject
);
448 /* If we're not unloading, stop here */
449 if (!SafeToUnload
) return;
452 /* Loop all the device objects */
453 DeviceObject
= DriverObject
->DeviceObject
;
457 * Make sure we're not attached, having a reference count
458 * or already deleting
460 if ((DeviceObject
->ReferenceCount
) ||
461 (DeviceObject
->AttachedDevice
) ||
462 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
463 (DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)))
465 /* We're not safe to unload, quit */
469 /* Check the next device */
470 DeviceObject
= DeviceObject
->NextDevice
;
473 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject
->DriverName
);
475 /* Set the unload invoked flag */
476 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
479 DriverObject
->DriverUnload(DriverObject
);
481 /* Make object temporary so it can be deleted */
482 ObMakeTemporaryObject(DriverObject
);
484 /* Dereference once more, referenced at driver object creation */
485 ObDereferenceObject(DriverObject
);
491 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
492 IN BOOLEAN ForceUnload
)
495 ASSERT(DeviceObject
->ReferenceCount
);
497 /* Dereference the device */
498 InterlockedDecrement(&DeviceObject
->ReferenceCount
);
501 * Check if we can unload it and it's safe to unload (or if we're forcing
502 * an unload, which is OK too).
504 if (!(DeviceObject
->ReferenceCount
) &&
505 ((ForceUnload
) || (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
506 (DOE_UNLOAD_PENDING
|
509 DOE_REMOVE_PROCESSED
))))
512 IopUnloadDevice(DeviceObject
);
518 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
519 IN BOOLEAN Cancelable
,
522 PKDEVICE_QUEUE_ENTRY Entry
;
526 /* Acquire the cancel lock if this is cancelable */
527 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
529 /* Clear the current IRP */
530 DeviceObject
->CurrentIrp
= NULL
;
532 /* Remove an entry from the queue */
533 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
536 /* Get the IRP and set it */
537 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
538 DeviceObject
->CurrentIrp
= Irp
;
540 /* Check if this is a cancelable packet */
543 /* Check if the caller requested no cancellation */
544 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
547 /* He did, so remove the cancel routine */
548 Irp
->CancelRoutine
= NULL
;
551 /* Release the cancel lock */
552 IoReleaseCancelSpinLock(OldIrql
);
555 /* Call the Start I/O Routine */
556 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
560 /* Otherwise, release the cancel lock if we had acquired it */
561 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
567 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
568 IN BOOLEAN Cancelable
)
570 PKDEVICE_QUEUE_ENTRY Entry
;
574 /* Acquire the cancel lock if this is cancelable */
575 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
577 /* Clear the current IRP */
578 DeviceObject
->CurrentIrp
= NULL
;
580 /* Remove an entry from the queue */
581 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
584 /* Get the IRP and set it */
585 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
586 DeviceObject
->CurrentIrp
= Irp
;
588 /* Check if this is a cancelable packet */
591 /* Check if the caller requested no cancellation */
592 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
595 /* He did, so remove the cancel routine */
596 Irp
->CancelRoutine
= NULL
;
599 /* Release the cancel lock */
600 IoReleaseCancelSpinLock(OldIrql
);
603 /* Call the Start I/O Routine */
604 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
608 /* Otherwise, release the cancel lock if we had acquired it */
609 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
615 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
619 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
620 ULONG CurrentKey
= Key
;
621 ULONG CurrentFlags
= Flags
;
623 /* Get the device extension and start the packet loop */
624 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
627 /* Increase the count */
628 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
631 * We've already called the routine once...
632 * All we have to do is save the key and add the new flags
634 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
635 DeviceExtension
->StartIoKey
= CurrentKey
;
639 /* Mask out the current packet flags and key */
640 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
643 DeviceExtension
->StartIoKey
= 0;
645 /* Check if this is a packet start with key */
646 if (Flags
& DOE_SIO_WITH_KEY
)
648 /* Start the packet with a key */
649 IopStartNextPacketByKey(DeviceObject
,
650 (Flags
& DOE_SIO_CANCELABLE
) ?
654 else if (Flags
& DOE_SIO_NO_KEY
)
656 /* Start the packet */
657 IopStartNextPacket(DeviceObject
,
658 (Flags
& DOE_SIO_CANCELABLE
) ?
663 /* Decrease the Start I/O count and check if it's 0 now */
664 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
666 /* Get the current active key and flags */
667 CurrentKey
= DeviceExtension
->StartIoKey
;
668 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
672 /* Check if we should still loop */
673 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
677 /* There are still Start I/Os active, so quit this loop */
685 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
686 OUT PDEVICE_NODE
*DeviceNode
)
689 IO_STACK_LOCATION Stack
= {0};
690 PDEVICE_RELATIONS DeviceRelations
;
691 PDEVICE_OBJECT DeviceObject
= NULL
;
695 /* Get DeviceObject related to given FileObject */
696 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
697 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
699 /* Define input parameters */
700 Stack
.MajorFunction
= IRP_MJ_PNP
;
701 Stack
.MinorFunction
= IRP_MN_QUERY_DEVICE_RELATIONS
;
702 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
703 Stack
.FileObject
= FileObject
;
705 /* Call the driver to query all relations (IRP_MJ_PNP) */
706 Status
= IopSynchronousCall(DeviceObject
,
708 (PVOID
)&DeviceRelations
);
709 if (!NT_SUCCESS(Status
)) return Status
;
711 /* Make sure it's not NULL and contains only one object */
712 ASSERT(DeviceRelations
);
713 ASSERT(DeviceRelations
->Count
== 1);
715 /* Finally get the device node */
716 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
717 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
719 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
720 ExFreePool(DeviceRelations
);
725 /* PUBLIC FUNCTIONS ***********************************************************/
730 * Layers a device over the highest device in a device stack.
734 * Device to be attached.
737 * Name of the target device.
740 * Caller storage for the device attached to.
747 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
748 PUNICODE_STRING TargetDeviceName
,
749 PDEVICE_OBJECT
*AttachedDevice
)
752 PFILE_OBJECT FileObject
= NULL
;
753 PDEVICE_OBJECT TargetDevice
= NULL
;
755 /* Call the helper routine for an attach operation */
756 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
757 FILE_READ_ATTRIBUTES
,
760 IO_ATTACH_DEVICE_API
);
761 if (!NT_SUCCESS(Status
)) return Status
;
763 /* Attach the device */
764 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
769 ObDereferenceObject(FileObject
);
774 * IoAttachDeviceByPointer
781 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
782 IN PDEVICE_OBJECT TargetDevice
)
784 PDEVICE_OBJECT AttachedDevice
;
785 NTSTATUS Status
= STATUS_SUCCESS
;
788 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
789 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
791 /* Return the status */
800 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
801 IN PDEVICE_OBJECT TargetDevice
)
803 /* Attach it safely */
804 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
814 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
815 IN PDEVICE_OBJECT TargetDevice
,
816 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
818 /* Call the internal function */
819 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
821 AttachedToDeviceObject
))
824 return STATUS_NO_SUCH_DEVICE
;
828 return STATUS_SUCCESS
;
834 * Allocates memory for and intializes a device object for use for
839 * Driver object passed by IO Manager when the driver was loaded.
841 * DeviceExtensionSize
842 * Number of bytes for the device extension.
845 * Unicode name of device.
848 * Device type of the new device.
850 * DeviceCharacteristics
851 * Bit mask of device characteristics.
854 * TRUE if only one thread can access the device at a time.
857 * On successful return this parameter is filled by pointer to
858 * allocated device object.
865 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
866 IN ULONG DeviceExtensionSize
,
867 IN PUNICODE_STRING DeviceName
,
868 IN DEVICE_TYPE DeviceType
,
869 IN ULONG DeviceCharacteristics
,
870 IN BOOLEAN Exclusive
,
871 OUT PDEVICE_OBJECT
*DeviceObject
)
873 WCHAR AutoNameBuffer
[20];
874 UNICODE_STRING AutoName
;
875 PDEVICE_OBJECT CreatedDeviceObject
;
876 PDEVOBJ_EXTENSION DeviceObjectExtension
;
877 OBJECT_ATTRIBUTES ObjectAttributes
;
879 ULONG AlignedDeviceExtensionSize
;
884 /* Check if we have to generate a name */
885 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
888 swprintf(AutoNameBuffer
,
890 InterlockedIncrementUL(&IopDeviceObjectNumber
));
892 /* Initialize the name */
893 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
894 DeviceName
= &AutoName
;
897 /* Initialize the Object Attributes */
898 InitializeObjectAttributes(&ObjectAttributes
,
904 /* Honor exclusive flag */
905 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
907 /* Create a permanent object for named devices */
908 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
910 /* Align the Extension Size to 8-bytes */
911 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
914 TotalSize
= AlignedDeviceExtensionSize
+
915 sizeof(DEVICE_OBJECT
) +
916 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
918 /* Create the Device Object */
919 *DeviceObject
= NULL
;
920 Status
= ObCreateObject(KernelMode
,
928 (PVOID
*)&CreatedDeviceObject
);
929 if (!NT_SUCCESS(Status
)) return Status
;
931 /* Clear the whole Object and extension so we don't null stuff manually */
932 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
935 * Setup the Type and Size. Note that we don't use the aligned size,
936 * because that's only padding for the DevObjExt and not part of the Object.
938 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
939 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
941 /* The kernel extension is after the driver internal extension */
942 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
943 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
944 AlignedDeviceExtensionSize
);
946 /* Set the Type and Size. Question: why is Size 0 on Windows? */
947 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
948 DeviceObjectExtension
->Size
= 0;
950 /* Initialize with Power Manager */
951 PoInitializeDeviceObject(DeviceObjectExtension
);
953 /* Link the Object and Extension */
954 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
955 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
957 /* Set Device Object Data */
958 CreatedDeviceObject
->DeviceType
= DeviceType
;
959 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
960 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
961 CreatedDeviceObject
+ 1 :
963 CreatedDeviceObject
->StackSize
= 1;
964 CreatedDeviceObject
->AlignmentRequirement
= 0;
967 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
968 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
969 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
971 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
972 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
973 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
974 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
975 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
978 Status
= IopCreateVpb(CreatedDeviceObject
);
979 if (!NT_SUCCESS(Status
))
981 /* Reference the device object and fail */
982 ObDereferenceObject(DeviceObject
);
986 /* Initialize Lock Event */
987 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
988 SynchronizationEvent
,
992 /* Set the right Sector Size */
995 /* All disk systems */
996 case FILE_DEVICE_DISK_FILE_SYSTEM
:
997 case FILE_DEVICE_DISK
:
998 case FILE_DEVICE_VIRTUAL_DISK
:
1000 /* The default is 512 bytes */
1001 CreatedDeviceObject
->SectorSize
= 512;
1004 /* CD-ROM file systems */
1005 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
1007 /* The default is 2048 bytes */
1008 CreatedDeviceObject
->SectorSize
= 2048;
1011 /* Create the Device Queue */
1012 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1013 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
1014 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1015 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
1016 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
1018 /* Simple FS Devices, they don't need a real Device Queue */
1019 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
1023 /* An actual Device, initialize its DQ */
1024 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
1027 /* Insert the Object */
1028 Status
= ObInsertObject(CreatedDeviceObject
,
1030 FILE_READ_DATA
| FILE_WRITE_DATA
,
1032 (PVOID
*)&CreatedDeviceObject
,
1034 if (!NT_SUCCESS(Status
)) return Status
;
1036 /* Now do the final linking */
1037 ObReferenceObject(DriverObject
);
1038 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
1039 CreatedDeviceObject
->DriverObject
= DriverObject
;
1040 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
1042 /* Link with the power manager */
1043 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
1045 /* Close the temporary handle and return to caller */
1046 ObCloseHandle(TempHandle
, KernelMode
);
1047 *DeviceObject
= CreatedDeviceObject
;
1048 return STATUS_SUCCESS
;
1059 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1063 /* Check if the device is registered for shutdown notifications */
1064 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1066 /* Call the shutdown notifications */
1067 IoUnregisterShutdownNotification(DeviceObject
);
1070 /* Check if it has a timer */
1071 Timer
= DeviceObject
->Timer
;
1074 /* Remove it and free it */
1075 IopRemoveTimerFromTimerList(Timer
);
1076 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1079 /* Check if the device has a name */
1080 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1082 /* It does, make it temporary so we can remove it */
1083 ObMakeTemporaryObject(DeviceObject
);
1086 /* Set the pending delete flag */
1087 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1089 /* Check if the device object can be unloaded */
1090 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1101 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1103 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1106 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1107 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1109 /* Remove the attachment */
1110 DeviceExtension
->AttachedTo
= NULL
;
1111 TargetDevice
->AttachedDevice
= NULL
;
1113 /* Check if it's ok to delete this device */
1114 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
&
1115 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)) &&
1116 !(TargetDevice
->ReferenceCount
))
1119 IopUnloadDevice(TargetDevice
);
1128 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1129 IN PDEVICE_OBJECT
*DeviceObjectList
,
1130 IN ULONG DeviceObjectListSize
,
1131 OUT PULONG ActualNumberDeviceObjects
)
1133 ULONG ActualDevices
= 1;
1134 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1136 /* Find out how many devices we'll enumerate */
1137 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1139 /* Go back to the first */
1140 CurrentDevice
= DriverObject
->DeviceObject
;
1142 /* Start by at least returning this */
1143 *ActualNumberDeviceObjects
= ActualDevices
;
1145 /* Check if we can support so many */
1146 if ((ActualDevices
* 4) > DeviceObjectListSize
)
1148 /* Fail because the buffer was too small */
1149 return STATUS_BUFFER_TOO_SMALL
;
1152 /* Check if the caller only wanted the size */
1153 if (DeviceObjectList
)
1155 /* Loop through all the devices */
1156 while (ActualDevices
)
1158 /* Reference each Device */
1159 ObReferenceObject(CurrentDevice
);
1161 /* Add it to the list */
1162 *DeviceObjectList
= CurrentDevice
;
1164 /* Go to the next one */
1165 CurrentDevice
= CurrentDevice
->NextDevice
;
1171 /* Return the status */
1172 return STATUS_SUCCESS
;
1176 * IoGetAttachedDevice
1183 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1185 /* Get the last attached device */
1186 while (DeviceObject
->AttachedDevice
)
1188 /* Move to the next one */
1189 DeviceObject
= DeviceObject
->AttachedDevice
;
1193 return DeviceObject
;
1197 * IoGetAttachedDeviceReference
1204 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1206 /* Reference the Attached Device */
1207 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1208 ObReferenceObject(DeviceObject
);
1209 return DeviceObject
;
1217 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1219 /* Reference the lowest attached device */
1220 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1221 ObReferenceObject(DeviceObject
);
1222 return DeviceObject
;
1226 * IoGetDeviceObjectPointer
1233 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1234 IN ACCESS_MASK DesiredAccess
,
1235 OUT PFILE_OBJECT
*FileObject
,
1236 OUT PDEVICE_OBJECT
*DeviceObject
)
1238 /* Call the helper routine for a normal operation */
1239 return IopGetDeviceObjectPointer(ObjectName
,
1251 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1252 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1254 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1259 /* Make sure there's a VPB */
1260 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1263 IoAcquireVpbSpinLock(&OldIrql
);
1265 /* Get the Device Extension */
1266 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1268 /* Make sure this one has a VPB too */
1269 Vpb
= DeviceExtension
->Vpb
;
1272 /* Make sure that it's mounted */
1273 if ((Vpb
->ReferenceCount
) &&
1274 (Vpb
->Flags
& VPB_MOUNTED
))
1276 /* Return the Disk Device Object */
1277 *DiskDeviceObject
= Vpb
->RealDevice
;
1279 /* Reference it and return success */
1280 ObReferenceObject(Vpb
->RealDevice
);
1281 Status
= STATUS_SUCCESS
;
1285 /* It's not, so return failure */
1286 Status
= STATUS_VOLUME_DISMOUNTED
;
1292 Status
= STATUS_INVALID_PARAMETER
;
1295 /* Release the lock */
1296 IoReleaseVpbSpinLock(OldIrql
);
1305 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1307 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1308 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1310 /* Make sure it's not getting deleted */
1311 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1312 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1313 DOE_DELETE_PENDING
|
1314 DOE_REMOVE_PENDING
|
1315 DOE_REMOVE_PROCESSED
)))
1317 /* Get the Lower Device Object */
1318 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1320 /* Check that we got a valid device object */
1321 if (LowerDeviceObject
)
1323 /* We did so let's reference it */
1324 ObReferenceObject(LowerDeviceObject
);
1329 return LowerDeviceObject
;
1337 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1339 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1341 /* Check if we have a VPB with a device object */
1342 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1344 /* Then use the DO from the VPB */
1345 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1346 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1348 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1349 (FileObject
->DeviceObject
->Vpb
) &&
1350 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1352 /* The disk device actually has a VPB, so get the DO from there */
1353 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1357 /* Otherwise, this was a direct open */
1358 DeviceObject
= FileObject
->DeviceObject
;
1362 ASSERT(DeviceObject
!= NULL
);
1364 /* Check if we were attached */
1365 if (DeviceObject
->AttachedDevice
)
1367 /* Check if the file object has an extension present */
1368 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1370 /* Sanity check, direct open files can't have this */
1371 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1373 /* Check if the extension is really present */
1374 if (FileObject
->FileObjectExtension
)
1376 /* FIXME: Unhandled yet */
1377 DPRINT1("FOEs not supported\n");
1382 /* Return the highest attached device */
1383 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1386 /* Return the DO we found */
1387 return DeviceObject
;
1395 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1396 OUT PDEVICE_OBJECT
*DeviceObject
)
1399 PDEVICE_NODE DeviceNode
= NULL
;
1401 /* Call the internal helper function */
1402 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1403 if (NT_SUCCESS(Status
) && DeviceNode
)
1405 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1415 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1417 PDEVICE_OBJECT DeviceObject
;
1420 * If the FILE_OBJECT's VPB is defined,
1421 * get the device from it.
1423 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1425 /* Use the VPB's Device Object's */
1426 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1428 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1429 (FileObject
->DeviceObject
->Vpb
) &&
1430 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1432 /* Use the VPB's File System Object */
1433 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1437 /* Use the FO's Device Object */
1438 DeviceObject
= FileObject
->DeviceObject
;
1441 /* Return the device object we found */
1442 ASSERT(DeviceObject
!= NULL
);
1443 return DeviceObject
;
1451 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1453 PSHUTDOWN_ENTRY Entry
;
1455 /* Allocate the shutdown entry */
1456 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1457 sizeof(SHUTDOWN_ENTRY
),
1458 TAG_SHUTDOWN_ENTRY
);
1459 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1462 Entry
->DeviceObject
= DeviceObject
;
1464 /* Reference it so it doesn't go away */
1465 ObReferenceObject(DeviceObject
);
1467 /* Insert it into the list */
1468 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1469 &Entry
->ShutdownList
,
1472 /* Set the shutdown registered flag */
1473 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1474 return STATUS_SUCCESS
;
1482 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1484 PSHUTDOWN_ENTRY Entry
;
1486 /* Allocate the shutdown entry */
1487 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1488 sizeof(SHUTDOWN_ENTRY
),
1489 TAG_SHUTDOWN_ENTRY
);
1490 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1493 Entry
->DeviceObject
= DeviceObject
;
1495 /* Reference it so it doesn't go away */
1496 ObReferenceObject(DeviceObject
);
1498 /* Insert it into the list */
1499 ExInterlockedInsertHeadList(&ShutdownListHead
,
1500 &Entry
->ShutdownList
,
1503 /* Set the shutdown registered flag */
1504 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1505 return STATUS_SUCCESS
;
1513 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1515 PSHUTDOWN_ENTRY ShutdownEntry
;
1516 PLIST_ENTRY NextEntry
;
1519 /* Acquire the shutdown lock and loop the shutdown list */
1520 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1521 NextEntry
= ShutdownListHead
.Flink
;
1522 while (NextEntry
!= &ShutdownListHead
)
1525 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1529 /* Get if the DO matches */
1530 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1532 /* Remove it from the list */
1533 RemoveEntryList(NextEntry
);
1534 NextEntry
= NextEntry
->Blink
;
1536 /* Free the entry */
1537 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1539 /* Get rid of our reference to it */
1540 ObDereferenceObject(DeviceObject
);
1543 /* Go to the next entry */
1544 NextEntry
= NextEntry
->Flink
;
1547 /* Now loop the last chance list */
1548 NextEntry
= LastChanceShutdownListHead
.Flink
;
1549 while (NextEntry
!= &LastChanceShutdownListHead
)
1552 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1556 /* Get if the DO matches */
1557 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1559 /* Remove it from the list */
1560 RemoveEntryList(NextEntry
);
1561 NextEntry
= NextEntry
->Blink
;
1563 /* Free the entry */
1564 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1566 /* Get rid of our reference to it */
1567 ObDereferenceObject(DeviceObject
);
1570 /* Go to the next entry */
1571 NextEntry
= NextEntry
->Flink
;
1574 /* Release the shutdown lock */
1575 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1577 /* Now remove the flag */
1578 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1586 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1587 IN BOOLEAN DeferredStartIo
,
1588 IN BOOLEAN NonCancelable
)
1590 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1592 /* Get the Device Extension */
1593 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1595 /* Set the flags the caller requested */
1596 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1597 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1605 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1606 IN BOOLEAN Cancelable
,
1609 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1611 /* Get the Device Extension */
1612 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1614 /* Check if deferred start was requested */
1615 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1617 /* Call our internal function to handle the defered case */
1618 IopStartNextPacketByKeyEx(DeviceObject
,
1621 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1625 /* Call the normal routine */
1626 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1635 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1636 IN BOOLEAN Cancelable
)
1638 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1640 /* Get the Device Extension */
1641 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1643 /* Check if deferred start was requested */
1644 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1646 /* Call our internal function to handle the defered case */
1647 IopStartNextPacketByKeyEx(DeviceObject
,
1650 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1654 /* Call the normal routine */
1655 IopStartNextPacket(DeviceObject
, Cancelable
);
1664 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1667 IN PDRIVER_CANCEL CancelFunction
)
1670 KIRQL OldIrql
, CancelIrql
;
1672 /* Raise to dispatch level */
1673 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1675 /* Check if we should acquire the cancel lock */
1678 /* Acquire and set it */
1679 IoAcquireCancelSpinLock(&CancelIrql
);
1680 Irp
->CancelRoutine
= CancelFunction
;
1683 /* Check if we have a key */
1687 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1688 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1693 /* Insert without a key */
1694 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1695 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1698 /* Check if this was a first insert */
1702 DeviceObject
->CurrentIrp
= Irp
;
1704 /* Check if this is a cancelable packet */
1707 /* Check if the caller requested no cancellation */
1708 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1711 /* He did, so remove the cancel routine */
1712 Irp
->CancelRoutine
= NULL
;
1715 /* Release the cancel lock */
1716 IoReleaseCancelSpinLock(CancelIrql
);
1719 /* Call the Start I/O function */
1720 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1724 /* The packet was inserted... check if we have a cancel function */
1727 /* Check if the IRP got cancelled */
1731 * Set the cancel IRQL, clear the currnet cancel routine and
1734 Irp
->CancelIrql
= CancelIrql
;
1735 Irp
->CancelRoutine
= NULL
;
1736 CancelFunction(DeviceObject
, Irp
);
1740 /* Otherwise, release the lock */
1741 IoReleaseCancelSpinLock(CancelIrql
);
1746 /* Return back to previous IRQL */
1747 KeLowerIrql(OldIrql
);
1750 #if defined (_WIN64)
1753 IoWMIDeviceObjectToProviderId(
1754 IN PDEVICE_OBJECT DeviceObject
)