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 IopDiskFsListHead
;
23 extern LIST_ENTRY IopCdRomFsListHead
;
24 extern LIST_ENTRY IopTapeFsListHead
;
26 /* PRIVATE FUNCTIONS **********************************************************/
30 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver
)
32 PDEVICE_OBJECT DeviceObject
;
35 /* Set the driver as initialized */
36 Driver
->Flags
|= DRVO_INITIALIZED
;
37 DeviceObject
= Driver
->DeviceObject
;
40 /* Set every device as initialized too */
41 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
42 DeviceObject
= DeviceObject
->NextDevice
;
48 IopDeleteDevice(IN PVOID ObjectBody
)
50 PDEVICE_OBJECT DeviceObject
= ObjectBody
;
53 /* TODO: Delete Device Node */
55 /* Dereference the driver object, referenced in IoCreateDevice */
56 if (DeviceObject
->DriverObject
)
57 ObDereferenceObject(DeviceObject
->DriverObject
);
63 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
64 IN PDEVICE_OBJECT TargetDevice
,
65 OUT PDEVICE_OBJECT
*AttachedToDeviceObject OPTIONAL
)
67 PDEVICE_OBJECT AttachedDevice
;
68 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension
;
70 /* Get the Attached Device and source extension */
71 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
72 SourceDeviceExtension
= IoGetDevObjExtension(SourceDevice
);
73 ASSERT(SourceDeviceExtension
->AttachedTo
== NULL
);
75 /* Make sure that it's in a correct state */
76 if ((AttachedDevice
->Flags
& DO_DEVICE_INITIALIZING
) ||
77 (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
81 DOE_REMOVE_PROCESSED
)))
83 /* Device was unloading or being removed */
84 AttachedDevice
= NULL
;
88 /* Update atached device fields */
89 AttachedDevice
->AttachedDevice
= SourceDevice
;
90 AttachedDevice
->Spare1
++;
92 /* Update the source with the attached data */
93 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
94 SourceDevice
->AlignmentRequirement
= AttachedDevice
->
96 SourceDevice
->SectorSize
= AttachedDevice
->SectorSize
;
98 /* Check for pending start flag */
99 if (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
103 IoGetDevObjExtension(SourceDevice
)->ExtensionFlags
|=
107 /* Set the attachment in the device extension */
108 SourceDeviceExtension
->AttachedTo
= AttachedDevice
;
111 /* Return the attached device */
112 if (AttachedToDeviceObject
) *AttachedToDeviceObject
= AttachedDevice
;
113 return AttachedDevice
;
118 IoShutdownPnpDevices(VOID
)
120 /* This routine is only used by Driver Verifier to validate shutdown */
126 IoShutdownSystem(IN ULONG Phase
)
128 PLIST_ENTRY ListEntry
;
129 PDEVICE_OBJECT DeviceObject
;
130 PSHUTDOWN_ENTRY ShutdownEntry
;
131 IO_STATUS_BLOCK StatusBlock
;
136 /* Initialize an event to wait on */
137 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
143 IoShutdownPnpDevices();
145 /* Loop first-chance shutdown notifications */
146 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
150 /* Get the shutdown entry */
151 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
155 /* Get the attached device */
156 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
158 /* Build the shutdown IRP and call the driver */
159 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
166 Status
= IoCallDriver(DeviceObject
, Irp
);
167 if (Status
== STATUS_PENDING
)
169 /* Wait on the driver */
170 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
173 /* Get rid of our reference to it */
174 ObDereferenceObject(DeviceObject
);
176 /* Free the shutdown entry and reset the event */
177 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
178 KeClearEvent(&Event
);
180 /* Go to the next entry */
181 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
187 /* Shutdown disk file systems */
188 IopShutdownBaseFileSystems(&IopDiskFsListHead
);
190 /* Shutdown cdrom file systems */
191 IopShutdownBaseFileSystems(&IopCdRomFsListHead
);
193 /* Shutdown tape filesystems */
194 IopShutdownBaseFileSystems(&IopTapeFsListHead
);
196 /* Loop last-chance shutdown notifications */
197 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
201 /* Get the shutdown entry */
202 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
206 /* Get the attached device */
207 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
209 /* Build the shutdown IRP and call the driver */
210 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
217 Status
= IoCallDriver(DeviceObject
, Irp
);
218 if (Status
== STATUS_PENDING
)
220 /* Wait on the driver */
221 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
224 /* Get rid of our reference to it */
225 ObDereferenceObject(DeviceObject
);
227 /* Free the shutdown entry and reset the event */
228 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
229 KeClearEvent(&Event
);
231 /* Go to the next entry */
232 ListEntry
= ExInterlockedRemoveHeadList(&LastChanceShutdownListHead
,
241 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
242 IN ACCESS_MASK DesiredAccess
,
243 OUT PFILE_OBJECT
*FileObject
,
244 OUT PDEVICE_OBJECT
*DeviceObject
,
247 OBJECT_ATTRIBUTES ObjectAttributes
;
248 IO_STATUS_BLOCK StatusBlock
;
249 PFILE_OBJECT LocalFileObject
;
253 /* Open the Device */
254 InitializeObjectAttributes(&ObjectAttributes
,
259 Status
= ZwOpenFile(&FileHandle
,
264 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
265 if (!NT_SUCCESS(Status
)) return Status
;
267 /* Get File Object */
268 Status
= ObReferenceObjectByHandle(FileHandle
,
272 (PVOID
*)&LocalFileObject
,
274 if (NT_SUCCESS(Status
))
276 /* Return the requested data */
277 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
278 *FileObject
= LocalFileObject
;
281 /* Close the handle */
289 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
291 PDEVICE_OBJECT LowestDevice
;
292 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
294 /* Get the current device and its extension */
295 LowestDevice
= DeviceObject
;
296 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
298 /* Keep looping as long as we're attached */
299 while (DeviceExtension
->AttachedTo
)
301 /* Get the lowest device and its extension */
302 LowestDevice
= DeviceExtension
->AttachedTo
;
303 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
306 /* Return the lowest device */
312 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
313 IN PDEVICE_OBJECT DeviceObject
,
314 IN IOP_DEVICE_LIST_OPERATION Type
)
316 PDEVICE_OBJECT Previous
;
318 /* Check the type of operation */
319 if (Type
== IopRemove
)
321 /* Get the current device and check if it's the current one */
322 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
323 if (Previous
== DeviceObject
)
325 /* It is, simply unlink this one directly */
326 DeviceObject
->DriverObject
->DeviceObject
=
327 DeviceObject
->NextDevice
;
331 /* It's not, so loop until we find the device */
332 while (Previous
->NextDevice
!= DeviceObject
)
334 /* Not this one, keep moving */
335 Previous
= Previous
->NextDevice
;
338 /* We found it, now unlink us */
339 Previous
->NextDevice
= DeviceObject
->NextDevice
;
344 /* Link the device object and the driver object */
345 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
346 DriverObject
->DeviceObject
= DeviceObject
;
352 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
354 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
355 PDEVICE_OBJECT AttachedDeviceObject
, LowestDeviceObject
;
356 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
, DeviceExtension
;
357 PDEVICE_NODE DeviceNode
;
358 BOOLEAN SafeToUnload
= TRUE
;
360 /* Check if removal is pending */
361 ThisExtension
= IoGetDevObjExtension(DeviceObject
);
362 if (ThisExtension
->ExtensionFlags
& DOE_REMOVE_PENDING
)
364 /* Get the PDO, extension, and node */
365 LowestDeviceObject
= IopGetLowestDevice(DeviceObject
);
366 DeviceExtension
= IoGetDevObjExtension(LowestDeviceObject
);
367 DeviceNode
= DeviceExtension
->DeviceNode
;
369 /* The PDO needs a device node */
370 ASSERT(DeviceNode
!= NULL
);
372 /* Loop all attached objects */
373 AttachedDeviceObject
= LowestDeviceObject
;
374 while (AttachedDeviceObject
)
376 /* Make sure they're dereferenced */
377 if (AttachedDeviceObject
->ReferenceCount
) return;
378 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
381 /* Loop all attached objects */
382 AttachedDeviceObject
= LowestDeviceObject
;
383 while (AttachedDeviceObject
)
385 /* Get the device extension */
386 DeviceExtension
= IoGetDevObjExtension(AttachedDeviceObject
);
388 /* Remove the pending flag and set processed */
389 DeviceExtension
->ExtensionFlags
&= ~DOE_REMOVE_PENDING
;
390 DeviceExtension
->ExtensionFlags
|= DOE_REMOVE_PROCESSED
;
391 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
395 * FIXME: TODO HPOUSSIN
396 * We need to parse/lock the device node, and if we have any pending
397 * surprise removals, query all relationships and send IRP_MN_REMOVE_
398 * _DEVICE to the devices related...
403 /* Check if deletion is pending */
404 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
406 /* Make sure unload is pending */
407 if (!(ThisExtension
->ExtensionFlags
& DOE_UNLOAD_PENDING
) ||
408 (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
))
410 /* We can't unload anymore */
411 SafeToUnload
= FALSE
;
415 * Check if we have an attached device and fail if we're attached
416 * and still have a reference count.
418 AttachedDeviceObject
= DeviceObject
->AttachedDevice
;
419 if ((AttachedDeviceObject
) && (DeviceObject
->ReferenceCount
)) return;
421 /* Check if we have a Security Descriptor */
422 if (DeviceObject
->SecurityDescriptor
)
425 ExFreePoolWithTag(DeviceObject
->SecurityDescriptor
, TAG_SD
);
428 /* Remove the device from the list */
429 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
431 /* Dereference the keep-alive */
432 ObDereferenceObject(DeviceObject
);
434 /* If we're not unloading, stop here */
435 if (!SafeToUnload
) return;
438 /* Loop all the device objects */
439 DeviceObject
= DriverObject
->DeviceObject
;
443 * Make sure we're not attached, having a reference count
444 * or already deleting
446 if ((DeviceObject
->ReferenceCount
) ||
447 (DeviceObject
->AttachedDevice
) ||
448 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
449 (DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)))
451 /* We're not safe to unload, quit */
455 /* Check the next device */
456 DeviceObject
= DeviceObject
->NextDevice
;
459 /* Set the unload invoked flag */
460 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
463 if (DriverObject
->DriverUnload
) DriverObject
->DriverUnload(DriverObject
);
465 /* Make object temporary so it can be deleted */
466 ObMakeTemporaryObject(DriverObject
);
468 /* Dereference once more, referenced at driver object creation */
469 ObDereferenceObject(DriverObject
);
475 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
476 IN BOOLEAN ForceUnload
)
479 ASSERT(DeviceObject
->ReferenceCount
);
481 /* Dereference the device */
482 DeviceObject
->ReferenceCount
--;
485 * Check if we can unload it and it's safe to unload (or if we're forcing
486 * an unload, which is OK too).
488 if (!(DeviceObject
->ReferenceCount
) &&
489 ((ForceUnload
) || (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
490 (DOE_UNLOAD_PENDING
|
493 DOE_REMOVE_PROCESSED
))))
496 IopUnloadDevice(DeviceObject
);
502 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
503 IN BOOLEAN Cancelable
,
506 PKDEVICE_QUEUE_ENTRY Entry
;
510 /* Acquire the cancel lock if this is cancelable */
511 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
513 /* Clear the current IRP */
514 DeviceObject
->CurrentIrp
= NULL
;
516 /* Remove an entry from the queue */
517 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
520 /* Get the IRP and set it */
521 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
522 DeviceObject
->CurrentIrp
= Irp
;
524 /* Check if this is a cancelable packet */
527 /* Check if the caller requested no cancellation */
528 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
531 /* He did, so remove the cancel routine */
532 Irp
->CancelRoutine
= NULL
;
535 /* Release the cancel lock */
536 IoReleaseCancelSpinLock(OldIrql
);
539 /* Call the Start I/O Routine */
540 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
544 /* Otherwise, release the cancel lock if we had acquired it */
545 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
551 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
552 IN BOOLEAN Cancelable
)
554 PKDEVICE_QUEUE_ENTRY Entry
;
558 /* Acquire the cancel lock if this is cancelable */
559 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
561 /* Clear the current IRP */
562 DeviceObject
->CurrentIrp
= NULL
;
564 /* Remove an entry from the queue */
565 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
568 /* Get the IRP and set it */
569 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
570 DeviceObject
->CurrentIrp
= Irp
;
572 /* Check if this is a cancelable packet */
575 /* Check if the caller requested no cancellation */
576 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
579 /* He did, so remove the cancel routine */
580 Irp
->CancelRoutine
= NULL
;
583 /* Release the cancel lock */
584 IoReleaseCancelSpinLock(OldIrql
);
587 /* Call the Start I/O Routine */
588 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
592 /* Otherwise, release the cancel lock if we had acquired it */
593 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
599 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
603 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
604 ULONG CurrentKey
= Key
;
605 ULONG CurrentFlags
= Flags
;
607 /* Get the device extension and start the packet loop */
608 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
611 /* Increase the count */
612 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
615 * We've already called the routine once...
616 * All we have to do is save the key and add the new flags
618 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
619 DeviceExtension
->StartIoKey
= CurrentKey
;
623 /* Mask out the current packet flags and key */
624 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
627 DeviceExtension
->StartIoKey
= 0;
629 /* Check if this is a packet start with key */
630 if (Flags
& DOE_SIO_WITH_KEY
)
632 /* Start the packet with a key */
633 IopStartNextPacketByKey(DeviceObject
,
634 (Flags
& DOE_SIO_CANCELABLE
) ?
638 else if (Flags
& DOE_SIO_NO_KEY
)
640 /* Start the packet */
641 IopStartNextPacket(DeviceObject
,
642 (Flags
& DOE_SIO_CANCELABLE
) ?
647 /* Decrease the Start I/O count and check if it's 0 now */
648 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
650 /* Get the current active key and flags */
651 CurrentKey
= DeviceExtension
->StartIoKey
;
652 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
656 /* Check if we should still loop */
657 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
661 /* There are still Start I/Os active, so quit this loop */
669 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
670 OUT PDEVICE_NODE
*DeviceNode
)
673 IO_STACK_LOCATION Stack
= {0};
674 IO_STATUS_BLOCK IoStatusBlock
;
675 PDEVICE_RELATIONS DeviceRelations
;
676 PDEVICE_OBJECT DeviceObject
= NULL
;
680 /* Get DeviceObject related to given FileObject */
681 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
682 if (!DeviceObject
) return STATUS_NO_SUCH_DEVICE
;
684 /* Define input parameters */
685 Stack
.Parameters
.QueryDeviceRelations
.Type
= TargetDeviceRelation
;
686 Stack
.FileObject
= FileObject
;
688 /* Call the driver to query all relations (IRP_MJ_PNP) */
689 Status
= IopInitiatePnpIrp(DeviceObject
,
691 IRP_MN_QUERY_DEVICE_RELATIONS
,
693 if (!NT_SUCCESS(Status
)) return Status
;
695 /* Get returned pointer to DEVICE_RELATIONS */
696 DeviceRelations
= (PDEVICE_RELATIONS
)IoStatusBlock
.Information
;
698 /* Make sure it's not NULL and contains only one object */
699 ASSERT(DeviceRelations
);
700 ASSERT(DeviceRelations
->Count
== 1);
702 /* Finally get the device node */
703 *DeviceNode
= IopGetDeviceNode(DeviceRelations
->Objects
[0]);
704 if (!*DeviceNode
) Status
= STATUS_NO_SUCH_DEVICE
;
706 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
707 ExFreePool(DeviceRelations
);
712 /* PUBLIC FUNCTIONS ***********************************************************/
717 * Layers a device over the highest device in a device stack.
721 * Device to be attached.
724 * Name of the target device.
727 * Caller storage for the device attached to.
734 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
735 PUNICODE_STRING TargetDeviceName
,
736 PDEVICE_OBJECT
*AttachedDevice
)
739 PFILE_OBJECT FileObject
= NULL
;
740 PDEVICE_OBJECT TargetDevice
= NULL
;
742 /* Call the helper routine for an attach operation */
743 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
744 FILE_READ_ATTRIBUTES
,
747 IO_ATTACH_DEVICE_API
);
748 if (!NT_SUCCESS(Status
)) return Status
;
750 /* Attach the device */
751 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
756 ObDereferenceObject(FileObject
);
761 * IoAttachDeviceByPointer
768 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
769 IN PDEVICE_OBJECT TargetDevice
)
771 PDEVICE_OBJECT AttachedDevice
;
772 NTSTATUS Status
= STATUS_SUCCESS
;
775 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
776 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
778 /* Return the status */
787 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
788 IN PDEVICE_OBJECT TargetDevice
)
790 /* Attach it safely */
791 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
801 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
802 IN PDEVICE_OBJECT TargetDevice
,
803 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
805 /* Call the internal function */
806 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
808 AttachedToDeviceObject
))
811 return STATUS_NO_SUCH_DEVICE
;
815 return STATUS_SUCCESS
;
821 * Allocates memory for and intializes a device object for use for
826 * Driver object passed by IO Manager when the driver was loaded.
828 * DeviceExtensionSize
829 * Number of bytes for the device extension.
832 * Unicode name of device.
835 * Device type of the new device.
837 * DeviceCharacteristics
838 * Bit mask of device characteristics.
841 * TRUE if only one thread can access the device at a time.
844 * On successful return this parameter is filled by pointer to
845 * allocated device object.
852 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
853 IN ULONG DeviceExtensionSize
,
854 IN PUNICODE_STRING DeviceName
,
855 IN DEVICE_TYPE DeviceType
,
856 IN ULONG DeviceCharacteristics
,
857 IN BOOLEAN Exclusive
,
858 OUT PDEVICE_OBJECT
*DeviceObject
)
860 WCHAR AutoNameBuffer
[20];
861 UNICODE_STRING AutoName
;
862 PDEVICE_OBJECT CreatedDeviceObject
;
863 PDEVOBJ_EXTENSION DeviceObjectExtension
;
864 OBJECT_ATTRIBUTES ObjectAttributes
;
866 ULONG AlignedDeviceExtensionSize
;
871 /* Check if we have to generate a name */
872 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
875 swprintf(AutoNameBuffer
,
877 InterlockedIncrementUL(&IopDeviceObjectNumber
));
879 /* Initialize the name */
880 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
881 DeviceName
= &AutoName
;
884 /* Initialize the Object Attributes */
885 InitializeObjectAttributes(&ObjectAttributes
,
891 /* Honor exclusive flag */
892 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
894 /* Create a permanent object for named devices */
895 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
897 /* Align the Extension Size to 8-bytes */
898 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
901 TotalSize
= AlignedDeviceExtensionSize
+
902 sizeof(DEVICE_OBJECT
) +
903 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
905 /* Create the Device Object */
906 *DeviceObject
= NULL
;
907 Status
= ObCreateObject(KernelMode
,
915 (PVOID
*)&CreatedDeviceObject
);
916 if (!NT_SUCCESS(Status
)) return Status
;
918 /* Clear the whole Object and extension so we don't null stuff manually */
919 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
922 * Setup the Type and Size. Note that we don't use the aligned size,
923 * because that's only padding for the DevObjExt and not part of the Object.
925 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
926 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + (USHORT
)DeviceExtensionSize
;
928 /* The kernel extension is after the driver internal extension */
929 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
930 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
931 AlignedDeviceExtensionSize
);
933 /* Set the Type and Size. Question: why is Size 0 on Windows? */
934 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
935 DeviceObjectExtension
->Size
= 0;
937 /* Initialize with Power Manager */
938 PoInitializeDeviceObject(DeviceObjectExtension
);
940 /* Link the Object and Extension */
941 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
942 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
944 /* Set Device Object Data */
945 CreatedDeviceObject
->DeviceType
= DeviceType
;
946 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
947 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
948 CreatedDeviceObject
+ 1 :
950 CreatedDeviceObject
->StackSize
= 1;
951 CreatedDeviceObject
->AlignmentRequirement
= 0;
954 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
955 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
956 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
958 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
959 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
960 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
961 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
962 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
965 Status
= IopCreateVpb(CreatedDeviceObject
);
966 if (!NT_SUCCESS(Status
))
968 /* Reference the device object and fail */
969 ObDereferenceObject(DeviceObject
);
973 /* Initialize Lock Event */
974 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
975 SynchronizationEvent
,
979 /* Set the right Sector Size */
982 /* All disk systems */
983 case FILE_DEVICE_DISK_FILE_SYSTEM
:
984 case FILE_DEVICE_DISK
:
985 case FILE_DEVICE_VIRTUAL_DISK
:
987 /* The default is 512 bytes */
988 CreatedDeviceObject
->SectorSize
= 512;
991 /* CD-ROM file systems */
992 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
994 /* The default is 2048 bytes */
995 CreatedDeviceObject
->SectorSize
= 2048;
998 /* Create the Device Queue */
999 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1000 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
1001 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1002 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
1003 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
1005 /* Simple FS Devices, they don't need a real Device Queue */
1006 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
1010 /* An actual Device, initialize its DQ */
1011 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
1014 /* Insert the Object */
1015 Status
= ObInsertObject(CreatedDeviceObject
,
1017 FILE_READ_DATA
| FILE_WRITE_DATA
,
1019 (PVOID
*)&CreatedDeviceObject
,
1021 if (!NT_SUCCESS(Status
)) return Status
;
1023 /* Now do the final linking */
1024 ObReferenceObject(DriverObject
);
1025 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
1026 CreatedDeviceObject
->DriverObject
= DriverObject
;
1027 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
1029 /* Link with the power manager */
1030 if (CreatedDeviceObject
->Vpb
) PoVolumeDevice(CreatedDeviceObject
);
1032 /* Close the temporary handle and return to caller */
1033 ObCloseHandle(TempHandle
, KernelMode
);
1034 *DeviceObject
= CreatedDeviceObject
;
1035 return STATUS_SUCCESS
;
1046 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
1050 /* Check if the device is registered for shutdown notifications */
1051 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
1053 /* Call the shutdown notifications */
1054 IoUnregisterShutdownNotification(DeviceObject
);
1057 /* Check if it has a timer */
1058 Timer
= DeviceObject
->Timer
;
1061 /* Remove it and free it */
1062 IopRemoveTimerFromTimerList(Timer
);
1063 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
1066 /* Check if the device has a name */
1067 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
1069 /* It does, make it temporary so we can remove it */
1070 ObMakeTemporaryObject(DeviceObject
);
1073 /* Set the pending delete flag */
1074 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
1076 /* Check if the device object can be unloaded */
1077 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
1088 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
1090 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1093 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
1094 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
1096 /* Remove the attachment */
1097 DeviceExtension
->AttachedTo
= NULL
;
1098 TargetDevice
->AttachedDevice
= NULL
;
1100 /* Check if it's ok to delete this device */
1101 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
&
1102 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)) &&
1103 !(TargetDevice
->ReferenceCount
))
1106 IopUnloadDevice(TargetDevice
);
1115 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
1116 IN PDEVICE_OBJECT
*DeviceObjectList
,
1117 IN ULONG DeviceObjectListSize
,
1118 OUT PULONG ActualNumberDeviceObjects
)
1120 ULONG ActualDevices
= 1;
1121 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
1123 /* Find out how many devices we'll enumerate */
1124 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
1126 /* Go back to the first */
1127 CurrentDevice
= DriverObject
->DeviceObject
;
1129 /* Start by at least returning this */
1130 *ActualNumberDeviceObjects
= ActualDevices
;
1132 /* Check if we can support so many */
1133 if ((ActualDevices
* 4) > DeviceObjectListSize
)
1135 /* Fail because the buffer was too small */
1136 return STATUS_BUFFER_TOO_SMALL
;
1139 /* Check if the caller only wanted the size */
1140 if (DeviceObjectList
)
1142 /* Loop through all the devices */
1143 while (ActualDevices
)
1145 /* Reference each Device */
1146 ObReferenceObject(CurrentDevice
);
1148 /* Add it to the list */
1149 *DeviceObjectList
= CurrentDevice
;
1151 /* Go to the next one */
1152 CurrentDevice
= CurrentDevice
->NextDevice
;
1158 /* Return the status */
1159 return STATUS_SUCCESS
;
1163 * IoGetAttachedDevice
1170 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1172 /* Get the last attached device */
1173 while (DeviceObject
->AttachedDevice
)
1175 /* Move to the next one */
1176 DeviceObject
= DeviceObject
->AttachedDevice
;
1180 return DeviceObject
;
1184 * IoGetAttachedDeviceReference
1191 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1193 /* Reference the Attached Device */
1194 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1195 ObReferenceObject(DeviceObject
);
1196 return DeviceObject
;
1204 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1206 /* Reference the lowest attached device */
1207 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1208 ObReferenceObject(DeviceObject
);
1209 return DeviceObject
;
1213 * IoGetDeviceObjectPointer
1220 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1221 IN ACCESS_MASK DesiredAccess
,
1222 OUT PFILE_OBJECT
*FileObject
,
1223 OUT PDEVICE_OBJECT
*DeviceObject
)
1225 /* Call the helper routine for a normal operation */
1226 return IopGetDeviceObjectPointer(ObjectName
,
1238 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1239 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1241 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1246 /* Make sure there's a VPB */
1247 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1250 IoAcquireVpbSpinLock(&OldIrql
);
1252 /* Get the Device Extension */
1253 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1255 /* Make sure this one has a VPB too */
1256 Vpb
= DeviceExtension
->Vpb
;
1259 /* Make sure that it's mounted */
1260 if ((Vpb
->ReferenceCount
) &&
1261 (Vpb
->Flags
& VPB_MOUNTED
))
1263 /* Return the Disk Device Object */
1264 *DiskDeviceObject
= Vpb
->RealDevice
;
1266 /* Reference it and return success */
1267 ObReferenceObject(Vpb
->RealDevice
);
1268 Status
= STATUS_SUCCESS
;
1272 /* It's not, so return failure */
1273 Status
= STATUS_VOLUME_DISMOUNTED
;
1279 Status
= STATUS_INVALID_PARAMETER
;
1282 /* Release the lock */
1283 IoReleaseVpbSpinLock(OldIrql
);
1292 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1294 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1295 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1297 /* Make sure it's not getting deleted */
1298 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1299 if (!(DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1300 DOE_DELETE_PENDING
|
1301 DOE_REMOVE_PENDING
|
1302 DOE_REMOVE_PROCESSED
)))
1304 /* Get the Lower Device Object */
1305 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1307 /* Check that we got a valid device object */
1308 if (LowerDeviceObject
)
1310 /* We did so let's reference it */
1311 ObReferenceObject(LowerDeviceObject
);
1316 return LowerDeviceObject
;
1324 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1326 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1328 /* Check if we have a VPB with a device object */
1329 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1331 /* Then use the DO from the VPB */
1332 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1333 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1335 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1336 (FileObject
->DeviceObject
->Vpb
) &&
1337 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1339 /* The disk device actually has a VPB, so get the DO from there */
1340 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1344 /* Otherwise, this was a direct open */
1345 DeviceObject
= FileObject
->DeviceObject
;
1349 ASSERT(DeviceObject
!= NULL
);
1351 /* Check if we were attached */
1352 if (DeviceObject
->AttachedDevice
)
1354 /* Check if the file object has an extension present */
1355 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1357 /* Sanity check, direct open files can't have this */
1358 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1360 /* Check if the extension is really present */
1361 if (FileObject
->FileObjectExtension
)
1363 /* FIXME: Unhandled yet */
1364 DPRINT1("FOEs not supported\n");
1369 /* Return the highest attached device */
1370 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1373 /* Return the DO we found */
1374 return DeviceObject
;
1382 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject
,
1383 OUT PDEVICE_OBJECT
*DeviceObject
)
1386 PDEVICE_NODE DeviceNode
= NULL
;
1388 /* Call the internal helper function */
1389 Status
= IopGetRelatedTargetDevice(FileObject
, &DeviceNode
);
1390 if (NT_SUCCESS(Status
) && DeviceNode
)
1392 *DeviceObject
= DeviceNode
->PhysicalDeviceObject
;
1402 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1404 PDEVICE_OBJECT DeviceObject
;
1407 * If the FILE_OBJECT's VPB is defined,
1408 * get the device from it.
1410 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1412 /* Use the VPB's Device Object's */
1413 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1415 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1416 (FileObject
->DeviceObject
->Vpb
) &&
1417 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1419 /* Use the VPB's File System Object */
1420 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1424 /* Use the FO's Device Object */
1425 DeviceObject
= FileObject
->DeviceObject
;
1428 /* Return the device object we found */
1429 ASSERT(DeviceObject
!= NULL
);
1430 return DeviceObject
;
1438 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1440 PSHUTDOWN_ENTRY Entry
;
1442 /* Allocate the shutdown entry */
1443 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1444 sizeof(SHUTDOWN_ENTRY
),
1445 TAG_SHUTDOWN_ENTRY
);
1446 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1449 Entry
->DeviceObject
= DeviceObject
;
1451 /* Reference it so it doesn't go away */
1452 ObReferenceObject(DeviceObject
);
1454 /* Insert it into the list */
1455 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1456 &Entry
->ShutdownList
,
1459 /* Set the shutdown registered flag */
1460 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1461 return STATUS_SUCCESS
;
1469 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1471 PSHUTDOWN_ENTRY Entry
;
1473 /* Allocate the shutdown entry */
1474 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1475 sizeof(SHUTDOWN_ENTRY
),
1476 TAG_SHUTDOWN_ENTRY
);
1477 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1480 Entry
->DeviceObject
= DeviceObject
;
1482 /* Reference it so it doesn't go away */
1483 ObReferenceObject(DeviceObject
);
1485 /* Insert it into the list */
1486 ExInterlockedInsertHeadList(&ShutdownListHead
,
1487 &Entry
->ShutdownList
,
1490 /* Set the shutdown registered flag */
1491 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1492 return STATUS_SUCCESS
;
1500 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1502 PSHUTDOWN_ENTRY ShutdownEntry
;
1503 PLIST_ENTRY NextEntry
;
1506 /* Acquire the shutdown lock and loop the shutdown list */
1507 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1508 NextEntry
= ShutdownListHead
.Flink
;
1509 while (NextEntry
!= &ShutdownListHead
)
1512 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1516 /* Get if the DO matches */
1517 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1519 /* Remove it from the list */
1520 RemoveEntryList(NextEntry
);
1521 NextEntry
= NextEntry
->Blink
;
1523 /* Free the entry */
1524 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1526 /* Get rid of our reference to it */
1527 ObDereferenceObject(DeviceObject
);
1530 /* Go to the next entry */
1531 NextEntry
= NextEntry
->Flink
;
1534 /* Now loop the last chance list */
1535 NextEntry
= LastChanceShutdownListHead
.Flink
;
1536 while (NextEntry
!= &LastChanceShutdownListHead
)
1539 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1543 /* Get if the DO matches */
1544 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1546 /* Remove it from the list */
1547 RemoveEntryList(NextEntry
);
1548 NextEntry
= NextEntry
->Blink
;
1550 /* Free the entry */
1551 ExFreePoolWithTag(ShutdownEntry
, TAG_SHUTDOWN_ENTRY
);
1553 /* Get rid of our reference to it */
1554 ObDereferenceObject(DeviceObject
);
1557 /* Go to the next entry */
1558 NextEntry
= NextEntry
->Flink
;
1561 /* Release the shutdown lock */
1562 KeReleaseSpinLock(&ShutdownListLock
, OldIrql
);
1564 /* Now remove the flag */
1565 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1573 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1574 IN BOOLEAN DeferredStartIo
,
1575 IN BOOLEAN NonCancelable
)
1577 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1579 /* Get the Device Extension */
1580 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1582 /* Set the flags the caller requested */
1583 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1584 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1592 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1593 IN BOOLEAN Cancelable
,
1596 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1598 /* Get the Device Extension */
1599 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1601 /* Check if deferred start was requested */
1602 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1604 /* Call our internal function to handle the defered case */
1605 IopStartNextPacketByKeyEx(DeviceObject
,
1608 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1612 /* Call the normal routine */
1613 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1622 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1623 IN BOOLEAN Cancelable
)
1625 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1627 /* Get the Device Extension */
1628 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1630 /* Check if deferred start was requested */
1631 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1633 /* Call our internal function to handle the defered case */
1634 IopStartNextPacketByKeyEx(DeviceObject
,
1637 (Cancelable
? DOE_SIO_CANCELABLE
: 0));
1641 /* Call the normal routine */
1642 IopStartNextPacket(DeviceObject
, Cancelable
);
1651 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1654 IN PDRIVER_CANCEL CancelFunction
)
1657 KIRQL OldIrql
, CancelIrql
;
1659 /* Raise to dispatch level */
1660 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1662 /* Check if we should acquire the cancel lock */
1665 /* Acquire and set it */
1666 IoAcquireCancelSpinLock(&CancelIrql
);
1667 Irp
->CancelRoutine
= CancelFunction
;
1670 /* Check if we have a key */
1674 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1675 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1680 /* Insert without a key */
1681 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1682 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1685 /* Check if this was a first insert */
1689 DeviceObject
->CurrentIrp
= Irp
;
1691 /* Check if this is a cancelable packet */
1694 /* Check if the caller requested no cancellation */
1695 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1698 /* He did, so remove the cancel routine */
1699 Irp
->CancelRoutine
= NULL
;
1702 /* Release the cancel lock */
1703 IoReleaseCancelSpinLock(CancelIrql
);
1706 /* Call the Start I/O function */
1707 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1711 /* The packet was inserted... check if we have a cancel function */
1714 /* Check if the IRP got cancelled */
1718 * Set the cancel IRQL, clear the currnet cancel routine and
1721 Irp
->CancelIrql
= CancelIrql
;
1722 Irp
->CancelRoutine
= NULL
;
1723 CancelFunction(DeviceObject
, Irp
);
1727 /* Otherwise, release the lock */
1728 IoReleaseCancelSpinLock(CancelIrql
);
1733 /* Return back to previous IRQL */
1734 KeLowerIrql(OldIrql
);