1 /* $Id: device.c,v 1.65 2003/12/15 17:50:23 ekohl Exp $
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>
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 ***************************************************************/
42 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
43 IN PDEVICE_OBJECT TargetDevice
)
45 PDEVICE_OBJECT AttachedDevice
;
47 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
51 AttachedDevice
= IoAttachDeviceToDeviceStack (SourceDevice
,
53 if (AttachedDevice
== NULL
)
54 return STATUS_NO_SUCH_DEVICE
;
56 return STATUS_SUCCESS
;
64 IoDeleteDevice(PDEVICE_OBJECT DeviceObject
)
66 PDEVICE_OBJECT Previous
;
68 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
69 IoUnregisterShutdownNotification(DeviceObject
);
71 /* remove the timer if it exists */
72 if (DeviceObject
->Timer
)
74 IoStopTimer(DeviceObject
);
75 ExFreePool(DeviceObject
->Timer
);
78 /* free device extension */
79 if (DeviceObject
->DeviceObjectExtension
)
80 ExFreePool (DeviceObject
->DeviceObjectExtension
);
82 /* remove device from driver device list */
83 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
84 if (Previous
== DeviceObject
)
86 DeviceObject
->DriverObject
->DeviceObject
= DeviceObject
->NextDevice
;
90 while (Previous
->NextDevice
!= DeviceObject
)
91 Previous
= Previous
->NextDevice
;
92 Previous
->NextDevice
= DeviceObject
->NextDevice
;
95 ObDereferenceObject (DeviceObject
);
104 IoGetRelatedDeviceObject (
105 IN PFILE_OBJECT FileObject
108 /*Win NT File System Internals, page 633-634*/
110 /*get logical volume mounted on a physical/virtual/logical device*/
111 if (FileObject
->Vpb
&& FileObject
->Vpb
->DeviceObject
)
113 return IoGetAttachedDevice(FileObject
->Vpb
->DeviceObject
);
116 /*check if fileobject has an associated device object mounted by some other file system*/
117 if (FileObject
->DeviceObject
->Vpb
&& FileObject
->DeviceObject
->Vpb
->DeviceObject
)
119 return IoGetAttachedDevice(FileObject
->DeviceObject
->Vpb
->DeviceObject
);
122 return IoGetAttachedDevice(FileObject
->DeviceObject
);
131 IoGetDeviceObjectPointer (
132 IN PUNICODE_STRING ObjectName
,
133 IN ACCESS_MASK DesiredAccess
,
134 OUT PFILE_OBJECT
* FileObject
,
135 OUT PDEVICE_OBJECT
* DeviceObject
)
137 OBJECT_ATTRIBUTES ObjectAttributes
;
138 IO_STATUS_BLOCK StatusBlock
;
139 PFILE_OBJECT LocalFileObject
;
143 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
149 InitializeObjectAttributes (&ObjectAttributes
,
155 Status
= NtOpenFile (&FileHandle
,
160 FILE_NON_DIRECTORY_FILE
);
161 if (!NT_SUCCESS(Status
))
164 Status
= ObReferenceObjectByHandle (FileHandle
,
168 (PVOID
*)&LocalFileObject
,
170 if (NT_SUCCESS(Status
))
172 *DeviceObject
= IoGetRelatedDeviceObject (LocalFileObject
);
173 *FileObject
= LocalFileObject
;
175 NtClose (FileHandle
);
186 IoDetachDevice(PDEVICE_OBJECT TargetDevice
)
189 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice
);
198 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
200 PDEVICE_OBJECT Current
= DeviceObject
;
202 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
204 while (Current
->AttachedDevice
!=NULL
)
206 Current
= Current
->AttachedDevice
;
207 // DPRINT("Current %x\n",Current);
210 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
219 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
221 PDEVICE_OBJECT Current
= DeviceObject
;
223 while (Current
->AttachedDevice
!=NULL
)
225 Current
= Current
->AttachedDevice
;
228 ObReferenceObject(Current
);
235 PDEVICE_OBJECT STDCALL
236 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice
,
237 PDEVICE_OBJECT TargetDevice
)
239 PDEVICE_OBJECT AttachedDevice
;
241 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
242 SourceDevice
,TargetDevice
);
244 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
245 AttachedDevice
->AttachedDevice
= SourceDevice
;
246 SourceDevice
->AttachedDevice
= NULL
;
247 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
248 SourceDevice
->Vpb
= AttachedDevice
->Vpb
;
249 return(AttachedDevice
);
254 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject
,
257 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
258 Irp
->IoStatus
.Information
= 0;
260 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
261 return(STATUS_NOT_IMPLEMENTED
);
266 IopCreateDriverObject(PDRIVER_OBJECT
*DriverObject
,
267 PUNICODE_STRING ServiceName
,
269 PVOID DriverImageStart
,
270 ULONG DriverImageSize
)
272 PDRIVER_OBJECT Object
;
274 WCHAR NameBuffer
[MAX_PATH
];
275 UNICODE_STRING DriverName
;
276 OBJECT_ATTRIBUTES ObjectAttributes
;
279 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n", DriverObject
, ServiceName
, FileSystem
,
280 DriverImageStart
, DriverImageSize
);
282 *DriverObject
= NULL
;
284 /* Create ModuleName string */
285 if ((ServiceName
!= NULL
) && (ServiceName
->Buffer
!= NULL
))
287 if (FileSystem
== TRUE
)
288 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
290 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
291 wcscat(NameBuffer
, ServiceName
->Buffer
);
293 RtlInitUnicodeString(&DriverName
,
295 DPRINT("Driver name: '%wZ'\n", &DriverName
);
298 /* Initialize ObjectAttributes for driver object */
299 InitializeObjectAttributes(&ObjectAttributes
,
300 ((ServiceName
!= NULL
) && (ServiceName
->Buffer
!= NULL
))? &DriverName
: NULL
,
305 /* Create driver object */
306 Status
= ObCreateObject(KernelMode
,
311 sizeof(DRIVER_OBJECT
),
315 if (!NT_SUCCESS(Status
))
320 /* Create driver extension */
321 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
322 ExAllocatePoolWithTag(NonPagedPool
,
323 sizeof(DRIVER_EXTENSION
),
324 TAG_DRIVER_EXTENSION
);
325 if (Object
->DriverExtension
== NULL
)
328 return(STATUS_INSUFFICIENT_RESOURCES
);
331 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
333 Object
->Type
= InternalDriverType
;
335 Object
->DriverStart
= DriverImageStart
;
336 Object
->DriverSize
= DriverImageSize
;
338 for (i
=0; i
<=IRP_MJ_MAXIMUM_FUNCTION
; i
++)
340 Object
->MajorFunction
[i
] = (PDRIVER_DISPATCH
) IopDefaultDispatchFunction
;
343 *DriverObject
= Object
;
345 return STATUS_SUCCESS
;
349 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode
,
352 return STATUS_SUCCESS
;
356 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
359 IO_STATUS_BLOCK IoStatusBlock
;
360 PDRIVER_OBJECT DriverObject
;
361 IO_STACK_LOCATION Stack
;
365 DriverObject
= DeviceNode
->DriverObject
;
367 if (DriverObject
->DriverExtension
->AddDevice
)
369 /* This is a Plug and Play driver */
370 DPRINT("Plug and Play driver found\n");
372 assert(DeviceNode
->Pdo
);
374 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
375 DriverObject
->DriverExtension
->AddDevice
);
376 Status
= DriverObject
->DriverExtension
->AddDevice(
377 DriverObject
, DeviceNode
->Pdo
);
378 if (!NT_SUCCESS(Status
))
383 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
385 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
387 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->Pdo
);
389 if (Fdo
== DeviceNode
->Pdo
)
391 /* FIXME: What do we do? Unload the driver or just disable the device? */
392 DbgPrint("An FDO was not attached\n");
396 /* FIXME: Put some resources in the IRP for the device */
397 Stack
.Parameters
.StartDevice
.AllocatedResources
= NULL
;
398 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= NULL
;
400 Status
= IopInitiatePnpIrp(
405 if (!NT_SUCCESS(Status
))
407 DPRINT("IopInitiatePnpIrp() failed\n");
408 ObDereferenceObject(Fdo
);
412 if (Fdo
->DeviceType
== FILE_DEVICE_BUS_EXTENDER
)
414 DPRINT("Bus extender found\n");
416 Status
= IopInvalidateDeviceRelations(
417 DeviceNode
, BusRelations
, BootDriver
);
418 if (!NT_SUCCESS(Status
))
420 ObDereferenceObject(Fdo
);
424 else if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
427 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
429 /* There can be only one system power device */
430 if (!SystemPowerDeviceNodeCreated
)
432 PopSystemPowerDeviceNode
= DeviceNode
;
433 SystemPowerDeviceNodeCreated
= TRUE
;
437 ObDereferenceObject(Fdo
);
440 return STATUS_SUCCESS
;
444 IopInitializeService(
445 PDEVICE_NODE DeviceNode
,
446 PUNICODE_STRING ImagePath
)
448 PMODULE_OBJECT ModuleObject
;
451 ModuleObject
= LdrGetModuleObject(&DeviceNode
->ServiceName
);
452 if (ModuleObject
== NULL
)
454 /* The module is currently not loaded, so load it now */
456 Status
= LdrLoadModule(ImagePath
, &ModuleObject
);
457 if (!NT_SUCCESS(Status
))
459 /* FIXME: Log the error */
460 CPRINT("Driver load failed\n");
464 Status
= IopInitializeDriver(ModuleObject
->EntryPoint
, DeviceNode
, FALSE
,
465 ModuleObject
->Base
, ModuleObject
->Length
,
467 if (!NT_SUCCESS(Status
))
469 LdrUnloadModule(ModuleObject
);
471 /* FIXME: Log the error */
472 CPRINT("A driver failed to initialize\n");
477 /* FIXME: This doesn't work for two devices with the same driver */
478 Status
= IopInitializeDevice(DeviceNode
, FALSE
);
485 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry
,
486 PDEVICE_NODE DeviceNode
,
487 BOOLEAN FileSystemDriver
,
488 PVOID DriverImageStart
,
489 ULONG DriverImageSize
,
492 * FUNCTION: Called to initalize a loaded driver
494 * DriverEntry = Pointer to driver entry routine
495 * DeviceNode = Pointer to device node
498 WCHAR RegistryKeyBuffer
[MAX_PATH
];
499 PDRIVER_OBJECT DriverObject
;
500 UNICODE_STRING RegistryKey
;
503 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
504 DriverEntry
, DeviceNode
);
506 Status
= IopCreateDriverObject(&DriverObject
,
507 &DeviceNode
->ServiceName
,
511 if (!NT_SUCCESS(Status
))
516 DeviceNode
->DriverObject
= DriverObject
;
518 if (DeviceNode
->ServiceName
.Buffer
)
520 wcscpy(RegistryKeyBuffer
, DRIVER_REGISTRY_KEY_BASENAME
);
521 wcscat(RegistryKeyBuffer
, DeviceNode
->ServiceName
.Buffer
);
522 RtlInitUnicodeString(&RegistryKey
, RegistryKeyBuffer
);
526 RtlInitUnicodeString(&RegistryKey
, NULL
);
529 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
530 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
532 IopMarkLastReinitializeDriver();
534 Status
= DriverEntry(DriverObject
, &RegistryKey
);
535 if (!NT_SUCCESS(Status
))
537 DeviceNode
->DriverObject
= NULL
;
538 ExFreePool(DriverObject
->DriverExtension
);
539 ObMakeTemporaryObject(DriverObject
);
540 ObDereferenceObject(DriverObject
);
544 IopReinitializeDrivers();
546 Status
= IopInitializeDevice(DeviceNode
, BootDriver
);
556 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
557 PUNICODE_STRING TargetDeviceName
,
558 PDEVICE_OBJECT
* AttachedDevice
)
560 * FUNCTION: Layers a device over the highest device in a device stack
562 * SourceDevice = Device to attached
563 * TargetDevice = Name of the target device
564 * AttachedDevice (OUT) = Caller storage for the device attached to
568 PFILE_OBJECT FileObject
;
569 PDEVICE_OBJECT TargetDevice
;
571 Status
= IoGetDeviceObjectPointer(TargetDeviceName
,
572 FILE_READ_ATTRIBUTES
,
576 if (!NT_SUCCESS(Status
))
581 *AttachedDevice
= IoAttachDeviceToDeviceStack(SourceDevice
,
584 ObDereferenceObject(FileObject
);
585 return STATUS_SUCCESS
;
590 IopCreateDevice(PVOID ObjectBody
,
593 POBJECT_ATTRIBUTES ObjectAttributes
)
596 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
597 ObjectBody
, Parent
, RemainingPath
);
599 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
601 return(STATUS_UNSUCCESSFUL
);
604 return(STATUS_SUCCESS
);
612 IoCreateDevice(PDRIVER_OBJECT DriverObject
,
613 ULONG DeviceExtensionSize
,
614 PUNICODE_STRING DeviceName
,
615 DEVICE_TYPE DeviceType
,
616 ULONG DeviceCharacteristics
,
618 PDEVICE_OBJECT
* DeviceObject
)
620 * FUNCTION: Allocates memory for and intializes a device object for use for
623 * DriverObject : Driver object passed by iomgr when the driver was
625 * DeviceExtensionSize : Number of bytes for the device extension
626 * DeviceName : Unicode name of device
627 * DeviceType : Device type
628 * DeviceCharacteristics : Bit mask of device characteristics
629 * Exclusive : True if only one thread can access the device at a
633 * DeviceObject : Contains a pointer to allocated device object
634 * if the call succeeded
635 * NOTES: See the DDK documentation for more information
638 PDEVICE_OBJECT CreatedDeviceObject
;
639 OBJECT_ATTRIBUTES ObjectAttributes
;
642 assert_irql(PASSIVE_LEVEL
);
644 if (DeviceName
!= NULL
)
646 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject
,
651 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject
);
654 if (DeviceName
!= NULL
)
656 InitializeObjectAttributes(&ObjectAttributes
,DeviceName
,0,NULL
,NULL
);
657 Status
= ObCreateObject(KernelMode
,
662 sizeof(DEVICE_OBJECT
),
665 (PVOID
*)&CreatedDeviceObject
);
669 Status
= ObCreateObject(KernelMode
,
674 sizeof(DEVICE_OBJECT
),
677 (PVOID
*)&CreatedDeviceObject
);
680 *DeviceObject
= NULL
;
682 if (!NT_SUCCESS(Status
))
684 DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status
);
688 if (DriverObject
->DeviceObject
== NULL
)
690 DriverObject
->DeviceObject
= CreatedDeviceObject
;
691 CreatedDeviceObject
->NextDevice
= NULL
;
695 CreatedDeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
696 DriverObject
->DeviceObject
= CreatedDeviceObject
;
699 CreatedDeviceObject
->Type
= DeviceType
;
700 CreatedDeviceObject
->DriverObject
= DriverObject
;
701 CreatedDeviceObject
->CurrentIrp
= NULL
;
702 CreatedDeviceObject
->Flags
= 0;
704 CreatedDeviceObject
->DeviceExtension
=
705 ExAllocatePoolWithTag(NonPagedPool
, DeviceExtensionSize
,
706 TAG_DEVICE_EXTENSION
);
707 if (DeviceExtensionSize
> 0 && CreatedDeviceObject
->DeviceExtension
== NULL
)
709 ExFreePool(CreatedDeviceObject
);
710 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES
);
711 return(STATUS_INSUFFICIENT_RESOURCES
);
714 if (DeviceExtensionSize
> 0)
716 RtlZeroMemory(CreatedDeviceObject
->DeviceExtension
,
717 DeviceExtensionSize
);
720 CreatedDeviceObject
->AttachedDevice
= NULL
;
721 CreatedDeviceObject
->DeviceType
= DeviceType
;
722 CreatedDeviceObject
->StackSize
= 1;
723 CreatedDeviceObject
->AlignmentRequirement
= 1;
724 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
726 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
727 SynchronizationEvent
,
730 /* FIXME: Do we need to add network drives too?! */
731 if (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
||
732 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
||
733 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
)
735 IoAttachVpb(CreatedDeviceObject
);
738 *DeviceObject
= CreatedDeviceObject
;
740 return(STATUS_SUCCESS
);
746 IoOpenDeviceInstanceKey (
755 return(STATUS_NOT_IMPLEMENTED
);
761 IoQueryDeviceEnumInfo (