3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/device.c
6 * PURPOSE: Manage devices
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS ********************************************************************/
19 #define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T')
21 static ULONG IopDeviceObjectNumber
= 0;
23 /* PRIVATE FUNCTIONS **********************************************************/
27 PDEVICE_NODE DeviceNode
,
28 PDRIVER_OBJECT DriverObject
)
30 IO_STATUS_BLOCK IoStatusBlock
;
31 IO_STACK_LOCATION Stack
;
35 if (DriverObject
->DriverExtension
->AddDevice
)
37 /* This is a Plug and Play driver */
38 DPRINT("Plug and Play driver found\n");
40 ASSERT(DeviceNode
->PhysicalDeviceObject
);
42 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
43 DriverObject
->DriverExtension
->AddDevice
);
45 Status
= DriverObject
->DriverExtension
->AddDevice(
46 DriverObject
, DeviceNode
->PhysicalDeviceObject
);
48 if (!NT_SUCCESS(Status
))
53 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->PhysicalDeviceObject
);
55 if (Fdo
== DeviceNode
->PhysicalDeviceObject
)
57 /* FIXME: What do we do? Unload the driver or just disable the device? */
58 DbgPrint("An FDO was not attached\n");
59 IopDeviceNodeSetFlag(DeviceNode
, DNF_DISABLED
);
60 return STATUS_UNSUCCESSFUL
;
63 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
65 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
67 /* FIXME: Should be DeviceNode->ResourceList */
68 Stack
.Parameters
.StartDevice
.AllocatedResources
= DeviceNode
->BootResources
;
69 /* FIXME: Should be DeviceNode->ResourceListTranslated */
70 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= DeviceNode
->BootResources
;
72 Status
= IopInitiatePnpIrp(
78 if (!NT_SUCCESS(Status
))
80 DPRINT("IopInitiatePnpIrp() failed\n");
81 ObDereferenceObject(Fdo
);
85 if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
87 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
89 /* There can be only one system power device */
90 if (!SystemPowerDeviceNodeCreated
)
92 PopSystemPowerDeviceNode
= DeviceNode
;
93 SystemPowerDeviceNodeCreated
= TRUE
;
97 if (Fdo
->DeviceType
== FILE_DEVICE_BUS_EXTENDER
||
98 Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
100 DPRINT("Bus extender found\n");
102 Status
= IopInvalidateDeviceRelations(DeviceNode
, BusRelations
);
103 if (!NT_SUCCESS(Status
))
105 ObDereferenceObject(Fdo
);
110 ObDereferenceObject(Fdo
);
113 return STATUS_SUCCESS
;
118 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
119 IN ACCESS_MASK DesiredAccess
,
120 OUT PFILE_OBJECT
*FileObject
,
121 OUT PDEVICE_OBJECT
*DeviceObject
,
124 OBJECT_ATTRIBUTES ObjectAttributes
;
125 IO_STATUS_BLOCK StatusBlock
;
126 PFILE_OBJECT LocalFileObject
;
130 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x,"
131 "FileObject %p DeviceObject %p)\n",
132 ObjectName
, DesiredAccess
, FileObject
, DeviceObject
);
134 /* Open the Device */
135 InitializeObjectAttributes(&ObjectAttributes
,
140 Status
= ZwOpenFile(&FileHandle
,
145 FILE_NON_DIRECTORY_FILE
| AttachFlag
);
147 if (!NT_SUCCESS(Status
))
149 DPRINT1("NtOpenFile failed, Status: 0x%x\n", Status
);
153 /* Get File Object */
154 Status
= ObReferenceObjectByHandle(FileHandle
,
158 (PVOID
*)&LocalFileObject
,
160 if (NT_SUCCESS(Status
))
162 /* Return the requested data */
163 *DeviceObject
= IoGetRelatedDeviceObject(LocalFileObject
);
164 *FileObject
= LocalFileObject
;
167 /* Close the handle */
172 /* PUBLIC FUNCTIONS ***********************************************************/
177 * Layers a device over the highest device in a device stack.
181 * Device to be attached.
184 * Name of the target device.
187 * Caller storage for the device attached to.
194 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
195 PUNICODE_STRING TargetDeviceName
,
196 PDEVICE_OBJECT
*AttachedDevice
)
199 PFILE_OBJECT FileObject
;
200 PDEVICE_OBJECT TargetDevice
;
202 /* Call the helper routine for an attach operation */
203 DPRINT("IoAttachDevice\n");
204 Status
= IopGetDeviceObjectPointer(TargetDeviceName
,
205 FILE_READ_ATTRIBUTES
,
208 IO_ATTACH_DEVICE_API
);
210 if (!NT_SUCCESS(Status
))
212 DPRINT1("Failed to get Device Object\n");
216 /* Attach the device */
217 IoAttachDeviceToDeviceStackSafe(SourceDevice
, TargetDevice
, AttachedDevice
);
220 ObDereferenceObject(FileObject
);
221 return STATUS_SUCCESS
;
225 * IoAttachDeviceByPointer
232 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
233 IN PDEVICE_OBJECT TargetDevice
)
235 PDEVICE_OBJECT AttachedDevice
;
236 NTSTATUS Status
= STATUS_SUCCESS
;
238 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
239 SourceDevice
, TargetDevice
);
242 AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
, TargetDevice
);
243 if (AttachedDevice
== NULL
) Status
= STATUS_NO_SUCH_DEVICE
;
245 /* Return the status */
250 * IoAttachDeviceToDeviceStack
257 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice
,
258 PDEVICE_OBJECT TargetDevice
)
261 PDEVICE_OBJECT LocalAttach
;
263 /* Attach it safely */
264 DPRINT("IoAttachDeviceToDeviceStack\n");
265 Status
= IoAttachDeviceToDeviceStackSafe(SourceDevice
,
270 DPRINT("IoAttachDeviceToDeviceStack DONE: %x\n", LocalAttach
);
279 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice
,
280 IN PDEVICE_OBJECT TargetDevice
,
281 OUT PDEVICE_OBJECT
*AttachedToDeviceObject
)
283 PDEVICE_OBJECT AttachedDevice
;
284 PDEVOBJ_EXTENSION SourceDeviceExtension
;
286 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
287 SourceDevice
, TargetDevice
);
289 /* Get the Attached Device and source extension */
290 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
291 SourceDeviceExtension
= SourceDevice
->DeviceObjectExtension
;
293 /* Make sure that it's in a correct state */
294 if (!(AttachedDevice
->DeviceObjectExtension
->ExtensionFlags
&
295 (DOE_UNLOAD_PENDING
| DOE_DELETE_PENDING
|
296 DOE_REMOVE_PENDING
| DOE_REMOVE_PROCESSED
)))
299 AttachedDevice
->AttachedDevice
= SourceDevice
;
300 SourceDevice
->AttachedDevice
= NULL
;
301 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
302 SourceDevice
->AlignmentRequirement
= AttachedDevice
->AlignmentRequirement
;
303 SourceDevice
->SectorSize
= AttachedDevice
->SectorSize
;
304 SourceDevice
->Vpb
= AttachedDevice
->Vpb
;
306 /* Set the attachment in the device extension */
307 SourceDeviceExtension
->AttachedTo
= AttachedDevice
;
311 /* Device was unloading or being removed */
312 AttachedDevice
= NULL
;
315 /* Return the attached device */
316 *AttachedToDeviceObject
= AttachedDevice
;
317 return STATUS_SUCCESS
;
323 * Allocates memory for and intializes a device object for use for
328 * Driver object passed by IO Manager when the driver was loaded.
330 * DeviceExtensionSize
331 * Number of bytes for the device extension.
334 * Unicode name of device.
337 * Device type of the new device.
339 * DeviceCharacteristics
340 * Bit mask of device characteristics.
343 * TRUE if only one thread can access the device at a time.
346 * On successful return this parameter is filled by pointer to
347 * allocated device object.
354 IoCreateDevice(PDRIVER_OBJECT DriverObject
,
355 ULONG DeviceExtensionSize
,
356 PUNICODE_STRING DeviceName
,
357 DEVICE_TYPE DeviceType
,
358 ULONG DeviceCharacteristics
,
360 PDEVICE_OBJECT
*DeviceObject
)
362 WCHAR AutoNameBuffer
[20];
363 UNICODE_STRING AutoName
;
364 PDEVICE_OBJECT CreatedDeviceObject
;
365 PDEVOBJ_EXTENSION DeviceObjectExtension
;
366 OBJECT_ATTRIBUTES ObjectAttributes
;
368 ULONG AlignedDeviceExtensionSize
;
372 ASSERT_IRQL(PASSIVE_LEVEL
);
373 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject
);
375 /* Generate a name if we have to */
376 if (DeviceCharacteristics
& FILE_AUTOGENERATED_DEVICE_NAME
)
378 swprintf(AutoNameBuffer
,
380 InterlockedIncrementUL(&IopDeviceObjectNumber
));
381 RtlInitUnicodeString(&AutoName
, AutoNameBuffer
);
382 DeviceName
= &AutoName
;
385 /* Initialize the Object Attributes */
386 InitializeObjectAttributes(&ObjectAttributes
, DeviceName
, 0, NULL
, NULL
);
388 /* Honour exclusive flag */
389 ObjectAttributes
.Attributes
|= OBJ_EXCLUSIVE
;
391 /* Align the Extension Size to 8-bytes */
392 AlignedDeviceExtensionSize
= (DeviceExtensionSize
+ 7) &~ 7;
393 DPRINT("AlignedDeviceExtensionSize %x\n", AlignedDeviceExtensionSize
);
396 TotalSize
= AlignedDeviceExtensionSize
+
397 sizeof(DEVICE_OBJECT
) + sizeof(DEVOBJ_EXTENSION
);
398 DPRINT("TotalSize %x\n", TotalSize
);
400 /* Create the Device Object */
401 Status
= ObCreateObject(KernelMode
,
409 (PVOID
*)&CreatedDeviceObject
);
411 if (!NT_SUCCESS(Status
))
413 DPRINT1("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status
);
417 /* Clear the whole Object and extension so we don't null stuff manually */
418 RtlZeroMemory(CreatedDeviceObject
, TotalSize
);
419 DPRINT("CreatedDeviceObject %x\n", CreatedDeviceObject
);
422 * Setup the Type and Size. Note that we don't use the aligned size,
423 * because that's only padding for the DevObjExt and not part of the Object.
425 CreatedDeviceObject
->Type
= IO_TYPE_DEVICE
;
426 CreatedDeviceObject
->Size
= sizeof(DEVICE_OBJECT
) + DeviceExtensionSize
;
428 /* The kernel extension is after the driver internal extension */
429 DeviceObjectExtension
= (PDEVOBJ_EXTENSION
)
430 ((ULONG_PTR
)(CreatedDeviceObject
+ 1) +
431 AlignedDeviceExtensionSize
);
433 /* Set the Type and Size. Question: why is Size 0 on Windows? */
434 DPRINT("DeviceObjectExtension %x\n", DeviceObjectExtension
);
435 DeviceObjectExtension
->Type
= IO_TYPE_DEVICE_OBJECT_EXTENSION
;
436 DeviceObjectExtension
->Size
= 0;
438 /* Link the Object and Extension */
439 DeviceObjectExtension
->DeviceObject
= CreatedDeviceObject
;
440 CreatedDeviceObject
->DeviceObjectExtension
= DeviceObjectExtension
;
442 /* Set Device Object Data */
443 CreatedDeviceObject
->DeviceType
= DeviceType
;
444 CreatedDeviceObject
->Characteristics
= DeviceCharacteristics
;
445 CreatedDeviceObject
->DeviceExtension
= CreatedDeviceObject
+ 1;
446 CreatedDeviceObject
->StackSize
= 1;
447 CreatedDeviceObject
->AlignmentRequirement
= 1; /* FIXME */
450 /* FIXME: After the Driver is Loaded, the flag below should be removed */
451 CreatedDeviceObject
->Flags
= DO_DEVICE_INITIALIZING
;
452 if (Exclusive
) CreatedDeviceObject
->Flags
|= DO_EXCLUSIVE
;
453 if (DeviceName
) CreatedDeviceObject
->Flags
|= DO_DEVICE_HAS_NAME
;
455 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
456 if (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
||
457 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_VIRTUAL_DISK
||
458 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
||
459 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
)
462 IopAttachVpb(CreatedDeviceObject
);
464 /* Initialize Lock Event */
465 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
466 SynchronizationEvent
,
470 /* Set the right Sector Size */
473 case FILE_DEVICE_DISK_FILE_SYSTEM
:
474 case FILE_DEVICE_DISK
:
475 case FILE_DEVICE_VIRTUAL_DISK
:
476 CreatedDeviceObject
->SectorSize
= 512;
479 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
480 CreatedDeviceObject
->SectorSize
= 2048;
484 /* Create the Device Queue */
485 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
487 /* Insert the Object */
488 Status
= ObInsertObject(CreatedDeviceObject
,
490 FILE_READ_DATA
| FILE_WRITE_DATA
,
495 if (!NT_SUCCESS(Status
))
497 DPRINT1("Cannot insert Device Object into Handle Table\n");
498 *DeviceObject
= NULL
;
502 /* Now do the final linking */
503 ObReferenceObject(DriverObject
);
504 CreatedDeviceObject
->DriverObject
= DriverObject
;
505 CreatedDeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
506 DriverObject
->DeviceObject
= CreatedDeviceObject
;
508 /* Close the temporary handle, but do an extra reference first so it doesn't die */
509 ObReferenceObject(CreatedDeviceObject
);
512 /* Return to caller */
513 *DeviceObject
= CreatedDeviceObject
;
514 return STATUS_SUCCESS
;
525 IoDeleteDevice(PDEVICE_OBJECT DeviceObject
)
527 PDEVICE_OBJECT Previous
;
529 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
530 IoUnregisterShutdownNotification(DeviceObject
);
532 /* Remove the timer if it exists */
533 if (DeviceObject
->Timer
)
535 IopRemoveTimerFromTimerList(DeviceObject
->Timer
);
536 ExFreePool(DeviceObject
->Timer
);
539 /* Remove device from driver device list */
540 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
541 if (Previous
== DeviceObject
)
543 DeviceObject
->DriverObject
->DeviceObject
= DeviceObject
->NextDevice
;
547 while (Previous
->NextDevice
!= DeviceObject
)
548 Previous
= Previous
->NextDevice
;
549 Previous
->NextDevice
= DeviceObject
->NextDevice
;
552 /* I guess this should be removed later... but it shouldn't cause problems */
553 DeviceObject
->DeviceObjectExtension
->ExtensionFlags
|= DOE_DELETE_PENDING
;
554 ObDereferenceObject(DeviceObject
);
565 IoDetachDevice(PDEVICE_OBJECT TargetDevice
)
567 DPRINT("IoDetachDevice(TargetDevice %x)\n", TargetDevice
);
569 /* Remove the attachment */
570 TargetDevice
->AttachedDevice
->DeviceObjectExtension
->AttachedTo
= NULL
;
571 TargetDevice
->AttachedDevice
= NULL
;
579 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject
,
580 IN PDEVICE_OBJECT
*DeviceObjectList
,
581 IN ULONG DeviceObjectListSize
,
582 OUT PULONG ActualNumberDeviceObjects
)
584 ULONG ActualDevices
= 1;
585 PDEVICE_OBJECT CurrentDevice
= DriverObject
->DeviceObject
;
587 DPRINT1("IoEnumerateDeviceObjectList\n");
589 /* Find out how many devices we'll enumerate */
590 while ((CurrentDevice
= CurrentDevice
->NextDevice
))
595 /* Go back to the first */
596 CurrentDevice
= DriverObject
->DeviceObject
;
598 /* Start by at least returning this */
599 *ActualNumberDeviceObjects
= ActualDevices
;
601 /* Check if we can support so many */
602 if ((ActualDevices
* 4) > DeviceObjectListSize
)
604 /* Fail because the buffer was too small */
605 return STATUS_BUFFER_TOO_SMALL
;
608 /* Check if the caller only wanted the size */
609 if (DeviceObjectList
)
611 /* Loop through all the devices */
612 while (ActualDevices
)
614 /* Reference each Device */
615 ObReferenceObject(CurrentDevice
);
617 /* Add it to the list */
618 *DeviceObjectList
= CurrentDevice
;
620 /* Go to the next one */
621 CurrentDevice
= CurrentDevice
->NextDevice
;
627 /* Return the status */
628 return STATUS_SUCCESS
;
632 * IoGetAttachedDevice
639 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
641 PDEVICE_OBJECT Current
= DeviceObject
;
643 /* Get the last attached device */
644 while (Current
->AttachedDevice
)
646 Current
= Current
->AttachedDevice
;
654 * IoGetAttachedDeviceReference
661 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
663 PDEVICE_OBJECT Current
= IoGetAttachedDevice(DeviceObject
);
665 /* Reference the ATtached Device */
666 ObReferenceObject(Current
);
675 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject
)
677 /* Return the attached Device */
678 return (DeviceObject
->DeviceObjectExtension
->AttachedTo
);
682 * IoGetDeviceObjectPointer
689 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName
,
690 IN ACCESS_MASK DesiredAccess
,
691 OUT PFILE_OBJECT
*FileObject
,
692 OUT PDEVICE_OBJECT
*DeviceObject
)
694 /* Call the helper routine for a normal operation */
695 return IopGetDeviceObjectPointer(ObjectName
,
707 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject
,
708 OUT PDEVICE_OBJECT
*DiskDeviceObject
)
710 PDEVOBJ_EXTENSION DeviceExtension
;
714 /* Make sure there's a VPB */
715 if (!FileSystemDeviceObject
->Vpb
) return STATUS_INVALID_PARAMETER
;
718 IoAcquireVpbSpinLock(&OldIrql
);
720 /* Get the Device Extension */
721 DeviceExtension
= FileSystemDeviceObject
->DeviceObjectExtension
;
723 /* Make sure this one has a VPB too */
724 Vpb
= DeviceExtension
->Vpb
;
725 if (!Vpb
) return STATUS_INVALID_PARAMETER
;
727 /* Make sure someone it's mounted */
728 if ((!Vpb
->ReferenceCount
) || (Vpb
->Flags
& VPB_MOUNTED
)) return STATUS_VOLUME_DISMOUNTED
;
730 /* Return the Disk Device Object */
731 *DiskDeviceObject
= Vpb
->RealDevice
;
733 /* Release the lock */
734 IoReleaseVpbSpinLock(OldIrql
);
735 return STATUS_SUCCESS
;
743 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject
)
745 PDEVOBJ_EXTENSION DeviceExtension
= DeviceObject
->DeviceObjectExtension
;
746 PDEVICE_OBJECT LowerDeviceObject
= NULL
;
748 /* Make sure it's not getting deleted */
749 if (DeviceExtension
->ExtensionFlags
& (DOE_UNLOAD_PENDING
|
752 DOE_REMOVE_PROCESSED
))
754 /* Get the Lower Device Object */
755 LowerDeviceObject
= DeviceExtension
->AttachedTo
;
758 ObReferenceObject(LowerDeviceObject
);
762 return LowerDeviceObject
;
766 * IoGetRelatedDeviceObject
769 * See "Windows NT File System Internals", page 633 - 634.
776 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject
)
778 PDEVICE_OBJECT DeviceObject
= FileObject
->DeviceObject
;
780 /* Get logical volume mounted on a physical/virtual/logical device */
781 if (FileObject
->Vpb
&& FileObject
->Vpb
->DeviceObject
)
783 DeviceObject
= FileObject
->Vpb
->DeviceObject
;
787 * Check if file object has an associated device object mounted by some
790 if (FileObject
->DeviceObject
->Vpb
&&
791 FileObject
->DeviceObject
->Vpb
->DeviceObject
)
793 DeviceObject
= FileObject
->DeviceObject
->Vpb
->DeviceObject
;
796 /* Return the highest attached device */
797 return IoGetAttachedDevice(DeviceObject
);
805 IoRegisterLastChanceShutdownNotification(
806 IN PDEVICE_OBJECT DeviceObject
810 return STATUS_NOT_IMPLEMENTED
;
818 IoSetStartIoAttributes(
819 IN PDEVICE_OBJECT DeviceObject
,
820 IN BOOLEAN DeferredStartIo
,
821 IN BOOLEAN NonCancelable
832 IoSynchronousInvalidateDeviceRelations(
833 IN PDEVICE_OBJECT DeviceObject
,
834 IN DEVICE_RELATION_TYPE Type
845 IoValidateDeviceIoControlAccess(
847 IN ULONG RequiredAccess
851 return STATUS_NOT_IMPLEMENTED
;