compile release builds with -O3 instead of -Os because it catches more mistakes
[reactos.git] / reactos / ntoskrnl / io / device.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/io/device.c
5 * PURPOSE: Device Object Management, including Notifications and Queues.
6 *
7 * PROGRAMMERS: Alex Ionescu
8 * David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 static ULONG IopDeviceObjectNumber = 0;
20
21 typedef struct _SHUTDOWN_ENTRY
22 {
23 LIST_ENTRY ShutdownList;
24 PDEVICE_OBJECT DeviceObject;
25 } SHUTDOWN_ENTRY, *PSHUTDOWN_ENTRY;
26
27 LIST_ENTRY ShutdownListHead;
28 KSPIN_LOCK ShutdownListLock;
29
30 /* PRIVATE FUNCTIONS **********************************************************/
31
32 VOID
33 IoShutdownRegisteredDevices(VOID)
34 {
35 PSHUTDOWN_ENTRY ShutdownEntry;
36 PLIST_ENTRY Entry;
37 IO_STATUS_BLOCK StatusBlock;
38 PIRP Irp;
39 KEVENT Event;
40 NTSTATUS Status;
41
42 Entry = ShutdownListHead.Flink;
43 while (Entry != &ShutdownListHead)
44 {
45 ShutdownEntry = CONTAINING_RECORD(Entry, SHUTDOWN_ENTRY, ShutdownList);
46
47 KeInitializeEvent (&Event,
48 NotificationEvent,
49 FALSE);
50
51 Irp = IoBuildSynchronousFsdRequest (IRP_MJ_SHUTDOWN,
52 ShutdownEntry->DeviceObject,
53 NULL,
54 0,
55 NULL,
56 &Event,
57 &StatusBlock);
58
59 Status = IoCallDriver (ShutdownEntry->DeviceObject,
60 Irp);
61 if (Status == STATUS_PENDING)
62 {
63 KeWaitForSingleObject (&Event,
64 Executive,
65 KernelMode,
66 FALSE,
67 NULL);
68 }
69
70 Entry = Entry->Flink;
71 }
72 }
73
74 NTSTATUS
75 FASTCALL
76 IopInitializeDevice(PDEVICE_NODE DeviceNode,
77 PDRIVER_OBJECT DriverObject)
78 {
79 PDEVICE_OBJECT Fdo;
80 NTSTATUS Status;
81
82 if (DriverObject->DriverExtension->AddDevice)
83 {
84 /* This is a Plug and Play driver */
85 DPRINT("Plug and Play driver found\n");
86
87 ASSERT(DeviceNode->PhysicalDeviceObject);
88
89 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
90 DriverObject->DriverExtension->AddDevice);
91
92 Status = DriverObject->DriverExtension->AddDevice(
93 DriverObject, DeviceNode->PhysicalDeviceObject);
94
95 if (!NT_SUCCESS(Status))
96 {
97 return Status;
98 }
99
100 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
101
102 if (Fdo == DeviceNode->PhysicalDeviceObject)
103 {
104 /* FIXME: What do we do? Unload the driver or just disable the device? */
105 DbgPrint("An FDO was not attached\n");
106 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
107 return STATUS_UNSUCCESSFUL;
108 }
109
110 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
111
112 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
113 {
114 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
115
116 /* There can be only one system power device */
117 if (!SystemPowerDeviceNodeCreated)
118 {
119 PopSystemPowerDeviceNode = DeviceNode;
120 SystemPowerDeviceNodeCreated = TRUE;
121 }
122 }
123
124 ObDereferenceObject(Fdo);
125 }
126
127 return STATUS_SUCCESS;
128 }
129
130 NTSTATUS
131 IopStartDevice(
132 PDEVICE_NODE DeviceNode)
133 {
134 IO_STATUS_BLOCK IoStatusBlock;
135 IO_STACK_LOCATION Stack;
136 PDEVICE_OBJECT Fdo;
137 NTSTATUS Status;
138
139 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
140
141 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
142 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
143 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
144
145 Status = IopInitiatePnpIrp(
146 Fdo,
147 &IoStatusBlock,
148 IRP_MN_START_DEVICE,
149 &Stack);
150
151 if (!NT_SUCCESS(Status))
152 {
153 DPRINT("IopInitiatePnpIrp() failed\n");
154 }
155 else
156 {
157 if (Fdo->DeviceType == FILE_DEVICE_BUS_EXTENDER ||
158 Fdo->DeviceType == FILE_DEVICE_ACPI)
159 {
160 DPRINT("Bus extender found\n");
161
162 Status = IopInvalidateDeviceRelations(DeviceNode, BusRelations);
163 }
164 }
165
166 ObDereferenceObject(Fdo);
167
168 return Status;
169 }
170
171 NTSTATUS
172 STDCALL
173 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
174 IN ACCESS_MASK DesiredAccess,
175 OUT PFILE_OBJECT *FileObject,
176 OUT PDEVICE_OBJECT *DeviceObject,
177 IN ULONG AttachFlag)
178 {
179 OBJECT_ATTRIBUTES ObjectAttributes;
180 IO_STATUS_BLOCK StatusBlock;
181 PFILE_OBJECT LocalFileObject;
182 HANDLE FileHandle;
183 NTSTATUS Status;
184
185 DPRINT("IoGetDeviceObjectPointer(ObjectName %wZ, DesiredAccess %x,"
186 "FileObject %p DeviceObject %p)\n",
187 ObjectName, DesiredAccess, FileObject, DeviceObject);
188
189 /* Open the Device */
190 InitializeObjectAttributes(&ObjectAttributes,
191 ObjectName,
192 0,
193 NULL,
194 NULL);
195 Status = ZwOpenFile(&FileHandle,
196 DesiredAccess,
197 &ObjectAttributes,
198 &StatusBlock,
199 0,
200 FILE_NON_DIRECTORY_FILE | AttachFlag);
201
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT1("NtOpenFile failed, Status: 0x%x\n", Status);
205 return Status;
206 }
207
208 /* Get File Object */
209 Status = ObReferenceObjectByHandle(FileHandle,
210 0,
211 IoFileObjectType,
212 KernelMode,
213 (PVOID*)&LocalFileObject,
214 NULL);
215 if (NT_SUCCESS(Status))
216 {
217 /* Return the requested data */
218 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
219 *FileObject = LocalFileObject;
220 }
221
222 /* Close the handle */
223 ZwClose(FileHandle);
224 return Status;
225 }
226
227 /* PUBLIC FUNCTIONS ***********************************************************/
228
229 /*
230 * IoAttachDevice
231 *
232 * Layers a device over the highest device in a device stack.
233 *
234 * Parameters
235 * SourceDevice
236 * Device to be attached.
237 *
238 * TargetDevice
239 * Name of the target device.
240 *
241 * AttachedDevice
242 * Caller storage for the device attached to.
243 *
244 * Status
245 * @implemented
246 */
247 NTSTATUS
248 STDCALL
249 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
250 PUNICODE_STRING TargetDeviceName,
251 PDEVICE_OBJECT *AttachedDevice)
252 {
253 NTSTATUS Status;
254 PFILE_OBJECT FileObject = NULL;
255 PDEVICE_OBJECT TargetDevice = NULL;
256
257 /* Call the helper routine for an attach operation */
258 DPRINT("IoAttachDevice\n");
259 Status = IopGetDeviceObjectPointer(TargetDeviceName,
260 FILE_READ_ATTRIBUTES,
261 &FileObject,
262 &TargetDevice,
263 IO_ATTACH_DEVICE_API);
264
265 if (!NT_SUCCESS(Status))
266 {
267 DPRINT1("Failed to get Device Object\n");
268 return Status;
269 }
270
271 /* Attach the device */
272 IoAttachDeviceToDeviceStackSafe(SourceDevice, TargetDevice, AttachedDevice);
273
274 /* Derference it */
275 ObDereferenceObject(FileObject);
276 return STATUS_SUCCESS;
277 }
278
279 /*
280 * IoAttachDeviceByPointer
281 *
282 * Status
283 * @implemented
284 */
285 NTSTATUS
286 STDCALL
287 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
288 IN PDEVICE_OBJECT TargetDevice)
289 {
290 PDEVICE_OBJECT AttachedDevice;
291 NTSTATUS Status = STATUS_SUCCESS;
292
293 DPRINT("IoAttachDeviceByPointer(SourceDevice 0x%p, TargetDevice 0x%p)\n",
294 SourceDevice, TargetDevice);
295
296 /* Do the Attach */
297 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
298 if (AttachedDevice == NULL) Status = STATUS_NO_SUCH_DEVICE;
299
300 /* Return the status */
301 return Status;
302 }
303
304 /*
305 * IoAttachDeviceToDeviceStack
306 *
307 * Status
308 * @implemented
309 */
310 PDEVICE_OBJECT
311 STDCALL
312 IoAttachDeviceToDeviceStack(PDEVICE_OBJECT SourceDevice,
313 PDEVICE_OBJECT TargetDevice)
314 {
315 NTSTATUS Status;
316 PDEVICE_OBJECT LocalAttach;
317
318 /* Attach it safely */
319 DPRINT("IoAttachDeviceToDeviceStack\n");
320 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
321 TargetDevice,
322 &LocalAttach);
323
324 /* Return it */
325 DPRINT("IoAttachDeviceToDeviceStack DONE: 0x%p\n", LocalAttach);
326 return LocalAttach;
327 }
328
329 /*
330 * @implemented
331 */
332 NTSTATUS
333 STDCALL
334 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
335 IN PDEVICE_OBJECT TargetDevice,
336 OUT PDEVICE_OBJECT *AttachedToDeviceObject)
337 {
338 PDEVICE_OBJECT AttachedDevice;
339 PDEVOBJ_EXTENSION SourceDeviceExtension;
340
341 DPRINT("IoAttachDeviceToDeviceStack(SourceDevice 0x%p, TargetDevice 0x%p)\n",
342 SourceDevice, TargetDevice);
343
344 /* Get the Attached Device and source extension */
345 AttachedDevice = IoGetAttachedDevice(TargetDevice);
346 SourceDeviceExtension = SourceDevice->DeviceObjectExtension;
347
348 /* Make sure that it's in a correct state */
349 if (!(AttachedDevice->DeviceObjectExtension->ExtensionFlags &
350 (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING |
351 DOE_REMOVE_PENDING | DOE_REMOVE_PROCESSED)))
352 {
353 /* Update fields */
354 AttachedDevice->AttachedDevice = SourceDevice;
355 SourceDevice->AttachedDevice = NULL;
356 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
357 SourceDevice->AlignmentRequirement = AttachedDevice->AlignmentRequirement;
358 SourceDevice->SectorSize = AttachedDevice->SectorSize;
359 SourceDevice->Vpb = AttachedDevice->Vpb;
360
361 /* Set the attachment in the device extension */
362 SourceDeviceExtension->AttachedTo = AttachedDevice;
363 }
364 else
365 {
366 /* Device was unloading or being removed */
367 AttachedDevice = NULL;
368 }
369
370 /* Return the attached device */
371 *AttachedToDeviceObject = AttachedDevice;
372 return STATUS_SUCCESS;
373 }
374
375 /*
376 * IoCreateDevice
377 *
378 * Allocates memory for and intializes a device object for use for
379 * a driver.
380 *
381 * Parameters
382 * DriverObject
383 * Driver object passed by IO Manager when the driver was loaded.
384 *
385 * DeviceExtensionSize
386 * Number of bytes for the device extension.
387 *
388 * DeviceName
389 * Unicode name of device.
390 *
391 * DeviceType
392 * Device type of the new device.
393 *
394 * DeviceCharacteristics
395 * Bit mask of device characteristics.
396 *
397 * Exclusive
398 * TRUE if only one thread can access the device at a time.
399 *
400 * DeviceObject
401 * On successful return this parameter is filled by pointer to
402 * allocated device object.
403 *
404 * Status
405 * @implemented
406 */
407 NTSTATUS
408 STDCALL
409 IoCreateDevice(PDRIVER_OBJECT DriverObject,
410 ULONG DeviceExtensionSize,
411 PUNICODE_STRING DeviceName,
412 DEVICE_TYPE DeviceType,
413 ULONG DeviceCharacteristics,
414 BOOLEAN Exclusive,
415 PDEVICE_OBJECT *DeviceObject)
416 {
417 WCHAR AutoNameBuffer[20];
418 UNICODE_STRING AutoName;
419 PDEVICE_OBJECT CreatedDeviceObject;
420 PDEVOBJ_EXTENSION DeviceObjectExtension;
421 OBJECT_ATTRIBUTES ObjectAttributes;
422 NTSTATUS Status;
423 ULONG AlignedDeviceExtensionSize;
424 ULONG TotalSize;
425 HANDLE TempHandle;
426
427 ASSERT_IRQL(PASSIVE_LEVEL);
428 DPRINT("IoCreateDevice(DriverObject 0x%p)\n", DriverObject);
429
430 /* Generate a name if we have to */
431 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
432 {
433 swprintf(AutoNameBuffer,
434 L"\\Device\\%08lx",
435 InterlockedIncrementUL(&IopDeviceObjectNumber));
436 RtlInitUnicodeString(&AutoName, AutoNameBuffer);
437 DeviceName = &AutoName;
438 }
439
440 /* Initialize the Object Attributes */
441 InitializeObjectAttributes(&ObjectAttributes, DeviceName, 0, NULL, NULL);
442
443 /* Honor exclusive flag */
444 ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
445
446 /* Create a permanent object for named devices */
447 if (DeviceName != NULL)
448 {
449 ObjectAttributes.Attributes |= OBJ_PERMANENT;
450 }
451
452 /* Align the Extension Size to 8-bytes */
453 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7;
454 DPRINT("AlignedDeviceExtensionSize %x\n", AlignedDeviceExtensionSize);
455
456 /* Total Size */
457 TotalSize = AlignedDeviceExtensionSize +
458 sizeof(DEVICE_OBJECT) + sizeof(DEVOBJ_EXTENSION);
459 DPRINT("TotalSize %x\n", TotalSize);
460
461 /* Create the Device Object */
462 Status = ObCreateObject(KernelMode,
463 IoDeviceObjectType,
464 &ObjectAttributes,
465 KernelMode,
466 NULL,
467 TotalSize,
468 0,
469 0,
470 (PVOID*)&CreatedDeviceObject);
471
472 if (!NT_SUCCESS(Status))
473 {
474 DPRINT1("IoCreateDevice() ObCreateObject failed, status: 0x%08X\n", Status);
475 return Status;
476 }
477
478 /* Clear the whole Object and extension so we don't null stuff manually */
479 RtlZeroMemory(CreatedDeviceObject, TotalSize);
480 DPRINT("CreatedDeviceObject 0x%p\n", CreatedDeviceObject);
481
482 /*
483 * Setup the Type and Size. Note that we don't use the aligned size,
484 * because that's only padding for the DevObjExt and not part of the Object.
485 */
486 CreatedDeviceObject->Type = IO_TYPE_DEVICE;
487 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + DeviceExtensionSize;
488
489 /* The kernel extension is after the driver internal extension */
490 DeviceObjectExtension = (PDEVOBJ_EXTENSION)
491 ((ULONG_PTR)(CreatedDeviceObject + 1) +
492 AlignedDeviceExtensionSize);
493
494 /* Set the Type and Size. Question: why is Size 0 on Windows? */
495 DPRINT("DeviceObjectExtension 0x%p\n", DeviceObjectExtension);
496 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
497 DeviceObjectExtension->Size = 0;
498
499 /* Link the Object and Extension */
500 DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
501 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
502
503 /* Set Device Object Data */
504 CreatedDeviceObject->DeviceType = DeviceType;
505 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
506 CreatedDeviceObject->DeviceExtension = CreatedDeviceObject + 1;
507 CreatedDeviceObject->StackSize = 1;
508 CreatedDeviceObject->AlignmentRequirement = 1; /* FIXME */
509
510 /* Set the Flags */
511 /* FIXME: After the Driver is Loaded, the flag below should be removed */
512 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
513 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
514 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
515
516 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
517 if (CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK ||
518 CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK ||
519 CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM ||
520 CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE)
521 {
522 /* Create Vpb */
523 IopAttachVpb(CreatedDeviceObject);
524
525 /* Initialize Lock Event */
526 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
527 SynchronizationEvent,
528 TRUE);
529 }
530
531 /* Set the right Sector Size */
532 switch (DeviceType)
533 {
534 case FILE_DEVICE_DISK_FILE_SYSTEM:
535 case FILE_DEVICE_DISK:
536 case FILE_DEVICE_VIRTUAL_DISK:
537 CreatedDeviceObject->SectorSize = 512;
538 break;
539
540 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
541 CreatedDeviceObject->SectorSize = 2048;
542 break;
543 }
544
545 /* Create the Device Queue */
546 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
547
548 /* Insert the Object */
549 Status = ObInsertObject(CreatedDeviceObject,
550 NULL,
551 FILE_READ_DATA | FILE_WRITE_DATA,
552 0,
553 NULL,
554 &TempHandle);
555
556 if (!NT_SUCCESS(Status))
557 {
558 DPRINT1("Cannot insert Device Object into Handle Table\n");
559 *DeviceObject = NULL;
560 return Status;
561 }
562
563 /* Now do the final linking */
564 ObReferenceObject(DriverObject);
565 CreatedDeviceObject->DriverObject = DriverObject;
566 CreatedDeviceObject->NextDevice = DriverObject->DeviceObject;
567 DriverObject->DeviceObject = CreatedDeviceObject;
568
569 NtClose(TempHandle);
570
571 /* Return to caller */
572 *DeviceObject = CreatedDeviceObject;
573 return STATUS_SUCCESS;
574 }
575
576 /*
577 * IoDeleteDevice
578 *
579 * Status
580 * @implemented
581 */
582 VOID
583 STDCALL
584 IoDeleteDevice(PDEVICE_OBJECT DeviceObject)
585 {
586 PDEVICE_OBJECT Previous;
587
588 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
589 IoUnregisterShutdownNotification(DeviceObject);
590
591 /* Remove the timer if it exists */
592 if (DeviceObject->Timer)
593 {
594 IopRemoveTimerFromTimerList(DeviceObject->Timer);
595 ExFreePoolWithTag(DeviceObject->Timer, TAG_IO_TIMER);
596 }
597
598 /* Remove device from driver device list */
599 Previous = DeviceObject->DriverObject->DeviceObject;
600 if (Previous == DeviceObject)
601 {
602 DeviceObject->DriverObject->DeviceObject = DeviceObject->NextDevice;
603 }
604 else
605 {
606 while (Previous->NextDevice != DeviceObject)
607 Previous = Previous->NextDevice;
608 Previous->NextDevice = DeviceObject->NextDevice;
609 }
610
611 /* I guess this should be removed later... but it shouldn't cause problems */
612 DeviceObject->DeviceObjectExtension->ExtensionFlags |= DOE_DELETE_PENDING;
613
614 /* Make the object temporary. This should automatically remove the device
615 from the namespace */
616 ObMakeTemporaryObject(DeviceObject);
617
618 /* Dereference the driver object */
619 ObDereferenceObject(DeviceObject->DriverObject);
620
621 /* Remove the keep-alive reference */
622 ObDereferenceObject(DeviceObject);
623 }
624
625 /*
626 * IoDetachDevice
627 *
628 * Status
629 * @implemented
630 */
631 VOID
632 STDCALL
633 IoDetachDevice(PDEVICE_OBJECT TargetDevice)
634 {
635 DPRINT("IoDetachDevice(TargetDevice 0x%p)\n", TargetDevice);
636
637 /* Remove the attachment */
638 TargetDevice->AttachedDevice->DeviceObjectExtension->AttachedTo = NULL;
639 TargetDevice->AttachedDevice = NULL;
640 }
641
642 /*
643 * @implemented
644 */
645 NTSTATUS
646 STDCALL
647 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject,
648 IN PDEVICE_OBJECT *DeviceObjectList,
649 IN ULONG DeviceObjectListSize,
650 OUT PULONG ActualNumberDeviceObjects)
651 {
652 ULONG ActualDevices = 1;
653 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
654
655 DPRINT1("IoEnumerateDeviceObjectList\n");
656
657 /* Find out how many devices we'll enumerate */
658 while ((CurrentDevice = CurrentDevice->NextDevice))
659 {
660 ActualDevices++;
661 }
662
663 /* Go back to the first */
664 CurrentDevice = DriverObject->DeviceObject;
665
666 /* Start by at least returning this */
667 *ActualNumberDeviceObjects = ActualDevices;
668
669 /* Check if we can support so many */
670 if ((ActualDevices * 4) > DeviceObjectListSize)
671 {
672 /* Fail because the buffer was too small */
673 return STATUS_BUFFER_TOO_SMALL;
674 }
675
676 /* Check if the caller only wanted the size */
677 if (DeviceObjectList)
678 {
679 /* Loop through all the devices */
680 while (ActualDevices)
681 {
682 /* Reference each Device */
683 ObReferenceObject(CurrentDevice);
684
685 /* Add it to the list */
686 *DeviceObjectList = CurrentDevice;
687
688 /* Go to the next one */
689 CurrentDevice = CurrentDevice->NextDevice;
690 ActualDevices--;
691 DeviceObjectList++;
692 }
693 }
694
695 /* Return the status */
696 return STATUS_SUCCESS;
697 }
698
699 /*
700 * IoGetAttachedDevice
701 *
702 * Status
703 * @implemented
704 */
705 PDEVICE_OBJECT
706 STDCALL
707 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
708 {
709 PDEVICE_OBJECT Current = DeviceObject;
710
711 /* Get the last attached device */
712 while (Current->AttachedDevice)
713 {
714 Current = Current->AttachedDevice;
715 }
716
717 /* Return it */
718 return Current;
719 }
720
721 /*
722 * IoGetAttachedDeviceReference
723 *
724 * Status
725 * @implemented
726 */
727 PDEVICE_OBJECT
728 STDCALL
729 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
730 {
731 PDEVICE_OBJECT Current = IoGetAttachedDevice(DeviceObject);
732
733 /* Reference the ATtached Device */
734 ObReferenceObject(Current);
735 return Current;
736 }
737
738 /*
739 * @implemented
740 */
741 PDEVICE_OBJECT
742 STDCALL
743 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
744 {
745 /* Return the attached Device */
746 return (DeviceObject->DeviceObjectExtension->AttachedTo);
747 }
748
749 /*
750 * IoGetDeviceObjectPointer
751 *
752 * Status
753 * @implemented
754 */
755 NTSTATUS
756 STDCALL
757 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
758 IN ACCESS_MASK DesiredAccess,
759 OUT PFILE_OBJECT *FileObject,
760 OUT PDEVICE_OBJECT *DeviceObject)
761 {
762 /* Call the helper routine for a normal operation */
763 return IopGetDeviceObjectPointer(ObjectName,
764 DesiredAccess,
765 FileObject,
766 DeviceObject,
767 0);
768 }
769
770 /*
771 * @implemented
772 */
773 NTSTATUS
774 STDCALL
775 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
776 OUT PDEVICE_OBJECT *DiskDeviceObject)
777 {
778 PDEVOBJ_EXTENSION DeviceExtension;
779 PVPB Vpb;
780 KIRQL OldIrql;
781
782 /* Make sure there's a VPB */
783 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
784
785 /* Acquire it */
786 IoAcquireVpbSpinLock(&OldIrql);
787
788 /* Get the Device Extension */
789 DeviceExtension = FileSystemDeviceObject->DeviceObjectExtension;
790
791 /* Make sure this one has a VPB too */
792 Vpb = DeviceExtension->Vpb;
793 if (!Vpb) return STATUS_INVALID_PARAMETER;
794
795 /* Make sure someone it's mounted */
796 if ((!Vpb->ReferenceCount) || (Vpb->Flags & VPB_MOUNTED)) return STATUS_VOLUME_DISMOUNTED;
797
798 /* Return the Disk Device Object */
799 *DiskDeviceObject = Vpb->RealDevice;
800
801 /* Release the lock */
802 IoReleaseVpbSpinLock(OldIrql);
803 return STATUS_SUCCESS;
804 }
805
806 /*
807 * @implemented
808 */
809 PDEVICE_OBJECT
810 STDCALL
811 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
812 {
813 PDEVOBJ_EXTENSION DeviceExtension = DeviceObject->DeviceObjectExtension;
814 PDEVICE_OBJECT LowerDeviceObject = NULL;
815
816 /* Make sure it's not getting deleted */
817 if (DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
818 DOE_DELETE_PENDING |
819 DOE_REMOVE_PENDING |
820 DOE_REMOVE_PROCESSED))
821 {
822 /* Get the Lower Device Object */
823 LowerDeviceObject = DeviceExtension->AttachedTo;
824
825 /* Reference it */
826 ObReferenceObject(LowerDeviceObject);
827 }
828
829 /* Return it */
830 return LowerDeviceObject;
831 }
832
833 /*
834 * IoGetRelatedDeviceObject
835 *
836 * Remarks
837 * See "Windows NT File System Internals", page 633 - 634.
838 *
839 * Status
840 * @implemented
841 */
842 PDEVICE_OBJECT
843 STDCALL
844 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
845 {
846 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
847
848 /* Get logical volume mounted on a physical/virtual/logical device */
849 if (FileObject->Vpb && FileObject->Vpb->DeviceObject)
850 {
851 DeviceObject = FileObject->Vpb->DeviceObject;
852 }
853
854 /*
855 * Check if file object has an associated device object mounted by some
856 * other file system.
857 */
858 if (FileObject->DeviceObject->Vpb &&
859 FileObject->DeviceObject->Vpb->DeviceObject)
860 {
861 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
862 }
863
864 /* Return the highest attached device */
865 return IoGetAttachedDevice(DeviceObject);
866 }
867
868 /*
869 * @unimplemented
870 */
871 NTSTATUS
872 STDCALL
873 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
874 {
875 UNIMPLEMENTED;
876 return STATUS_NOT_IMPLEMENTED;
877 }
878
879 /*
880 * @implemented
881 */
882 NTSTATUS
883 STDCALL
884 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
885 {
886 PSHUTDOWN_ENTRY Entry;
887
888 Entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(SHUTDOWN_ENTRY),
889 TAG_SHUTDOWN_ENTRY);
890 if (Entry == NULL)
891 return STATUS_INSUFFICIENT_RESOURCES;
892
893 Entry->DeviceObject = DeviceObject;
894
895 ExInterlockedInsertHeadList(&ShutdownListHead,
896 &Entry->ShutdownList,
897 &ShutdownListLock);
898
899 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
900
901 return STATUS_SUCCESS;
902 }
903
904 /*
905 * @unimplemented
906 */
907 VOID
908 STDCALL
909 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
910 IN BOOLEAN DeferredStartIo,
911 IN BOOLEAN NonCancelable)
912 {
913 UNIMPLEMENTED;
914 }
915
916 /*
917 * @implemented
918 *
919 * FUNCTION: Dequeues the next packet from the given device object's
920 * associated device queue according to a specified sort-key value and calls
921 * the drivers StartIo routine with that IRP
922 * ARGUMENTS:
923 * DeviceObject = Device object for which the irp is to dequeued
924 * Cancelable = True if IRPs in the key can be canceled
925 * Key = Sort key specifing which entry to remove from the queue
926 */
927 VOID
928 STDCALL
929 IoStartNextPacketByKey(PDEVICE_OBJECT DeviceObject,
930 BOOLEAN Cancelable,
931 ULONG Key)
932 {
933 PKDEVICE_QUEUE_ENTRY entry;
934 PIRP Irp;
935
936 entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue,
937 Key);
938
939 if (entry != NULL)
940 {
941 Irp = CONTAINING_RECORD(entry,
942 IRP,
943 Tail.Overlay.DeviceQueueEntry);
944 DeviceObject->CurrentIrp = Irp;
945 DPRINT("Next irp is 0x%p\n", Irp);
946 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
947 }
948 else
949 {
950 DPRINT("No next irp\n");
951 DeviceObject->CurrentIrp = NULL;
952 }
953 }
954
955 /*
956 * @implemented
957 *
958 * FUNCTION: Removes the next packet from the device's queue and calls
959 * the driver's StartIO
960 * ARGUMENTS:
961 * DeviceObject = Device
962 * Cancelable = True if irps in the queue can be canceled
963 */
964 VOID
965 STDCALL
966 IoStartNextPacket(PDEVICE_OBJECT DeviceObject,
967 BOOLEAN Cancelable)
968 {
969 PKDEVICE_QUEUE_ENTRY entry;
970 PIRP Irp;
971
972 DPRINT("IoStartNextPacket(DeviceObject 0x%p, Cancelable %d)\n",
973 DeviceObject, Cancelable);
974
975 entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
976
977 if (entry!=NULL)
978 {
979 Irp = CONTAINING_RECORD(entry,IRP,Tail.Overlay.DeviceQueueEntry);
980 DeviceObject->CurrentIrp = Irp;
981 DeviceObject->DriverObject->DriverStartIo(DeviceObject,Irp);
982 }
983 else
984 {
985 DeviceObject->CurrentIrp = NULL;
986 }
987 }
988
989 /*
990 * @implemented
991 *
992 * FUNCTION: Either call the device's StartIO routine with the packet or,
993 * if the device is busy, queue it.
994 * ARGUMENTS:
995 * DeviceObject = Device to start the packet on
996 * Irp = Irp to queue
997 * Key = Where to insert the irp
998 * If zero then insert in the tail of the queue
999 * CancelFunction = Optional function to cancel the irqp
1000 */
1001 VOID
1002 STDCALL
1003 IoStartPacket(PDEVICE_OBJECT DeviceObject,
1004 PIRP Irp,
1005 PULONG Key,
1006 PDRIVER_CANCEL CancelFunction)
1007 {
1008 BOOLEAN stat;
1009 KIRQL oldirql;
1010
1011 DPRINT("IoStartPacket(Irp 0x%p)\n", Irp);
1012
1013 ASSERT_IRQL(DISPATCH_LEVEL);
1014
1015 IoAcquireCancelSpinLock(&oldirql);
1016
1017 if (CancelFunction != NULL)
1018 {
1019 Irp->CancelRoutine = CancelFunction;
1020 }
1021
1022 if (Key!=0)
1023 {
1024 stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
1025 &Irp->Tail.Overlay.DeviceQueueEntry,
1026 *Key);
1027 }
1028 else
1029 {
1030 stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
1031 &Irp->Tail.Overlay.DeviceQueueEntry);
1032 }
1033
1034
1035 if (!stat)
1036 {
1037 IoReleaseCancelSpinLock(DISPATCH_LEVEL);
1038 DeviceObject->CurrentIrp = Irp;
1039 DeviceObject->DriverObject->DriverStartIo(DeviceObject,Irp);
1040 if (oldirql < DISPATCH_LEVEL)
1041 {
1042 KeLowerIrql(oldirql);
1043 }
1044 }
1045 else
1046 {
1047 IoReleaseCancelSpinLock(oldirql);
1048 }
1049
1050 }
1051
1052 /*
1053 * @unimplemented
1054 */
1055 VOID
1056 STDCALL
1057 IoSynchronousInvalidateDeviceRelations(IN PDEVICE_OBJECT DeviceObject,
1058 IN DEVICE_RELATION_TYPE Type)
1059 {
1060 UNIMPLEMENTED;
1061 }
1062
1063 /*
1064 * @implemented
1065 */
1066 VOID
1067 STDCALL
1068 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1069 {
1070 PSHUTDOWN_ENTRY ShutdownEntry;
1071 PLIST_ENTRY Entry;
1072 KIRQL oldlvl;
1073
1074 Entry = ShutdownListHead.Flink;
1075 while (Entry != &ShutdownListHead)
1076 {
1077 ShutdownEntry = CONTAINING_RECORD(Entry, SHUTDOWN_ENTRY, ShutdownList);
1078 if (ShutdownEntry->DeviceObject == DeviceObject)
1079 {
1080 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
1081
1082 KeAcquireSpinLock(&ShutdownListLock,&oldlvl);
1083 RemoveEntryList(Entry);
1084 KeReleaseSpinLock(&ShutdownListLock,oldlvl);
1085
1086 ExFreePool(Entry);
1087 return;
1088 }
1089
1090 Entry = Entry->Flink;
1091 }
1092 }
1093
1094 /*
1095 * @unimplemented
1096 */
1097 NTSTATUS
1098 STDCALL
1099 IoValidateDeviceIoControlAccess(IN PIRP Irp,
1100 IN ULONG RequiredAccess)
1101 {
1102 UNIMPLEMENTED;
1103 return STATUS_NOT_IMPLEMENTED;
1104 }
1105
1106 /* EOF */