3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/device.c
6 * PURPOSE: Manage devices
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES ****************************************************************/
14 #define NTOS_MODE_KERNEL
16 #include <internal/io.h>
17 #include <internal/po.h>
18 #include <internal/ldr.h>
19 #include <internal/id.h>
20 #include <internal/pool.h>
21 #include <internal/registry.h>
27 #include <internal/debug.h>
29 /* GLOBALS *******************************************************************/
31 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
32 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
33 #define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T')
35 #define DRIVER_REGISTRY_KEY_BASENAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
37 /* FUNCTIONS ***************************************************************/
43 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
44 IN PDEVICE_OBJECT TargetDevice)
46 PDEVICE_OBJECT AttachedDevice;
48 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
52 AttachedDevice = IoAttachDeviceToDeviceStack (SourceDevice,
54 if (AttachedDevice == NULL)
55 return STATUS_NO_SUCH_DEVICE;
57 return STATUS_SUCCESS;
65 IoDeleteDevice(PDEVICE_OBJECT DeviceObject)
67 PDEVICE_OBJECT Previous;
69 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
70 IoUnregisterShutdownNotification(DeviceObject);
72 /* remove the timer if it exists */
73 if (DeviceObject->Timer)
75 IoStopTimer(DeviceObject);
76 ExFreePool(DeviceObject->Timer);
79 /* free device extension */
80 if (DeviceObject->DeviceObjectExtension)
81 ExFreePool (DeviceObject->DeviceObjectExtension);
83 /* remove device from driver device list */
84 Previous = DeviceObject->DriverObject->DeviceObject;
85 if (Previous == DeviceObject)
87 DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice;
91 while (Previous->NextDevice != DeviceObject)
92 Previous = Previous->NextDevice;
93 Previous->NextDevice = DeviceObject->NextDevice;
96 ObDereferenceObject (DeviceObject);
105 IoGetRelatedDeviceObject (
106 IN PFILE_OBJECT FileObject
109 /*Win NT File System Internals, page 633-634*/
111 /*get logical volume mounted on a physical/virtual/logical device*/
112 if (FileObject->Vpb && FileObject->Vpb->DeviceObject)
114 return IoGetAttachedDevice(FileObject->Vpb->DeviceObject);
117 /*check if fileobject has an associated device object mounted by some other file system*/
118 if (FileObject->DeviceObject->Vpb && FileObject->DeviceObject->Vpb->DeviceObject)
120 return IoGetAttachedDevice(FileObject->DeviceObject->Vpb->DeviceObject);
123 return IoGetAttachedDevice(FileObject->DeviceObject);
132 IoGetDeviceObjectPointer (
133 IN PUNICODE_STRING ObjectName,
134 IN ACCESS_MASK DesiredAccess,
135 OUT PFILE_OBJECT * FileObject,
136 OUT PDEVICE_OBJECT * DeviceObject)
138 OBJECT_ATTRIBUTES ObjectAttributes;
139 IO_STATUS_BLOCK StatusBlock;
140 PFILE_OBJECT LocalFileObject;
144 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
150 InitializeObjectAttributes (&ObjectAttributes,
156 Status = NtOpenFile (&FileHandle,
161 FILE_NON_DIRECTORY_FILE);
162 if (!NT_SUCCESS(Status))
165 Status = ObReferenceObjectByHandle (FileHandle,
169 (PVOID*)&LocalFileObject,
171 if (NT_SUCCESS(Status))
173 *DeviceObject = IoGetRelatedDeviceObject (LocalFileObject);
174 *FileObject = LocalFileObject;
176 NtClose (FileHandle);
187 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
190 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice);
199 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
201 PDEVICE_OBJECT Current = DeviceObject;
203 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
205 while (Current->AttachedDevice!=NULL)
207 Current = Current->AttachedDevice;
208 // DPRINT("Current %x\n",Current);
211 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
220 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
222 PDEVICE_OBJECT Current = DeviceObject;
224 while (Current->AttachedDevice!=NULL)
226 Current = Current->AttachedDevice;
229 ObReferenceObject(Current);
236 PDEVICE_OBJECT STDCALL
237 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
238 PDEVICE_OBJECT TargetDevice)
240 PDEVICE_OBJECT AttachedDevice;
242 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
243 SourceDevice,TargetDevice);
245 AttachedDevice = IoGetAttachedDevice(TargetDevice);
246 AttachedDevice->AttachedDevice = SourceDevice;
247 SourceDevice->AttachedDevice = NULL;
248 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
249 SourceDevice->Vpb = AttachedDevice->Vpb;
250 return(AttachedDevice);
257 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject,
258 PDRIVER_REINITIALIZE ReinitRoutine,
265 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject,
268 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
269 Irp->IoStatus.Information = 0;
271 IoCompleteRequest(Irp, IO_NO_INCREMENT);
272 return(STATUS_NOT_IMPLEMENTED);
277 IopCreateDriverObject(PDRIVER_OBJECT *DriverObject,
278 PUNICODE_STRING ServiceName,
280 PVOID DriverImageStart,
281 ULONG DriverImageSize)
283 PDRIVER_OBJECT Object;
284 HANDLE DriverHandle = 0;
286 WCHAR NameBuffer[MAX_PATH];
287 UNICODE_STRING DriverName;
288 OBJECT_ATTRIBUTES ObjectAttributes;
291 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n", DriverObject, ServiceName, FileSystem,
292 DriverImageStart, DriverImageSize);
294 *DriverObject = NULL;
296 /* Create ModuleName string */
297 if ((ServiceName != NULL) && (ServiceName->Buffer != NULL))
299 if (FileSystem == TRUE)
300 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
302 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
303 wcscat(NameBuffer, ServiceName->Buffer);
305 RtlInitUnicodeString(&DriverName,
307 DPRINT("Driver name: '%wZ'\n", &DriverName);
310 /* Initialize ObjectAttributes for driver object */
311 InitializeObjectAttributes(&ObjectAttributes,
312 ((ServiceName != NULL) && (ServiceName->Buffer != NULL))? &DriverName : NULL,
317 /* Create module object */
318 Status = ObRosCreateObject(&DriverHandle,
319 STANDARD_RIGHTS_REQUIRED,
323 if (!NT_SUCCESS(Status))
328 NtClose(DriverHandle);
330 /* Create driver extension */
331 Object->DriverExtension = (PDRIVER_EXTENSION)
332 ExAllocatePoolWithTag(NonPagedPool,
333 sizeof(DRIVER_EXTENSION),
334 TAG_DRIVER_EXTENSION);
335 if (Object->DriverExtension == NULL)
338 return(STATUS_INSUFFICIENT_RESOURCES);
341 RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
343 Object->Type = InternalDriverType;
345 Object->DriverStart = DriverImageStart;
346 Object->DriverSize = DriverImageSize;
348 for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
350 Object->MajorFunction[i] = (PDRIVER_DISPATCH) IopDefaultDispatchFunction;
353 *DriverObject = Object;
355 return STATUS_SUCCESS;
359 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode,
362 return STATUS_SUCCESS;
366 IopInitializeDevice(PDEVICE_NODE DeviceNode,
367 BOOLEAN BootDriversOnly)
369 IO_STATUS_BLOCK IoStatusBlock;
370 PDRIVER_OBJECT DriverObject;
371 IO_STACK_LOCATION Stack;
375 DriverObject = DeviceNode->DriverObject;
377 if (DriverObject->DriverExtension->AddDevice)
379 /* This is a Plug and Play driver */
380 DPRINT("Plug and Play driver found\n");
382 assert(DeviceNode->Pdo);
384 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
385 DriverObject->DriverExtension->AddDevice);
386 Status = DriverObject->DriverExtension->AddDevice(
387 DriverObject, DeviceNode->Pdo);
388 if (!NT_SUCCESS(Status))
393 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
395 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
397 Fdo = IoGetAttachedDeviceReference(DeviceNode->Pdo);
399 if (Fdo == DeviceNode->Pdo)
401 /* FIXME: What do we do? Unload the driver or just disable the device? */
402 DbgPrint("An FDO was not attached\n");
406 /* FIXME: Put some resources in the IRP for the device */
407 Stack.Parameters.StartDevice.AllocatedResources = NULL;
408 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
410 Status = IopInitiatePnpIrp(
415 if (!NT_SUCCESS(Status))
417 DPRINT("IopInitiatePnpIrp() failed\n");
418 ObDereferenceObject(Fdo);
422 if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER)
424 DPRINT("Bus extender found\n");
426 Status = IopInterrogateBusExtender(
427 DeviceNode, Fdo, BootDriversOnly);
428 if (!NT_SUCCESS(Status))
430 ObDereferenceObject(Fdo);
434 else if (Fdo->DeviceType == FILE_DEVICE_ACPI)
437 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
439 /* There can be only one system power device */
440 if (!SystemPowerDeviceNodeCreated)
442 PopSystemPowerDeviceNode = DeviceNode;
443 SystemPowerDeviceNodeCreated = TRUE;
447 ObDereferenceObject(Fdo);
450 return STATUS_SUCCESS;
454 IopInitializeService(
455 PDEVICE_NODE DeviceNode,
456 PUNICODE_STRING ImagePath)
458 PMODULE_OBJECT ModuleObject;
461 ModuleObject = LdrGetModuleObject(&DeviceNode->ServiceName);
462 if (ModuleObject == NULL)
464 /* The module is currently not loaded, so load it now */
466 Status = LdrLoadModule(ImagePath, &ModuleObject);
467 if (!NT_SUCCESS(Status))
469 /* FIXME: Log the error */
470 CPRINT("Driver load failed\n");
474 Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode, FALSE,
475 ModuleObject->Base, ModuleObject->Length);
476 if (!NT_SUCCESS(Status))
478 LdrUnloadModule(ModuleObject);
480 /* FIXME: Log the error */
481 CPRINT("A driver failed to initialize\n");
486 Status = IopInitializeDevice(DeviceNode, TRUE);
492 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode)
494 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
495 UNICODE_STRING ImagePath;
499 Status = RtlpGetRegistryHandle(
500 RTL_REGISTRY_SERVICES,
501 DeviceNode->ServiceName.Buffer,
504 if (!NT_SUCCESS(Status))
506 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
510 RtlZeroMemory(QueryTable, sizeof(QueryTable));
512 RtlInitUnicodeString(&ImagePath, NULL);
514 QueryTable[0].Name = L"ImagePath";
515 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
516 QueryTable[0].EntryContext = &ImagePath;
518 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
525 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
527 if (NT_SUCCESS(Status))
529 DPRINT("Got ImagePath %S\n", ImagePath.Buffer);
531 Status = IopInitializeService(DeviceNode, &ImagePath);
533 RtlFreeUnicodeString(&ImagePath);
540 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry,
541 PDEVICE_NODE DeviceNode,
542 BOOLEAN FileSystemDriver,
543 PVOID DriverImageStart,
544 ULONG DriverImageSize)
546 * FUNCTION: Called to initalize a loaded driver
548 * DriverEntry = Pointer to driver entry routine
549 * DeviceNode = Pointer to device node
552 WCHAR RegistryKeyBuffer[MAX_PATH];
553 PDRIVER_OBJECT DriverObject;
554 UNICODE_STRING RegistryKey;
557 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
558 DriverEntry, DeviceNode);
560 Status = IopCreateDriverObject(&DriverObject,
561 &DeviceNode->ServiceName,
565 if (!NT_SUCCESS(Status))
570 DeviceNode->DriverObject = DriverObject;
572 if (DeviceNode->ServiceName.Buffer)
574 wcscpy(RegistryKeyBuffer, DRIVER_REGISTRY_KEY_BASENAME);
575 wcscat(RegistryKeyBuffer, DeviceNode->ServiceName.Buffer);
576 RtlInitUnicodeString(&RegistryKey, RegistryKeyBuffer);
580 RtlInitUnicodeString(&RegistryKey, NULL);
583 DPRINT("RegistryKey: %wZ\n", &RegistryKey);
584 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
586 Status = DriverEntry(DriverObject, &RegistryKey);
587 if (!NT_SUCCESS(Status))
589 DeviceNode->DriverObject = NULL;
590 ExFreePool(DriverObject->DriverExtension);
591 ObMakeTemporaryObject(DriverObject);
592 ObDereferenceObject(DriverObject);
596 Status = IopInitializeDevice(DeviceNode, TRUE);
606 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
607 PUNICODE_STRING TargetDeviceName,
608 PDEVICE_OBJECT* AttachedDevice)
610 * FUNCTION: Layers a device over the highest device in a device stack
612 * SourceDevice = Device to attached
613 * TargetDevice = Name of the target device
614 * AttachedDevice (OUT) = Caller storage for the device attached to
618 PFILE_OBJECT FileObject;
619 PDEVICE_OBJECT TargetDevice;
621 Status = IoGetDeviceObjectPointer(TargetDeviceName,
622 FILE_READ_ATTRIBUTES,
626 if (!NT_SUCCESS(Status))
631 *AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice,
634 ObDereferenceObject(FileObject);
635 return STATUS_SUCCESS;
640 IopCreateDevice(PVOID ObjectBody,
643 POBJECT_ATTRIBUTES ObjectAttributes)
646 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
647 ObjectBody, Parent, RemainingPath);
649 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
651 return(STATUS_UNSUCCESSFUL);
654 return(STATUS_SUCCESS);
662 IoCreateDevice(PDRIVER_OBJECT DriverObject,
663 ULONG DeviceExtensionSize,
664 PUNICODE_STRING DeviceName,
665 DEVICE_TYPE DeviceType,
666 ULONG DeviceCharacteristics,
668 PDEVICE_OBJECT* DeviceObject)
670 * FUNCTION: Allocates memory for and intializes a device object for use for
673 * DriverObject : Driver object passed by iomgr when the driver was
675 * DeviceExtensionSize : Number of bytes for the device extension
676 * DeviceName : Unicode name of device
677 * DeviceType : Device type
678 * DeviceCharacteristics : Bit mask of device characteristics
679 * Exclusive : True if only one thread can access the device at a
683 * DeviceObject : Contains a pointer to allocated device object
684 * if the call succeeded
685 * NOTES: See the DDK documentation for more information
688 PDEVICE_OBJECT CreatedDeviceObject;
689 OBJECT_ATTRIBUTES ObjectAttributes;
692 assert_irql(PASSIVE_LEVEL);
694 if (DeviceName != NULL)
696 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject,
701 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject);
704 if (DeviceName != NULL)
706 InitializeObjectAttributes(&ObjectAttributes,DeviceName,0,NULL,NULL);
707 Status = ObRosCreateObject(NULL,
711 (PVOID*)&CreatedDeviceObject);
715 Status = ObRosCreateObject(NULL,
719 (PVOID*)&CreatedDeviceObject);
722 *DeviceObject = NULL;
724 if (!NT_SUCCESS(Status))
726 DPRINT("IoCreateDevice() ObRosCreateObject failed, status: 0x%08X\n", Status);
730 if (DriverObject->DeviceObject == NULL)
732 DriverObject->DeviceObject = CreatedDeviceObject;
733 CreatedDeviceObject->NextDevice = NULL;
737 CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
738 DriverObject->DeviceObject = CreatedDeviceObject;
741 CreatedDeviceObject->Type = DeviceType;
742 CreatedDeviceObject->DriverObject = DriverObject;
743 CreatedDeviceObject->CurrentIrp = NULL;
744 CreatedDeviceObject->Flags = 0;
746 CreatedDeviceObject->DeviceExtension =
747 ExAllocatePoolWithTag(NonPagedPool, DeviceExtensionSize,
748 TAG_DEVICE_EXTENSION);
749 if (DeviceExtensionSize > 0 && CreatedDeviceObject->DeviceExtension == NULL)
751 ExFreePool(CreatedDeviceObject);
752 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
753 return(STATUS_INSUFFICIENT_RESOURCES);
756 if (DeviceExtensionSize > 0)
758 RtlZeroMemory(CreatedDeviceObject->DeviceExtension,
759 DeviceExtensionSize);
762 CreatedDeviceObject->AttachedDevice = NULL;
763 CreatedDeviceObject->DeviceType = DeviceType;
764 CreatedDeviceObject->StackSize = 1;
765 CreatedDeviceObject->AlignmentRequirement = 1;
766 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
768 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
769 SynchronizationEvent,
772 /* FIXME: Do we need to add network drives too?! */
773 if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
774 CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
775 CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
777 IoAttachVpb(CreatedDeviceObject);
780 *DeviceObject = CreatedDeviceObject;
782 return(STATUS_SUCCESS);
788 IoOpenDeviceInstanceKey (
797 return(STATUS_NOT_IMPLEMENTED);
803 IoQueryDeviceEnumInfo (