1 /* $Id: device.c,v 1.48 2002/09/08 10:23:24 chorns 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>
25 #include <internal/debug.h>
27 /* GLOBALS *******************************************************************/
29 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
30 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
31 #define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T')
33 #define DRIVER_REGISTRY_KEY_BASENAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
35 /* FUNCTIONS ***************************************************************/
38 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice
,
39 IN PDEVICE_OBJECT TargetDevice
)
41 PDEVICE_OBJECT AttachedDevice
;
43 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
47 AttachedDevice
= IoAttachDeviceToDeviceStack (SourceDevice
,
49 if (AttachedDevice
== NULL
)
50 return STATUS_NO_SUCH_DEVICE
;
52 return STATUS_SUCCESS
;
57 IoDeleteDevice(PDEVICE_OBJECT DeviceObject
)
59 PDEVICE_OBJECT Previous
;
61 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
62 IoUnregisterShutdownNotification(DeviceObject
);
64 /* remove the timer if it exists */
65 if (DeviceObject
->Timer
)
67 IoStopTimer(DeviceObject
);
68 ExFreePool(DeviceObject
->Timer
);
71 /* free device extension */
72 if (DeviceObject
->DeviceObjectExtension
)
73 ExFreePool (DeviceObject
->DeviceObjectExtension
);
75 /* remove device from driver device list */
76 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
77 if (Previous
== DeviceObject
)
79 DeviceObject
->DriverObject
->DeviceObject
= DeviceObject
->NextDevice
;
83 while (Previous
->NextDevice
!= DeviceObject
)
84 Previous
= Previous
->NextDevice
;
85 Previous
->NextDevice
= DeviceObject
->NextDevice
;
88 ObDereferenceObject (DeviceObject
);
94 IoGetRelatedDeviceObject (
95 IN PFILE_OBJECT FileObject
98 return (FileObject
->DeviceObject
);
104 IoGetDeviceObjectPointer (
105 IN PUNICODE_STRING ObjectName
,
106 IN ACCESS_MASK DesiredAccess
,
107 OUT PFILE_OBJECT
* FileObject
,
108 OUT PDEVICE_OBJECT
* DeviceObject
)
110 OBJECT_ATTRIBUTES ObjectAttributes
;
111 IO_STATUS_BLOCK StatusBlock
;
112 PFILE_OBJECT LocalFileObject
;
116 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
122 InitializeObjectAttributes (&ObjectAttributes
,
128 Status
= NtOpenFile (&FileHandle
,
133 FILE_NON_DIRECTORY_FILE
);
134 if (!NT_SUCCESS(Status
))
137 Status
= ObReferenceObjectByHandle (FileHandle
,
141 (PVOID
*)&LocalFileObject
,
143 if (NT_SUCCESS(Status
))
145 *DeviceObject
= IoGetRelatedDeviceObject (LocalFileObject
);
146 *FileObject
= LocalFileObject
;
148 NtClose (FileHandle
);
156 IoDetachDevice(PDEVICE_OBJECT TargetDevice
)
164 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
166 PDEVICE_OBJECT Current
= DeviceObject
;
168 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
170 while (Current
->AttachedDevice
!=NULL
)
172 Current
= Current
->AttachedDevice
;
173 // DPRINT("Current %x\n",Current);
176 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
182 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
184 PDEVICE_OBJECT Current
= DeviceObject
;
186 while (Current
->AttachedDevice
!=NULL
)
188 Current
= Current
->AttachedDevice
;
191 ObReferenceObject(Current
);
195 PDEVICE_OBJECT STDCALL
196 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice
,
197 PDEVICE_OBJECT TargetDevice
)
199 PDEVICE_OBJECT AttachedDevice
;
201 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
202 SourceDevice
,TargetDevice
);
204 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
205 AttachedDevice
->AttachedDevice
= SourceDevice
;
206 SourceDevice
->AttachedDevice
= NULL
;
207 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
208 SourceDevice
->Vpb
= AttachedDevice
->Vpb
;
209 return(AttachedDevice
);
213 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject
,
214 PDRIVER_REINITIALIZE ReinitRoutine
,
221 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject
,
224 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
225 Irp
->IoStatus
.Information
= 0;
227 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
228 return(STATUS_NOT_IMPLEMENTED
);
233 IopCreateDriverObject(PDRIVER_OBJECT
*DriverObject
,
234 PUNICODE_STRING ServiceName
,
237 PDRIVER_OBJECT Object
;
238 HANDLE DriverHandle
= 0;
240 WCHAR NameBuffer
[MAX_PATH
];
241 UNICODE_STRING DriverName
;
242 OBJECT_ATTRIBUTES ObjectAttributes
;
245 DPRINT("IopCreateDriverObject(%p '%wZ' %x)\n", DriverObject
, ServiceName
, FileSystem
);
247 *DriverObject
= NULL
;
249 /* Create ModuleName string */
250 if (ServiceName
!= NULL
)
252 if (FileSystem
== TRUE
)
253 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
255 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
256 wcscat(NameBuffer
, ServiceName
->Buffer
);
258 RtlInitUnicodeString(&DriverName
,
260 DPRINT("Driver name: '%wZ'\n", &DriverName
);
263 /* Initialize ObjectAttributes for ModuleObject */
264 InitializeObjectAttributes(&ObjectAttributes
,
265 (ServiceName
!= NULL
)? &DriverName
: NULL
,
270 /* Create module object */
271 Status
= ObCreateObject(&DriverHandle
,
272 STANDARD_RIGHTS_REQUIRED
,
276 if (!NT_SUCCESS(Status
))
281 NtClose(DriverHandle
);
283 /* Create driver extension */
284 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
285 ExAllocatePoolWithTag(NonPagedPool
,
286 sizeof(DRIVER_EXTENSION
),
287 TAG_DRIVER_EXTENSION
);
288 if (Object
->DriverExtension
== NULL
)
291 return(STATUS_INSUFFICIENT_RESOURCES
);
294 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
296 Object
->Type
= InternalDriverType
;
298 for (i
=0; i
<=IRP_MJ_MAXIMUM_FUNCTION
; i
++)
300 Object
->MajorFunction
[i
] = (PDRIVER_DISPATCH
) IopDefaultDispatchFunction
;
303 *DriverObject
= Object
;
305 return STATUS_SUCCESS
;
309 IopAttachFilterDrivers(PDEVICE_NODE DeviceNode
,
312 return STATUS_SUCCESS
;
316 IopInitializeDevice(PDEVICE_NODE DeviceNode
,
317 BOOLEAN BootDriversOnly
)
319 IO_STATUS_BLOCK IoStatusBlock
;
320 PDRIVER_OBJECT DriverObject
;
321 IO_STACK_LOCATION Stack
;
325 DriverObject
= DeviceNode
->DriverObject
;
327 if (DriverObject
->DriverExtension
->AddDevice
)
329 /* This is a Plug and Play driver */
330 DPRINT("Plug and Play driver found\n");
332 assert(DeviceNode
->Pdo
);
334 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
335 DriverObject
->DriverExtension
->AddDevice
);
336 Status
= DriverObject
->DriverExtension
->AddDevice(
337 DriverObject
, DeviceNode
->Pdo
);
338 if (!NT_SUCCESS(Status
))
343 IopDeviceNodeSetFlag(DeviceNode
, DNF_ADDED
);
345 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
347 Fdo
= IoGetAttachedDeviceReference(DeviceNode
->Pdo
);
349 if (Fdo
== DeviceNode
->Pdo
)
351 /* FIXME: What do we do? Unload the driver or just disable the device? */
352 DbgPrint("An FDO was not attached\n");
356 /* FIXME: Put some resources in the IRP for the device */
357 Stack
.Parameters
.StartDevice
.AllocatedResources
= NULL
;
358 Stack
.Parameters
.StartDevice
.AllocatedResourcesTranslated
= NULL
;
360 Status
= IopInitiatePnpIrp(
365 if (!NT_SUCCESS(Status
))
367 DPRINT("IopInitiatePnpIrp() failed\n");
368 ObDereferenceObject(Fdo
);
372 if (Fdo
->DeviceType
== FILE_DEVICE_BUS_EXTENDER
)
374 DPRINT("Bus extender found\n");
376 Status
= IopInterrogateBusExtender(
377 DeviceNode
, Fdo
, BootDriversOnly
);
378 if (!NT_SUCCESS(Status
))
380 ObDereferenceObject(Fdo
);
384 else if (Fdo
->DeviceType
== FILE_DEVICE_ACPI
)
387 static BOOLEAN SystemPowerDeviceNodeCreated
= FALSE
;
389 /* There can be only one system power device */
390 if (!SystemPowerDeviceNodeCreated
)
392 PopSystemPowerDeviceNode
= DeviceNode
;
393 SystemPowerDeviceNodeCreated
= TRUE
;
397 ObDereferenceObject(Fdo
);
400 return STATUS_SUCCESS
;
404 IopInitializeService(
405 PDEVICE_NODE DeviceNode
,
406 PUNICODE_STRING ImagePath
)
408 PMODULE_OBJECT ModuleObject
;
411 ModuleObject
= LdrGetModuleObject(&DeviceNode
->ServiceName
);
412 if (ModuleObject
== NULL
)
414 /* The module is currently not loaded, so load it now */
416 Status
= LdrLoadModule(ImagePath
, &ModuleObject
);
417 if (!NT_SUCCESS(Status
))
419 /* FIXME: Log the error */
420 CPRINT("Driver load failed\n");
424 Status
= IopInitializeDriver(ModuleObject
->EntryPoint
, DeviceNode
, FALSE
);
425 if (!NT_SUCCESS(Status
))
427 LdrUnloadModule(ModuleObject
);
429 /* FIXME: Log the error */
430 CPRINT("A driver failed to initialize\n");
435 Status
= IopInitializeDevice(DeviceNode
, TRUE
);
441 IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode
)
443 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
444 UNICODE_STRING ImagePath
;
448 Status
= RtlpGetRegistryHandle(
449 RTL_REGISTRY_SERVICES
,
450 DeviceNode
->ServiceName
.Buffer
,
453 if (!NT_SUCCESS(Status
))
455 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status
);
459 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
461 RtlInitUnicodeString(&ImagePath
, NULL
);
463 QueryTable
[0].Name
= L
"ImagePath";
464 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
465 QueryTable
[0].EntryContext
= &ImagePath
;
467 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
474 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status
);
476 if (NT_SUCCESS(Status
))
478 DPRINT("Got ImagePath %S\n", ImagePath
.Buffer
);
480 Status
= IopInitializeService(DeviceNode
, &ImagePath
);
482 RtlFreeUnicodeString(&ImagePath
);
489 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry
,
490 PDEVICE_NODE DeviceNode
,
491 BOOLEAN FileSystemDriver
)
493 * FUNCTION: Called to initalize a loaded driver
495 * DriverEntry = Pointer to driver entry routine
496 * DeviceNode = Pointer to device node
499 WCHAR RegistryKeyBuffer
[MAX_PATH
];
500 PDRIVER_OBJECT DriverObject
;
501 UNICODE_STRING RegistryKey
;
504 DPRINT("IopInitializeDriver(DriverEntry %08lx, DeviceNode %08lx)\n",
505 DriverEntry
, DeviceNode
);
507 Status
= IopCreateDriverObject(&DriverObject
,
508 &DeviceNode
->ServiceName
,
510 if (!NT_SUCCESS(Status
))
515 DeviceNode
->DriverObject
= DriverObject
;
517 if (DeviceNode
->ServiceName
.Buffer
)
519 wcscpy(RegistryKeyBuffer
, DRIVER_REGISTRY_KEY_BASENAME
);
520 wcscat(RegistryKeyBuffer
, DeviceNode
->ServiceName
.Buffer
);
521 RtlInitUnicodeString(&RegistryKey
, RegistryKeyBuffer
);
525 RtlInitUnicodeString(&RegistryKey
, NULL
);
528 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
529 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
531 Status
= DriverEntry(DriverObject
, &RegistryKey
);
532 if (!NT_SUCCESS(Status
))
534 DeviceNode
->DriverObject
= NULL
;
535 ExFreePool(DriverObject
->DriverExtension
);
536 ObMakeTemporaryObject(DriverObject
);
537 ObDereferenceObject(DriverObject
);
541 Status
= IopInitializeDevice(DeviceNode
, TRUE
);
548 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
549 PUNICODE_STRING TargetDevice
,
550 PDEVICE_OBJECT
* AttachedDevice
)
552 * FUNCTION: Layers a device over the highest device in a device stack
554 * SourceDevice = Device to attached
555 * TargetDevice = Name of the target device
556 * AttachedDevice (OUT) = Caller storage for the device attached to
564 IopCreateDevice(PVOID ObjectBody
,
567 POBJECT_ATTRIBUTES ObjectAttributes
)
570 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
571 ObjectBody
, Parent
, RemainingPath
);
573 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
575 return(STATUS_UNSUCCESSFUL
);
578 return(STATUS_SUCCESS
);
583 IoCreateDevice(PDRIVER_OBJECT DriverObject
,
584 ULONG DeviceExtensionSize
,
585 PUNICODE_STRING DeviceName
,
586 DEVICE_TYPE DeviceType
,
587 ULONG DeviceCharacteristics
,
589 PDEVICE_OBJECT
* DeviceObject
)
591 * FUNCTION: Allocates memory for and intializes a device object for use for
594 * DriverObject : Driver object passed by iomgr when the driver was
596 * DeviceExtensionSize : Number of bytes for the device extension
597 * DeviceName : Unicode name of device
598 * DeviceType : Device type
599 * DeviceCharacteristics : Bit mask of device characteristics
600 * Exclusive : True if only one thread can access the device at a
604 * DeviceObject : Contains a pointer to allocated device object
605 * if the call succeeded
606 * NOTES: See the DDK documentation for more information
609 PDEVICE_OBJECT CreatedDeviceObject
;
610 OBJECT_ATTRIBUTES ObjectAttributes
;
614 assert_irql(PASSIVE_LEVEL
);
616 if (DeviceName
!= NULL
)
618 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject
,
623 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject
);
626 if (DeviceName
!= NULL
)
628 InitializeObjectAttributes(&ObjectAttributes
,DeviceName
,0,NULL
,NULL
);
629 Status
= ObCreateObject(&DeviceHandle
,
633 (PVOID
*)&CreatedDeviceObject
);
637 Status
= ObCreateObject(&DeviceHandle
,
641 (PVOID
*)&CreatedDeviceObject
);
644 *DeviceObject
= NULL
;
646 if (!NT_SUCCESS(Status
))
651 if (DriverObject
->DeviceObject
== NULL
)
653 DriverObject
->DeviceObject
= CreatedDeviceObject
;
654 CreatedDeviceObject
->NextDevice
= NULL
;
658 CreatedDeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
659 DriverObject
->DeviceObject
= CreatedDeviceObject
;
662 CreatedDeviceObject
->Type
= DeviceType
;
663 CreatedDeviceObject
->DriverObject
= DriverObject
;
664 CreatedDeviceObject
->CurrentIrp
= NULL
;
665 CreatedDeviceObject
->Flags
= 0;
667 CreatedDeviceObject
->DeviceExtension
=
668 ExAllocatePoolWithTag(NonPagedPool
, DeviceExtensionSize
,
669 TAG_DEVICE_EXTENSION
);
670 if (DeviceExtensionSize
> 0 && CreatedDeviceObject
->DeviceExtension
== NULL
)
672 ExFreePool(CreatedDeviceObject
);
673 return(STATUS_INSUFFICIENT_RESOURCES
);
676 if (DeviceExtensionSize
> 0)
678 RtlZeroMemory(CreatedDeviceObject
->DeviceExtension
,
679 DeviceExtensionSize
);
682 CreatedDeviceObject
->AttachedDevice
= NULL
;
683 CreatedDeviceObject
->DeviceType
= DeviceType
;
684 CreatedDeviceObject
->StackSize
= 1;
685 CreatedDeviceObject
->AlignmentRequirement
= 1;
686 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
688 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
689 SynchronizationEvent
,
692 /* FIXME: Do we need to add network drives too?! */
693 if (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
||
694 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
||
695 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
)
697 IoAttachVpb(CreatedDeviceObject
);
700 *DeviceObject
= CreatedDeviceObject
;
702 return(STATUS_SUCCESS
);
708 IoOpenDeviceInstanceKey (
717 return(STATUS_NOT_IMPLEMENTED
);
723 IoQueryDeviceEnumInfo (