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