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