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