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