1 /* $Id: device.c,v 1.49 2002/10/03 19:22:27 robd 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 #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 ***************************************************************/
39 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
40 IN PDEVICE_OBJECT TargetDevice
)
42 PDEVICE_OBJECT AttachedDevice
;
44 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
48 AttachedDevice
= IoAttachDeviceToDeviceStack (SourceDevice
,
50 if (AttachedDevice
== NULL
)
51 return STATUS_NO_SUCH_DEVICE
;
53 return STATUS_SUCCESS
;
58 IoDeleteDevice(PDEVICE_OBJECT DeviceObject
)
60 PDEVICE_OBJECT Previous
;
62 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
63 IoUnregisterShutdownNotification(DeviceObject
);
65 /* remove the timer if it exists */
66 if (DeviceObject
->Timer
)
68 IoStopTimer(DeviceObject
);
69 ExFreePool(DeviceObject
->Timer
);
72 /* free device extension */
73 if (DeviceObject
->DeviceObjectExtension
)
74 ExFreePool (DeviceObject
->DeviceObjectExtension
);
76 /* remove device from driver device list */
77 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
78 if (Previous
== DeviceObject
)
80 DeviceObject
->DriverObject
->DeviceObject
= DeviceObject
->NextDevice
;
84 while (Previous
->NextDevice
!= DeviceObject
)
85 Previous
= Previous
->NextDevice
;
86 Previous
->NextDevice
= DeviceObject
->NextDevice
;
89 ObDereferenceObject (DeviceObject
);
95 IoGetRelatedDeviceObject (
96 IN PFILE_OBJECT FileObject
99 return (FileObject
->DeviceObject
);
105 IoGetDeviceObjectPointer (
106 IN PUNICODE_STRING ObjectName
,
107 IN ACCESS_MASK DesiredAccess
,
108 OUT PFILE_OBJECT
* FileObject
,
109 OUT PDEVICE_OBJECT
* DeviceObject
)
111 OBJECT_ATTRIBUTES ObjectAttributes
;
112 IO_STATUS_BLOCK StatusBlock
;
113 PFILE_OBJECT LocalFileObject
;
117 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
123 InitializeObjectAttributes (&ObjectAttributes
,
129 Status
= NtOpenFile (&FileHandle
,
134 FILE_NON_DIRECTORY_FILE
);
135 if (!NT_SUCCESS(Status
))
138 Status
= ObReferenceObjectByHandle (FileHandle
,
142 (PVOID
*)&LocalFileObject
,
144 if (NT_SUCCESS(Status
))
146 *DeviceObject
= IoGetRelatedDeviceObject (LocalFileObject
);
147 *FileObject
= LocalFileObject
;
149 NtClose (FileHandle
);
157 IoDetachDevice(PDEVICE_OBJECT TargetDevice
)
160 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice
);
166 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
168 PDEVICE_OBJECT Current
= DeviceObject
;
170 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
172 while (Current
->AttachedDevice
!=NULL
)
174 Current
= Current
->AttachedDevice
;
175 // DPRINT("Current %x\n",Current);
178 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
184 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
186 PDEVICE_OBJECT Current
= DeviceObject
;
188 while (Current
->AttachedDevice
!=NULL
)
190 Current
= Current
->AttachedDevice
;
193 ObReferenceObject(Current
);
197 PDEVICE_OBJECT STDCALL
198 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice
,
199 PDEVICE_OBJECT TargetDevice
)
201 PDEVICE_OBJECT AttachedDevice
;
203 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
204 SourceDevice
,TargetDevice
);
206 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
207 AttachedDevice
->AttachedDevice
= SourceDevice
;
208 SourceDevice
->AttachedDevice
= NULL
;
209 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
210 SourceDevice
->Vpb
= AttachedDevice
->Vpb
;
211 return(AttachedDevice
);
215 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject
,
216 PDRIVER_REINITIALIZE ReinitRoutine
,
223 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject
,
226 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
227 Irp
->IoStatus
.Information
= 0;
229 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
230 return(STATUS_NOT_IMPLEMENTED
);
235 IopCreateDriverObject(PDRIVER_OBJECT
*DriverObject
,
236 PUNICODE_STRING ServiceName
,
239 PDRIVER_OBJECT Object
;
240 HANDLE DriverHandle
= 0;
242 WCHAR NameBuffer
[MAX_PATH
];
243 UNICODE_STRING DriverName
;
244 OBJECT_ATTRIBUTES ObjectAttributes
;
247 DPRINT("IopCreateDriverObject(%p '%wZ' %x)\n", DriverObject
, ServiceName
, FileSystem
);
249 *DriverObject
= NULL
;
251 /* Create ModuleName string */
252 if (ServiceName
!= NULL
)
254 if (FileSystem
== TRUE
)
255 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
257 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
258 wcscat(NameBuffer
, ServiceName
->Buffer
);
260 RtlInitUnicodeString(&DriverName
,
262 DPRINT("Driver name: '%wZ'\n", &DriverName
);
265 /* Initialize ObjectAttributes for ModuleObject */
266 InitializeObjectAttributes(&ObjectAttributes
,
267 (ServiceName
!= NULL
)? &DriverName
: NULL
,
272 /* Create module object */
273 Status
= ObCreateObject(&DriverHandle
,
274 STANDARD_RIGHTS_REQUIRED
,
278 if (!NT_SUCCESS(Status
))
283 NtClose(DriverHandle
);
285 /* Create driver extension */
286 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
287 ExAllocatePoolWithTag(NonPagedPool
,
288 sizeof(DRIVER_EXTENSION
),
289 TAG_DRIVER_EXTENSION
);
290 if (Object
->DriverExtension
== NULL
)
293 return(STATUS_INSUFFICIENT_RESOURCES
);
296 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
298 Object
->Type
= InternalDriverType
;
300 for (i
=0; i
<=IRP_MJ_MAXIMUM_FUNCTION
; i
++)
302 Object
->MajorFunction
[i
] = (PDRIVER_DISPATCH
) IopDefaultDispatchFunction
;
305 *DriverObject
= Object
;
307 return STATUS_SUCCESS
;
311 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode
,
314 return STATUS_SUCCESS
;
318 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
319 BOOLEAN BootDriversOnly
)
321 IO_STATUS_BLOCK IoStatusBlock
;
322 PDRIVER_OBJECT DriverObject
;
323 IO_STACK_LOCATION Stack
;
327 DriverObject
= DeviceNode
->DriverObject
;
329 if (DriverObject
->DriverExtension
->AddDevice
)
331 /* This is a Plug and Play driver */
332 DPRINT("Plug and Play driver found\n");
334 assert(DeviceNode
->Pdo
);
336 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
337 DriverObject
->DriverExtension
->AddDevice
);
338 Status
= DriverObject
->DriverExtension
->AddDevice(
339 DriverObject
, DeviceNode
->Pdo
);
340 if (!NT_SUCCESS(Status
))
345 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
347 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
349 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->Pdo
);
351 if (Fdo
== DeviceNode
->Pdo
)
353 /* FIXME: What do we do? Unload the driver or just disable the device? */
354 DbgPrint("An FDO was not attached\n");
358 /* FIXME: Put some resources in the IRP for the device */
359 Stack
.Parameters
.StartDevice
.AllocatedResources
= NULL
;
360 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= NULL
;
362 Status
= IopInitiatePnpIrp(
367 if (!NT_SUCCESS(Status
))
369 DPRINT("IopInitiatePnpIrp() failed\n");
370 ObDereferenceObject(Fdo
);
374 if (Fdo
->DeviceType
== FILE_DEVICE_BUS_EXTENDER
)
376 DPRINT("Bus extender found\n");
378 Status
= IopInterrogateBusExtender(
379 DeviceNode
, Fdo
, BootDriversOnly
);
380 if (!NT_SUCCESS(Status
))
382 ObDereferenceObject(Fdo
);
386 else if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
389 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
391 /* There can be only one system power device */
392 if (!SystemPowerDeviceNodeCreated
)
394 PopSystemPowerDeviceNode
= DeviceNode
;
395 SystemPowerDeviceNodeCreated
= TRUE
;
399 ObDereferenceObject(Fdo
);
402 return STATUS_SUCCESS
;
406 IopInitializeService(
407 PDEVICE_NODE DeviceNode
,
408 PUNICODE_STRING ImagePath
)
410 PMODULE_OBJECT ModuleObject
;
413 ModuleObject
= LdrGetModuleObject(&DeviceNode
->ServiceName
);
414 if (ModuleObject
== NULL
)
416 /* The module is currently not loaded, so load it now */
418 Status
= LdrLoadModule(ImagePath
, &ModuleObject
);
419 if (!NT_SUCCESS(Status
))
421 /* FIXME: Log the error */
422 CPRINT("Driver load failed\n");
426 Status
= IopInitializeDriver(ModuleObject
->EntryPoint
, DeviceNode
, FALSE
);
427 if (!NT_SUCCESS(Status
))
429 LdrUnloadModule(ModuleObject
);
431 /* FIXME: Log the error */
432 CPRINT("A driver failed to initialize\n");
437 Status
= IopInitializeDevice(DeviceNode
, TRUE
);
443 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode
)
445 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
446 UNICODE_STRING ImagePath
;
450 Status
= RtlpGetRegistryHandle(
451 RTL_REGISTRY_SERVICES
,
452 DeviceNode
->ServiceName
.Buffer
,
455 if (!NT_SUCCESS(Status
))
457 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status
);
461 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
463 RtlInitUnicodeString(&ImagePath
, NULL
);
465 QueryTable
[0].Name
= L
"ImagePath";
466 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
467 QueryTable
[0].EntryContext
= &ImagePath
;
469 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
476 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status
);
478 if (NT_SUCCESS(Status
))
480 DPRINT("Got ImagePath %S\n", ImagePath
.Buffer
);
482 Status
= IopInitializeService(DeviceNode
, &ImagePath
);
484 RtlFreeUnicodeString(&ImagePath
);
491 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry
,
492 PDEVICE_NODE DeviceNode
,
493 BOOLEAN FileSystemDriver
)
495 * FUNCTION: Called to initalize a loaded driver
497 * DriverEntry = Pointer to driver entry routine
498 * DeviceNode = Pointer to device node
501 WCHAR RegistryKeyBuffer
[MAX_PATH
];
502 PDRIVER_OBJECT DriverObject
;
503 UNICODE_STRING RegistryKey
;
506 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
507 DriverEntry
, DeviceNode
);
509 Status
= IopCreateDriverObject(&DriverObject
,
510 &DeviceNode
->ServiceName
,
512 if (!NT_SUCCESS(Status
))
517 DeviceNode
->DriverObject
= DriverObject
;
519 if (DeviceNode
->ServiceName
.Buffer
)
521 wcscpy(RegistryKeyBuffer
, DRIVER_REGISTRY_KEY_BASENAME
);
522 wcscat(RegistryKeyBuffer
, DeviceNode
->ServiceName
.Buffer
);
523 RtlInitUnicodeString(&RegistryKey
, RegistryKeyBuffer
);
527 RtlInitUnicodeString(&RegistryKey
, NULL
);
530 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
531 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
533 Status
= DriverEntry(DriverObject
, &RegistryKey
);
534 if (!NT_SUCCESS(Status
))
536 DeviceNode
->DriverObject
= NULL
;
537 ExFreePool(DriverObject
->DriverExtension
);
538 ObMakeTemporaryObject(DriverObject
);
539 ObDereferenceObject(DriverObject
);
543 Status
= IopInitializeDevice(DeviceNode
, TRUE
);
550 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
551 PUNICODE_STRING TargetDevice
,
552 PDEVICE_OBJECT
* AttachedDevice
)
554 * FUNCTION: Layers a device over the highest device in a device stack
556 * SourceDevice = Device to attached
557 * TargetDevice = Name of the target device
558 * AttachedDevice (OUT) = Caller storage for the device attached to
566 IopCreateDevice(PVOID ObjectBody
,
569 POBJECT_ATTRIBUTES ObjectAttributes
)
572 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
573 ObjectBody
, Parent
, RemainingPath
);
575 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
577 return(STATUS_UNSUCCESSFUL
);
580 return(STATUS_SUCCESS
);
585 IoCreateDevice(PDRIVER_OBJECT DriverObject
,
586 ULONG DeviceExtensionSize
,
587 PUNICODE_STRING DeviceName
,
588 DEVICE_TYPE DeviceType
,
589 ULONG DeviceCharacteristics
,
591 PDEVICE_OBJECT
* DeviceObject
)
593 * FUNCTION: Allocates memory for and intializes a device object for use for
596 * DriverObject : Driver object passed by iomgr when the driver was
598 * DeviceExtensionSize : Number of bytes for the device extension
599 * DeviceName : Unicode name of device
600 * DeviceType : Device type
601 * DeviceCharacteristics : Bit mask of device characteristics
602 * Exclusive : True if only one thread can access the device at a
606 * DeviceObject : Contains a pointer to allocated device object
607 * if the call succeeded
608 * NOTES: See the DDK documentation for more information
611 PDEVICE_OBJECT CreatedDeviceObject
;
612 OBJECT_ATTRIBUTES ObjectAttributes
;
616 assert_irql(PASSIVE_LEVEL
);
618 if (DeviceName
!= NULL
)
620 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject
,
625 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject
);
628 if (DeviceName
!= NULL
)
630 InitializeObjectAttributes(&ObjectAttributes
,DeviceName
,0,NULL
,NULL
);
631 Status
= ObCreateObject(&DeviceHandle
,
635 (PVOID
*)&CreatedDeviceObject
);
639 Status
= ObCreateObject(&DeviceHandle
,
643 (PVOID
*)&CreatedDeviceObject
);
646 *DeviceObject
= NULL
;
648 if (!NT_SUCCESS(Status
))
650 DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status
);
654 if (DriverObject
->DeviceObject
== NULL
)
656 DriverObject
->DeviceObject
= CreatedDeviceObject
;
657 CreatedDeviceObject
->NextDevice
= NULL
;
661 CreatedDeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
662 DriverObject
->DeviceObject
= CreatedDeviceObject
;
665 CreatedDeviceObject
->Type
= DeviceType
;
666 CreatedDeviceObject
->DriverObject
= DriverObject
;
667 CreatedDeviceObject
->CurrentIrp
= NULL
;
668 CreatedDeviceObject
->Flags
= 0;
670 CreatedDeviceObject
->DeviceExtension
=
671 ExAllocatePoolWithTag(NonPagedPool
, DeviceExtensionSize
,
672 TAG_DEVICE_EXTENSION
);
673 if (DeviceExtensionSize
> 0 && CreatedDeviceObject
->DeviceExtension
== NULL
)
675 ExFreePool(CreatedDeviceObject
);
676 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES
);
677 return(STATUS_INSUFFICIENT_RESOURCES
);
680 if (DeviceExtensionSize
> 0)
682 RtlZeroMemory(CreatedDeviceObject
->DeviceExtension
,
683 DeviceExtensionSize
);
686 CreatedDeviceObject
->AttachedDevice
= NULL
;
687 CreatedDeviceObject
->DeviceType
= DeviceType
;
688 CreatedDeviceObject
->StackSize
= 1;
689 CreatedDeviceObject
->AlignmentRequirement
= 1;
690 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
692 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
693 SynchronizationEvent
,
696 /* FIXME: Do we need to add network drives too?! */
697 if (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
||
698 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
||
699 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
)
701 IoAttachVpb(CreatedDeviceObject
);
704 *DeviceObject
= CreatedDeviceObject
;
706 return(STATUS_SUCCESS
);
712 IoOpenDeviceInstanceKey (
721 return(STATUS_NOT_IMPLEMENTED
);
727 IoQueryDeviceEnumInfo (