1 /* $Id: device.c,v 1.41 2002/05/16 06:40:29 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 #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 NTSTATUS STDCALL
NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
44 /**********************************************************************
49 * Loads a device driver.
53 * Name of the service to load (registry key).
63 PUNICODE_STRING DriverServiceName
66 PDEVICE_NODE DeviceNode
;
69 /* FIXME: this should lookup the filename from the registry and then call LdrLoadDriver */
71 /* Use IopRootDeviceNode for now */
72 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
73 if (!NT_SUCCESS(Status
))
78 Status
= LdrLoadDriver (DriverServiceName
, DeviceNode
, FALSE
);
79 if (!NT_SUCCESS(Status
))
81 IopFreeDeviceNode(DeviceNode
);
82 DPRINT("Driver load failed, status (%x)\n", Status
);
91 IoAttachDeviceByPointer (
92 IN PDEVICE_OBJECT SourceDevice
,
93 IN PDEVICE_OBJECT TargetDevice
96 PDEVICE_OBJECT AttachedDevice
;
98 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
102 AttachedDevice
= IoAttachDeviceToDeviceStack (SourceDevice
,
104 if (AttachedDevice
== NULL
)
105 return STATUS_NO_SUCH_DEVICE
;
107 return STATUS_SUCCESS
;
113 IoDeleteDevice(PDEVICE_OBJECT DeviceObject
)
115 PDEVICE_OBJECT Previous
;
117 if (DeviceObject
->Flags
& DO_SHUTDOWN_REGISTERED
)
118 IoUnregisterShutdownNotification(DeviceObject
);
120 /* remove the timer if it exists */
121 if (DeviceObject
->Timer
)
123 IoStopTimer(DeviceObject
);
124 ExFreePool(DeviceObject
->Timer
);
127 /* free device extension */
128 if (DeviceObject
->DeviceObjectExtension
)
129 ExFreePool (DeviceObject
->DeviceObjectExtension
);
131 /* remove device from driver device list */
132 Previous
= DeviceObject
->DriverObject
->DeviceObject
;
133 if (Previous
== DeviceObject
)
135 DeviceObject
->DriverObject
->DeviceObject
= DeviceObject
->NextDevice
;
139 while (Previous
->NextDevice
!= DeviceObject
)
140 Previous
= Previous
->NextDevice
;
141 Previous
->NextDevice
= DeviceObject
->NextDevice
;
144 ObDereferenceObject (DeviceObject
);
150 IoGetRelatedDeviceObject (
151 IN PFILE_OBJECT FileObject
154 return (FileObject
->DeviceObject
);
160 IoGetDeviceObjectPointer (
161 IN PUNICODE_STRING ObjectName
,
162 IN ACCESS_MASK DesiredAccess
,
163 OUT PFILE_OBJECT
* FileObject
,
164 OUT PDEVICE_OBJECT
* DeviceObject
)
166 OBJECT_ATTRIBUTES ObjectAttributes
;
167 IO_STATUS_BLOCK StatusBlock
;
168 PFILE_OBJECT LocalFileObject
;
172 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
178 InitializeObjectAttributes (&ObjectAttributes
,
184 Status
= NtOpenFile (&FileHandle
,
189 FILE_NON_DIRECTORY_FILE
);
190 if (!NT_SUCCESS(Status
))
193 Status
= ObReferenceObjectByHandle (FileHandle
,
197 (PVOID
*)&LocalFileObject
,
199 if (NT_SUCCESS(Status
))
201 *DeviceObject
= IoGetRelatedDeviceObject (LocalFileObject
);
202 *FileObject
= LocalFileObject
;
204 NtClose (FileHandle
);
212 IoDetachDevice(PDEVICE_OBJECT TargetDevice
)
220 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject
)
222 PDEVICE_OBJECT Current
= DeviceObject
;
224 // DPRINT("IoGetAttachedDevice(DeviceObject %x)\n",DeviceObject);
226 while (Current
->AttachedDevice
!=NULL
)
228 Current
= Current
->AttachedDevice
;
229 // DPRINT("Current %x\n",Current);
232 // DPRINT("IoGetAttachedDevice() = %x\n",DeviceObject);
238 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject
)
240 PDEVICE_OBJECT Current
= DeviceObject
;
242 while (Current
->AttachedDevice
!=NULL
)
244 Current
= Current
->AttachedDevice
;
247 ObReferenceObject(Current
);
251 PDEVICE_OBJECT STDCALL
252 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice
,
253 PDEVICE_OBJECT TargetDevice
)
255 PDEVICE_OBJECT AttachedDevice
;
257 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
258 SourceDevice
,TargetDevice
);
260 AttachedDevice
= IoGetAttachedDevice(TargetDevice
);
261 AttachedDevice
->AttachedDevice
= SourceDevice
;
262 SourceDevice
->AttachedDevice
= NULL
;
263 SourceDevice
->StackSize
= AttachedDevice
->StackSize
+ 1;
264 SourceDevice
->Vpb
= AttachedDevice
->Vpb
;
265 return(AttachedDevice
);
269 IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject
,
270 PDRIVER_REINITIALIZE ReinitRoutine
,
277 IopDefaultDispatchFunction(PDEVICE_OBJECT DeviceObject
,
280 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
281 Irp
->IoStatus
.Information
= 0;
283 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
284 return(STATUS_NOT_IMPLEMENTED
);
288 IopCreateDriverObject(PDRIVER_OBJECT
*DriverObject
)
290 PDRIVER_OBJECT Object
;
293 Object
= ExAllocatePoolWithTag(NonPagedPool
,
294 sizeof(DRIVER_OBJECT
),
298 return STATUS_INSUFFICIENT_RESOURCES
;
301 RtlZeroMemory(Object
, sizeof(DRIVER_OBJECT
));
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 Status
= LdrFindModuleObject(&DeviceNode
->ServiceName
, &ModuleObject
);
431 if (!NT_SUCCESS(Status
))
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
);
444 if (!NT_SUCCESS(Status
))
446 /* FIXME: Log the error */
447 CPRINT("A driver failed to initialize\n");
452 ObDereferenceObject(ModuleObject
);
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(
494 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status
);
496 if (NT_SUCCESS(Status
))
498 DPRINT("Got ImagePath %S\n", ImagePath
.Buffer
);
500 Status
= IopInitializeService(DeviceNode
, &ImagePath
);
502 RtlFreeUnicodeString(&ImagePath
);
509 IopInitializeDriver(PDRIVER_INITIALIZE DriverEntry
,
510 PDEVICE_NODE DeviceNode
)
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 if (!NT_SUCCESS(Status
))
532 DeviceNode
->DriverObject
= DriverObject
;
534 if (DeviceNode
->ServiceName
.Buffer
)
536 wcscpy(RegistryKeyBuffer
, DRIVER_REGISTRY_KEY_BASENAME
);
537 wcscat(RegistryKeyBuffer
, DeviceNode
->ServiceName
.Buffer
);
538 RtlInitUnicodeString(&RegistryKey
, RegistryKeyBuffer
);
542 RtlInitUnicodeString(&RegistryKey
, NULL
);
545 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
546 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
548 Status
= DriverEntry(DriverObject
, &RegistryKey
);
549 if (!NT_SUCCESS(Status
))
551 DeviceNode
->DriverObject
= NULL
;
552 ExFreePool(DriverObject
->DriverExtension
);
553 ExFreePool(DriverObject
);
557 Status
= IopInitializeDevice(DeviceNode
, TRUE
);
564 IoAttachDevice(PDEVICE_OBJECT SourceDevice
,
565 PUNICODE_STRING TargetDevice
,
566 PDEVICE_OBJECT
* AttachedDevice
)
568 * FUNCTION: Layers a device over the highest device in a device stack
570 * SourceDevice = Device to attached
571 * TargetDevice = Name of the target device
572 * AttachedDevice (OUT) = Caller storage for the device attached to
580 IopCreateDevice(PVOID ObjectBody
,
583 POBJECT_ATTRIBUTES ObjectAttributes
)
586 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
587 ObjectBody
, Parent
, RemainingPath
);
589 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
591 return(STATUS_UNSUCCESSFUL
);
594 return(STATUS_SUCCESS
);
599 IoCreateDevice(PDRIVER_OBJECT DriverObject
,
600 ULONG DeviceExtensionSize
,
601 PUNICODE_STRING DeviceName
,
602 DEVICE_TYPE DeviceType
,
603 ULONG DeviceCharacteristics
,
605 PDEVICE_OBJECT
* DeviceObject
)
607 * FUNCTION: Allocates memory for and intializes a device object for use for
610 * DriverObject : Driver object passed by iomgr when the driver was
612 * DeviceExtensionSize : Number of bytes for the device extension
613 * DeviceName : Unicode name of device
614 * DeviceType : Device type
615 * DeviceCharacteristics : Bit mask of device characteristics
616 * Exclusive : True if only one thread can access the device at a
620 * DeviceObject : Contains a pointer to allocated device object
621 * if the call succeeded
622 * NOTES: See the DDK documentation for more information
625 PDEVICE_OBJECT CreatedDeviceObject
;
626 OBJECT_ATTRIBUTES ObjectAttributes
;
630 assert_irql(PASSIVE_LEVEL
);
632 if (DeviceName
!= NULL
)
634 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",DriverObject
,
639 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject
);
642 if (DeviceName
!= NULL
)
644 InitializeObjectAttributes(&ObjectAttributes
,DeviceName
,0,NULL
,NULL
);
645 Status
= ObCreateObject(&DeviceHandle
,
649 (PVOID
*)&CreatedDeviceObject
);
653 Status
= ObCreateObject(&DeviceHandle
,
657 (PVOID
*)&CreatedDeviceObject
);
660 *DeviceObject
= NULL
;
662 if (!NT_SUCCESS(Status
))
667 if (DriverObject
->DeviceObject
== NULL
)
669 DriverObject
->DeviceObject
= CreatedDeviceObject
;
670 CreatedDeviceObject
->NextDevice
= NULL
;
674 CreatedDeviceObject
->NextDevice
= DriverObject
->DeviceObject
;
675 DriverObject
->DeviceObject
= CreatedDeviceObject
;
678 CreatedDeviceObject
->Type
= DeviceType
;
679 CreatedDeviceObject
->DriverObject
= DriverObject
;
680 CreatedDeviceObject
->CurrentIrp
= NULL
;
681 CreatedDeviceObject
->Flags
= 0;
683 CreatedDeviceObject
->DeviceExtension
=
684 ExAllocatePoolWithTag(NonPagedPool
, DeviceExtensionSize
,
685 TAG_DEVICE_EXTENSION
);
686 if (DeviceExtensionSize
> 0 && CreatedDeviceObject
->DeviceExtension
== NULL
)
688 ExFreePool(CreatedDeviceObject
);
689 return(STATUS_INSUFFICIENT_RESOURCES
);
692 if (DeviceExtensionSize
> 0)
694 RtlZeroMemory(CreatedDeviceObject
->DeviceExtension
,
695 DeviceExtensionSize
);
698 CreatedDeviceObject
->AttachedDevice
= NULL
;
699 CreatedDeviceObject
->DeviceType
= DeviceType
;
700 CreatedDeviceObject
->StackSize
= 1;
701 CreatedDeviceObject
->AlignmentRequirement
= 1;
702 KeInitializeDeviceQueue(&CreatedDeviceObject
->DeviceQueue
);
704 KeInitializeEvent(&CreatedDeviceObject
->DeviceLock
,
705 SynchronizationEvent
,
708 /* FIXME: Do we need to add network drives too?! */
709 if (CreatedDeviceObject
->DeviceType
== FILE_DEVICE_DISK
||
710 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
||
711 CreatedDeviceObject
->DeviceType
== FILE_DEVICE_TAPE
)
713 IoAttachVpb(CreatedDeviceObject
);
716 *DeviceObject
= CreatedDeviceObject
;
718 return(STATUS_SUCCESS
);
724 IoOpenDeviceInstanceKey (
733 return(STATUS_NOT_IMPLEMENTED
);
739 IoQueryDeviceEnumInfo (