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 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/po.h>
17 #include <internal/ldr.h>
18 #include <internal/id.h>
19 #include <internal/pool.h>
20 #include <internal/registry.h>
26 #include <internal/debug.h>
28 /* GLOBALS *******************************************************************/
30 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
31 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
32 #define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T')
34 #define DRIVER_REGISTRY_KEY_BASENAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
36 /* FUNCTIONS ***************************************************************/
41 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
42 IN PDEVICE_OBJECT TargetDevice)
44 PDEVICE_OBJECT AttachedDevice;
46 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
50 AttachedDevice = IoAttachDeviceToDeviceStack (SourceDevice,
52 if (AttachedDevice == NULL)
53 return STATUS_NO_SUCH_DEVICE;
55 return STATUS_SUCCESS;
58 #endif /* LIBCAPTIVE */
61 IoDeleteDevice(PDEVICE_OBJECT DeviceObject)
63 PDEVICE_OBJECT Previous;
65 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
66 IoUnregisterShutdownNotification(DeviceObject);
68 /* remove the timer if it exists */
69 if (DeviceObject->Timer)
72 IoStopTimer(DeviceObject);
73 ExFreePool(DeviceObject->Timer);
74 #else /* !LIBCAPTIVE */
76 #endif /* !LIBCAPTIVE */
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);
103 IoGetRelatedDeviceObject (
104 IN PFILE_OBJECT FileObject
107 return (FileObject->DeviceObject);
113 IoGetDeviceObjectPointer (
114 IN PUNICODE_STRING ObjectName,
115 IN ACCESS_MASK DesiredAccess,
116 OUT PFILE_OBJECT * FileObject,
117 OUT PDEVICE_OBJECT * DeviceObject)
119 OBJECT_ATTRIBUTES ObjectAttributes;
120 IO_STATUS_BLOCK StatusBlock;
121 PFILE_OBJECT LocalFileObject;
125 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
131 InitializeObjectAttributes (&ObjectAttributes,
137 Status = NtOpenFile (&FileHandle,
142 FILE_NON_DIRECTORY_FILE);
143 if (!NT_SUCCESS(Status))
146 Status = ObReferenceObjectByHandle (FileHandle,
150 (PVOID*)&LocalFileObject,
152 if (NT_SUCCESS(Status))
154 *DeviceObject = IoGetRelatedDeviceObject (LocalFileObject);
155 *FileObject = LocalFileObject;
157 NtClose (FileHandle);
165 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
168 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice);
171 #endif /* LIBCAPTIVE */
175 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
177 PDEVICE_OBJECT Current = DeviceObject;
179 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
181 while (Current->AttachedDevice!=NULL)
183 Current = Current->AttachedDevice;
184 // DPRINT("Current %x\n",Current);
187 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
195 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
197 PDEVICE_OBJECT Current = DeviceObject;
199 while (Current->AttachedDevice!=NULL)
201 Current = Current->AttachedDevice;
204 ObReferenceObject(Current);
208 PDEVICE_OBJECT STDCALL
209 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
210 PDEVICE_OBJECT TargetDevice)
212 PDEVICE_OBJECT AttachedDevice;
214 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
215 SourceDevice,TargetDevice);
217 AttachedDevice = IoGetAttachedDevice(TargetDevice);
218 AttachedDevice->AttachedDevice = SourceDevice;
219 SourceDevice->AttachedDevice = NULL;
220 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
221 SourceDevice->Vpb = AttachedDevice->Vpb;
222 return(AttachedDevice);
226 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject,
227 PDRIVER_REINITIALIZE ReinitRoutine,
234 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject,
237 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
238 Irp->IoStatus.Information = 0;
240 IoCompleteRequest(Irp, IO_NO_INCREMENT);
241 return(STATUS_NOT_IMPLEMENTED);
246 IopCreateDriverObject(PDRIVER_OBJECT *DriverObject,
247 PUNICODE_STRING ServiceName,
250 PDRIVER_OBJECT Object;
251 HANDLE DriverHandle = 0;
253 WCHAR NameBuffer[MAX_PATH];
254 UNICODE_STRING DriverName;
255 OBJECT_ATTRIBUTES ObjectAttributes;
258 DPRINT("IopCreateDriverObject(%p '%wZ' %x)\n", DriverObject, ServiceName, FileSystem);
260 *DriverObject = NULL;
262 /* Create ModuleName string */
263 if (ServiceName != NULL)
265 if (FileSystem == TRUE)
266 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
268 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
269 wcscat(NameBuffer, ServiceName->Buffer);
271 RtlInitUnicodeString(&DriverName,
273 DPRINT("Driver name: '%wZ'\n", &DriverName);
276 /* Initialize ObjectAttributes for ModuleObject */
277 InitializeObjectAttributes(&ObjectAttributes,
278 (ServiceName != NULL)? &DriverName : NULL,
283 /* Create module object */
284 Status = ObCreateObject(&DriverHandle,
285 STANDARD_RIGHTS_REQUIRED,
289 if (!NT_SUCCESS(Status))
294 NtClose(DriverHandle);
296 /* Create driver extension */
297 Object->DriverExtension = (PDRIVER_EXTENSION)
298 ExAllocatePoolWithTag(NonPagedPool,
299 sizeof(DRIVER_EXTENSION),
300 TAG_DRIVER_EXTENSION);
301 if (Object->DriverExtension == NULL)
304 return(STATUS_INSUFFICIENT_RESOURCES);
307 RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
309 Object->Type = InternalDriverType;
311 for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
313 Object->MajorFunction[i] = (PDRIVER_DISPATCH) IopDefaultDispatchFunction;
316 *DriverObject = Object;
318 return STATUS_SUCCESS;
322 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode,
325 return STATUS_SUCCESS;
329 IopInitializeDevice(PDEVICE_NODE DeviceNode,
330 BOOLEAN BootDriversOnly)
332 IO_STATUS_BLOCK IoStatusBlock;
333 PDRIVER_OBJECT DriverObject;
334 IO_STACK_LOCATION Stack;
338 DriverObject = DeviceNode->DriverObject;
340 if (DriverObject->DriverExtension->AddDevice)
342 /* This is a Plug and Play driver */
343 DPRINT("Plug and Play driver found\n");
345 assert(DeviceNode->Pdo);
347 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
348 DriverObject->DriverExtension->AddDevice);
349 Status = DriverObject->DriverExtension->AddDevice(
350 DriverObject, DeviceNode->Pdo);
351 if (!NT_SUCCESS(Status))
356 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
358 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
360 Fdo = IoGetAttachedDeviceReference(DeviceNode->Pdo);
362 if (Fdo == DeviceNode->Pdo)
364 /* FIXME: What do we do? Unload the driver or just disable the device? */
365 DbgPrint("An FDO was not attached\n");
369 /* FIXME: Put some resources in the IRP for the device */
370 Stack.Parameters.StartDevice.AllocatedResources = NULL;
371 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
373 Status = IopInitiatePnpIrp(
378 if (!NT_SUCCESS(Status))
380 DPRINT("IopInitiatePnpIrp() failed\n");
381 ObDereferenceObject(Fdo);
385 if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER)
387 DPRINT("Bus extender found\n");
389 Status = IopInterrogateBusExtender(
390 DeviceNode, Fdo, BootDriversOnly);
391 if (!NT_SUCCESS(Status))
393 ObDereferenceObject(Fdo);
397 else if (Fdo->DeviceType == FILE_DEVICE_ACPI)
400 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
402 /* There can be only one system power device */
403 if (!SystemPowerDeviceNodeCreated)
405 PopSystemPowerDeviceNode = DeviceNode;
406 SystemPowerDeviceNodeCreated = TRUE;
410 ObDereferenceObject(Fdo);
413 return STATUS_SUCCESS;
417 IopInitializeService(
418 PDEVICE_NODE DeviceNode,
419 PUNICODE_STRING ImagePath)
421 PMODULE_OBJECT ModuleObject;
424 ModuleObject = LdrGetModuleObject(&DeviceNode->ServiceName);
425 if (ModuleObject == NULL)
427 /* The module is currently not loaded, so load it now */
429 Status = LdrLoadModule(ImagePath, &ModuleObject);
430 if (!NT_SUCCESS(Status))
432 /* FIXME: Log the error */
433 CPRINT("Driver load failed\n");
437 Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode, FALSE);
438 if (!NT_SUCCESS(Status))
440 LdrUnloadModule(ModuleObject);
442 /* FIXME: Log the error */
443 CPRINT("A driver failed to initialize\n");
448 Status = IopInitializeDevice(DeviceNode, TRUE);
454 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode)
456 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
457 UNICODE_STRING ImagePath;
461 Status = RtlpGetRegistryHandle(
462 RTL_REGISTRY_SERVICES,
463 DeviceNode->ServiceName.Buffer,
466 if (!NT_SUCCESS(Status))
468 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
472 RtlZeroMemory(QueryTable, sizeof(QueryTable));
474 RtlInitUnicodeString(&ImagePath, NULL);
476 QueryTable[0].Name = L"ImagePath";
477 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
478 QueryTable[0].EntryContext = &ImagePath;
480 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
487 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
489 if (NT_SUCCESS(Status))
491 DPRINT("Got ImagePath %S\n", ImagePath.Buffer);
493 Status = IopInitializeService(DeviceNode, &ImagePath);
495 RtlFreeUnicodeString(&ImagePath);
502 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry,
503 PDEVICE_NODE DeviceNode,
504 BOOLEAN FileSystemDriver)
506 * FUNCTION: Called to initalize a loaded driver
508 * DriverEntry = Pointer to driver entry routine
509 * DeviceNode = Pointer to device node
512 WCHAR RegistryKeyBuffer[MAX_PATH];
513 PDRIVER_OBJECT DriverObject;
514 UNICODE_STRING RegistryKey;
517 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
518 DriverEntry, DeviceNode);
520 Status = IopCreateDriverObject(&DriverObject,
521 &DeviceNode->ServiceName,
523 if (!NT_SUCCESS(Status))
528 DeviceNode->DriverObject = DriverObject;
530 if (DeviceNode->ServiceName.Buffer)
532 wcscpy(RegistryKeyBuffer, DRIVER_REGISTRY_KEY_BASENAME);
533 wcscat(RegistryKeyBuffer, DeviceNode->ServiceName.Buffer);
534 RtlInitUnicodeString(&RegistryKey, RegistryKeyBuffer);
538 RtlInitUnicodeString(&RegistryKey, NULL);
541 DPRINT("RegistryKey: %wZ\n", &RegistryKey);
542 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
544 Status = DriverEntry(DriverObject, &RegistryKey);
545 if (!NT_SUCCESS(Status))
547 DeviceNode->DriverObject = NULL;
548 ExFreePool(DriverObject->DriverExtension);
549 ObMakeTemporaryObject(DriverObject);
550 ObDereferenceObject(DriverObject);
554 Status = IopInitializeDevice(DeviceNode, TRUE);
561 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
562 PUNICODE_STRING TargetDevice,
563 PDEVICE_OBJECT* AttachedDevice)
565 * FUNCTION: Layers a device over the highest device in a device stack
567 * SourceDevice = Device to attached
568 * TargetDevice = Name of the target device
569 * AttachedDevice (OUT) = Caller storage for the device attached to
575 #endif /* LIBCAPTIVE */
578 IopCreateDevice(PVOID ObjectBody,
581 POBJECT_ATTRIBUTES ObjectAttributes)
584 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
585 ObjectBody, Parent, RemainingPath);
587 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
589 return(STATUS_UNSUCCESSFUL);
592 return(STATUS_SUCCESS);
596 IoCreateDevice(PDRIVER_OBJECT DriverObject,
597 ULONG DeviceExtensionSize,
598 PUNICODE_STRING DeviceName,
599 DEVICE_TYPE DeviceType,
600 ULONG DeviceCharacteristics,
602 PDEVICE_OBJECT* DeviceObject)
604 * FUNCTION: Allocates memory for and intializes a device object for use for
607 * DriverObject : Driver object passed by iomgr when the driver was
609 * DeviceExtensionSize : Number of bytes for the device extension
610 * DeviceName : Unicode name of device
611 * DeviceType : Device type
612 * DeviceCharacteristics : Bit mask of device characteristics
613 * Exclusive : True if only one thread can access the device at a
617 * DeviceObject : Contains a pointer to allocated device object
618 * if the call succeeded
619 * NOTES: See the DDK documentation for more information
622 PDEVICE_OBJECT CreatedDeviceObject;
623 OBJECT_ATTRIBUTES ObjectAttributes;
627 assert_irql(PASSIVE_LEVEL);
629 assert(sizeof(CreatedDeviceObject->Queue.Wcb) == 40);
630 assert(sizeof(CreatedDeviceObject->DeviceQueue) == 20);
631 assert(sizeof(CreatedDeviceObject->Dpc) == 32);
632 assert(sizeof(CreatedDeviceObject->DeviceLock) == 16);
633 assert(sizeof(DEVICE_OBJECT) == 184);
635 if (DeviceName != NULL)
637 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject,
642 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject);
646 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
647 * Undocumented by W32!
650 IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT) + DeviceExtensionSize;
651 #endif /* LIBCAPTIVE */
653 if (DeviceName != NULL)
655 InitializeObjectAttributes(&ObjectAttributes,DeviceName,0,NULL,NULL);
656 Status = ObCreateObject(&DeviceHandle,
660 (PVOID*)&CreatedDeviceObject);
664 Status = ObCreateObject(&DeviceHandle,
668 (PVOID*)&CreatedDeviceObject);
672 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
673 * Undocumented by W32!
676 IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT); /* restore */
677 #endif /* LIBCAPTIVE */
679 *DeviceObject = NULL;
681 if (!NT_SUCCESS(Status))
683 DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status);
687 if (DriverObject->DeviceObject == NULL)
689 DriverObject->DeviceObject = CreatedDeviceObject;
690 CreatedDeviceObject->NextDevice = NULL;
694 CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
695 DriverObject->DeviceObject = CreatedDeviceObject;
698 CreatedDeviceObject->Type = DeviceType;
699 CreatedDeviceObject->Size = sizeof (*CreatedDeviceObject);
700 CreatedDeviceObject->ReferenceCount = 0; /* or 1? it is floating unused this way */
701 CreatedDeviceObject->DriverObject = DriverObject;
702 CreatedDeviceObject->CurrentIrp = NULL;
703 CreatedDeviceObject->Flags = 0;
704 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
707 CreatedDeviceObject->DeviceExtension =
708 ExAllocatePoolWithTag(NonPagedPool, DeviceExtensionSize,
709 TAG_DEVICE_EXTENSION);
710 #else /* !LIBCAPTIVE */
711 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
712 * Undocumented by W32!
714 CreatedDeviceObject->DeviceExtension = (void *)(CreatedDeviceObject+1);
715 #endif /* LIBCAPTIVE */
716 if (DeviceExtensionSize > 0 && CreatedDeviceObject->DeviceExtension == NULL)
718 ExFreePool(CreatedDeviceObject);
719 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
720 return(STATUS_INSUFFICIENT_RESOURCES);
723 if (DeviceExtensionSize > 0)
725 RtlZeroMemory(CreatedDeviceObject->DeviceExtension,
726 DeviceExtensionSize);
729 CreatedDeviceObject->AttachedDevice = NULL;
730 CreatedDeviceObject->DeviceType = DeviceType;
731 CreatedDeviceObject->StackSize = 1;
732 CreatedDeviceObject->AlignmentRequirement = 1;
733 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
735 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
736 SynchronizationEvent,
739 /* FIXME: Do we need to add network drives too?! */
740 if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
741 CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
742 CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
744 IoAttachVpb(CreatedDeviceObject);
747 *DeviceObject = CreatedDeviceObject;
749 return(STATUS_SUCCESS);
756 IoOpenDeviceInstanceKey (
765 return(STATUS_NOT_IMPLEMENTED);
771 IoQueryDeviceEnumInfo (
780 #endif /* LIBCAPTIVE */