Create the AHCI branch for Aman's work
[reactos.git] / ntoskrnl / io / iomgr / device.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/device.c
5 * PURPOSE: Device Object Management, including Notifications and Queues.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ********************************************************************/
18
19 ULONG IopDeviceObjectNumber = 0;
20 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
21 KSPIN_LOCK ShutdownListLock;
22 extern LIST_ENTRY IopDiskFileSystemQueueHead;
23 extern LIST_ENTRY IopCdRomFileSystemQueueHead;
24 extern LIST_ENTRY IopTapeFileSystemQueueHead;
25 extern ERESOURCE IopDatabaseResource;
26
27 /* PRIVATE FUNCTIONS **********************************************************/
28
29 VOID
30 NTAPI
31 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)
32 {
33 PDEVICE_OBJECT DeviceObject;
34 PAGED_CODE();
35
36 /* Set the driver as initialized */
37 Driver->Flags |= DRVO_INITIALIZED;
38 DeviceObject = Driver->DeviceObject;
39 while (DeviceObject)
40 {
41 /* Set every device as initialized too */
42 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
43 DeviceObject = DeviceObject->NextDevice;
44 }
45 }
46
47 VOID
48 NTAPI
49 IopDeleteDevice(IN PVOID ObjectBody)
50 {
51 PDEVICE_OBJECT DeviceObject = ObjectBody;
52 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
53 PAGED_CODE();
54
55 /* Cleanup and free the device node */
56 if (DeviceNode)
57 IopFreeDeviceNode(DeviceNode);
58
59 /* Dereference the driver object, referenced in IoCreateDevice */
60 if (DeviceObject->DriverObject)
61 ObDereferenceObject(DeviceObject->DriverObject);
62 }
63
64
65 PDEVICE_OBJECT
66 NTAPI
67 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
68 IN PDEVICE_OBJECT TargetDevice,
69 OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
70 {
71 PDEVICE_OBJECT AttachedDevice;
72 PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
73
74 /* Get the Attached Device and source extension */
75 AttachedDevice = IoGetAttachedDevice(TargetDevice);
76 SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
77 ASSERT(SourceDeviceExtension->AttachedTo == NULL);
78
79 /* Make sure that it's in a correct state */
80 if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
81 (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
82 (DOE_UNLOAD_PENDING |
83 DOE_DELETE_PENDING |
84 DOE_REMOVE_PENDING |
85 DOE_REMOVE_PROCESSED)))
86 {
87 /* Device was unloading or being removed */
88 AttachedDevice = NULL;
89 }
90 else
91 {
92 /* Update atached device fields */
93 AttachedDevice->AttachedDevice = SourceDevice;
94 AttachedDevice->Spare1++;
95
96 /* Update the source with the attached data */
97 SourceDevice->StackSize = AttachedDevice->StackSize + 1;
98 SourceDevice->AlignmentRequirement = AttachedDevice->
99 AlignmentRequirement;
100 SourceDevice->SectorSize = AttachedDevice->SectorSize;
101
102 /* Check for pending start flag */
103 if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
104 DOE_START_PENDING)
105 {
106 /* Propagate */
107 IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
108 DOE_START_PENDING;
109 }
110
111 /* Set the attachment in the device extension */
112 SourceDeviceExtension->AttachedTo = AttachedDevice;
113 }
114
115 /* Return the attached device */
116 if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
117 return AttachedDevice;
118 }
119
120 VOID
121 NTAPI
122 IoShutdownPnpDevices(VOID)
123 {
124 /* This routine is only used by Driver Verifier to validate shutdown */
125 return;
126 }
127
128 VOID
129 NTAPI
130 IoShutdownSystem(IN ULONG Phase)
131 {
132 PLIST_ENTRY ListEntry;
133 PDEVICE_OBJECT DeviceObject;
134 PSHUTDOWN_ENTRY ShutdownEntry;
135 IO_STATUS_BLOCK StatusBlock;
136 PIRP Irp;
137 KEVENT Event;
138 NTSTATUS Status;
139
140 /* Initialize an event to wait on */
141 KeInitializeEvent(&Event, NotificationEvent, FALSE);
142
143 /* What phase? */
144 if (Phase == 0)
145 {
146 /* Shutdown PnP */
147 IoShutdownPnpDevices();
148
149 /* Loop first-chance shutdown notifications */
150 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
151 &ShutdownListLock);
152 while (ListEntry)
153 {
154 /* Get the shutdown entry */
155 ShutdownEntry = CONTAINING_RECORD(ListEntry,
156 SHUTDOWN_ENTRY,
157 ShutdownList);
158
159 /* Get the attached device */
160 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
161
162 /* Build the shutdown IRP and call the driver */
163 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
164 DeviceObject,
165 NULL,
166 0,
167 NULL,
168 &Event,
169 &StatusBlock);
170 if (Irp)
171 {
172 Status = IoCallDriver(DeviceObject, Irp);
173 if (Status == STATUS_PENDING)
174 {
175 /* Wait on the driver */
176 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
177 }
178 }
179
180 /* Remove the flag */
181 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
182
183 /* Get rid of our reference to it */
184 ObDereferenceObject(ShutdownEntry->DeviceObject);
185
186 /* Free the shutdown entry and reset the event */
187 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
188 KeClearEvent(&Event);
189
190 /* Go to the next entry */
191 ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
192 &ShutdownListLock);
193 }
194 }
195 else if (Phase == 1)
196 {
197 /* Acquire resource forever */
198 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE);
199
200 /* Shutdown disk file systems */
201 IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
202
203 /* Shutdown cdrom file systems */
204 IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
205
206 /* Shutdown tape filesystems */
207 IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
208
209 /* Loop last-chance shutdown notifications */
210 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
211 &ShutdownListLock);
212 while (ListEntry)
213 {
214 /* Get the shutdown entry */
215 ShutdownEntry = CONTAINING_RECORD(ListEntry,
216 SHUTDOWN_ENTRY,
217 ShutdownList);
218
219 /* Get the attached device */
220 DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
221
222 /* Build the shutdown IRP and call the driver */
223 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
224 DeviceObject,
225 NULL,
226 0,
227 NULL,
228 &Event,
229 &StatusBlock);
230 if (Irp)
231 {
232 Status = IoCallDriver(DeviceObject, Irp);
233 if (Status == STATUS_PENDING)
234 {
235 /* Wait on the driver */
236 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
237 }
238 }
239
240 /* Remove the flag */
241 ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
242
243 /* Get rid of our reference to it */
244 ObDereferenceObject(ShutdownEntry->DeviceObject);
245
246 /* Free the shutdown entry and reset the event */
247 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
248 KeClearEvent(&Event);
249
250 /* Go to the next entry */
251 ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
252 &ShutdownListLock);
253 }
254
255 }
256 }
257
258 NTSTATUS
259 NTAPI
260 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
261 IN ACCESS_MASK DesiredAccess,
262 OUT PFILE_OBJECT *FileObject,
263 OUT PDEVICE_OBJECT *DeviceObject,
264 IN ULONG AttachFlag)
265 {
266 OBJECT_ATTRIBUTES ObjectAttributes;
267 IO_STATUS_BLOCK StatusBlock;
268 PFILE_OBJECT LocalFileObject;
269 HANDLE FileHandle;
270 NTSTATUS Status;
271
272 /* Open the Device */
273 InitializeObjectAttributes(&ObjectAttributes,
274 ObjectName,
275 OBJ_KERNEL_HANDLE,
276 NULL,
277 NULL);
278 Status = ZwOpenFile(&FileHandle,
279 DesiredAccess,
280 &ObjectAttributes,
281 &StatusBlock,
282 0,
283 FILE_NON_DIRECTORY_FILE | AttachFlag);
284 if (!NT_SUCCESS(Status)) return Status;
285
286 /* Get File Object */
287 Status = ObReferenceObjectByHandle(FileHandle,
288 0,
289 IoFileObjectType,
290 KernelMode,
291 (PVOID*)&LocalFileObject,
292 NULL);
293 if (NT_SUCCESS(Status))
294 {
295 /* Return the requested data */
296 *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
297 *FileObject = LocalFileObject;
298 }
299
300 /* Close the handle */
301 ZwClose(FileHandle);
302
303 return Status;
304 }
305
306 PDEVICE_OBJECT
307 NTAPI
308 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject)
309 {
310 PDEVICE_OBJECT LowestDevice;
311 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
312
313 /* Get the current device and its extension */
314 LowestDevice = DeviceObject;
315 DeviceExtension = IoGetDevObjExtension(LowestDevice);
316
317 /* Keep looping as long as we're attached */
318 while (DeviceExtension->AttachedTo)
319 {
320 /* Get the lowest device and its extension */
321 LowestDevice = DeviceExtension->AttachedTo;
322 DeviceExtension = IoGetDevObjExtension(LowestDevice);
323 }
324
325 /* Return the lowest device */
326 return LowestDevice;
327 }
328
329 VOID
330 NTAPI
331 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject,
332 IN PDEVICE_OBJECT DeviceObject,
333 IN IOP_DEVICE_LIST_OPERATION Type)
334 {
335 PDEVICE_OBJECT Previous;
336 KIRQL OldIrql;
337
338 /* Lock the Device list while we edit it */
339 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
340
341 /* Check the type of operation */
342 if (Type == IopRemove)
343 {
344 /* Get the current device and check if it's the current one */
345 Previous = DeviceObject->DriverObject->DeviceObject;
346 if (Previous == DeviceObject)
347 {
348 /* It is, simply unlink this one directly */
349 DeviceObject->DriverObject->DeviceObject =
350 DeviceObject->NextDevice;
351 }
352 else
353 {
354 /* It's not, so loop until we find the device */
355 while (Previous->NextDevice != DeviceObject)
356 {
357 /* Not this one, keep moving */
358 if (!Previous->NextDevice)
359 {
360 DPRINT1("Failed to remove PDO %p on driver %wZ (not found)\n",
361 DeviceObject,
362 &DeviceObject->DriverObject->DriverName);
363
364 ASSERT(FALSE);
365 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
366 return;
367 }
368 Previous = Previous->NextDevice;
369 }
370
371 /* We found it, now unlink us */
372 Previous->NextDevice = DeviceObject->NextDevice;
373 }
374 }
375 else
376 {
377 /* Link the device object and the driver object */
378 DeviceObject->NextDevice = DriverObject->DeviceObject;
379 DriverObject->DeviceObject = DeviceObject;
380 }
381
382 /* Release the device list lock */
383 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
384 }
385
386 VOID
387 NTAPI
388 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
389 {
390 PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject;
391 PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
392
393 /* Check if deletion is pending */
394 if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING)
395 {
396 if (DeviceObject->AttachedDevice)
397 {
398 DPRINT("Device object is in the middle of a device stack\n");
399 return;
400 }
401
402 if (DeviceObject->ReferenceCount)
403 {
404 DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
405 return;
406 }
407
408 /* Check if we have a Security Descriptor */
409 if (DeviceObject->SecurityDescriptor)
410 {
411 /* Dereference it */
412 ObDereferenceSecurityDescriptor(DeviceObject->SecurityDescriptor, 1);
413 }
414
415 /* Remove the device from the list */
416 IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove);
417
418 /* Dereference the keep-alive */
419 ObDereferenceObject(DeviceObject);
420 }
421
422 /* We can't unload a non-PnP driver here */
423 if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
424 {
425 DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
426 return;
427 }
428
429 /* Return if we've already called unload (maybe we're in it?) */
430 if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
431
432 /* We can't unload unless there's an unload handler */
433 if (!DriverObject->DriverUnload)
434 {
435 DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
436 return;
437 }
438
439 /* Bail if there are still devices present */
440 if (DriverObject->DeviceObject)
441 {
442 DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
443 return;
444 }
445
446 DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
447
448 /* Set the unload invoked flag */
449 DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
450
451 /* Unload it */
452 DriverObject->DriverUnload(DriverObject);
453
454 /* Make object temporary so it can be deleted */
455 ObMakeTemporaryObject(DriverObject);
456 }
457
458 VOID
459 NTAPI
460 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
461 IN BOOLEAN ForceUnload)
462 {
463 /* Sanity check */
464 ASSERT(DeviceObject->ReferenceCount);
465
466 /* Dereference the device */
467 InterlockedDecrement(&DeviceObject->ReferenceCount);
468
469 /*
470 * Check if we can unload it and it's safe to unload (or if we're forcing
471 * an unload, which is OK too).
472 */
473 ASSERT(!ForceUnload);
474 if (!(DeviceObject->ReferenceCount) &&
475 (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
476 {
477 /* Unload it */
478 IopUnloadDevice(DeviceObject);
479 }
480 }
481
482 VOID
483 NTAPI
484 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
485 IN BOOLEAN Cancelable,
486 IN ULONG Key)
487 {
488 PKDEVICE_QUEUE_ENTRY Entry;
489 PIRP Irp;
490 KIRQL OldIrql;
491
492 /* Acquire the cancel lock if this is cancelable */
493 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
494
495 /* Clear the current IRP */
496 DeviceObject->CurrentIrp = NULL;
497
498 /* Remove an entry from the queue */
499 Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key);
500 if (Entry)
501 {
502 /* Get the IRP and set it */
503 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
504 DeviceObject->CurrentIrp = Irp;
505
506 /* Check if this is a cancelable packet */
507 if (Cancelable)
508 {
509 /* Check if the caller requested no cancellation */
510 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
511 DOE_SIO_NO_CANCEL)
512 {
513 /* He did, so remove the cancel routine */
514 Irp->CancelRoutine = NULL;
515 }
516
517 /* Release the cancel lock */
518 IoReleaseCancelSpinLock(OldIrql);
519 }
520
521 /* Call the Start I/O Routine */
522 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
523 }
524 else
525 {
526 /* Otherwise, release the cancel lock if we had acquired it */
527 if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
528 }
529 }
530
531 VOID
532 NTAPI
533 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
534 IN BOOLEAN Cancelable)
535 {
536 PKDEVICE_QUEUE_ENTRY Entry;
537 PIRP Irp;
538 KIRQL OldIrql;
539
540 /* Acquire the cancel lock if this is cancelable */
541 if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
542
543 /* Clear the current IRP */
544 DeviceObject->CurrentIrp = NULL;
545
546 /* Remove an entry from the queue */
547 Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
548 if (Entry)
549 {
550 /* Get the IRP and set it */
551 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
552 DeviceObject->CurrentIrp = Irp;
553
554 /* Check if this is a cancelable packet */
555 if (Cancelable)
556 {
557 /* Check if the caller requested no cancellation */
558 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
559 DOE_SIO_NO_CANCEL)
560 {
561 /* He did, so remove the cancel routine */
562 Irp->CancelRoutine = NULL;
563 }
564
565 /* Release the cancel lock */
566 IoReleaseCancelSpinLock(OldIrql);
567 }
568
569 /* Call the Start I/O Routine */
570 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
571 }
572 else
573 {
574 /* Otherwise, release the cancel lock if we had acquired it */
575 if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
576 }
577 }
578
579 VOID
580 NTAPI
581 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
582 IN ULONG Key,
583 IN ULONG Flags)
584 {
585 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
586 ULONG CurrentKey = Key;
587 ULONG CurrentFlags = Flags;
588
589 /* Get the device extension and start the packet loop */
590 DeviceExtension = IoGetDevObjExtension(DeviceObject);
591 while (TRUE)
592 {
593 /* Increase the count */
594 if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1)
595 {
596 /*
597 * We've already called the routine once...
598 * All we have to do is save the key and add the new flags
599 */
600 DeviceExtension->StartIoFlags |= CurrentFlags;
601 DeviceExtension->StartIoKey = CurrentKey;
602 }
603 else
604 {
605 /* Mask out the current packet flags and key */
606 DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY |
607 DOE_SIO_NO_KEY |
608 DOE_SIO_CANCELABLE);
609 DeviceExtension->StartIoKey = 0;
610
611 /* Check if this is a packet start with key */
612 if (Flags & DOE_SIO_WITH_KEY)
613 {
614 /* Start the packet with a key */
615 IopStartNextPacketByKey(DeviceObject,
616 (Flags & DOE_SIO_CANCELABLE) ?
617 TRUE : FALSE,
618 CurrentKey);
619 }
620 else if (Flags & DOE_SIO_NO_KEY)
621 {
622 /* Start the packet */
623 IopStartNextPacket(DeviceObject,
624 (Flags & DOE_SIO_CANCELABLE) ?
625 TRUE : FALSE);
626 }
627 }
628
629 /* Decrease the Start I/O count and check if it's 0 now */
630 if (!InterlockedDecrement(&DeviceExtension->StartIoCount))
631 {
632 /* Get the current active key and flags */
633 CurrentKey = DeviceExtension->StartIoKey;
634 CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY |
635 DOE_SIO_NO_KEY |
636 DOE_SIO_CANCELABLE);
637
638 /* Check if we should still loop */
639 if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break;
640 }
641 else
642 {
643 /* There are still Start I/Os active, so quit this loop */
644 break;
645 }
646 }
647 }
648
649 NTSTATUS
650 NTAPI
651 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
652 OUT PDEVICE_NODE *DeviceNode)
653 {
654 NTSTATUS Status;
655 IO_STACK_LOCATION Stack = {0};
656 PDEVICE_RELATIONS DeviceRelations;
657 PDEVICE_OBJECT DeviceObject = NULL;
658
659 ASSERT(FileObject);
660
661 /* Get DeviceObject related to given FileObject */
662 DeviceObject = IoGetRelatedDeviceObject(FileObject);
663 if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
664
665 /* Define input parameters */
666 Stack.MajorFunction = IRP_MJ_PNP;
667 Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
668 Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
669 Stack.FileObject = FileObject;
670
671 /* Call the driver to query all relations (IRP_MJ_PNP) */
672 Status = IopSynchronousCall(DeviceObject,
673 &Stack,
674 (PVOID)&DeviceRelations);
675 if (!NT_SUCCESS(Status)) return Status;
676
677 /* Make sure it's not NULL and contains only one object */
678 ASSERT(DeviceRelations);
679 ASSERT(DeviceRelations->Count == 1);
680
681 /* Finally get the device node */
682 *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]);
683 if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE;
684
685 /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
686 ExFreePool(DeviceRelations);
687
688 return Status;
689 }
690
691 /* PUBLIC FUNCTIONS ***********************************************************/
692
693 /*
694 * IoAttachDevice
695 *
696 * Layers a device over the highest device in a device stack.
697 *
698 * Parameters
699 * SourceDevice
700 * Device to be attached.
701 *
702 * TargetDevice
703 * Name of the target device.
704 *
705 * AttachedDevice
706 * Caller storage for the device attached to.
707 *
708 * Status
709 * @implemented
710 */
711 NTSTATUS
712 NTAPI
713 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
714 PUNICODE_STRING TargetDeviceName,
715 PDEVICE_OBJECT *AttachedDevice)
716 {
717 NTSTATUS Status;
718 PFILE_OBJECT FileObject = NULL;
719 PDEVICE_OBJECT TargetDevice = NULL;
720
721 /* Call the helper routine for an attach operation */
722 Status = IopGetDeviceObjectPointer(TargetDeviceName,
723 FILE_READ_ATTRIBUTES,
724 &FileObject,
725 &TargetDevice,
726 IO_ATTACH_DEVICE_API);
727 if (!NT_SUCCESS(Status)) return Status;
728
729 /* Attach the device */
730 Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
731 TargetDevice,
732 AttachedDevice);
733
734 /* Dereference it */
735 ObDereferenceObject(FileObject);
736 return Status;
737 }
738
739 /*
740 * IoAttachDeviceByPointer
741 *
742 * Status
743 * @implemented
744 */
745 NTSTATUS
746 NTAPI
747 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
748 IN PDEVICE_OBJECT TargetDevice)
749 {
750 PDEVICE_OBJECT AttachedDevice;
751 NTSTATUS Status = STATUS_SUCCESS;
752
753 /* Do the Attach */
754 AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
755 if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE;
756
757 /* Return the status */
758 return Status;
759 }
760
761 /*
762 * @implemented
763 */
764 PDEVICE_OBJECT
765 NTAPI
766 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,
767 IN PDEVICE_OBJECT TargetDevice)
768 {
769 /* Attach it safely */
770 return IopAttachDeviceToDeviceStackSafe(SourceDevice,
771 TargetDevice,
772 NULL);
773 }
774
775 /*
776 * @implemented
777 */
778 NTSTATUS
779 NTAPI
780 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
781 IN PDEVICE_OBJECT TargetDevice,
782 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
783 {
784 /* Call the internal function */
785 if (!IopAttachDeviceToDeviceStackSafe(SourceDevice,
786 TargetDevice,
787 AttachedToDeviceObject))
788 {
789 /* Nothing found */
790 return STATUS_NO_SUCH_DEVICE;
791 }
792
793 /* Success! */
794 return STATUS_SUCCESS;
795 }
796
797 /*
798 * IoCreateDevice
799 *
800 * Allocates memory for and intializes a device object for use for
801 * a driver.
802 *
803 * Parameters
804 * DriverObject
805 * Driver object passed by IO Manager when the driver was loaded.
806 *
807 * DeviceExtensionSize
808 * Number of bytes for the device extension.
809 *
810 * DeviceName
811 * Unicode name of device.
812 *
813 * DeviceType
814 * Device type of the new device.
815 *
816 * DeviceCharacteristics
817 * Bit mask of device characteristics.
818 *
819 * Exclusive
820 * TRUE if only one thread can access the device at a time.
821 *
822 * DeviceObject
823 * On successful return this parameter is filled by pointer to
824 * allocated device object.
825 *
826 * Status
827 * @implemented
828 */
829 NTSTATUS
830 NTAPI
831 IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
832 IN ULONG DeviceExtensionSize,
833 IN PUNICODE_STRING DeviceName,
834 IN DEVICE_TYPE DeviceType,
835 IN ULONG DeviceCharacteristics,
836 IN BOOLEAN Exclusive,
837 OUT PDEVICE_OBJECT *DeviceObject)
838 {
839 WCHAR AutoNameBuffer[20];
840 UNICODE_STRING AutoName;
841 PDEVICE_OBJECT CreatedDeviceObject;
842 PDEVOBJ_EXTENSION DeviceObjectExtension;
843 OBJECT_ATTRIBUTES ObjectAttributes;
844 NTSTATUS Status;
845 ULONG AlignedDeviceExtensionSize;
846 ULONG TotalSize;
847 HANDLE TempHandle;
848 PAGED_CODE();
849
850 /* Check if we have to generate a name */
851 if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
852 {
853 /* Generate it */
854 swprintf(AutoNameBuffer,
855 L"\\Device\\%08lx",
856 InterlockedIncrementUL(&IopDeviceObjectNumber));
857
858 /* Initialize the name */
859 RtlInitUnicodeString(&AutoName, AutoNameBuffer);
860 DeviceName = &AutoName;
861 }
862
863 /* Initialize the Object Attributes */
864 InitializeObjectAttributes(&ObjectAttributes,
865 DeviceName,
866 OBJ_KERNEL_HANDLE,
867 NULL,
868 SePublicOpenUnrestrictedSd);
869
870 /* Honor exclusive flag */
871 if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
872
873 /* Create a permanent object for named devices */
874 if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT;
875
876 /* Align the Extension Size to 8-bytes */
877 AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7;
878
879 /* Total Size */
880 TotalSize = AlignedDeviceExtensionSize +
881 sizeof(DEVICE_OBJECT) +
882 sizeof(EXTENDED_DEVOBJ_EXTENSION);
883
884 /* Create the Device Object */
885 *DeviceObject = NULL;
886 Status = ObCreateObject(KernelMode,
887 IoDeviceObjectType,
888 &ObjectAttributes,
889 KernelMode,
890 NULL,
891 TotalSize,
892 0,
893 0,
894 (PVOID*)&CreatedDeviceObject);
895 if (!NT_SUCCESS(Status)) return Status;
896
897 /* Clear the whole Object and extension so we don't null stuff manually */
898 RtlZeroMemory(CreatedDeviceObject, TotalSize);
899
900 /*
901 * Setup the Type and Size. Note that we don't use the aligned size,
902 * because that's only padding for the DevObjExt and not part of the Object.
903 */
904 CreatedDeviceObject->Type = IO_TYPE_DEVICE;
905 CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
906
907 /* The kernel extension is after the driver internal extension */
908 DeviceObjectExtension = (PDEVOBJ_EXTENSION)
909 ((ULONG_PTR)(CreatedDeviceObject + 1) +
910 AlignedDeviceExtensionSize);
911
912 /* Set the Type and Size. Question: why is Size 0 on Windows? */
913 DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
914 DeviceObjectExtension->Size = 0;
915
916 /* Initialize with Power Manager */
917 PoInitializeDeviceObject(DeviceObjectExtension);
918
919 /* Link the Object and Extension */
920 DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
921 CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
922
923 /* Set Device Object Data */
924 CreatedDeviceObject->DeviceType = DeviceType;
925 CreatedDeviceObject->Characteristics = DeviceCharacteristics;
926 CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
927 CreatedDeviceObject + 1 :
928 NULL;
929 CreatedDeviceObject->StackSize = 1;
930 CreatedDeviceObject->AlignmentRequirement = 0;
931
932 /* Set the Flags */
933 CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
934 if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
935 if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
936
937 /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
938 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
939 (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
940 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
941 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
942 {
943 /* Create Vpb */
944 Status = IopCreateVpb(CreatedDeviceObject);
945 if (!NT_SUCCESS(Status))
946 {
947 /* Dereference the device object and fail */
948 ObDereferenceObject(CreatedDeviceObject);
949 return Status;
950 }
951
952 /* Initialize Lock Event */
953 KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
954 SynchronizationEvent,
955 TRUE);
956 }
957
958 /* Set the right Sector Size */
959 switch (DeviceType)
960 {
961 /* All disk systems */
962 case FILE_DEVICE_DISK_FILE_SYSTEM:
963 case FILE_DEVICE_DISK:
964 case FILE_DEVICE_VIRTUAL_DISK:
965
966 /* The default is 512 bytes */
967 CreatedDeviceObject->SectorSize = 512;
968 break;
969
970 /* CD-ROM file systems */
971 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
972
973 /* The default is 2048 bytes */
974 CreatedDeviceObject->SectorSize = 2048;
975 }
976
977 /* Create the Device Queue */
978 if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
979 (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
980 (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
981 (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
982 (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
983 {
984 /* Simple FS Devices, they don't need a real Device Queue */
985 InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
986 }
987 else
988 {
989 /* An actual Device, initialize its DQ */
990 KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
991 }
992
993 /* Insert the Object */
994 Status = ObInsertObject(CreatedDeviceObject,
995 NULL,
996 FILE_READ_DATA | FILE_WRITE_DATA,
997 1,
998 (PVOID*)&CreatedDeviceObject,
999 &TempHandle);
1000 if (!NT_SUCCESS(Status)) return Status;
1001
1002 /* Now do the final linking */
1003 ObReferenceObject(DriverObject);
1004 ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
1005 CreatedDeviceObject->DriverObject = DriverObject;
1006 IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
1007
1008 /* Link with the power manager */
1009 if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
1010
1011 /* Close the temporary handle and return to caller */
1012 ObCloseHandle(TempHandle, KernelMode);
1013 *DeviceObject = CreatedDeviceObject;
1014 return STATUS_SUCCESS;
1015 }
1016
1017 /*
1018 * IoDeleteDevice
1019 *
1020 * Status
1021 * @implemented
1022 */
1023 VOID
1024 NTAPI
1025 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
1026 {
1027 PIO_TIMER Timer;
1028
1029 /* Check if the device is registered for shutdown notifications */
1030 if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
1031 {
1032 /* Call the shutdown notifications */
1033 IoUnregisterShutdownNotification(DeviceObject);
1034 }
1035
1036 /* Check if it has a timer */
1037 Timer = DeviceObject->Timer;
1038 if (Timer)
1039 {
1040 /* Remove it and free it */
1041 IopRemoveTimerFromTimerList(Timer);
1042 ExFreePoolWithTag(Timer, TAG_IO_TIMER);
1043 }
1044
1045 /* Check if the device has a name */
1046 if (DeviceObject->Flags & DO_DEVICE_HAS_NAME)
1047 {
1048 /* It does, make it temporary so we can remove it */
1049 ObMakeTemporaryObject(DeviceObject);
1050 }
1051
1052 /* Set the pending delete flag */
1053 IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
1054
1055 /* Unlink with the power manager */
1056 if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
1057
1058 /* Check if the device object can be unloaded */
1059 if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
1060 }
1061
1062 /*
1063 * IoDetachDevice
1064 *
1065 * Status
1066 * @implemented
1067 */
1068 VOID
1069 NTAPI
1070 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
1071 {
1072 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1073
1074 /* Sanity check */
1075 DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
1076 ASSERT(DeviceExtension->AttachedTo == TargetDevice);
1077
1078 /* Remove the attachment */
1079 DeviceExtension->AttachedTo = NULL;
1080 TargetDevice->AttachedDevice = NULL;
1081
1082 /* Check if it's ok to delete this device */
1083 if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
1084 !(TargetDevice->ReferenceCount))
1085 {
1086 /* It is, do it */
1087 IopUnloadDevice(TargetDevice);
1088 }
1089 }
1090
1091 /*
1092 * @implemented
1093 */
1094 NTSTATUS
1095 NTAPI
1096 IoEnumerateDeviceObjectList(IN PDRIVER_OBJECT DriverObject,
1097 IN PDEVICE_OBJECT *DeviceObjectList,
1098 IN ULONG DeviceObjectListSize,
1099 OUT PULONG ActualNumberDeviceObjects)
1100 {
1101 ULONG ActualDevices = 1;
1102 PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
1103 KIRQL OldIrql;
1104
1105 /* Lock the Device list while we enumerate it */
1106 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1107
1108 /* Find out how many devices we'll enumerate */
1109 while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
1110
1111 /* Go back to the first */
1112 CurrentDevice = DriverObject->DeviceObject;
1113
1114 /* Start by at least returning this */
1115 *ActualNumberDeviceObjects = ActualDevices;
1116
1117 /* Check if we can support so many */
1118 if ((ActualDevices * sizeof(PDEVICE_OBJECT)) > DeviceObjectListSize)
1119 {
1120 /* Fail because the buffer was too small */
1121 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1122 return STATUS_BUFFER_TOO_SMALL;
1123 }
1124
1125 /* Check if the caller wanted the device list */
1126 if (DeviceObjectList)
1127 {
1128 /* Loop through all the devices */
1129 while (ActualDevices)
1130 {
1131 /* Reference each Device */
1132 ObReferenceObject(CurrentDevice);
1133
1134 /* Add it to the list */
1135 *DeviceObjectList = CurrentDevice;
1136
1137 /* Go to the next one */
1138 CurrentDevice = CurrentDevice->NextDevice;
1139 ActualDevices--;
1140 DeviceObjectList++;
1141 }
1142 }
1143
1144 /* Release the device list lock */
1145 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1146
1147 /* Return the status */
1148 return STATUS_SUCCESS;
1149 }
1150
1151 /*
1152 * IoGetAttachedDevice
1153 *
1154 * Status
1155 * @implemented
1156 */
1157 PDEVICE_OBJECT
1158 NTAPI
1159 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
1160 {
1161 /* Get the last attached device */
1162 while (DeviceObject->AttachedDevice)
1163 {
1164 /* Move to the next one */
1165 DeviceObject = DeviceObject->AttachedDevice;
1166 }
1167
1168 /* Return it */
1169 return DeviceObject;
1170 }
1171
1172 /*
1173 * IoGetAttachedDeviceReference
1174 *
1175 * Status
1176 * @implemented
1177 */
1178 PDEVICE_OBJECT
1179 NTAPI
1180 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
1181 {
1182 /* Reference the Attached Device */
1183 DeviceObject = IoGetAttachedDevice(DeviceObject);
1184 ObReferenceObject(DeviceObject);
1185 return DeviceObject;
1186 }
1187
1188 /*
1189 * @implemented
1190 */
1191 PDEVICE_OBJECT
1192 NTAPI
1193 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
1194 {
1195 /* Reference the lowest attached device */
1196 DeviceObject = IopGetLowestDevice(DeviceObject);
1197 ObReferenceObject(DeviceObject);
1198 return DeviceObject;
1199 }
1200
1201 /*
1202 * IoGetDeviceObjectPointer
1203 *
1204 * Status
1205 * @implemented
1206 */
1207 NTSTATUS
1208 NTAPI
1209 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
1210 IN ACCESS_MASK DesiredAccess,
1211 OUT PFILE_OBJECT *FileObject,
1212 OUT PDEVICE_OBJECT *DeviceObject)
1213 {
1214 /* Call the helper routine for a normal operation */
1215 return IopGetDeviceObjectPointer(ObjectName,
1216 DesiredAccess,
1217 FileObject,
1218 DeviceObject,
1219 0);
1220 }
1221
1222 /*
1223 * @implemented
1224 */
1225 NTSTATUS
1226 NTAPI
1227 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
1228 OUT PDEVICE_OBJECT *DiskDeviceObject)
1229 {
1230 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1231 PVPB Vpb;
1232 KIRQL OldIrql;
1233 NTSTATUS Status;
1234
1235 /* Make sure there's a VPB */
1236 if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
1237
1238 /* Acquire it */
1239 IoAcquireVpbSpinLock(&OldIrql);
1240
1241 /* Get the Device Extension */
1242 DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject);
1243
1244 /* Make sure this one has a VPB too */
1245 Vpb = DeviceExtension->Vpb;
1246 if (Vpb)
1247 {
1248 /* Make sure that it's mounted */
1249 if ((Vpb->ReferenceCount) &&
1250 (Vpb->Flags & VPB_MOUNTED))
1251 {
1252 /* Return the Disk Device Object */
1253 *DiskDeviceObject = Vpb->RealDevice;
1254
1255 /* Reference it and return success */
1256 ObReferenceObject(Vpb->RealDevice);
1257 Status = STATUS_SUCCESS;
1258 }
1259 else
1260 {
1261 /* It's not, so return failure */
1262 Status = STATUS_VOLUME_DISMOUNTED;
1263 }
1264 }
1265 else
1266 {
1267 /* Fail */
1268 Status = STATUS_INVALID_PARAMETER;
1269 }
1270
1271 /* Release the lock */
1272 IoReleaseVpbSpinLock(OldIrql);
1273 return Status;
1274 }
1275
1276 /*
1277 * @implemented
1278 */
1279 PDEVICE_OBJECT
1280 NTAPI
1281 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
1282 {
1283 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1284 PDEVICE_OBJECT LowerDeviceObject = NULL;
1285
1286 /* Make sure it's not getting deleted */
1287 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1288 if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
1289 DOE_DELETE_PENDING |
1290 DOE_REMOVE_PENDING |
1291 DOE_REMOVE_PROCESSED)))
1292 {
1293 /* Get the Lower Device Object */
1294 LowerDeviceObject = DeviceExtension->AttachedTo;
1295
1296 /* Check that we got a valid device object */
1297 if (LowerDeviceObject)
1298 {
1299 /* We did so let's reference it */
1300 ObReferenceObject(LowerDeviceObject);
1301 }
1302 }
1303
1304 /* Return it */
1305 return LowerDeviceObject;
1306 }
1307
1308 /*
1309 * @implemented
1310 */
1311 PDEVICE_OBJECT
1312 NTAPI
1313 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
1314 {
1315 PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
1316
1317 /* Check if we have a VPB with a device object */
1318 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1319 {
1320 /* Then use the DO from the VPB */
1321 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1322 DeviceObject = FileObject->Vpb->DeviceObject;
1323 }
1324 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1325 (FileObject->DeviceObject->Vpb) &&
1326 (FileObject->DeviceObject->Vpb->DeviceObject))
1327 {
1328 /* The disk device actually has a VPB, so get the DO from there */
1329 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1330 }
1331 else
1332 {
1333 /* Otherwise, this was a direct open */
1334 DeviceObject = FileObject->DeviceObject;
1335 }
1336
1337 /* Sanity check */
1338 ASSERT(DeviceObject != NULL);
1339
1340 /* Check if we were attached */
1341 if (DeviceObject->AttachedDevice)
1342 {
1343 /* Check if the file object has an extension present */
1344 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1345 {
1346 /* Sanity check, direct open files can't have this */
1347 ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
1348
1349 /* Check if the extension is really present */
1350 if (FileObject->FileObjectExtension)
1351 {
1352 /* FIXME: Unhandled yet */
1353 DPRINT1("FOEs not supported\n");
1354 ASSERT(FALSE);
1355 }
1356 }
1357
1358 /* Return the highest attached device */
1359 DeviceObject = IoGetAttachedDevice(DeviceObject);
1360 }
1361
1362 /* Return the DO we found */
1363 return DeviceObject;
1364 }
1365
1366 /*
1367 * @implemented
1368 */
1369 NTSTATUS
1370 NTAPI
1371 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
1372 OUT PDEVICE_OBJECT *DeviceObject)
1373 {
1374 NTSTATUS Status;
1375 PDEVICE_NODE DeviceNode = NULL;
1376
1377 /* Call the internal helper function */
1378 Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
1379 if (NT_SUCCESS(Status) && DeviceNode)
1380 {
1381 *DeviceObject = DeviceNode->PhysicalDeviceObject;
1382 }
1383 return Status;
1384 }
1385
1386 /*
1387 * @implemented
1388 */
1389 PDEVICE_OBJECT
1390 NTAPI
1391 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
1392 {
1393 PDEVICE_OBJECT DeviceObject;
1394
1395 /*
1396 * If the FILE_OBJECT's VPB is defined,
1397 * get the device from it.
1398 */
1399 if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
1400 {
1401 /* Use the VPB's Device Object's */
1402 DeviceObject = FileObject->Vpb->DeviceObject;
1403 }
1404 else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
1405 (FileObject->DeviceObject->Vpb) &&
1406 (FileObject->DeviceObject->Vpb->DeviceObject))
1407 {
1408 /* Use the VPB's File System Object */
1409 DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
1410 }
1411 else
1412 {
1413 /* Use the FO's Device Object */
1414 DeviceObject = FileObject->DeviceObject;
1415 }
1416
1417 /* Return the device object we found */
1418 ASSERT(DeviceObject != NULL);
1419 return DeviceObject;
1420 }
1421
1422 /*
1423 * @implemented
1424 */
1425 NTSTATUS
1426 NTAPI
1427 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
1428 {
1429 PSHUTDOWN_ENTRY Entry;
1430
1431 /* Allocate the shutdown entry */
1432 Entry = ExAllocatePoolWithTag(NonPagedPool,
1433 sizeof(SHUTDOWN_ENTRY),
1434 TAG_SHUTDOWN_ENTRY);
1435 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1436
1437 /* Set the DO */
1438 Entry->DeviceObject = DeviceObject;
1439
1440 /* Reference it so it doesn't go away */
1441 ObReferenceObject(DeviceObject);
1442
1443 /* Insert it into the list */
1444 ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
1445 &Entry->ShutdownList,
1446 &ShutdownListLock);
1447
1448 /* Set the shutdown registered flag */
1449 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1450 return STATUS_SUCCESS;
1451 }
1452
1453 /*
1454 * @implemented
1455 */
1456 NTSTATUS
1457 NTAPI
1458 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1459 {
1460 PSHUTDOWN_ENTRY Entry;
1461
1462 /* Allocate the shutdown entry */
1463 Entry = ExAllocatePoolWithTag(NonPagedPool,
1464 sizeof(SHUTDOWN_ENTRY),
1465 TAG_SHUTDOWN_ENTRY);
1466 if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
1467
1468 /* Set the DO */
1469 Entry->DeviceObject = DeviceObject;
1470
1471 /* Reference it so it doesn't go away */
1472 ObReferenceObject(DeviceObject);
1473
1474 /* Insert it into the list */
1475 ExInterlockedInsertHeadList(&ShutdownListHead,
1476 &Entry->ShutdownList,
1477 &ShutdownListLock);
1478
1479 /* Set the shutdown registered flag */
1480 DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
1481 return STATUS_SUCCESS;
1482 }
1483
1484 /*
1485 * @implemented
1486 */
1487 VOID
1488 NTAPI
1489 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
1490 {
1491 PSHUTDOWN_ENTRY ShutdownEntry;
1492 PLIST_ENTRY NextEntry;
1493 KIRQL OldIrql;
1494
1495 /* Remove the flag */
1496 DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
1497
1498 /* Acquire the shutdown lock and loop the shutdown list */
1499 KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
1500 NextEntry = ShutdownListHead.Flink;
1501 while (NextEntry != &ShutdownListHead)
1502 {
1503 /* Get the entry */
1504 ShutdownEntry = CONTAINING_RECORD(NextEntry,
1505 SHUTDOWN_ENTRY,
1506 ShutdownList);
1507
1508 /* Get if the DO matches */
1509 if (ShutdownEntry->DeviceObject == DeviceObject)
1510 {
1511 /* Remove it from the list */
1512 RemoveEntryList(NextEntry);
1513 NextEntry = NextEntry->Blink;
1514
1515 /* Free the entry */
1516 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1517
1518 /* Get rid of our reference to it */
1519 ObDereferenceObject(DeviceObject);
1520 }
1521
1522 /* Go to the next entry */
1523 NextEntry = NextEntry->Flink;
1524 }
1525
1526 /* Now loop the last chance list */
1527 NextEntry = LastChanceShutdownListHead.Flink;
1528 while (NextEntry != &LastChanceShutdownListHead)
1529 {
1530 /* Get the entry */
1531 ShutdownEntry = CONTAINING_RECORD(NextEntry,
1532 SHUTDOWN_ENTRY,
1533 ShutdownList);
1534
1535 /* Get if the DO matches */
1536 if (ShutdownEntry->DeviceObject == DeviceObject)
1537 {
1538 /* Remove it from the list */
1539 RemoveEntryList(NextEntry);
1540 NextEntry = NextEntry->Blink;
1541
1542 /* Free the entry */
1543 ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
1544
1545 /* Get rid of our reference to it */
1546 ObDereferenceObject(DeviceObject);
1547 }
1548
1549 /* Go to the next entry */
1550 NextEntry = NextEntry->Flink;
1551 }
1552
1553 /* Release the shutdown lock */
1554 KeReleaseSpinLock(&ShutdownListLock, OldIrql);
1555 }
1556
1557 /*
1558 * @implemented
1559 */
1560 VOID
1561 NTAPI
1562 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
1563 IN BOOLEAN DeferredStartIo,
1564 IN BOOLEAN NonCancelable)
1565 {
1566 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1567
1568 /* Get the Device Extension */
1569 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1570
1571 /* Set the flags the caller requested */
1572 DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0;
1573 DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0;
1574 }
1575
1576 /*
1577 * @implemented
1578 */
1579 VOID
1580 NTAPI
1581 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
1582 IN BOOLEAN Cancelable,
1583 IN ULONG Key)
1584 {
1585 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1586
1587 /* Get the Device Extension */
1588 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1589
1590 /* Check if deferred start was requested */
1591 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1592 {
1593 /* Call our internal function to handle the defered case */
1594 IopStartNextPacketByKeyEx(DeviceObject,
1595 Key,
1596 DOE_SIO_WITH_KEY |
1597 (Cancelable ? DOE_SIO_CANCELABLE : 0));
1598 }
1599 else
1600 {
1601 /* Call the normal routine */
1602 IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
1603 }
1604 }
1605
1606 /*
1607 * @implemented
1608 */
1609 VOID
1610 NTAPI
1611 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
1612 IN BOOLEAN Cancelable)
1613 {
1614 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
1615
1616 /* Get the Device Extension */
1617 DeviceExtension = IoGetDevObjExtension(DeviceObject);
1618
1619 /* Check if deferred start was requested */
1620 if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
1621 {
1622 /* Call our internal function to handle the defered case */
1623 IopStartNextPacketByKeyEx(DeviceObject,
1624 0,
1625 DOE_SIO_NO_KEY |
1626 (Cancelable ? DOE_SIO_CANCELABLE : 0));
1627 }
1628 else
1629 {
1630 /* Call the normal routine */
1631 IopStartNextPacket(DeviceObject, Cancelable);
1632 }
1633 }
1634
1635 /*
1636 * @implemented
1637 */
1638 VOID
1639 NTAPI
1640 IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
1641 IN PIRP Irp,
1642 IN PULONG Key,
1643 IN PDRIVER_CANCEL CancelFunction)
1644 {
1645 BOOLEAN Stat;
1646 KIRQL OldIrql, CancelIrql;
1647
1648 /* Raise to dispatch level */
1649 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1650
1651 /* Check if we should acquire the cancel lock */
1652 if (CancelFunction)
1653 {
1654 /* Acquire and set it */
1655 IoAcquireCancelSpinLock(&CancelIrql);
1656 Irp->CancelRoutine = CancelFunction;
1657 }
1658
1659 /* Check if we have a key */
1660 if (Key)
1661 {
1662 /* Insert by key */
1663 Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
1664 &Irp->Tail.Overlay.DeviceQueueEntry,
1665 *Key);
1666 }
1667 else
1668 {
1669 /* Insert without a key */
1670 Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
1671 &Irp->Tail.Overlay.DeviceQueueEntry);
1672 }
1673
1674 /* Check if this was a first insert */
1675 if (!Stat)
1676 {
1677 /* Set the IRP */
1678 DeviceObject->CurrentIrp = Irp;
1679
1680 /* Check if this is a cancelable packet */
1681 if (CancelFunction)
1682 {
1683 /* Check if the caller requested no cancellation */
1684 if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
1685 DOE_SIO_NO_CANCEL)
1686 {
1687 /* He did, so remove the cancel routine */
1688 Irp->CancelRoutine = NULL;
1689 }
1690
1691 /* Release the cancel lock */
1692 IoReleaseCancelSpinLock(CancelIrql);
1693 }
1694
1695 /* Call the Start I/O function */
1696 DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
1697 }
1698 else
1699 {
1700 /* The packet was inserted... check if we have a cancel function */
1701 if (CancelFunction)
1702 {
1703 /* Check if the IRP got cancelled */
1704 if (Irp->Cancel)
1705 {
1706 /*
1707 * Set the cancel IRQL, clear the currnet cancel routine and
1708 * call ours
1709 */
1710 Irp->CancelIrql = CancelIrql;
1711 Irp->CancelRoutine = NULL;
1712 CancelFunction(DeviceObject, Irp);
1713 }
1714 else
1715 {
1716 /* Otherwise, release the lock */
1717 IoReleaseCancelSpinLock(CancelIrql);
1718 }
1719 }
1720 }
1721
1722 /* Return back to previous IRQL */
1723 KeLowerIrql(OldIrql);
1724 }
1725
1726 #if defined (_WIN64)
1727 ULONG
1728 NTAPI
1729 IoWMIDeviceObjectToProviderId(
1730 IN PDEVICE_OBJECT DeviceObject)
1731 {
1732 UNIMPLEMENTED;
1733 return 0;
1734 }
1735 #endif
1736
1737 /* EOF */