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