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 *******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ********************************************************************/
19 ULONG IopDeviceObjectNumber
= 0;
21 LIST_ENTRY ShutdownListHead
, LastChanceShutdownListHead
;
22 KSPIN_LOCK ShutdownListLock
;
24 /* PRIVATE FUNCTIONS **********************************************************/
28 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
29 IN PDEVICE_OBJECT TargetDevice
,
30 OUT PDEVICE_OBJECT
*AttachedToDeviceObject OPTIONAL
)
32 PDEVICE_OBJECT AttachedDevice
;
33 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension
;
35 /* Get the Attached Device and source extension */
36 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
37 SourceDeviceExtension
= IoGetDevObjExtension(SourceDevice
);
38 ASSERT(SourceDeviceExtension
->AttachedTo
== NULL
);
40 /* Make sure that it's in a correct state */
41 if ((AttachedDevice
->Flags
& DO_DEVICE_INITIALIZING
) ||
42 (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
46 DOE_REMOVE_PROCESSED
)))
48 /* Device was unloading or being removed */
49 AttachedDevice
= NULL
;
53 /* Update atached device fields */
54 AttachedDevice
->AttachedDevice
= SourceDevice
;
55 AttachedDevice
->Spare1
++;
57 /* Update the source with the attached data */
58 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
59 SourceDevice
->AlignmentRequirement
= AttachedDevice
->
61 SourceDevice
->SectorSize
= AttachedDevice
->SectorSize
;
63 /* Check for pending start flag */
64 if (IoGetDevObjExtension(AttachedDevice
)->ExtensionFlags
&
68 IoGetDevObjExtension(SourceDevice
)->ExtensionFlags
|=
72 /* Set the attachment in the device extension */
73 SourceDeviceExtension
->AttachedTo
= AttachedDevice
;
76 /* Return the attached device */
77 if (AttachedToDeviceObject
) *AttachedToDeviceObject
= AttachedDevice
;
78 return AttachedDevice
;
83 IoShutdownRegisteredDevices(VOID
)
85 PLIST_ENTRY ListEntry
;
86 PDEVICE_OBJECT DeviceObject
;
87 PSHUTDOWN_ENTRY ShutdownEntry
;
88 IO_STATUS_BLOCK StatusBlock
;
93 /* Initialize an event to wait on */
94 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
96 /* Get the first entry and start looping */
97 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
101 /* Get the shutdown entry */
102 ShutdownEntry
= CONTAINING_RECORD(ListEntry
,
106 /* Get the attached device */
107 DeviceObject
= IoGetAttachedDevice(ShutdownEntry
->DeviceObject
);
109 /* Build the shutdown IRP and call the driver */
110 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
117 Status
= IoCallDriver(DeviceObject
, Irp
);
118 if (Status
== STATUS_PENDING
)
120 /* Wait on the driver */
121 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
124 /* Free the shutdown entry and reset the event */
125 ExFreePool(ShutdownEntry
);
126 KeClearEvent(&Event
);
128 /* Go to the next entry */
129 ListEntry
= ExInterlockedRemoveHeadList(&ShutdownListHead
,
136 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
137 IN ACCESS_MASK DesiredAccess
,
138 OUT PFILE_OBJECT
*FileObject
,
139 OUT PDEVICE_OBJECT
*DeviceObject
,
142 OBJECT_ATTRIBUTES ObjectAttributes
;
143 IO_STATUS_BLOCK StatusBlock
;
144 PFILE_OBJECT LocalFileObject
;
148 /* Open the Device */
149 InitializeObjectAttributes(&ObjectAttributes
,
154 Status
= ZwOpenFile(&FileHandle
,
159 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
160 if (!NT_SUCCESS(Status
)) return Status
;
162 /* Get File Object */
163 Status
= ObReferenceObjectByHandle(FileHandle
,
167 (PVOID
*)&LocalFileObject
,
169 if (NT_SUCCESS(Status
))
171 /* Return the requested data */
172 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
173 *FileObject
= LocalFileObject
;
177 /* Close the handle */
183 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject
)
185 PDEVICE_OBJECT LowestDevice
;
186 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
188 /* Get the current device and its extension */
189 LowestDevice
= DeviceObject
;
190 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
192 /* Keep looping as long as we're attached */
193 while (DeviceExtension
->AttachedTo
)
195 /* Get the lowest device and its extension */
196 LowestDevice
= DeviceExtension
->AttachedTo
;
197 DeviceExtension
= IoGetDevObjExtension(LowestDevice
);
200 /* Return the lowest device */
206 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject
,
207 IN PDEVICE_OBJECT DeviceObject
,
208 IN IOP_DEVICE_LIST_OPERATION Type
)
210 PDEVICE_OBJECT Previous
;
212 /* Check the type of operation */
213 if (Type
== IopRemove
)
215 /* Get the current device and check if it's the current one */
216 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
217 if (Previous
== DeviceObject
)
219 /* It is, simply unlink this one directly */
220 DeviceObject
->DriverObject
->DeviceObject
=
221 DeviceObject
->NextDevice
;
225 /* It's not, so loop until we find the device */
226 while (Previous
->NextDevice
!= DeviceObject
)
228 /* Not this one, keep moving */
229 Previous
= Previous
->NextDevice
;
232 /* We found it, now unlink us */
233 Previous
->NextDevice
= DeviceObject
->NextDevice
;
238 /* Link the device object and the driver object */
239 DeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
240 DriverObject
->DeviceObject
= DeviceObject
;
246 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject
)
248 PDRIVER_OBJECT DriverObject
= DeviceObject
->DriverObject
;
249 PDEVICE_OBJECT AttachedDeviceObject
, LowestDeviceObject
;
250 PEXTENDED_DEVOBJ_EXTENSION ThisExtension
, DeviceExtension
;
251 PDEVICE_NODE DeviceNode
;
252 BOOLEAN SafeToUnload
= TRUE
;
254 /* Check if removal is pending */
255 ThisExtension
= IoGetDevObjExtension(DeviceObject
);
256 if (ThisExtension
->ExtensionFlags
& DOE_REMOVE_PENDING
)
258 /* Get the PDO, extension, and node */
259 LowestDeviceObject
= IopGetLowestDevice(DeviceObject
);
260 DeviceExtension
= IoGetDevObjExtension(LowestDeviceObject
);
261 DeviceNode
= DeviceExtension
->DeviceNode
;
263 /* The PDO needs a device node */
264 ASSERT(DeviceNode
!= NULL
);
266 /* Loop all attached objects */
267 AttachedDeviceObject
= LowestDeviceObject
;
268 while (AttachedDeviceObject
)
270 /* Make sure they're dereferenced */
271 if (AttachedDeviceObject
->ReferenceCount
) return;
272 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
275 /* Loop all attached objects */
276 AttachedDeviceObject
= LowestDeviceObject
;
277 while (AttachedDeviceObject
)
279 /* Get the device extension */
280 DeviceExtension
= IoGetDevObjExtension(AttachedDeviceObject
);
282 /* Remove the pending flag and set processed */
283 DeviceExtension
->ExtensionFlags
&= ~DOE_REMOVE_PENDING
;
284 DeviceExtension
->ExtensionFlags
|= DOE_REMOVE_PROCESSED
;
285 AttachedDeviceObject
= AttachedDeviceObject
->AttachedDevice
;
289 * FIXME: TODO HPOUSSIN
290 * We need to parse/lock the device node, and if we have any pending
291 * surprise removals, query all relationships and send IRP_MN_REMOVE_
292 * _DEVICE to the devices related...
297 /* Check if deletion is pending */
298 if (ThisExtension
->ExtensionFlags
& DOE_DELETE_PENDING
)
300 /* Make sure unload is pending */
301 if (!(ThisExtension
->ExtensionFlags
& DOE_UNLOAD_PENDING
) ||
302 (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
))
304 /* We can't unload anymore */
305 SafeToUnload
= FALSE
;
309 * Check if we have an attached device and fail if we're attached
310 * and still have a reference count.
312 AttachedDeviceObject
= DeviceObject
->AttachedDevice
;
313 if ((AttachedDeviceObject
) && (DeviceObject
->ReferenceCount
)) return;
315 /* Check if we have a Security Descriptor */
316 if (DeviceObject
->SecurityDescriptor
)
319 ExFreePool(DeviceObject
->SecurityDescriptor
);
322 /* Remove the device from the list */
323 IopEditDeviceList(DeviceObject
->DriverObject
, DeviceObject
, IopRemove
);
325 /* Dereference the keep-alive */
326 ObDereferenceObject(DeviceObject
);
328 /* If we're not unloading, stop here */
329 if (!SafeToUnload
) return;
332 /* Loop all the device objects */
333 DeviceObject
= DriverObject
->DeviceObject
;
337 * Make sure we're not attached, having a reference count
338 * or already deleting
340 if ((DeviceObject
->ReferenceCount
) ||
341 (DeviceObject
->AttachedDevice
) ||
342 (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
343 (DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)))
345 /* We're not safe to unload, quit */
349 /* Check the next device */
350 DeviceObject
= DeviceObject
->NextDevice
;
353 /* Set the unload invoked flag */
354 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
357 if (DriverObject
->DriverUnload
) DriverObject
->DriverUnload(DriverObject
);
362 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject
,
363 IN BOOLEAN ForceUnload
)
366 ASSERT(DeviceObject
->ReferenceCount
);
368 /* Dereference the device */
369 DeviceObject
->ReferenceCount
--;
372 * Check if we can unload it and it's safe to unload (or if we're forcing
373 * an unload, which is OK too).
375 if (!(DeviceObject
->ReferenceCount
) &&
376 ((ForceUnload
) || (IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
377 (DOE_UNLOAD_PENDING
|
380 DOE_REMOVE_PROCESSED
))))
383 IopUnloadDevice(DeviceObject
);
389 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
390 IN BOOLEAN Cancelable
,
393 PKDEVICE_QUEUE_ENTRY Entry
;
397 /* Acquire the cancel lock if this is cancelable */
398 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
400 /* Clear the current IRP */
401 DeviceObject
->CurrentIrp
= NULL
;
403 /* Remove an entry from the queue */
404 Entry
= KeRemoveByKeyDeviceQueue(&DeviceObject
->DeviceQueue
, Key
);
407 /* Get the IRP and set it */
408 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
409 DeviceObject
->CurrentIrp
= Irp
;
411 /* Check if this is a cancelable packet */
414 /* Check if the caller requested no cancellation */
415 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
418 /* He did, so remove the cancel routine */
419 Irp
->CancelRoutine
= NULL
;
422 /* Release the cancel lock */
423 IoReleaseCancelSpinLock(OldIrql
);
426 /* Call the Start I/O Routine */
427 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
431 /* Otherwise, release the cancel lock if we had acquired it */
432 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
438 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
439 IN BOOLEAN Cancelable
)
441 PKDEVICE_QUEUE_ENTRY Entry
;
445 /* Acquire the cancel lock if this is cancelable */
446 if (Cancelable
) IoAcquireCancelSpinLock(&OldIrql
);
448 /* Clear the current IRP */
449 DeviceObject
->CurrentIrp
= NULL
;
451 /* Remove an entry from the queue */
452 Entry
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
455 /* Get the IRP and set it */
456 Irp
= CONTAINING_RECORD(Entry
, IRP
, Tail
.Overlay
.DeviceQueueEntry
);
457 DeviceObject
->CurrentIrp
= Irp
;
459 /* Check if this is a cancelable packet */
462 /* Check if the caller requested no cancellation */
463 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
466 /* He did, so remove the cancel routine */
467 Irp
->CancelRoutine
= NULL
;
470 /* Release the cancel lock */
471 IoReleaseCancelSpinLock(OldIrql
);
474 /* Call the Start I/O Routine */
475 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
479 /* Otherwise, release the cancel lock if we had acquired it */
480 if (Cancelable
) IoReleaseCancelSpinLock(OldIrql
);
486 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject
,
490 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
491 ULONG CurrentKey
= Key
;
492 ULONG CurrentFlags
= Flags
;
494 /* Get the device extension and start the packet loop */
495 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
498 /* Increase the count */
499 if (InterlockedIncrement(&DeviceExtension
->StartIoCount
) > 1)
502 * We've already called the routine once...
503 * All we have to do is save the key and add the new flags
505 DeviceExtension
->StartIoFlags
|= CurrentFlags
;
506 DeviceExtension
->StartIoKey
= CurrentKey
;
510 /* Mask out the current packet flags and key */
511 DeviceExtension
->StartIoFlags
&= ~(DOE_SIO_WITH_KEY
|
514 DeviceExtension
->StartIoKey
= 0;
516 /* Check if this is a packet start with key */
517 if (Flags
& DOE_SIO_WITH_KEY
)
519 /* Start the packet with a key */
520 IopStartNextPacketByKey(DeviceObject
,
521 (Flags
& DOE_SIO_CANCELABLE
) ?
525 else if (Flags
& DOE_SIO_NO_KEY
)
527 /* Start the packet */
528 IopStartNextPacket(DeviceObject
,
529 (Flags
& DOE_SIO_CANCELABLE
) ?
534 /* Decrease the Start I/O count and check if it's 0 now */
535 if (!InterlockedDecrement(&DeviceExtension
->StartIoCount
))
537 /* Get the current active key and flags */
538 CurrentKey
= DeviceExtension
->StartIoKey
;
539 CurrentFlags
= DeviceExtension
->StartIoFlags
& (DOE_SIO_WITH_KEY
|
543 /* Check if we should still loop */
544 if (!(CurrentFlags
& (DOE_SIO_WITH_KEY
| DOE_SIO_NO_KEY
))) break;
548 /* There are still Start I/Os active, so quit this loop */
554 /* PUBLIC FUNCTIONS ***********************************************************/
559 * Layers a device over the highest device in a device stack.
563 * Device to be attached.
566 * Name of the target device.
569 * Caller storage for the device attached to.
576 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
577 PUNICODE_STRING TargetDeviceName
,
578 PDEVICE_OBJECT
*AttachedDevice
)
581 PFILE_OBJECT FileObject
= NULL
;
582 PDEVICE_OBJECT TargetDevice
= NULL
;
584 /* Call the helper routine for an attach operation */
585 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
586 FILE_READ_ATTRIBUTES
,
589 IO_ATTACH_DEVICE_API
);
590 if (!NT_SUCCESS(Status
)) return Status
;
592 /* Attach the device */
593 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
598 ObDereferenceObject(FileObject
);
603 * IoAttachDeviceByPointer
610 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
611 IN PDEVICE_OBJECT TargetDevice
)
613 PDEVICE_OBJECT AttachedDevice
;
614 NTSTATUS Status
= STATUS_SUCCESS
;
617 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
618 if (!AttachedDevice
) Status
= STATUS_NO_SUCH_DEVICE
;
620 /* Return the status */
629 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice
,
630 IN PDEVICE_OBJECT TargetDevice
)
632 /* Attach it safely */
633 return IopAttachDeviceToDeviceStackSafe(SourceDevice
,
643 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
644 IN PDEVICE_OBJECT TargetDevice
,
645 IN OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
647 /* Call the internal function */
648 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice
,
650 AttachedToDeviceObject
))
653 return STATUS_NO_SUCH_DEVICE
;
657 return STATUS_SUCCESS
;
663 * Allocates memory for and intializes a device object for use for
668 * Driver object passed by IO Manager when the driver was loaded.
670 * DeviceExtensionSize
671 * Number of bytes for the device extension.
674 * Unicode name of device.
677 * Device type of the new device.
679 * DeviceCharacteristics
680 * Bit mask of device characteristics.
683 * TRUE if only one thread can access the device at a time.
686 * On successful return this parameter is filled by pointer to
687 * allocated device object.
694 IoCreateDevice(IN PDRIVER_OBJECT DriverObject
,
695 IN ULONG DeviceExtensionSize
,
696 IN PUNICODE_STRING DeviceName
,
697 IN DEVICE_TYPE DeviceType
,
698 IN ULONG DeviceCharacteristics
,
699 IN BOOLEAN Exclusive
,
700 OUT PDEVICE_OBJECT
*DeviceObject
)
702 WCHAR AutoNameBuffer
[20];
703 UNICODE_STRING AutoName
;
704 PDEVICE_OBJECT CreatedDeviceObject
;
705 PDEVOBJ_EXTENSION DeviceObjectExtension
;
706 OBJECT_ATTRIBUTES ObjectAttributes
;
708 ULONG AlignedDeviceExtensionSize
;
713 /* Check if we have to generate a name */
714 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
717 swprintf(AutoNameBuffer
,
719 InterlockedIncrementUL(&IopDeviceObjectNumber
));
721 /* Initialize the name */
722 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
723 DeviceName
= &AutoName
;
726 /* Initialize the Object Attributes */
727 InitializeObjectAttributes(&ObjectAttributes
,
733 /* Honor exclusive flag */
734 if (Exclusive
) ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
736 /* Create a permanent object for named devices */
737 if (DeviceName
) ObjectAttributes
.Attributes
|= OBJ_PERMANENT
;
739 /* Align the Extension Size to 8-bytes */
740 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
743 TotalSize
= AlignedDeviceExtensionSize
+
744 sizeof(DEVICE_OBJECT
) +
745 sizeof(EXTENDED_DEVOBJ_EXTENSION
);
747 /* Create the Device Object */
748 *DeviceObject
= NULL
;
749 Status
= ObCreateObject(KernelMode
,
757 (PVOID
*)&CreatedDeviceObject
);
758 if (!NT_SUCCESS(Status
)) return Status
;
760 /* Clear the whole Object and extension so we don't null stuff manually */
761 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
764 * Setup the Type and Size. Note that we don't use the aligned size,
765 * because that's only padding for the DevObjExt and not part of the Object.
767 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
768 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + DeviceExtensionSize
;
770 /* The kernel extension is after the driver internal extension */
771 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
772 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
773 AlignedDeviceExtensionSize
);
775 /* Set the Type and Size. Question: why is Size 0 on Windows? */
776 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
777 DeviceObjectExtension
->Size
= 0;
779 /* Link the Object and Extension */
780 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
781 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
783 /* Set Device Object Data */
784 CreatedDeviceObject
->DeviceType
= DeviceType
;
785 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
786 CreatedDeviceObject
->DeviceExtension
= DeviceExtensionSize
?
787 CreatedDeviceObject
+ 1 :
789 CreatedDeviceObject
->StackSize
= 1;
790 CreatedDeviceObject
->AlignmentRequirement
= 0;
793 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
794 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
795 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
797 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
798 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
799 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
) ||
800 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
) ||
801 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
))
804 Status
= IopCreateVpb(CreatedDeviceObject
);
805 if (!NT_SUCCESS(Status
))
807 /* Reference the device object and fail */
808 ObDereferenceObject(DeviceObject
);
812 /* Initialize Lock Event */
813 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
814 SynchronizationEvent
,
818 /* Set the right Sector Size */
821 /* All disk systems */
822 case FILE_DEVICE_DISK_FILE_SYSTEM
:
823 case FILE_DEVICE_DISK
:
824 case FILE_DEVICE_VIRTUAL_DISK
:
826 /* The default is 512 bytes */
827 CreatedDeviceObject
->SectorSize
= 512;
830 /* CD-ROM file systems */
831 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
833 /* The default is 2048 bytes */
834 CreatedDeviceObject
->SectorSize
= 2048;
837 /* Create the Device Queue */
838 if ((CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
839 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
) ||
840 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
841 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
) ||
842 (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
))
844 /* Simple FS Devices, they don't need a real Device Queue */
845 InitializeListHead(&CreatedDeviceObject
->Queue
.ListEntry
);
849 /* An actual Device, initialize its DQ */
850 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
853 /* Insert the Object */
854 Status
= ObInsertObject(CreatedDeviceObject
,
856 FILE_READ_DATA
| FILE_WRITE_DATA
,
858 (PVOID
*)&CreatedDeviceObject
,
860 if (!NT_SUCCESS(Status
)) return Status
;
862 /* Now do the final linking */
863 ObReferenceObject(DriverObject
);
864 ASSERT((DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
) == 0);
865 CreatedDeviceObject
->DriverObject
= DriverObject
;
866 IopEditDeviceList(DriverObject
, CreatedDeviceObject
, IopAdd
);
868 /* Close the temporary handle and return to caller */
869 ObCloseHandle(TempHandle
, KernelMode
);
870 *DeviceObject
= CreatedDeviceObject
;
871 return STATUS_SUCCESS
;
882 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject
)
886 /* Check if the device is registered for shutdown notifications */
887 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
889 /* Call the shutdown notifications */
890 IoUnregisterShutdownNotification(DeviceObject
);
893 /* Check if it has a timer */
894 Timer
= DeviceObject
->Timer
;
897 /* Remove it and free it */
898 IopRemoveTimerFromTimerList(Timer
);
899 ExFreePoolWithTag(Timer
, TAG_IO_TIMER
);
902 /* Check if the device has a name */
903 if (DeviceObject
->Flags
& DO_DEVICE_HAS_NAME
)
905 /* It does, make it temporary so we can remove it */
906 ObMakeTemporaryObject(DeviceObject
);
909 /* Set the pending delete flag */
910 IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
|= DOE_DELETE_PENDING
;
912 /* Check if the device object can be unloaded */
913 if (!DeviceObject
->ReferenceCount
) IopUnloadDevice(DeviceObject
);
924 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice
)
926 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
929 DeviceExtension
= IoGetDevObjExtension(TargetDevice
->AttachedDevice
);
930 ASSERT(DeviceExtension
->AttachedTo
== TargetDevice
);
932 /* Remove the attachment */
933 DeviceExtension
->AttachedTo
= NULL
;
934 TargetDevice
->AttachedDevice
= NULL
;
936 /* Check if it's ok to delete this device */
937 if ((IoGetDevObjExtension(TargetDevice
)->ExtensionFlags
&
938 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
| DOE_REMOVE_PENDING
)) &&
939 !(TargetDevice
->ReferenceCount
))
942 IopUnloadDevice(TargetDevice
);
951 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
952 IN PDEVICE_OBJECT
*DeviceObjectList
,
953 IN ULONG DeviceObjectListSize
,
954 OUT PULONG ActualNumberDeviceObjects
)
956 ULONG ActualDevices
= 1;
957 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
959 /* Find out how many devices we'll enumerate */
960 while ((CurrentDevice
= CurrentDevice
->NextDevice
)) ActualDevices
++;
962 /* Go back to the first */
963 CurrentDevice
= DriverObject
->DeviceObject
;
965 /* Start by at least returning this */
966 *ActualNumberDeviceObjects
= ActualDevices
;
968 /* Check if we can support so many */
969 if ((ActualDevices
* 4) > DeviceObjectListSize
)
971 /* Fail because the buffer was too small */
972 return STATUS_BUFFER_TOO_SMALL
;
975 /* Check if the caller only wanted the size */
976 if (DeviceObjectList
)
978 /* Loop through all the devices */
979 while (ActualDevices
)
981 /* Reference each Device */
982 ObReferenceObject(CurrentDevice
);
984 /* Add it to the list */
985 *DeviceObjectList
= CurrentDevice
;
987 /* Go to the next one */
988 CurrentDevice
= CurrentDevice
->NextDevice
;
994 /* Return the status */
995 return STATUS_SUCCESS
;
999 * IoGetAttachedDevice
1006 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
1008 /* Get the last attached device */
1009 while (DeviceObject
->AttachedDevice
)
1011 /* Move to the next one */
1012 DeviceObject
= DeviceObject
->AttachedDevice
;
1016 return DeviceObject
;
1020 * IoGetAttachedDeviceReference
1027 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
1029 /* Reference the Attached Device */
1030 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1031 ObReferenceObject(DeviceObject
);
1032 return DeviceObject
;
1040 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
1042 /* Reference the lowest attached device */
1043 DeviceObject
= IopGetLowestDevice(DeviceObject
);
1044 ObReferenceObject(DeviceObject
);
1045 return DeviceObject
;
1049 * IoGetDeviceObjectPointer
1056 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
1057 IN ACCESS_MASK DesiredAccess
,
1058 OUT PFILE_OBJECT
*FileObject
,
1059 OUT PDEVICE_OBJECT
*DeviceObject
)
1061 /* Call the helper routine for a normal operation */
1062 return IopGetDeviceObjectPointer(ObjectName
,
1074 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
1075 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
1077 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1082 /* Make sure there's a VPB */
1083 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
1086 IoAcquireVpbSpinLock(&OldIrql
);
1088 /* Get the Device Extension */
1089 DeviceExtension
= IoGetDevObjExtension(FileSystemDeviceObject
);
1091 /* Make sure this one has a VPB too */
1092 Vpb
= DeviceExtension
->Vpb
;
1095 /* Make sure that it's mounted */
1096 if ((Vpb
->ReferenceCount
) &&
1097 (Vpb
->Flags
& VPB_MOUNTED
))
1099 /* Return the Disk Device Object */
1100 *DiskDeviceObject
= Vpb
->RealDevice
;
1102 /* Reference it and return success */
1103 ObReferenceObject(Vpb
->RealDevice
);
1104 Status
= STATUS_SUCCESS
;
1108 /* It's not, so return failure */
1109 Status
= STATUS_VOLUME_DISMOUNTED
;
1115 Status
= STATUS_INVALID_PARAMETER
;
1118 /* Release the lock */
1119 IoReleaseVpbSpinLock(OldIrql
);
1128 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
1130 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1131 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
1133 /* Make sure it's not getting deleted */
1134 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1135 if (DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
1136 DOE_DELETE_PENDING
|
1137 DOE_REMOVE_PENDING
|
1138 DOE_REMOVE_PROCESSED
))
1140 /* Get the Lower Device Object */
1141 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
1144 ObReferenceObject(LowerDeviceObject
);
1148 return LowerDeviceObject
;
1156 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
1158 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
1160 /* Check if we have a VPB with a device object */
1161 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1163 /* Then use the DO from the VPB */
1164 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1165 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1167 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1168 (FileObject
->DeviceObject
->Vpb
) &&
1169 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1171 /* The disk device actually has a VPB, so get the DO from there */
1172 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1176 /* Otherwise, this was a direct open */
1177 DeviceObject
= FileObject
->DeviceObject
;
1181 ASSERT(DeviceObject
!= NULL
);
1183 /* Check if we were attached */
1184 if (DeviceObject
->AttachedDevice
)
1186 /* Check if the file object has an extension present */
1187 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1189 /* Sanity check, direct open files can't have this */
1190 ASSERT(!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
));
1192 /* Check if the extension is really present */
1193 if (FileObject
->FileObjectExtension
)
1195 /* FIXME: Unhandled yet */
1196 DPRINT1("FOEs not supported\n");
1201 /* Return the highest attached device */
1202 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
1205 /* Return the DO we found */
1206 return DeviceObject
;
1214 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
1216 PDEVICE_OBJECT DeviceObject
;
1219 * If the FILE_OBJECT's VPB is defined,
1220 * get the device from it.
1222 if ((FileObject
->Vpb
) && (FileObject
->Vpb
->DeviceObject
))
1224 /* Use the VPB's Device Object's */
1225 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
1227 else if (!(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
) &&
1228 (FileObject
->DeviceObject
->Vpb
) &&
1229 (FileObject
->DeviceObject
->Vpb
->DeviceObject
))
1231 /* Use the VPB's File System Object */
1232 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
1236 /* Use the FO's Device Object */
1237 DeviceObject
= FileObject
->DeviceObject
;
1240 /* Return the device object we found */
1241 ASSERT(DeviceObject
!= NULL
);
1242 return DeviceObject
;
1250 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject
)
1252 PSHUTDOWN_ENTRY Entry
;
1254 /* Allocate the shutdown entry */
1255 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1256 sizeof(SHUTDOWN_ENTRY
),
1257 TAG_SHUTDOWN_ENTRY
);
1258 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1261 Entry
->DeviceObject
= DeviceObject
;
1263 /* Insert it into the list */
1264 ExInterlockedInsertHeadList(&LastChanceShutdownListHead
,
1265 &Entry
->ShutdownList
,
1268 /* Set the shutdown registered flag */
1269 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1270 return STATUS_SUCCESS
;
1278 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1280 PSHUTDOWN_ENTRY Entry
;
1282 /* Allocate the shutdown entry */
1283 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
1284 sizeof(SHUTDOWN_ENTRY
),
1285 TAG_SHUTDOWN_ENTRY
);
1286 if (!Entry
) return STATUS_INSUFFICIENT_RESOURCES
;
1289 Entry
->DeviceObject
= DeviceObject
;
1291 /* Insert it into the list */
1292 ExInterlockedInsertHeadList(&ShutdownListHead
,
1293 &Entry
->ShutdownList
,
1296 /* Set the shutdown registered flag */
1297 DeviceObject
->Flags
|= DO_SHUTDOWN_REGISTERED
;
1298 return STATUS_SUCCESS
;
1306 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject
)
1308 PSHUTDOWN_ENTRY ShutdownEntry
;
1309 PLIST_ENTRY NextEntry
;
1312 /* Acquire the shutdown lock and loop the shutdown list */
1313 KeAcquireSpinLock(&ShutdownListLock
, &OldIrql
);
1314 NextEntry
= ShutdownListHead
.Flink
;
1315 while (NextEntry
!= &ShutdownListHead
)
1318 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1322 /* Get if the DO matches */
1323 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1325 /* Remove it from the list */
1326 RemoveEntryList(NextEntry
);
1327 NextEntry
= NextEntry
->Blink
;
1329 /* Free the entry */
1330 ExFreePool(ShutdownEntry
);
1333 /* Go to the next entry */
1334 NextEntry
= NextEntry
->Flink
;
1337 /* Now loop the last chance list */
1338 NextEntry
= LastChanceShutdownListHead
.Flink
;
1339 while (NextEntry
!= &LastChanceShutdownListHead
)
1342 ShutdownEntry
= CONTAINING_RECORD(NextEntry
,
1346 /* Get if the DO matches */
1347 if (ShutdownEntry
->DeviceObject
== DeviceObject
)
1349 /* Remove it from the list */
1350 RemoveEntryList(NextEntry
);
1351 NextEntry
= NextEntry
->Blink
;
1353 /* Free the entry */
1354 ExFreePool(ShutdownEntry
);
1357 /* Go to the next entry */
1358 NextEntry
= NextEntry
->Flink
;
1361 /* Now remove the flag */
1362 DeviceObject
->Flags
&= ~DO_SHUTDOWN_REGISTERED
;
1370 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject
,
1371 IN BOOLEAN DeferredStartIo
,
1372 IN BOOLEAN NonCancelable
)
1374 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1376 /* Get the Device Extension */
1377 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1379 /* Set the flags the caller requested */
1380 DeviceExtension
->StartIoFlags
|= (DeferredStartIo
) ? DOE_SIO_DEFERRED
: 0;
1381 DeviceExtension
->StartIoFlags
|= (NonCancelable
) ? DOE_SIO_NO_CANCEL
: 0;
1389 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject
,
1390 IN BOOLEAN Cancelable
,
1393 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1395 /* Get the Device Extension */
1396 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1398 /* Check if deferred start was requested */
1399 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1401 /* Call our internal function to handle the defered case */
1402 IopStartNextPacketByKeyEx(DeviceObject
,
1405 (Cancelable
) ? DOE_SIO_CANCELABLE
: 0);
1409 /* Call the normal routine */
1410 IopStartNextPacketByKey(DeviceObject
, Cancelable
, Key
);
1419 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject
,
1420 IN BOOLEAN Cancelable
)
1422 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
1424 /* Get the Device Extension */
1425 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1427 /* Check if deferred start was requested */
1428 if (DeviceExtension
->StartIoFlags
& DOE_SIO_DEFERRED
)
1430 /* Call our internal function to handle the defered case */
1431 IopStartNextPacketByKeyEx(DeviceObject
,
1434 (Cancelable
) ? DOE_SIO_CANCELABLE
: 0);
1438 /* Call the normal routine */
1439 IopStartNextPacket(DeviceObject
, Cancelable
);
1448 IoStartPacket(IN PDEVICE_OBJECT DeviceObject
,
1451 IN PDRIVER_CANCEL CancelFunction
)
1454 KIRQL OldIrql
, CancelIrql
;
1456 /* Raise to dispatch level */
1457 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
1459 /* Check if we should acquire the cancel lock */
1462 /* Acquire and set it */
1463 IoAcquireCancelSpinLock(&CancelIrql
);
1464 Irp
->CancelRoutine
= CancelFunction
;
1467 /* Check if we have a key */
1471 Stat
= KeInsertByKeyDeviceQueue(&DeviceObject
->DeviceQueue
,
1472 &Irp
->Tail
.Overlay
.DeviceQueueEntry
,
1477 /* Insert without a key */
1478 Stat
= KeInsertDeviceQueue(&DeviceObject
->DeviceQueue
,
1479 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
1482 /* Check if this was a first insert */
1486 DeviceObject
->CurrentIrp
= Irp
;
1488 /* Check if this is a cancelable packet */
1491 /* Check if the caller requested no cancellation */
1492 if (IoGetDevObjExtension(DeviceObject
)->StartIoFlags
&
1495 /* He did, so remove the cancel routine */
1496 Irp
->CancelRoutine
= NULL
;
1499 /* Release the cancel lock */
1500 IoReleaseCancelSpinLock(OldIrql
);
1503 /* Call the Start I/O function */
1504 DeviceObject
->DriverObject
->DriverStartIo(DeviceObject
, Irp
);
1508 /* The packet was inserted... check if we have a cancel function */
1511 /* Check if the IRP got cancelled */
1515 * Set the cancel IRQL, clear the currnet cancel routine and
1518 Irp
->CancelIrql
= CancelIrql
;
1519 Irp
->CancelRoutine
= NULL
;
1520 CancelFunction(DeviceObject
, Irp
);
1524 /* Otherwise, release the lock */
1525 IoReleaseCancelSpinLock(CancelIrql
);
1530 /* Return back to previous IRQL */
1531 KeLowerIrql(OldIrql
);