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 */
80 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
81 * Undocumented by W32!
82 * See also IoCreateDevice().
84 /* free device extension */
85 if (DeviceObject->DeviceObjectExtension)
86 ExFreePool (DeviceObject->DeviceObjectExtension);
87 #endif /* LIBCAPTIVE */
89 /* remove device from driver device list */
90 Previous = DeviceObject->DriverObject->DeviceObject;
91 if (Previous == DeviceObject)
93 DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice;
97 while (Previous->NextDevice != DeviceObject)
98 Previous = Previous->NextDevice;
99 Previous->NextDevice = DeviceObject->NextDevice;
102 ObDereferenceObject (DeviceObject);
109 IoGetRelatedDeviceObject (
110 IN PFILE_OBJECT FileObject
113 return (FileObject->DeviceObject);
119 IoGetDeviceObjectPointer (
120 IN PUNICODE_STRING ObjectName,
121 IN ACCESS_MASK DesiredAccess,
122 OUT PFILE_OBJECT * FileObject,
123 OUT PDEVICE_OBJECT * DeviceObject)
125 OBJECT_ATTRIBUTES ObjectAttributes;
126 IO_STATUS_BLOCK StatusBlock;
127 PFILE_OBJECT LocalFileObject;
131 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
137 InitializeObjectAttributes (&ObjectAttributes,
143 Status = NtOpenFile (&FileHandle,
148 FILE_NON_DIRECTORY_FILE);
149 if (!NT_SUCCESS(Status))
152 Status = ObReferenceObjectByHandle (FileHandle,
156 (PVOID*)&LocalFileObject,
158 if (NT_SUCCESS(Status))
160 *DeviceObject = IoGetRelatedDeviceObject (LocalFileObject);
161 *FileObject = LocalFileObject;
163 NtClose (FileHandle);
171 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
174 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice);
177 #endif /* LIBCAPTIVE */
181 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
183 PDEVICE_OBJECT Current = DeviceObject;
185 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
187 while (Current->AttachedDevice!=NULL)
189 Current = Current->AttachedDevice;
190 // DPRINT("Current %x\n",Current);
193 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
201 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
203 PDEVICE_OBJECT Current = DeviceObject;
205 while (Current->AttachedDevice!=NULL)
207 Current = Current->AttachedDevice;
210 ObReferenceObject(Current);
214 PDEVICE_OBJECT STDCALL
215 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
216 PDEVICE_OBJECT TargetDevice)
218 PDEVICE_OBJECT AttachedDevice;
220 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
221 SourceDevice,TargetDevice);
223 AttachedDevice = IoGetAttachedDevice(TargetDevice);
224 AttachedDevice->AttachedDevice = SourceDevice;
225 SourceDevice->AttachedDevice = NULL;
226 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
227 SourceDevice->Vpb = AttachedDevice->Vpb;
228 return(AttachedDevice);
232 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject,
233 PDRIVER_REINITIALIZE ReinitRoutine,
240 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject,
243 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
244 Irp->IoStatus.Information = 0;
246 IoCompleteRequest(Irp, IO_NO_INCREMENT);
247 return(STATUS_NOT_IMPLEMENTED);
252 IopCreateDriverObject(PDRIVER_OBJECT *DriverObject,
253 PUNICODE_STRING ServiceName,
256 PDRIVER_OBJECT Object;
257 HANDLE DriverHandle = 0;
259 WCHAR NameBuffer[MAX_PATH];
260 UNICODE_STRING DriverName;
261 OBJECT_ATTRIBUTES ObjectAttributes;
264 DPRINT("IopCreateDriverObject(%p '%wZ' %x)\n", DriverObject, ServiceName, FileSystem);
266 *DriverObject = NULL;
268 /* Create ModuleName string */
269 if (ServiceName != NULL)
271 if (FileSystem == TRUE)
272 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
274 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
275 wcscat(NameBuffer, ServiceName->Buffer);
277 RtlInitUnicodeString(&DriverName,
279 DPRINT("Driver name: '%wZ'\n", &DriverName);
282 /* Initialize ObjectAttributes for ModuleObject */
283 InitializeObjectAttributes(&ObjectAttributes,
284 (ServiceName != NULL)? &DriverName : NULL,
289 /* Create module object */
290 Status = ObCreateObject(&DriverHandle,
291 STANDARD_RIGHTS_REQUIRED,
295 if (!NT_SUCCESS(Status))
300 NtClose(DriverHandle);
302 /* Create driver extension */
303 Object->DriverExtension = (PDRIVER_EXTENSION)
304 ExAllocatePoolWithTag(NonPagedPool,
305 sizeof(DRIVER_EXTENSION),
306 TAG_DRIVER_EXTENSION);
307 if (Object->DriverExtension == NULL)
310 return(STATUS_INSUFFICIENT_RESOURCES);
313 RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
315 Object->Type = InternalDriverType;
317 for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
319 Object->MajorFunction[i] = (PDRIVER_DISPATCH) IopDefaultDispatchFunction;
322 *DriverObject = Object;
324 return STATUS_SUCCESS;
328 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode,
331 return STATUS_SUCCESS;
335 IopInitializeDevice(PDEVICE_NODE DeviceNode,
336 BOOLEAN BootDriversOnly)
338 IO_STATUS_BLOCK IoStatusBlock;
339 PDRIVER_OBJECT DriverObject;
340 IO_STACK_LOCATION Stack;
344 DriverObject = DeviceNode->DriverObject;
346 if (DriverObject->DriverExtension->AddDevice)
348 /* This is a Plug and Play driver */
349 DPRINT("Plug and Play driver found\n");
351 assert(DeviceNode->Pdo);
353 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
354 DriverObject->DriverExtension->AddDevice);
355 Status = DriverObject->DriverExtension->AddDevice(
356 DriverObject, DeviceNode->Pdo);
357 if (!NT_SUCCESS(Status))
362 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
364 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
366 Fdo = IoGetAttachedDeviceReference(DeviceNode->Pdo);
368 if (Fdo == DeviceNode->Pdo)
370 /* FIXME: What do we do? Unload the driver or just disable the device? */
371 DbgPrint("An FDO was not attached\n");
375 /* FIXME: Put some resources in the IRP for the device */
376 Stack.Parameters.StartDevice.AllocatedResources = NULL;
377 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = NULL;
379 Status = IopInitiatePnpIrp(
384 if (!NT_SUCCESS(Status))
386 DPRINT("IopInitiatePnpIrp() failed\n");
387 ObDereferenceObject(Fdo);
391 if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER)
393 DPRINT("Bus extender found\n");
395 Status = IopInterrogateBusExtender(
396 DeviceNode, Fdo, BootDriversOnly);
397 if (!NT_SUCCESS(Status))
399 ObDereferenceObject(Fdo);
403 else if (Fdo->DeviceType == FILE_DEVICE_ACPI)
406 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
408 /* There can be only one system power device */
409 if (!SystemPowerDeviceNodeCreated)
411 PopSystemPowerDeviceNode = DeviceNode;
412 SystemPowerDeviceNodeCreated = TRUE;
416 ObDereferenceObject(Fdo);
419 return STATUS_SUCCESS;
423 IopInitializeService(
424 PDEVICE_NODE DeviceNode,
425 PUNICODE_STRING ImagePath)
427 PMODULE_OBJECT ModuleObject;
430 ModuleObject = LdrGetModuleObject(&DeviceNode->ServiceName);
431 if (ModuleObject == NULL)
433 /* The module is currently not loaded, so load it now */
435 Status = LdrLoadModule(ImagePath, &ModuleObject);
436 if (!NT_SUCCESS(Status))
438 /* FIXME: Log the error */
439 CPRINT("Driver load failed\n");
443 Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode, FALSE);
444 if (!NT_SUCCESS(Status))
446 LdrUnloadModule(ModuleObject);
448 /* FIXME: Log the error */
449 CPRINT("A driver failed to initialize\n");
454 Status = IopInitializeDevice(DeviceNode, TRUE);
460 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode)
462 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
463 UNICODE_STRING ImagePath;
467 Status = RtlpGetRegistryHandle(
468 RTL_REGISTRY_SERVICES,
469 DeviceNode->ServiceName.Buffer,
472 if (!NT_SUCCESS(Status))
474 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
478 RtlZeroMemory(QueryTable, sizeof(QueryTable));
480 RtlInitUnicodeString(&ImagePath, NULL);
482 QueryTable[0].Name = L"ImagePath";
483 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
484 QueryTable[0].EntryContext = &ImagePath;
486 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
493 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
495 if (NT_SUCCESS(Status))
497 DPRINT("Got ImagePath %S\n", ImagePath.Buffer);
499 Status = IopInitializeService(DeviceNode, &ImagePath);
501 RtlFreeUnicodeString(&ImagePath);
508 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry,
509 PDEVICE_NODE DeviceNode,
510 BOOLEAN FileSystemDriver)
512 * FUNCTION: Called to initalize a loaded driver
514 * DriverEntry = Pointer to driver entry routine
515 * DeviceNode = Pointer to device node
518 WCHAR RegistryKeyBuffer[MAX_PATH];
519 PDRIVER_OBJECT DriverObject;
520 UNICODE_STRING RegistryKey;
523 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
524 DriverEntry, DeviceNode);
526 Status = IopCreateDriverObject(&DriverObject,
527 &DeviceNode->ServiceName,
529 if (!NT_SUCCESS(Status))
534 DeviceNode->DriverObject = DriverObject;
536 if (DeviceNode->ServiceName.Buffer)
538 wcscpy(RegistryKeyBuffer, DRIVER_REGISTRY_KEY_BASENAME);
539 wcscat(RegistryKeyBuffer, DeviceNode->ServiceName.Buffer);
540 RtlInitUnicodeString(&RegistryKey, RegistryKeyBuffer);
544 RtlInitUnicodeString(&RegistryKey, NULL);
547 DPRINT("RegistryKey: %wZ\n", &RegistryKey);
548 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
550 Status = DriverEntry(DriverObject, &RegistryKey);
551 if (!NT_SUCCESS(Status))
553 DeviceNode->DriverObject = NULL;
554 ExFreePool(DriverObject->DriverExtension);
555 ObMakeTemporaryObject(DriverObject);
556 ObDereferenceObject(DriverObject);
560 Status = IopInitializeDevice(DeviceNode, TRUE);
567 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
568 PUNICODE_STRING TargetDevice,
569 PDEVICE_OBJECT* AttachedDevice)
571 * FUNCTION: Layers a device over the highest device in a device stack
573 * SourceDevice = Device to attached
574 * TargetDevice = Name of the target device
575 * AttachedDevice (OUT) = Caller storage for the device attached to
581 #endif /* LIBCAPTIVE */
584 IopCreateDevice(PVOID ObjectBody,
587 POBJECT_ATTRIBUTES ObjectAttributes)
590 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
591 ObjectBody, Parent, RemainingPath);
593 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
595 return(STATUS_UNSUCCESSFUL);
598 return(STATUS_SUCCESS);
602 IoCreateDevice(PDRIVER_OBJECT DriverObject,
603 ULONG DeviceExtensionSize,
604 PUNICODE_STRING DeviceName,
605 DEVICE_TYPE DeviceType,
606 ULONG DeviceCharacteristics,
608 PDEVICE_OBJECT* DeviceObject)
610 * FUNCTION: Allocates memory for and intializes a device object for use for
613 * DriverObject : Driver object passed by iomgr when the driver was
615 * DeviceExtensionSize : Number of bytes for the device extension
616 * DeviceName : Unicode name of device
617 * DeviceType : Device type
618 * DeviceCharacteristics : Bit mask of device characteristics
619 * Exclusive : True if only one thread can access the device at a
623 * DeviceObject : Contains a pointer to allocated device object
624 * if the call succeeded
625 * NOTES: See the DDK documentation for more information
628 PDEVICE_OBJECT CreatedDeviceObject;
629 OBJECT_ATTRIBUTES ObjectAttributes;
633 assert_irql(PASSIVE_LEVEL);
635 assert(sizeof(CreatedDeviceObject->Queue.Wcb) == 40);
636 assert(sizeof(CreatedDeviceObject->DeviceQueue) == 20);
637 assert(sizeof(CreatedDeviceObject->Dpc) == 32);
638 assert(sizeof(CreatedDeviceObject->DeviceLock) == 16);
639 assert(sizeof(DEVICE_OBJECT) == 184);
641 if (DeviceName != NULL)
643 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject,
648 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject);
652 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
653 * Undocumented by W32!
654 * See also IoDeleteDevice().
657 IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT) + DeviceExtensionSize;
658 #endif /* LIBCAPTIVE */
660 if (DeviceName != NULL)
662 InitializeObjectAttributes(&ObjectAttributes,DeviceName,0,NULL,NULL);
663 Status = ObCreateObject(&DeviceHandle,
667 (PVOID*)&CreatedDeviceObject);
671 Status = ObCreateObject(&DeviceHandle,
675 (PVOID*)&CreatedDeviceObject);
679 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
680 * Undocumented by W32!
681 * See also IoDeleteDevice().
684 IoDeviceObjectType->NonpagedPoolCharge = sizeof (DEVICE_OBJECT); /* restore */
685 #endif /* LIBCAPTIVE */
687 *DeviceObject = NULL;
689 if (!NT_SUCCESS(Status))
691 DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status);
695 if (DriverObject->DeviceObject == NULL)
697 DriverObject->DeviceObject = CreatedDeviceObject;
698 CreatedDeviceObject->NextDevice = NULL;
702 CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
703 DriverObject->DeviceObject = CreatedDeviceObject;
706 CreatedDeviceObject->Type = DeviceType;
707 CreatedDeviceObject->Size = sizeof (*CreatedDeviceObject);
708 CreatedDeviceObject->ReferenceCount = 0; /* or 1? it is floating unused this way */
709 CreatedDeviceObject->DriverObject = DriverObject;
710 CreatedDeviceObject->CurrentIrp = NULL;
711 CreatedDeviceObject->Flags = 0;
712 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
713 CreatedDeviceObject->Timer = NULL;
714 CreatedDeviceObject->Vpb = NULL;
717 CreatedDeviceObject->DeviceExtension =
718 ExAllocatePoolWithTag(NonPagedPool, DeviceExtensionSize,
719 TAG_DEVICE_EXTENSION);
720 #else /* !LIBCAPTIVE */
721 /* W32 expects CreatedDeviceObject->DeviceExtension to follow *CreatedDeviceObject!
722 * Undocumented by W32!
723 * See also IoDeleteDevice().
725 CreatedDeviceObject->DeviceExtension = (void *)(CreatedDeviceObject+1);
726 #endif /* LIBCAPTIVE */
727 if (DeviceExtensionSize > 0 && CreatedDeviceObject->DeviceExtension == NULL)
729 ExFreePool(CreatedDeviceObject);
730 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
731 return(STATUS_INSUFFICIENT_RESOURCES);
734 if (DeviceExtensionSize > 0)
736 RtlZeroMemory(CreatedDeviceObject->DeviceExtension,
737 DeviceExtensionSize);
740 CreatedDeviceObject->AttachedDevice = NULL;
741 CreatedDeviceObject->DeviceType = DeviceType;
742 CreatedDeviceObject->StackSize = 1;
743 CreatedDeviceObject->AlignmentRequirement = 1;
744 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
746 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
747 SynchronizationEvent,
750 /* FIXME: Do we need to add network drives too?! */
751 if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
752 CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
753 CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
755 IoAttachVpb(CreatedDeviceObject);
758 *DeviceObject = CreatedDeviceObject;
760 return(STATUS_SUCCESS);
767 IoOpenDeviceInstanceKey (
776 return(STATUS_NOT_IMPLEMENTED);
782 IoQueryDeviceEnumInfo (
791 #endif /* LIBCAPTIVE */