ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

device.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/io/device.c
00005  * PURPOSE:         Device Object Management, including Notifications and Queues.
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Filip Navara (navaraf@reactos.org)
00008  *                  Hervé Poussineau (hpoussin@reactos.org)
00009  */
00010 
00011 /* INCLUDES *******************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 /* GLOBALS ********************************************************************/
00018 
00019 ULONG IopDeviceObjectNumber = 0;
00020 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
00021 KSPIN_LOCK ShutdownListLock;
00022 extern LIST_ENTRY IopDiskFileSystemQueueHead;
00023 extern LIST_ENTRY IopCdRomFileSystemQueueHead;
00024 extern LIST_ENTRY IopTapeFileSystemQueueHead;
00025 extern ERESOURCE IopDatabaseResource;
00026 
00027 /* PRIVATE FUNCTIONS **********************************************************/
00028 
00029 VOID
00030 NTAPI
00031 IopReadyDeviceObjects(IN PDRIVER_OBJECT Driver)
00032 {
00033     PDEVICE_OBJECT DeviceObject;
00034     PAGED_CODE();
00035 
00036     /* Set the driver as initialized */
00037     Driver->Flags |= DRVO_INITIALIZED;
00038     DeviceObject = Driver->DeviceObject;
00039     while (DeviceObject)
00040     {
00041         /* Set every device as initialized too */
00042         DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
00043         DeviceObject = DeviceObject->NextDevice;
00044     }
00045 }
00046 
00047 VOID
00048 NTAPI
00049 IopDeleteDevice(IN PVOID ObjectBody)
00050 {
00051     PDEVICE_OBJECT DeviceObject = ObjectBody;
00052     PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
00053     PAGED_CODE();
00054 
00055     /* Cleanup and free the device node */
00056     if (DeviceNode)
00057         IopFreeDeviceNode(DeviceNode);
00058 
00059     /* Dereference the driver object, referenced in IoCreateDevice */
00060     if (DeviceObject->DriverObject)
00061         ObDereferenceObject(DeviceObject->DriverObject);
00062 }
00063 
00064 
00065 PDEVICE_OBJECT
00066 NTAPI
00067 IopAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
00068                                  IN PDEVICE_OBJECT TargetDevice,
00069                                  OUT PDEVICE_OBJECT *AttachedToDeviceObject OPTIONAL)
00070 {
00071     PDEVICE_OBJECT AttachedDevice;
00072     PEXTENDED_DEVOBJ_EXTENSION SourceDeviceExtension;
00073 
00074     /* Get the Attached Device and source extension */
00075     AttachedDevice = IoGetAttachedDevice(TargetDevice);
00076     SourceDeviceExtension = IoGetDevObjExtension(SourceDevice);
00077     ASSERT(SourceDeviceExtension->AttachedTo == NULL);
00078 
00079     /* Make sure that it's in a correct state */
00080     if ((AttachedDevice->Flags & DO_DEVICE_INITIALIZING) ||
00081         (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
00082          (DOE_UNLOAD_PENDING |
00083           DOE_DELETE_PENDING |
00084           DOE_REMOVE_PENDING |
00085           DOE_REMOVE_PROCESSED)))
00086     {
00087         /* Device was unloading or being removed */
00088         AttachedDevice = NULL;
00089     }
00090     else
00091     {
00092         /* Update atached device fields */
00093         AttachedDevice->AttachedDevice = SourceDevice;
00094         AttachedDevice->Spare1++;
00095 
00096         /* Update the source with the attached data */
00097         SourceDevice->StackSize = AttachedDevice->StackSize + 1;
00098         SourceDevice->AlignmentRequirement = AttachedDevice->
00099                                              AlignmentRequirement;
00100         SourceDevice->SectorSize = AttachedDevice->SectorSize;
00101 
00102         /* Check for pending start flag */
00103         if (IoGetDevObjExtension(AttachedDevice)->ExtensionFlags &
00104             DOE_START_PENDING)
00105         {
00106             /* Propagate */
00107             IoGetDevObjExtension(SourceDevice)->ExtensionFlags |=
00108                 DOE_START_PENDING;
00109         }
00110 
00111         /* Set the attachment in the device extension */
00112         SourceDeviceExtension->AttachedTo = AttachedDevice;
00113     }
00114 
00115     /* Return the attached device */
00116     if (AttachedToDeviceObject) *AttachedToDeviceObject = AttachedDevice;
00117     return AttachedDevice;
00118 }
00119 
00120 VOID
00121 NTAPI
00122 IoShutdownPnpDevices(VOID)
00123 {
00124     /* This routine is only used by Driver Verifier to validate shutdown */
00125     return;
00126 }
00127 
00128 VOID
00129 NTAPI
00130 IoShutdownSystem(IN ULONG Phase)
00131 {
00132     PLIST_ENTRY ListEntry;
00133     PDEVICE_OBJECT DeviceObject;
00134     PSHUTDOWN_ENTRY ShutdownEntry;
00135     IO_STATUS_BLOCK StatusBlock;
00136     PIRP Irp;
00137     KEVENT Event;
00138     NTSTATUS Status;
00139         
00140     /* Initialize an event to wait on */
00141     KeInitializeEvent(&Event, NotificationEvent, FALSE);
00142     
00143     /* What phase? */
00144     if (Phase == 0)
00145     {
00146         /* Shutdown PnP */
00147         IoShutdownPnpDevices();
00148 
00149         /* Loop first-chance shutdown notifications */
00150         ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
00151                                                 &ShutdownListLock);
00152         while (ListEntry)
00153         {
00154             /* Get the shutdown entry */
00155             ShutdownEntry = CONTAINING_RECORD(ListEntry,
00156                                               SHUTDOWN_ENTRY,
00157                                               ShutdownList);
00158 
00159             /* Get the attached device */
00160             DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
00161 
00162             /* Build the shutdown IRP and call the driver */
00163             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
00164                                                DeviceObject,
00165                                                NULL,
00166                                                0,
00167                                                NULL,
00168                                                &Event,
00169                                                &StatusBlock);
00170             Status = IoCallDriver(DeviceObject, Irp);
00171             if (Status == STATUS_PENDING)
00172             {
00173                 /* Wait on the driver */
00174                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00175             }
00176 
00177             /* Remove the flag */
00178             ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
00179 
00180             /* Get rid of our reference to it */
00181             ObDereferenceObject(ShutdownEntry->DeviceObject);
00182 
00183             /* Free the shutdown entry and reset the event */
00184             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
00185             KeClearEvent(&Event);
00186 
00187             /* Go to the next entry */
00188             ListEntry = ExInterlockedRemoveHeadList(&ShutdownListHead,
00189                                                     &ShutdownListLock);
00190          }
00191     }
00192     else if (Phase == 1)
00193     {
00194         /* Acquire resource forever */
00195         ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE);
00196 
00197         /* Shutdown disk file systems */
00198         IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
00199 
00200         /* Shutdown cdrom file systems */
00201         IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
00202 
00203         /* Shutdown tape filesystems */
00204         IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
00205         
00206         /* Loop last-chance shutdown notifications */
00207         ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
00208                                                 &ShutdownListLock);
00209         while (ListEntry)
00210         {
00211             /* Get the shutdown entry */
00212             ShutdownEntry = CONTAINING_RECORD(ListEntry,
00213                                               SHUTDOWN_ENTRY,
00214                                               ShutdownList);
00215 
00216             /* Get the attached device */
00217             DeviceObject = IoGetAttachedDevice(ShutdownEntry->DeviceObject);
00218 
00219             /* Build the shutdown IRP and call the driver */
00220             Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
00221                                                DeviceObject,
00222                                                NULL,
00223                                                0,
00224                                                NULL,
00225                                                &Event,
00226                                                &StatusBlock);
00227             Status = IoCallDriver(DeviceObject, Irp);
00228             if (Status == STATUS_PENDING)
00229             {
00230                 /* Wait on the driver */
00231                 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
00232             }
00233 
00234             /* Remove the flag */
00235             ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
00236 
00237             /* Get rid of our reference to it */
00238             ObDereferenceObject(ShutdownEntry->DeviceObject);
00239 
00240             /* Free the shutdown entry and reset the event */
00241             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
00242             KeClearEvent(&Event);
00243 
00244             /* Go to the next entry */
00245             ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
00246                                                     &ShutdownListLock);
00247          }
00248 
00249     }
00250 }
00251 
00252 NTSTATUS
00253 NTAPI
00254 IopGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
00255                           IN ACCESS_MASK DesiredAccess,
00256                           OUT PFILE_OBJECT *FileObject,
00257                           OUT PDEVICE_OBJECT *DeviceObject,
00258                           IN ULONG AttachFlag)
00259 {
00260     OBJECT_ATTRIBUTES ObjectAttributes;
00261     IO_STATUS_BLOCK StatusBlock;
00262     PFILE_OBJECT LocalFileObject;
00263     HANDLE FileHandle;
00264     NTSTATUS Status;
00265 
00266     /* Open the Device */
00267     InitializeObjectAttributes(&ObjectAttributes,
00268                                ObjectName,
00269                                OBJ_KERNEL_HANDLE,
00270                                NULL,
00271                                NULL);
00272     Status = ZwOpenFile(&FileHandle,
00273                         DesiredAccess,
00274                         &ObjectAttributes,
00275                         &StatusBlock,
00276                         0,
00277                         FILE_NON_DIRECTORY_FILE | AttachFlag);
00278     if (!NT_SUCCESS(Status)) return Status;
00279 
00280     /* Get File Object */
00281     Status = ObReferenceObjectByHandle(FileHandle,
00282                                        0,
00283                                        IoFileObjectType,
00284                                        KernelMode,
00285                                        (PVOID*)&LocalFileObject,
00286                                        NULL);
00287     if (NT_SUCCESS(Status))
00288     {
00289         /* Return the requested data */
00290         *DeviceObject = IoGetRelatedDeviceObject(LocalFileObject);
00291         *FileObject = LocalFileObject;
00292     }
00293 
00294     /* Close the handle */
00295     ZwClose(FileHandle);
00296 
00297     return Status;
00298 }
00299 
00300 PDEVICE_OBJECT
00301 NTAPI
00302 IopGetLowestDevice(IN PDEVICE_OBJECT DeviceObject)
00303 {
00304     PDEVICE_OBJECT LowestDevice;
00305     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
00306 
00307     /* Get the current device and its extension */
00308     LowestDevice = DeviceObject;
00309     DeviceExtension = IoGetDevObjExtension(LowestDevice);
00310 
00311     /* Keep looping as long as we're attached */
00312     while (DeviceExtension->AttachedTo)
00313     {
00314         /* Get the lowest device and its extension */
00315         LowestDevice = DeviceExtension->AttachedTo;
00316         DeviceExtension = IoGetDevObjExtension(LowestDevice);
00317     }
00318 
00319     /* Return the lowest device */
00320     return LowestDevice;
00321 }
00322 
00323 VOID
00324 NTAPI
00325 IopEditDeviceList(IN PDRIVER_OBJECT DriverObject,
00326                   IN PDEVICE_OBJECT DeviceObject,
00327                   IN IOP_DEVICE_LIST_OPERATION Type)
00328 {
00329     PDEVICE_OBJECT Previous;
00330 
00331     /* Check the type of operation */
00332     if (Type == IopRemove)
00333     {
00334         /* Get the current device and check if it's the current one */
00335         Previous = DeviceObject->DriverObject->DeviceObject;
00336         if (Previous == DeviceObject)
00337         {
00338             /* It is, simply unlink this one directly */
00339             DeviceObject->DriverObject->DeviceObject =
00340                 DeviceObject->NextDevice;
00341         }
00342         else
00343         {
00344             /* It's not, so loop until we find the device */
00345             while (Previous->NextDevice != DeviceObject)
00346             {
00347                 /* Not this one, keep moving */
00348                 Previous = Previous->NextDevice;
00349             }
00350 
00351             /* We found it, now unlink us */
00352             Previous->NextDevice = DeviceObject->NextDevice;
00353         }
00354     }
00355     else
00356     {
00357         /* Link the device object and the driver object */
00358         DeviceObject->NextDevice = DriverObject->DeviceObject;
00359         DriverObject->DeviceObject = DeviceObject;
00360     }
00361 }
00362 
00363 VOID
00364 NTAPI
00365 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
00366 {
00367     PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject;
00368     PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
00369 
00370     /* Check if deletion is pending */
00371     if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING)
00372     {
00373         if (DeviceObject->AttachedDevice)
00374         {
00375             DPRINT("Device object is in the middle of a device stack\n");
00376             return;
00377         }
00378 
00379         if (DeviceObject->ReferenceCount)
00380         {
00381             DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
00382             return;
00383         }
00384 
00385         /* Check if we have a Security Descriptor */
00386         if (DeviceObject->SecurityDescriptor)
00387         {
00388             /* Free it */
00389             ExFreePoolWithTag(DeviceObject->SecurityDescriptor, TAG_SD);
00390         }
00391 
00392         /* Remove the device from the list */
00393         IopEditDeviceList(DeviceObject->DriverObject, DeviceObject, IopRemove);
00394 
00395         /* Dereference the keep-alive */
00396         ObDereferenceObject(DeviceObject);
00397     }
00398 
00399     /* We can't unload a non-PnP driver here */
00400     if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
00401     {
00402         DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
00403         return;
00404     }
00405 
00406     /* Return if we've already called unload (maybe we're in it?) */
00407     if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
00408 
00409     /* We can't unload unless there's an unload handler */
00410     if (!DriverObject->DriverUnload)
00411     {
00412         DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
00413         return;
00414     }
00415 
00416     /* Bail if there are still devices present */
00417     if (DriverObject->DeviceObject)
00418     {
00419         DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
00420         return;
00421     }
00422 
00423     DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
00424 
00425     /* Set the unload invoked flag */
00426     DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
00427 
00428     /* Unload it */
00429     DriverObject->DriverUnload(DriverObject);
00430 
00431     /* Make object temporary so it can be deleted */
00432     ObMakeTemporaryObject(DriverObject);
00433 }
00434 
00435 VOID
00436 NTAPI
00437 IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
00438                            IN BOOLEAN ForceUnload)
00439 {
00440     /* Sanity check */
00441     ASSERT(DeviceObject->ReferenceCount);
00442 
00443     /* Dereference the device */
00444     InterlockedDecrement(&DeviceObject->ReferenceCount);
00445 
00446     /*
00447      * Check if we can unload it and it's safe to unload (or if we're forcing
00448      * an unload, which is OK too).
00449      */
00450     ASSERT(!ForceUnload);
00451     if (!(DeviceObject->ReferenceCount) &&
00452         (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
00453     {
00454         /* Unload it */
00455         IopUnloadDevice(DeviceObject);
00456     }
00457 }
00458 
00459 VOID
00460 NTAPI
00461 IopStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
00462                         IN BOOLEAN Cancelable,
00463                         IN ULONG Key)
00464 {
00465     PKDEVICE_QUEUE_ENTRY Entry;
00466     PIRP Irp;
00467     KIRQL OldIrql;
00468 
00469     /* Acquire the cancel lock if this is cancelable */
00470     if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
00471 
00472     /* Clear the current IRP */
00473     DeviceObject->CurrentIrp = NULL;
00474 
00475     /* Remove an entry from the queue */
00476     Entry = KeRemoveByKeyDeviceQueue(&DeviceObject->DeviceQueue, Key);
00477     if (Entry)
00478     {
00479         /* Get the IRP and set it */
00480         Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
00481         DeviceObject->CurrentIrp = Irp;
00482 
00483         /* Check if this is a cancelable packet */
00484         if (Cancelable)
00485         {
00486             /* Check if the caller requested no cancellation */
00487             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
00488                 DOE_SIO_NO_CANCEL)
00489             {
00490                 /* He did, so remove the cancel routine */
00491                 Irp->CancelRoutine = NULL;
00492             }
00493 
00494             /* Release the cancel lock */
00495             IoReleaseCancelSpinLock(OldIrql);
00496         }
00497 
00498         /* Call the Start I/O Routine */
00499         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
00500     }
00501     else
00502     {
00503         /* Otherwise, release the cancel lock if we had acquired it */
00504         if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
00505     }
00506 }
00507 
00508 VOID
00509 NTAPI
00510 IopStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
00511                    IN BOOLEAN Cancelable)
00512 {
00513     PKDEVICE_QUEUE_ENTRY Entry;
00514     PIRP Irp;
00515     KIRQL OldIrql;
00516 
00517     /* Acquire the cancel lock if this is cancelable */
00518     if (Cancelable) IoAcquireCancelSpinLock(&OldIrql);
00519 
00520     /* Clear the current IRP */
00521     DeviceObject->CurrentIrp = NULL;
00522 
00523     /* Remove an entry from the queue */
00524     Entry = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
00525     if (Entry)
00526     {
00527         /* Get the IRP and set it */
00528         Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
00529         DeviceObject->CurrentIrp = Irp;
00530 
00531         /* Check if this is a cancelable packet */
00532         if (Cancelable)
00533         {
00534             /* Check if the caller requested no cancellation */
00535             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
00536                 DOE_SIO_NO_CANCEL)
00537             {
00538                 /* He did, so remove the cancel routine */
00539                 Irp->CancelRoutine = NULL;
00540             }
00541 
00542             /* Release the cancel lock */
00543             IoReleaseCancelSpinLock(OldIrql);
00544         }
00545 
00546         /* Call the Start I/O Routine */
00547         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
00548     }
00549     else
00550     {
00551         /* Otherwise, release the cancel lock if we had acquired it */
00552         if (Cancelable) IoReleaseCancelSpinLock(OldIrql);
00553     }
00554 }
00555 
00556 VOID
00557 NTAPI
00558 IopStartNextPacketByKeyEx(IN PDEVICE_OBJECT DeviceObject,
00559                           IN ULONG Key,
00560                           IN ULONG Flags)
00561 {
00562     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
00563     ULONG CurrentKey = Key;
00564     ULONG CurrentFlags = Flags;
00565 
00566     /* Get the device extension and start the packet loop */
00567     DeviceExtension = IoGetDevObjExtension(DeviceObject);
00568     while (TRUE)
00569     {
00570         /* Increase the count */
00571         if (InterlockedIncrement(&DeviceExtension->StartIoCount) > 1)
00572         {
00573             /*
00574              * We've already called the routine once...
00575              * All we have to do is save the key and add the new flags
00576              */
00577             DeviceExtension->StartIoFlags |= CurrentFlags;
00578             DeviceExtension->StartIoKey = CurrentKey;
00579         }
00580         else
00581         {
00582             /* Mask out the current packet flags and key */
00583             DeviceExtension->StartIoFlags &= ~(DOE_SIO_WITH_KEY |
00584                                                DOE_SIO_NO_KEY |
00585                                                DOE_SIO_CANCELABLE);
00586             DeviceExtension->StartIoKey = 0;
00587 
00588             /* Check if this is a packet start with key */
00589             if (Flags & DOE_SIO_WITH_KEY)
00590             {
00591                 /* Start the packet with a key */
00592                 IopStartNextPacketByKey(DeviceObject,
00593                                         (Flags & DOE_SIO_CANCELABLE) ?
00594                                         TRUE : FALSE,
00595                                         CurrentKey);
00596             }
00597             else if (Flags & DOE_SIO_NO_KEY)
00598             {
00599                 /* Start the packet */
00600                 IopStartNextPacket(DeviceObject,
00601                                    (Flags & DOE_SIO_CANCELABLE) ?
00602                                    TRUE : FALSE);
00603             }
00604         }
00605 
00606         /* Decrease the Start I/O count and check if it's 0 now */
00607         if (!InterlockedDecrement(&DeviceExtension->StartIoCount))
00608         {
00609             /* Get the current active key and flags */
00610             CurrentKey = DeviceExtension->StartIoKey;
00611             CurrentFlags = DeviceExtension->StartIoFlags & (DOE_SIO_WITH_KEY |
00612                                                             DOE_SIO_NO_KEY |
00613                                                             DOE_SIO_CANCELABLE);
00614 
00615             /* Check if we should still loop */
00616             if (!(CurrentFlags & (DOE_SIO_WITH_KEY | DOE_SIO_NO_KEY))) break;
00617         }
00618         else
00619         {
00620             /* There are still Start I/Os active, so quit this loop */
00621             break;
00622         }
00623     }
00624 }
00625 
00626 NTSTATUS
00627 NTAPI
00628 IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
00629                           OUT PDEVICE_NODE *DeviceNode)
00630 {
00631     NTSTATUS Status;
00632     IO_STACK_LOCATION Stack = {0};
00633     PDEVICE_RELATIONS DeviceRelations;
00634     PDEVICE_OBJECT DeviceObject = NULL;
00635 
00636     ASSERT(FileObject);
00637 
00638     /* Get DeviceObject related to given FileObject */
00639     DeviceObject = IoGetRelatedDeviceObject(FileObject);
00640     if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
00641 
00642     /* Define input parameters */
00643     Stack.MajorFunction = IRP_MJ_PNP;
00644     Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
00645     Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
00646     Stack.FileObject = FileObject;
00647 
00648     /* Call the driver to query all relations (IRP_MJ_PNP) */
00649     Status = IopSynchronousCall(DeviceObject,
00650                                 &Stack,
00651                                 (PVOID)&DeviceRelations);
00652     if (!NT_SUCCESS(Status)) return Status;
00653 
00654     /* Make sure it's not NULL and contains only one object */
00655     ASSERT(DeviceRelations);
00656     ASSERT(DeviceRelations->Count == 1);
00657 
00658     /* Finally get the device node */
00659     *DeviceNode = IopGetDeviceNode(DeviceRelations->Objects[0]);
00660     if (!*DeviceNode) Status = STATUS_NO_SUCH_DEVICE;
00661 
00662     /* Free the DEVICE_RELATIONS structure, it's not needed anymore */
00663     ExFreePool(DeviceRelations);
00664 
00665     return Status;
00666 }
00667 
00668 /* PUBLIC FUNCTIONS ***********************************************************/
00669 
00670 /*
00671  * IoAttachDevice
00672  *
00673  * Layers a device over the highest device in a device stack.
00674  *
00675  * Parameters
00676  *    SourceDevice
00677  *       Device to be attached.
00678  *
00679  *    TargetDevice
00680  *       Name of the target device.
00681  *
00682  *    AttachedDevice
00683  *       Caller storage for the device attached to.
00684  *
00685  * Status
00686  *    @implemented
00687  */
00688 NTSTATUS
00689 NTAPI
00690 IoAttachDevice(PDEVICE_OBJECT SourceDevice,
00691                PUNICODE_STRING TargetDeviceName,
00692                PDEVICE_OBJECT *AttachedDevice)
00693 {
00694    NTSTATUS Status;
00695    PFILE_OBJECT FileObject = NULL;
00696    PDEVICE_OBJECT TargetDevice = NULL;
00697 
00698     /* Call the helper routine for an attach operation */
00699     Status = IopGetDeviceObjectPointer(TargetDeviceName,
00700                                        FILE_READ_ATTRIBUTES,
00701                                        &FileObject,
00702                                        &TargetDevice,
00703                                        IO_ATTACH_DEVICE_API);
00704     if (!NT_SUCCESS(Status)) return Status;
00705 
00706     /* Attach the device */
00707     Status = IoAttachDeviceToDeviceStackSafe(SourceDevice,
00708                                              TargetDevice,
00709                                              AttachedDevice);
00710 
00711     /* Dereference it */
00712     ObDereferenceObject(FileObject);
00713     return Status;
00714 }
00715 
00716 /*
00717  * IoAttachDeviceByPointer
00718  *
00719  * Status
00720  *    @implemented
00721  */
00722 NTSTATUS
00723 NTAPI
00724 IoAttachDeviceByPointer(IN PDEVICE_OBJECT SourceDevice,
00725                         IN PDEVICE_OBJECT TargetDevice)
00726 {
00727     PDEVICE_OBJECT AttachedDevice;
00728     NTSTATUS Status = STATUS_SUCCESS;
00729 
00730     /* Do the Attach */
00731     AttachedDevice = IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice);
00732     if (!AttachedDevice) Status = STATUS_NO_SUCH_DEVICE;
00733 
00734     /* Return the status */
00735     return Status;
00736 }
00737 
00738 /*
00739  * @implemented
00740  */
00741 PDEVICE_OBJECT
00742 NTAPI
00743 IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT SourceDevice,
00744                             IN PDEVICE_OBJECT TargetDevice)
00745 {
00746     /* Attach it safely */
00747     return IopAttachDeviceToDeviceStackSafe(SourceDevice,
00748                                             TargetDevice,
00749                                             NULL);
00750 }
00751 
00752 /*
00753  * @implemented
00754  */
00755 NTSTATUS
00756 NTAPI
00757 IoAttachDeviceToDeviceStackSafe(IN PDEVICE_OBJECT SourceDevice,
00758                                 IN PDEVICE_OBJECT TargetDevice,
00759                                 IN OUT PDEVICE_OBJECT *AttachedToDeviceObject)
00760 {
00761     /* Call the internal function */
00762     if (!IopAttachDeviceToDeviceStackSafe(SourceDevice,
00763                                           TargetDevice,
00764                                           AttachedToDeviceObject))
00765     {
00766         /* Nothing found */
00767         return STATUS_NO_SUCH_DEVICE;
00768     }
00769 
00770     /* Success! */
00771     return STATUS_SUCCESS;
00772 }
00773 
00774 /*
00775  * IoCreateDevice
00776  *
00777  * Allocates memory for and intializes a device object for use for
00778  * a driver.
00779  *
00780  * Parameters
00781  *    DriverObject
00782  *       Driver object passed by IO Manager when the driver was loaded.
00783  *
00784  *    DeviceExtensionSize
00785  *       Number of bytes for the device extension.
00786  *
00787  *    DeviceName
00788  *       Unicode name of device.
00789  *
00790  *    DeviceType
00791  *       Device type of the new device.
00792  *
00793  *    DeviceCharacteristics
00794  *       Bit mask of device characteristics.
00795  *
00796  *    Exclusive
00797  *       TRUE if only one thread can access the device at a time.
00798  *
00799  *    DeviceObject
00800  *       On successful return this parameter is filled by pointer to
00801  *       allocated device object.
00802  *
00803  * Status
00804  *    @implemented
00805  */
00806 NTSTATUS
00807 NTAPI
00808 IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
00809                IN ULONG DeviceExtensionSize,
00810                IN PUNICODE_STRING DeviceName,
00811                IN DEVICE_TYPE DeviceType,
00812                IN ULONG DeviceCharacteristics,
00813                IN BOOLEAN Exclusive,
00814                OUT PDEVICE_OBJECT *DeviceObject)
00815 {
00816     WCHAR AutoNameBuffer[20];
00817     UNICODE_STRING AutoName;
00818     PDEVICE_OBJECT CreatedDeviceObject;
00819     PDEVOBJ_EXTENSION DeviceObjectExtension;
00820     OBJECT_ATTRIBUTES ObjectAttributes;
00821     NTSTATUS Status;
00822     ULONG AlignedDeviceExtensionSize;
00823     ULONG TotalSize;
00824     HANDLE TempHandle;
00825     PAGED_CODE();
00826 
00827     /* Check if we have to generate a name */
00828     if (DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME)
00829     {
00830         /* Generate it */
00831         swprintf(AutoNameBuffer,
00832                  L"\\Device\\%08lx",
00833                  InterlockedIncrementUL(&IopDeviceObjectNumber));
00834 
00835         /* Initialize the name */
00836         RtlInitUnicodeString(&AutoName, AutoNameBuffer);
00837         DeviceName = &AutoName;
00838    }
00839 
00840     /* Initialize the Object Attributes */
00841     InitializeObjectAttributes(&ObjectAttributes,
00842                                DeviceName,
00843                                OBJ_KERNEL_HANDLE,
00844                                NULL,
00845                                NULL);
00846 
00847     /* Honor exclusive flag */
00848     if (Exclusive) ObjectAttributes.Attributes |= OBJ_EXCLUSIVE;
00849 
00850     /* Create a permanent object for named devices */
00851     if (DeviceName) ObjectAttributes.Attributes |= OBJ_PERMANENT;
00852 
00853     /* Align the Extension Size to 8-bytes */
00854     AlignedDeviceExtensionSize = (DeviceExtensionSize + 7) &~ 7;
00855 
00856     /* Total Size */
00857     TotalSize = AlignedDeviceExtensionSize +
00858                 sizeof(DEVICE_OBJECT) +
00859                 sizeof(EXTENDED_DEVOBJ_EXTENSION);
00860 
00861     /* Create the Device Object */
00862     *DeviceObject = NULL;
00863     Status = ObCreateObject(KernelMode,
00864                             IoDeviceObjectType,
00865                             &ObjectAttributes,
00866                             KernelMode,
00867                             NULL,
00868                             TotalSize,
00869                             0,
00870                             0,
00871                             (PVOID*)&CreatedDeviceObject);
00872     if (!NT_SUCCESS(Status)) return Status;
00873 
00874     /* Clear the whole Object and extension so we don't null stuff manually */
00875     RtlZeroMemory(CreatedDeviceObject, TotalSize);
00876 
00877     /*
00878      * Setup the Type and Size. Note that we don't use the aligned size,
00879      * because that's only padding for the DevObjExt and not part of the Object.
00880      */
00881     CreatedDeviceObject->Type = IO_TYPE_DEVICE;
00882     CreatedDeviceObject->Size = sizeof(DEVICE_OBJECT) + (USHORT)DeviceExtensionSize;
00883 
00884     /* The kernel extension is after the driver internal extension */
00885     DeviceObjectExtension = (PDEVOBJ_EXTENSION)
00886                             ((ULONG_PTR)(CreatedDeviceObject + 1) +
00887                              AlignedDeviceExtensionSize);
00888 
00889     /* Set the Type and Size. Question: why is Size 0 on Windows? */
00890     DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
00891     DeviceObjectExtension->Size = 0;
00892     
00893     /* Initialize with Power Manager */
00894     PoInitializeDeviceObject(DeviceObjectExtension);
00895 
00896     /* Link the Object and Extension */
00897     DeviceObjectExtension->DeviceObject = CreatedDeviceObject;
00898     CreatedDeviceObject->DeviceObjectExtension = DeviceObjectExtension;
00899 
00900     /* Set Device Object Data */
00901     CreatedDeviceObject->DeviceType = DeviceType;
00902     CreatedDeviceObject->Characteristics = DeviceCharacteristics;
00903     CreatedDeviceObject->DeviceExtension = DeviceExtensionSize ?
00904                                            CreatedDeviceObject + 1 :
00905                                            NULL;
00906     CreatedDeviceObject->StackSize = 1;
00907     CreatedDeviceObject->AlignmentRequirement = 0;
00908 
00909     /* Set the Flags */
00910     CreatedDeviceObject->Flags = DO_DEVICE_INITIALIZING;
00911     if (Exclusive) CreatedDeviceObject->Flags |= DO_EXCLUSIVE;
00912     if (DeviceName) CreatedDeviceObject->Flags |= DO_DEVICE_HAS_NAME;
00913 
00914     /* Attach a Vpb for Disks and Tapes, and create the Device Lock */
00915     if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
00916         (CreatedDeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK) ||
00917         (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM) ||
00918         (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE))
00919     {
00920         /* Create Vpb */
00921         Status = IopCreateVpb(CreatedDeviceObject);
00922         if (!NT_SUCCESS(Status))
00923         {
00924             /* Dereference the device object and fail */
00925             ObDereferenceObject(CreatedDeviceObject);
00926             return Status;
00927         }
00928 
00929         /* Initialize Lock Event */
00930         KeInitializeEvent(&CreatedDeviceObject->DeviceLock,
00931                           SynchronizationEvent,
00932                           TRUE);
00933     }
00934 
00935     /* Set the right Sector Size */
00936     switch (DeviceType)
00937     {
00938         /* All disk systems */
00939         case FILE_DEVICE_DISK_FILE_SYSTEM:
00940         case FILE_DEVICE_DISK:
00941         case FILE_DEVICE_VIRTUAL_DISK:
00942 
00943             /* The default is 512 bytes */
00944             CreatedDeviceObject->SectorSize  = 512;
00945             break;
00946 
00947         /* CD-ROM file systems */
00948         case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
00949 
00950             /* The default is 2048 bytes */
00951             CreatedDeviceObject->SectorSize = 2048;
00952     }
00953 
00954     /* Create the Device Queue */
00955     if ((CreatedDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
00956         (CreatedDeviceObject->DeviceType == FILE_DEVICE_FILE_SYSTEM) ||
00957         (CreatedDeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
00958         (CreatedDeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) ||
00959         (CreatedDeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM))
00960     {
00961         /* Simple FS Devices, they don't need a real Device Queue */
00962         InitializeListHead(&CreatedDeviceObject->Queue.ListEntry);
00963     }
00964     else
00965     {
00966         /* An actual Device, initialize its DQ */
00967         KeInitializeDeviceQueue(&CreatedDeviceObject->DeviceQueue);
00968     }
00969 
00970     /* Insert the Object */
00971     Status = ObInsertObject(CreatedDeviceObject,
00972                             NULL,
00973                             FILE_READ_DATA | FILE_WRITE_DATA,
00974                             1,
00975                             (PVOID*)&CreatedDeviceObject,
00976                             &TempHandle);
00977     if (!NT_SUCCESS(Status)) return Status;
00978 
00979     /* Now do the final linking */
00980     ObReferenceObject(DriverObject);
00981     ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
00982     CreatedDeviceObject->DriverObject = DriverObject;
00983     IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
00984     
00985     /* Link with the power manager */
00986     if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
00987 
00988     /* Close the temporary handle and return to caller */
00989     ObCloseHandle(TempHandle, KernelMode);
00990     *DeviceObject = CreatedDeviceObject;
00991     return STATUS_SUCCESS;
00992 }
00993 
00994 /*
00995  * IoDeleteDevice
00996  *
00997  * Status
00998  *    @implemented
00999  */
01000 VOID
01001 NTAPI
01002 IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
01003 {
01004     PIO_TIMER Timer;
01005 
01006     /* Check if the device is registered for shutdown notifications */
01007     if (DeviceObject->Flags & DO_SHUTDOWN_REGISTERED)
01008     {
01009         /* Call the shutdown notifications */
01010         IoUnregisterShutdownNotification(DeviceObject);
01011     }
01012 
01013     /* Check if it has a timer */
01014     Timer = DeviceObject->Timer;
01015     if (Timer)
01016     {
01017         /* Remove it and free it */
01018         IopRemoveTimerFromTimerList(Timer);
01019         ExFreePoolWithTag(Timer, TAG_IO_TIMER);
01020     }
01021 
01022     /* Check if the device has a name */
01023     if (DeviceObject->Flags & DO_DEVICE_HAS_NAME)
01024     {
01025         /* It does, make it temporary so we can remove it */
01026         ObMakeTemporaryObject(DeviceObject);
01027     }
01028 
01029     /* Set the pending delete flag */
01030     IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
01031 
01032     /* Check if the device object can be unloaded */
01033     if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
01034 }
01035 
01036 /*
01037  * IoDetachDevice
01038  *
01039  * Status
01040  *    @implemented
01041  */
01042 VOID
01043 NTAPI
01044 IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
01045 {
01046     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01047 
01048     /* Sanity check */
01049     DeviceExtension = IoGetDevObjExtension(TargetDevice->AttachedDevice);
01050     ASSERT(DeviceExtension->AttachedTo == TargetDevice);
01051 
01052     /* Remove the attachment */
01053     DeviceExtension->AttachedTo = NULL;
01054     TargetDevice->AttachedDevice = NULL;
01055 
01056     /* Check if it's ok to delete this device */
01057     if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
01058         !(TargetDevice->ReferenceCount))
01059     {
01060         /* It is, do it */
01061         IopUnloadDevice(TargetDevice);
01062     }
01063 }
01064 
01065 /*
01066  * @implemented
01067  */
01068 NTSTATUS
01069 NTAPI
01070 IoEnumerateDeviceObjectList(IN  PDRIVER_OBJECT DriverObject,
01071                             IN  PDEVICE_OBJECT *DeviceObjectList,
01072                             IN  ULONG DeviceObjectListSize,
01073                             OUT PULONG ActualNumberDeviceObjects)
01074 {
01075     ULONG ActualDevices = 1;
01076     PDEVICE_OBJECT CurrentDevice = DriverObject->DeviceObject;
01077 
01078     /* Find out how many devices we'll enumerate */
01079     while ((CurrentDevice = CurrentDevice->NextDevice)) ActualDevices++;
01080 
01081     /* Go back to the first */
01082     CurrentDevice = DriverObject->DeviceObject;
01083 
01084     /* Start by at least returning this */
01085     *ActualNumberDeviceObjects = ActualDevices;
01086 
01087     /* Check if we can support so many */
01088     if ((ActualDevices * 4) > DeviceObjectListSize)
01089     {
01090         /* Fail because the buffer was too small */
01091         return STATUS_BUFFER_TOO_SMALL;
01092     }
01093 
01094     /* Check if the caller only wanted the size */
01095     if (DeviceObjectList)
01096     {
01097         /* Loop through all the devices */
01098         while (ActualDevices)
01099         {
01100             /* Reference each Device */
01101             ObReferenceObject(CurrentDevice);
01102 
01103             /* Add it to the list */
01104             *DeviceObjectList = CurrentDevice;
01105 
01106             /* Go to the next one */
01107             CurrentDevice = CurrentDevice->NextDevice;
01108             ActualDevices--;
01109             DeviceObjectList++;
01110         }
01111     }
01112 
01113     /* Return the status */
01114     return STATUS_SUCCESS;
01115 }
01116 
01117 /*
01118  * IoGetAttachedDevice
01119  *
01120  * Status
01121  *    @implemented
01122  */
01123 PDEVICE_OBJECT
01124 NTAPI
01125 IoGetAttachedDevice(PDEVICE_OBJECT DeviceObject)
01126 {
01127     /* Get the last attached device */
01128     while (DeviceObject->AttachedDevice)
01129     {
01130         /* Move to the next one */
01131         DeviceObject = DeviceObject->AttachedDevice;
01132     }
01133 
01134     /* Return it */
01135     return DeviceObject;
01136 }
01137 
01138 /*
01139  * IoGetAttachedDeviceReference
01140  *
01141  * Status
01142  *    @implemented
01143  */
01144 PDEVICE_OBJECT
01145 NTAPI
01146 IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
01147 {
01148     /* Reference the Attached Device */
01149     DeviceObject = IoGetAttachedDevice(DeviceObject);
01150     ObReferenceObject(DeviceObject);
01151     return DeviceObject;
01152 }
01153 
01154 /*
01155  * @implemented
01156  */
01157 PDEVICE_OBJECT
01158 NTAPI
01159 IoGetDeviceAttachmentBaseRef(IN PDEVICE_OBJECT DeviceObject)
01160 {
01161     /* Reference the lowest attached device */
01162     DeviceObject = IopGetLowestDevice(DeviceObject);
01163     ObReferenceObject(DeviceObject);
01164     return DeviceObject;
01165 }
01166 
01167 /*
01168  * IoGetDeviceObjectPointer
01169  *
01170  * Status
01171  *    @implemented
01172  */
01173 NTSTATUS
01174 NTAPI
01175 IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName,
01176                          IN ACCESS_MASK DesiredAccess,
01177                          OUT PFILE_OBJECT *FileObject,
01178                          OUT PDEVICE_OBJECT *DeviceObject)
01179 {
01180     /* Call the helper routine for a normal operation */
01181     return IopGetDeviceObjectPointer(ObjectName,
01182                                      DesiredAccess,
01183                                      FileObject,
01184                                      DeviceObject,
01185                                      0);
01186 }
01187 
01188 /*
01189  * @implemented
01190  */
01191 NTSTATUS
01192 NTAPI
01193 IoGetDiskDeviceObject(IN PDEVICE_OBJECT FileSystemDeviceObject,
01194                       OUT PDEVICE_OBJECT *DiskDeviceObject)
01195 {
01196     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01197     PVPB Vpb;
01198     KIRQL OldIrql;
01199     NTSTATUS Status;
01200 
01201     /* Make sure there's a VPB */
01202     if (!FileSystemDeviceObject->Vpb) return STATUS_INVALID_PARAMETER;
01203 
01204     /* Acquire it */
01205     IoAcquireVpbSpinLock(&OldIrql);
01206 
01207     /* Get the Device Extension */
01208     DeviceExtension = IoGetDevObjExtension(FileSystemDeviceObject);
01209 
01210     /* Make sure this one has a VPB too */
01211     Vpb = DeviceExtension->Vpb;
01212     if (Vpb)
01213     {
01214         /* Make sure that it's mounted */
01215         if ((Vpb->ReferenceCount) &&
01216             (Vpb->Flags & VPB_MOUNTED))
01217         {
01218             /* Return the Disk Device Object */
01219             *DiskDeviceObject = Vpb->RealDevice;
01220 
01221             /* Reference it and return success */
01222             ObReferenceObject(Vpb->RealDevice);
01223             Status = STATUS_SUCCESS;
01224         }
01225         else
01226         {
01227             /* It's not, so return failure */
01228             Status = STATUS_VOLUME_DISMOUNTED;
01229         }
01230     }
01231     else
01232     {
01233         /* Fail */
01234         Status = STATUS_INVALID_PARAMETER;
01235     }
01236 
01237     /* Release the lock */
01238     IoReleaseVpbSpinLock(OldIrql);
01239     return Status;
01240 }
01241 
01242 /*
01243  * @implemented
01244  */
01245 PDEVICE_OBJECT
01246 NTAPI
01247 IoGetLowerDeviceObject(IN PDEVICE_OBJECT DeviceObject)
01248 {
01249     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01250     PDEVICE_OBJECT LowerDeviceObject = NULL;
01251 
01252     /* Make sure it's not getting deleted */
01253     DeviceExtension = IoGetDevObjExtension(DeviceObject);
01254     if (!(DeviceExtension->ExtensionFlags & (DOE_UNLOAD_PENDING |
01255                                            DOE_DELETE_PENDING |
01256                                            DOE_REMOVE_PENDING |
01257                                            DOE_REMOVE_PROCESSED)))
01258     {
01259         /* Get the Lower Device Object */
01260         LowerDeviceObject = DeviceExtension->AttachedTo;
01261 
01262         /* Check that we got a valid device object */
01263         if (LowerDeviceObject)
01264         {
01265             /* We did so let's reference it */
01266             ObReferenceObject(LowerDeviceObject);
01267         }
01268     }
01269 
01270     /* Return it */
01271     return LowerDeviceObject;
01272 }
01273 
01274 /*
01275  * @implemented
01276  */
01277 PDEVICE_OBJECT
01278 NTAPI
01279 IoGetRelatedDeviceObject(IN PFILE_OBJECT FileObject)
01280 {
01281     PDEVICE_OBJECT DeviceObject = FileObject->DeviceObject;
01282 
01283     /* Check if we have a VPB with a device object */
01284     if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
01285     {
01286         /* Then use the DO from the VPB */
01287         ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
01288         DeviceObject = FileObject->Vpb->DeviceObject;
01289     }
01290     else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
01291               (FileObject->DeviceObject->Vpb) &&
01292               (FileObject->DeviceObject->Vpb->DeviceObject))
01293     {
01294         /* The disk device actually has a VPB, so get the DO from there */
01295         DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
01296     }
01297     else
01298     {
01299         /* Otherwise, this was a direct open */
01300         DeviceObject = FileObject->DeviceObject;
01301     }
01302 
01303     /* Sanity check */
01304     ASSERT(DeviceObject != NULL);
01305 
01306     /* Check if we were attached */
01307     if (DeviceObject->AttachedDevice)
01308     {
01309         /* Check if the file object has an extension present */
01310         if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
01311         {
01312             /* Sanity check, direct open files can't have this */
01313             ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
01314 
01315             /* Check if the extension is really present */
01316             if (FileObject->FileObjectExtension)
01317             {
01318                 /* FIXME: Unhandled yet */
01319                 DPRINT1("FOEs not supported\n");
01320                 ASSERT(FALSE);
01321             }
01322         }
01323 
01324         /* Return the highest attached device */
01325         DeviceObject = IoGetAttachedDevice(DeviceObject);
01326     }
01327 
01328     /* Return the DO we found */
01329     return DeviceObject;
01330 }
01331 
01332 /*
01333  * @implemented
01334  */
01335 NTSTATUS
01336 NTAPI
01337 IoGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
01338                          OUT PDEVICE_OBJECT *DeviceObject)
01339 {
01340     NTSTATUS Status;
01341     PDEVICE_NODE DeviceNode = NULL;
01342 
01343     /* Call the internal helper function */
01344     Status = IopGetRelatedTargetDevice(FileObject, &DeviceNode);
01345     if (NT_SUCCESS(Status) && DeviceNode)
01346     {
01347         *DeviceObject = DeviceNode->PhysicalDeviceObject;
01348     }
01349     return Status;
01350 }
01351 
01352 /*
01353  * @implemented
01354  */
01355 PDEVICE_OBJECT
01356 NTAPI
01357 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
01358 {
01359     PDEVICE_OBJECT DeviceObject;
01360 
01361     /*
01362     * If the FILE_OBJECT's VPB is defined,
01363     * get the device from it.
01364     */
01365     if ((FileObject->Vpb) && (FileObject->Vpb->DeviceObject))
01366     {
01367         /* Use the VPB's Device Object's */
01368         DeviceObject = FileObject->Vpb->DeviceObject;
01369     }
01370     else if (!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
01371              (FileObject->DeviceObject->Vpb) &&
01372              (FileObject->DeviceObject->Vpb->DeviceObject))
01373     {
01374         /* Use the VPB's File System Object */
01375         DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
01376     }
01377     else
01378     {
01379         /* Use the FO's Device Object */
01380         DeviceObject = FileObject->DeviceObject;
01381     }
01382 
01383     /* Return the device object we found */
01384     ASSERT(DeviceObject != NULL);
01385     return DeviceObject;
01386 }
01387 
01388 /*
01389  * @implemented
01390  */
01391 NTSTATUS
01392 NTAPI
01393 IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
01394 {
01395     PSHUTDOWN_ENTRY Entry;
01396 
01397     /* Allocate the shutdown entry */
01398     Entry = ExAllocatePoolWithTag(NonPagedPool,
01399                                   sizeof(SHUTDOWN_ENTRY),
01400                                   TAG_SHUTDOWN_ENTRY);
01401     if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
01402 
01403     /* Set the DO */
01404     Entry->DeviceObject = DeviceObject;
01405     
01406     /* Reference it so it doesn't go away */
01407     ObReferenceObject(DeviceObject);
01408 
01409     /* Insert it into the list */
01410     ExInterlockedInsertHeadList(&LastChanceShutdownListHead,
01411                                 &Entry->ShutdownList,
01412                                 &ShutdownListLock);
01413 
01414     /* Set the shutdown registered flag */
01415     DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
01416     return STATUS_SUCCESS;
01417 }
01418 
01419 /*
01420  * @implemented
01421  */
01422 NTSTATUS
01423 NTAPI
01424 IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
01425 {
01426     PSHUTDOWN_ENTRY Entry;
01427 
01428     /* Allocate the shutdown entry */
01429     Entry = ExAllocatePoolWithTag(NonPagedPool,
01430                                   sizeof(SHUTDOWN_ENTRY),
01431                                   TAG_SHUTDOWN_ENTRY);
01432     if (!Entry) return STATUS_INSUFFICIENT_RESOURCES;
01433 
01434     /* Set the DO */
01435     Entry->DeviceObject = DeviceObject;
01436     
01437     /* Reference it so it doesn't go away */
01438     ObReferenceObject(DeviceObject);
01439 
01440     /* Insert it into the list */
01441     ExInterlockedInsertHeadList(&ShutdownListHead,
01442                                 &Entry->ShutdownList,
01443                                 &ShutdownListLock);
01444 
01445     /* Set the shutdown registered flag */
01446     DeviceObject->Flags |= DO_SHUTDOWN_REGISTERED;
01447     return STATUS_SUCCESS;
01448 }
01449 
01450 /*
01451  * @implemented
01452  */
01453 VOID
01454 NTAPI
01455 IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
01456 {
01457     PSHUTDOWN_ENTRY ShutdownEntry;
01458     PLIST_ENTRY NextEntry;
01459     KIRQL OldIrql;
01460     
01461     /* Remove the flag */
01462     DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
01463 
01464     /* Acquire the shutdown lock and loop the shutdown list */
01465     KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
01466     NextEntry = ShutdownListHead.Flink;
01467     while (NextEntry != &ShutdownListHead)
01468     {
01469         /* Get the entry */
01470         ShutdownEntry = CONTAINING_RECORD(NextEntry,
01471                                           SHUTDOWN_ENTRY,
01472                                           ShutdownList);
01473 
01474         /* Get if the DO matches */
01475         if (ShutdownEntry->DeviceObject == DeviceObject)
01476         {
01477             /* Remove it from the list */
01478             RemoveEntryList(NextEntry);
01479             NextEntry = NextEntry->Blink;
01480 
01481             /* Free the entry */
01482             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
01483             
01484             /* Get rid of our reference to it */
01485             ObDereferenceObject(DeviceObject);
01486         }
01487 
01488         /* Go to the next entry */
01489         NextEntry = NextEntry->Flink;
01490     }
01491 
01492     /* Now loop the last chance list */
01493     NextEntry = LastChanceShutdownListHead.Flink;
01494     while (NextEntry != &LastChanceShutdownListHead)
01495     {
01496         /* Get the entry */
01497         ShutdownEntry = CONTAINING_RECORD(NextEntry,
01498                                           SHUTDOWN_ENTRY,
01499                                           ShutdownList);
01500 
01501         /* Get if the DO matches */
01502         if (ShutdownEntry->DeviceObject == DeviceObject)
01503         {
01504             /* Remove it from the list */
01505             RemoveEntryList(NextEntry);
01506             NextEntry = NextEntry->Blink;
01507 
01508             /* Free the entry */
01509             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
01510             
01511             /* Get rid of our reference to it */
01512             ObDereferenceObject(DeviceObject);
01513         }
01514 
01515         /* Go to the next entry */
01516         NextEntry = NextEntry->Flink;
01517     }
01518 
01519     /* Release the shutdown lock */
01520     KeReleaseSpinLock(&ShutdownListLock, OldIrql);
01521 }
01522 
01523 /*
01524  * @implemented
01525  */
01526 VOID
01527 NTAPI
01528 IoSetStartIoAttributes(IN PDEVICE_OBJECT DeviceObject,
01529                        IN BOOLEAN DeferredStartIo,
01530                        IN BOOLEAN NonCancelable)
01531 {
01532     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01533 
01534     /* Get the Device Extension */
01535     DeviceExtension = IoGetDevObjExtension(DeviceObject);
01536 
01537     /* Set the flags the caller requested */
01538     DeviceExtension->StartIoFlags |= (DeferredStartIo) ? DOE_SIO_DEFERRED : 0;
01539     DeviceExtension->StartIoFlags |= (NonCancelable) ? DOE_SIO_NO_CANCEL : 0;
01540 }
01541 
01542 /*
01543  * @implemented
01544  */
01545 VOID
01546 NTAPI
01547 IoStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
01548                        IN BOOLEAN Cancelable,
01549                        IN ULONG Key)
01550 {
01551     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01552 
01553     /* Get the Device Extension */
01554     DeviceExtension = IoGetDevObjExtension(DeviceObject);
01555 
01556     /* Check if deferred start was requested */
01557     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
01558     {
01559         /* Call our internal function to handle the defered case */
01560         IopStartNextPacketByKeyEx(DeviceObject,
01561                                   Key,
01562                                   DOE_SIO_WITH_KEY |
01563                                   (Cancelable ? DOE_SIO_CANCELABLE : 0));
01564     }
01565     else
01566     {
01567         /* Call the normal routine */
01568         IopStartNextPacketByKey(DeviceObject, Cancelable, Key);
01569     }
01570 }
01571 
01572 /*
01573  * @implemented
01574  */
01575 VOID
01576 NTAPI
01577 IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
01578                   IN BOOLEAN Cancelable)
01579 {
01580     PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
01581 
01582     /* Get the Device Extension */
01583     DeviceExtension = IoGetDevObjExtension(DeviceObject);
01584 
01585     /* Check if deferred start was requested */
01586     if (DeviceExtension->StartIoFlags & DOE_SIO_DEFERRED)
01587     {
01588         /* Call our internal function to handle the defered case */
01589         IopStartNextPacketByKeyEx(DeviceObject,
01590                                   0,
01591                                   DOE_SIO_NO_KEY |
01592                                   (Cancelable ? DOE_SIO_CANCELABLE : 0));
01593     }
01594     else
01595     {
01596         /* Call the normal routine */
01597         IopStartNextPacket(DeviceObject, Cancelable);
01598     }
01599 }
01600 
01601 /*
01602  * @implemented
01603  */
01604 VOID
01605 NTAPI
01606 IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
01607               IN PIRP Irp,
01608               IN PULONG Key,
01609               IN PDRIVER_CANCEL CancelFunction)
01610 {
01611     BOOLEAN Stat;
01612     KIRQL OldIrql, CancelIrql;
01613 
01614     /* Raise to dispatch level */
01615     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
01616 
01617     /* Check if we should acquire the cancel lock */
01618     if (CancelFunction)
01619     {
01620         /* Acquire and set it */
01621         IoAcquireCancelSpinLock(&CancelIrql);
01622         Irp->CancelRoutine = CancelFunction;
01623     }
01624 
01625     /* Check if we have a key */
01626     if (Key)
01627     {
01628         /* Insert by key */
01629         Stat = KeInsertByKeyDeviceQueue(&DeviceObject->DeviceQueue,
01630                                         &Irp->Tail.Overlay.DeviceQueueEntry,
01631                                         *Key);
01632     }
01633     else
01634     {
01635         /* Insert without a key */
01636         Stat = KeInsertDeviceQueue(&DeviceObject->DeviceQueue,
01637                                    &Irp->Tail.Overlay.DeviceQueueEntry);
01638     }
01639 
01640     /* Check if this was a first insert */
01641     if (!Stat)
01642     {
01643         /* Set the IRP */
01644         DeviceObject->CurrentIrp = Irp;
01645 
01646         /* Check if this is a cancelable packet */
01647         if (CancelFunction)
01648         {
01649             /* Check if the caller requested no cancellation */
01650             if (IoGetDevObjExtension(DeviceObject)->StartIoFlags &
01651                 DOE_SIO_NO_CANCEL)
01652             {
01653                 /* He did, so remove the cancel routine */
01654                 Irp->CancelRoutine = NULL;
01655             }
01656 
01657             /* Release the cancel lock */
01658             IoReleaseCancelSpinLock(CancelIrql);
01659         }
01660 
01661         /* Call the Start I/O function */
01662         DeviceObject->DriverObject->DriverStartIo(DeviceObject, Irp);
01663     }
01664     else
01665     {
01666         /* The packet was inserted... check if we have a cancel function */
01667         if (CancelFunction)
01668         {
01669             /* Check if the IRP got cancelled */
01670             if (Irp->Cancel)
01671             {
01672                 /*
01673                  * Set the cancel IRQL, clear the currnet cancel routine and
01674                  * call ours
01675                  */
01676                 Irp->CancelIrql = CancelIrql;
01677                 Irp->CancelRoutine = NULL;
01678                 CancelFunction(DeviceObject, Irp);
01679             }
01680             else
01681             {
01682                 /* Otherwise, release the lock */
01683                 IoReleaseCancelSpinLock(CancelIrql);
01684             }
01685         }
01686     }
01687 
01688     /* Return back to previous IRQL */
01689     KeLowerIrql(OldIrql);
01690 }
01691 
01692 #if defined (_WIN64)
01693 ULONG
01694 NTAPI
01695 IoWMIDeviceObjectToProviderId(
01696     IN PDEVICE_OBJECT DeviceObject)
01697 {
01698     UNIMPLEMENTED;
01699     return 0;
01700 }
01701 #endif
01702 
01703 /* EOF */

Generated on Sat May 26 2012 04:19:57 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.