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