44e6ec892ac3de2ec1da86348be8f68e4f833442
[reactos.git] / reactos / ntoskrnl / io / device.c
1 /* $Id$
2 *
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)
8 * UPDATE HISTORY:
9 * 15/05/98: Created
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 #define TAG_DEVICE_EXTENSION TAG('D', 'E', 'X', 'T')
21
22 static ULONG IopDeviceObjectNumber = 0;
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 NTSTATUS FASTCALL
27 IopInitializeDevice(
28 PDEVICE_NODE DeviceNode,
29 PDRIVER_OBJECT DriverObject)
30 {
31 IO_STATUS_BLOCK IoStatusBlock;
32 IO_STACK_LOCATION Stack;
33 PDEVICE_OBJECT Fdo;
34 NTSTATUS Status;
35
36 if (DriverObject->DriverExtension->AddDevice)
37 {
38 /* This is a Plug and Play driver */
39 DPRINT("Plug and Play driver found\n");
40
41 ASSERT(DeviceNode->PhysicalDeviceObject);
42
43 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
44 DriverObject->DriverExtension->AddDevice);
45
46 Status = DriverObject->DriverExtension->AddDevice(
47 DriverObject, DeviceNode->PhysicalDeviceObject);
48
49 if (!NT_SUCCESS(Status))
50 {
51 return Status;
52 }
53
54 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
55
56 if (Fdo == DeviceNode->PhysicalDeviceObject)
57 {
58 /* FIXME: What do we do? Unload the driver or just disable the device? */
59 DbgPrint("An FDO was not attached\n");
60 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
61 return STATUS_UNSUCCESSFUL;
62 }
63
64 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
65
66 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
67
68 /* FIXME: Should be DeviceNode->ResourceList */
69 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->BootResources;
70 /* FIXME: Should be DeviceNode->ResourceListTranslated */
71 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->BootResources;
72
73 Status = IopInitiatePnpIrp(
74 Fdo,
75 &IoStatusBlock,
76 IRP_MN_START_DEVICE,
77 &Stack);
78
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT("IopInitiatePnpIrp() failed\n");
82 ObDereferenceObject(Fdo);
83 return Status;
84 }
85
86 #ifdef ACPI
87 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
88 {
89 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
90
91 /* There can be only one system power device */
92 if (!SystemPowerDeviceNodeCreated)
93 {
94 PopSystemPowerDeviceNode = DeviceNode;
95 SystemPowerDeviceNodeCreated = TRUE;
96 }
97 }
98 #endif /* ACPI */
99
100 if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER ||
101 Fdo->DeviceType == FILE_DEVICE_ACPI)
102 {
103 DPRINT("Bus extender found\n");
104
105 Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations);
106 if (!NT_SUCCESS(Status))
107 {
108 ObDereferenceObject(Fdo);
109 return Status;
110 }
111 }
112
113 ObDereferenceObject(Fdo);
114 }
115
116 return STATUS_SUCCESS;
117 }
118
119 NTSTATUS STDCALL
120 IopCreateDevice(
121 PVOID ObjectBody,
122 PVOID Parent,
123 PWSTR RemainingPath,
124 POBJECT_ATTRIBUTES ObjectAttributes)
125 {
126 DPRINT("IopCreateDevice(ObjectBody %x, Parent %x, RemainingPath %S)\n",
127 ObjectBody, Parent, RemainingPath);
128
129 if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
130 return STATUS_UNSUCCESSFUL;
131
132 return STATUS_SUCCESS;
133 }
134
135 /* PUBLIC FUNCTIONS ***********************************************************/
136
137 /*
138 * IoAttachDeviceByPointer
139 *
140 * Status
141 * @implemented
142 */
143
144 NTSTATUS STDCALL
145 IoAttachDeviceByPointer(
146 IN PDEVICE_OBJECT SourceDevice,
147 IN PDEVICE_OBJECT TargetDevice)
148 {
149 PDEVICE_OBJECT AttachedDevice;
150
151 DPRINT("IoAttachDeviceByPointer(SourceDevice %x, TargetDevice %x)\n",
152 SourceDevice, TargetDevice);
153
154 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
155 if (AttachedDevice == NULL)
156 return STATUS_NO_SUCH_DEVICE;
157
158 return STATUS_SUCCESS;
159 }
160
161 /*
162 * @unimplemented
163 */
164 NTSTATUS
165 STDCALL
166 IoAttachDeviceToDeviceStackSafe(
167 IN PDEVICE_OBJECT SourceDevice,
168 IN PDEVICE_OBJECT TargetDevice,
169 OUT PDEVICE_OBJECT *AttachedToDeviceObject
170 )
171 {
172 UNIMPLEMENTED;
173 return STATUS_NOT_IMPLEMENTED;
174 }
175
176 /*
177 * IoDeleteDevice
178 *
179 * Status
180 * @implemented
181 */
182
183 VOID STDCALL
184 IoDeleteDevice(PDEVICE_OBJECT DeviceObject)
185 {
186 PDEVICE_OBJECT Previous;
187
188 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
189 IoUnregisterShutdownNotification(DeviceObject);
190
191 /* Remove the timer if it exists */
192 if (DeviceObject->Timer)
193 {
194 IopRemoveTimerFromTimerList(DeviceObject->Timer);
195 ExFreePool(DeviceObject->Timer);
196 }
197
198 /* Free device extension */
199 if (DeviceObject->DeviceObjectExtension)
200 ExFreePool(DeviceObject->DeviceObjectExtension);
201
202 /* Remove device from driver device list */
203 Previous = DeviceObject->DriverObject->DeviceObject;
204 if (Previous == DeviceObject)
205 {
206 DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice;
207 }
208 else
209 {
210 while (Previous->NextDevice != DeviceObject)
211 Previous = Previous->NextDevice;
212 Previous->NextDevice = DeviceObject->NextDevice;
213 }
214
215 ObDereferenceObject(DeviceObject);
216 }
217
218
219 /*
220 * @unimplemented
221 */
222 NTSTATUS
223 STDCALL
224 IoEnumerateDeviceObjectList(
225 IN PDRIVER_OBJECT DriverObject,
226 IN PDEVICE_OBJECT *DeviceObjectList,
227 IN ULONG DeviceObjectListSize,
228 OUT PULONG ActualNumberDeviceObjects
229 )
230 {
231 UNIMPLEMENTED;
232 return STATUS_NOT_IMPLEMENTED;
233 }
234
235
236 /*
237 * @unimplemented
238 */
239 PDEVICE_OBJECT
240 STDCALL
241 IoGetDeviceAttachmentBaseRef(
242 IN PDEVICE_OBJECT DeviceObject
243 )
244 {
245 UNIMPLEMENTED;
246 return 0;
247 }
248
249 /*
250 * @unimplemented
251 */
252 NTSTATUS
253 STDCALL
254 IoGetDiskDeviceObject(
255 IN PDEVICE_OBJECT FileSystemDeviceObject,
256 OUT PDEVICE_OBJECT *DiskDeviceObject
257 )
258 {
259 UNIMPLEMENTED;
260 return STATUS_NOT_IMPLEMENTED;
261 }
262
263 /*
264 * @unimplemented
265 */
266 PDEVICE_OBJECT
267 STDCALL
268 IoGetLowerDeviceObject(
269 IN PDEVICE_OBJECT DeviceObject
270 )
271 {
272 UNIMPLEMENTED;
273 return 0;
274 }
275
276 /*
277 * IoGetRelatedDeviceObject
278 *
279 * Remarks
280 * See "Windows NT File System Internals", page 633 - 634.
281 *
282 * Status
283 * @implemented
284 */
285
286 PDEVICE_OBJECT STDCALL
287 IoGetRelatedDeviceObject(
288 IN PFILE_OBJECT FileObject)
289 {
290 /*
291 * Get logical volume mounted on a physical/virtual/logical device
292 */
293
294 if (FileObject->Vpb && FileObject->Vpb->DeviceObject)
295 {
296 return IoGetAttachedDevice(FileObject->Vpb->DeviceObject);
297 }
298
299 /*
300 * Check if file object has an associated device object mounted by some
301 * other file system.
302 */
303
304 if (FileObject->DeviceObject->Vpb &&
305 FileObject->DeviceObject->Vpb->DeviceObject)
306 {
307 return IoGetAttachedDevice(FileObject->DeviceObject->Vpb->DeviceObject);
308 }
309
310 return IoGetAttachedDevice(FileObject->DeviceObject);
311 }
312
313 /*
314 * IoGetDeviceObjectPointer
315 *
316 * Status
317 * @implemented
318 */
319
320 NTSTATUS STDCALL
321 IoGetDeviceObjectPointer(
322 IN PUNICODE_STRING ObjectName,
323 IN ACCESS_MASK DesiredAccess,
324 OUT PFILE_OBJECT *FileObject,
325 OUT PDEVICE_OBJECT *DeviceObject)
326 {
327 OBJECT_ATTRIBUTES ObjectAttributes;
328 IO_STATUS_BLOCK StatusBlock;
329 PFILE_OBJECT LocalFileObject;
330 HANDLE FileHandle;
331 NTSTATUS Status;
332
333 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x, FileObject %p DeviceObject %p)\n",
334 ObjectName, DesiredAccess, FileObject, DeviceObject);
335
336 InitializeObjectAttributes(
337 &ObjectAttributes,
338 ObjectName,
339 0,
340 NULL,
341 NULL);
342
343 Status = NtOpenFile(
344 &FileHandle,
345 DesiredAccess,
346 &ObjectAttributes,
347 &StatusBlock,
348 0,
349 FILE_NON_DIRECTORY_FILE);
350
351 if (!NT_SUCCESS(Status))
352 return Status;
353
354 Status = ObReferenceObjectByHandle(
355 FileHandle,
356 0,
357 IoFileObjectType,
358 KernelMode,
359 (PVOID*)&LocalFileObject,
360 NULL);
361
362 if (NT_SUCCESS(Status))
363 {
364 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
365 *FileObject = LocalFileObject;
366 }
367
368 NtClose(FileHandle);
369
370 return Status;
371 }
372
373 /*
374 * IoDetachDevice
375 *
376 * Status
377 * @unimplemented
378 */
379
380 VOID STDCALL
381 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
382 {
383 DPRINT("IoDetachDevice(TargetDevice %x) - UNIMPLEMENTED\n", TargetDevice);
384 }
385
386 /*
387 * IoGetAttachedDevice
388 *
389 * Status
390 * @implemented
391 */
392
393 PDEVICE_OBJECT STDCALL
394 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
395 {
396 PDEVICE_OBJECT Current = DeviceObject;
397
398 while (Current->AttachedDevice != NULL)
399 Current = Current->AttachedDevice;
400
401 return Current;
402 }
403
404 /*
405 * IoGetAttachedDeviceReference
406 *
407 * Status
408 * @implemented
409 */
410
411 PDEVICE_OBJECT STDCALL
412 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
413 {
414 PDEVICE_OBJECT Current = IoGetAttachedDevice(DeviceObject);
415 ObReferenceObject(Current);
416 return Current;
417 }
418
419 /*
420 * IoAttachDeviceToDeviceStack
421 *
422 * Status
423 * @implemented
424 */
425
426 PDEVICE_OBJECT STDCALL
427 IoAttachDeviceToDeviceStack(
428 PDEVICE_OBJECT SourceDevice,
429 PDEVICE_OBJECT TargetDevice)
430 {
431 PDEVICE_OBJECT AttachedDevice;
432
433 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice %x, TargetDevice %x)\n",
434 SourceDevice, TargetDevice);
435
436 AttachedDevice = IoGetAttachedDevice(TargetDevice);
437 AttachedDevice->AttachedDevice = SourceDevice;
438 SourceDevice->AttachedDevice = NULL;
439 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
440 SourceDevice->AlignmentRequirement = AttachedDevice->AlignmentRequirement;
441 SourceDevice->SectorSize = AttachedDevice->SectorSize;
442 SourceDevice->Vpb = AttachedDevice->Vpb;
443 return AttachedDevice;
444 }
445
446 /*
447 * IoAttachDevice
448 *
449 * Layers a device over the highest device in a device stack.
450 *
451 * Parameters
452 * SourceDevice
453 * Device to be attached.
454 *
455 * TargetDevice
456 * Name of the target device.
457 *
458 * AttachedDevice
459 * Caller storage for the device attached to.
460 *
461 * Status
462 * @implemented
463 */
464
465 NTSTATUS STDCALL
466 IoAttachDevice(
467 PDEVICE_OBJECT SourceDevice,
468 PUNICODE_STRING TargetDeviceName,
469 PDEVICE_OBJECT *AttachedDevice)
470 {
471 NTSTATUS Status;
472 PFILE_OBJECT FileObject;
473 PDEVICE_OBJECT TargetDevice;
474
475 Status = IoGetDeviceObjectPointer(
476 TargetDeviceName,
477 FILE_READ_ATTRIBUTES,
478 &FileObject,
479 &TargetDevice);
480
481 if (!NT_SUCCESS(Status))
482 {
483 return Status;
484 }
485
486 *AttachedDevice = IoAttachDeviceToDeviceStack(
487 SourceDevice,
488 TargetDevice);
489
490 ObDereferenceObject(FileObject);
491
492 return STATUS_SUCCESS;
493 }
494
495 /*
496 * IoCreateDevice
497 *
498 * Allocates memory for and intializes a device object for use for
499 * a driver.
500 *
501 * Parameters
502 * DriverObject
503 * Driver object passed by IO Manager when the driver was loaded.
504 *
505 * DeviceExtensionSize
506 * Number of bytes for the device extension.
507 *
508 * DeviceName
509 * Unicode name of device.
510 *
511 * DeviceType
512 * Device type of the new device.
513 *
514 * DeviceCharacteristics
515 * Bit mask of device characteristics.
516 *
517 * Exclusive
518 * TRUE if only one thread can access the device at a time.
519 *
520 * DeviceObject
521 * On successful return this parameter is filled by pointer to
522 * allocated device object.
523 *
524 * Status
525 * @implemented
526 */
527
528 NTSTATUS STDCALL
529 IoCreateDevice(
530 PDRIVER_OBJECT DriverObject,
531 ULONG DeviceExtensionSize,
532 PUNICODE_STRING DeviceName,
533 DEVICE_TYPE DeviceType,
534 ULONG DeviceCharacteristics,
535 BOOLEAN Exclusive,
536 PDEVICE_OBJECT *DeviceObject)
537 {
538 WCHAR AutoNameBuffer[20];
539 UNICODE_STRING AutoName;
540 PDEVICE_OBJECT CreatedDeviceObject;
541 PDEVOBJ_EXTENSION DeviceObjectExtension;
542 OBJECT_ATTRIBUTES ObjectAttributes;
543 NTSTATUS Status;
544
545 ASSERT_IRQL(PASSIVE_LEVEL);
546
547 if (DeviceName != NULL)
548 {
549 DPRINT("IoCreateDevice(DriverObject %x, DeviceName %S)\n",
550 DriverObject, DeviceName->Buffer);
551 }
552 else
553 {
554 DPRINT("IoCreateDevice(DriverObject %x)\n",DriverObject);
555 }
556
557 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
558 {
559 swprintf(AutoNameBuffer,
560 L"\\Device\\%08lx",
561 InterlockedIncrementUL(&IopDeviceObjectNumber));
562 RtlInitUnicodeString(&AutoName,
563 AutoNameBuffer);
564 DeviceName = &AutoName;
565 }
566
567 if (DeviceName != NULL)
568 {
569 InitializeObjectAttributes(&ObjectAttributes, DeviceName, 0, NULL, NULL);
570 Status = ObCreateObject(
571 KernelMode,
572 IoDeviceObjectType,
573 &ObjectAttributes,
574 KernelMode,
575 NULL,
576 sizeof(DEVICE_OBJECT),
577 0,
578 0,
579 (PVOID*)&CreatedDeviceObject);
580 }
581 else
582 {
583 Status = ObCreateObject(
584 KernelMode,
585 IoDeviceObjectType,
586 NULL,
587 KernelMode,
588 NULL,
589 sizeof(DEVICE_OBJECT),
590 0,
591 0,
592 (PVOID*)&CreatedDeviceObject);
593 }
594
595 *DeviceObject = NULL;
596
597 if (!NT_SUCCESS(Status))
598 {
599 DPRINT("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status);
600 return Status;
601 }
602
603 if (DriverObject->DeviceObject == NULL)
604 {
605 DriverObject->DeviceObject = CreatedDeviceObject;
606 CreatedDeviceObject->NextDevice = NULL;
607 }
608 else
609 {
610 CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
611 DriverObject->DeviceObject = CreatedDeviceObject;
612 }
613
614 CreatedDeviceObject->Type = DeviceType;
615 CreatedDeviceObject->DriverObject = DriverObject;
616 CreatedDeviceObject->CurrentIrp = NULL;
617 CreatedDeviceObject->Flags = 0;
618
619 CreatedDeviceObject->DeviceExtension =
620 ExAllocatePoolWithTag(
621 NonPagedPool,
622 DeviceExtensionSize,
623 TAG_DEVICE_EXTENSION);
624
625 if (DeviceExtensionSize > 0 && CreatedDeviceObject->DeviceExtension == NULL)
626 {
627 ExFreePool(CreatedDeviceObject);
628 DPRINT("IoCreateDevice() ExAllocatePoolWithTag failed, returning: 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES);
629 return STATUS_INSUFFICIENT_RESOURCES;
630 }
631
632 if (DeviceExtensionSize > 0)
633 {
634 RtlZeroMemory(CreatedDeviceObject->DeviceExtension, DeviceExtensionSize);
635 }
636
637 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + DeviceExtensionSize;
638 CreatedDeviceObject->ReferenceCount = 1;
639 CreatedDeviceObject->AttachedDevice = NULL;
640 CreatedDeviceObject->DeviceType = DeviceType;
641 CreatedDeviceObject->StackSize = 1;
642 CreatedDeviceObject->AlignmentRequirement = 1;
643 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
644 CreatedDeviceObject->Timer = NULL;
645 CreatedDeviceObject->Vpb = NULL;
646 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
647
648 KeInitializeEvent(
649 &CreatedDeviceObject->DeviceLock,
650 SynchronizationEvent,
651 TRUE);
652
653 /* FIXME: Do we need to add network drives too?! */
654 if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
655 CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
656 CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
657 {
658 IoAttachVpb(CreatedDeviceObject);
659 }
660 CreatedDeviceObject->SectorSize = 512; /* FIXME */
661
662 DeviceObjectExtension =
663 ExAllocatePoolWithTag(
664 NonPagedPool,
665 sizeof(DEVOBJ_EXTENSION),
666 TAG_DEVICE_EXTENSION);
667
668 DeviceObjectExtension->Type = 0 /* ?? */;
669 DeviceObjectExtension->Size = sizeof(DEVOBJ_EXTENSION);
670 DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
671 DeviceObjectExtension->DeviceNode = NULL;
672
673 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
674
675 *DeviceObject = CreatedDeviceObject;
676
677 return STATUS_SUCCESS;
678 }
679
680 /*
681 * IoOpenDeviceInstanceKey
682 *
683 * Status
684 * @unimplemented
685 */
686
687 NTSTATUS STDCALL
688 IoOpenDeviceInstanceKey(
689 DWORD Unknown0,
690 DWORD Unknown1,
691 DWORD Unknown2,
692 DWORD Unknown3,
693 DWORD Unknown4)
694 {
695 UNIMPLEMENTED;
696 return STATUS_NOT_IMPLEMENTED;
697 }
698
699 /*
700 * @unimplemented
701 */
702 VOID
703 STDCALL
704 IoRegisterBootDriverReinitialization(
705 IN PDRIVER_OBJECT DriverObject,
706 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
707 IN PVOID Context
708 )
709 {
710 UNIMPLEMENTED;
711 }
712
713
714 /*
715 * @unimplemented
716 */
717 NTSTATUS
718 STDCALL
719 IoRegisterLastChanceShutdownNotification(
720 IN PDEVICE_OBJECT DeviceObject
721 )
722 {
723 UNIMPLEMENTED;
724 return STATUS_NOT_IMPLEMENTED;
725 }
726
727 /*
728 * IoQueryDeviceEnumInfo
729 *
730 * Status
731 * @unimplemented
732 */
733
734 DWORD STDCALL
735 IoQueryDeviceEnumInfo(
736 DWORD Unknown0,
737 DWORD Unknown1)
738 {
739 UNIMPLEMENTED;
740 return 0;
741 }
742
743 /*
744 * @unimplemented
745 */
746 VOID
747 STDCALL
748 IoSetStartIoAttributes(
749 IN PDEVICE_OBJECT DeviceObject,
750 IN BOOLEAN DeferredStartIo,
751 IN BOOLEAN NonCancelable
752 )
753 {
754 UNIMPLEMENTED;
755 }
756
757 /*
758 * @unimplemented
759 */
760 VOID
761 STDCALL
762 IoSynchronousInvalidateDeviceRelations(
763 IN PDEVICE_OBJECT DeviceObject,
764 IN DEVICE_RELATION_TYPE Type
765 )
766 {
767 UNIMPLEMENTED;
768 }
769
770
771 /*
772 * @unimplemented
773 */
774 NTSTATUS
775 STDCALL
776 IoValidateDeviceIoControlAccess(
777 IN PIRP Irp,
778 IN ULONG RequiredAccess
779 )
780 {
781 UNIMPLEMENTED;
782 return STATUS_NOT_IMPLEMENTED;
783 }
784
785 /* EOF */