[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / device.c
index ec6de6c..a0e1961 100644 (file)
 ULONG IopDeviceObjectNumber = 0;
 LIST_ENTRY ShutdownListHead, LastChanceShutdownListHead;
 KSPIN_LOCK ShutdownListLock;
-extern LIST_ENTRY IopDiskFsListHead;
-extern LIST_ENTRY IopCdRomFsListHead;
-extern LIST_ENTRY IopTapeFsListHead;
+extern LIST_ENTRY IopDiskFileSystemQueueHead;
+extern LIST_ENTRY IopCdRomFileSystemQueueHead;
+extern LIST_ENTRY IopTapeFileSystemQueueHead;
+extern ERESOURCE IopDatabaseResource;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
@@ -48,9 +49,12 @@ NTAPI
 IopDeleteDevice(IN PVOID ObjectBody)
 {
     PDEVICE_OBJECT DeviceObject = ObjectBody;
+    PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
     PAGED_CODE();
-    /* TODO: Delete Device Node */
+
+    /* Cleanup and free the device node */
+    if (DeviceNode)
+        IopFreeDeviceNode(DeviceNode);
 
     /* Dereference the driver object, referenced in IoCreateDevice */
     if (DeviceObject->DriverObject)
@@ -132,10 +136,10 @@ IoShutdownSystem(IN ULONG Phase)
     PIRP Irp;
     KEVENT Event;
     NTSTATUS Status;
-        
+
     /* Initialize an event to wait on */
     KeInitializeEvent(&Event, NotificationEvent, FALSE);
-    
+
     /* What phase? */
     if (Phase == 0)
     {
@@ -163,16 +167,22 @@ IoShutdownSystem(IN ULONG Phase)
                                                NULL,
                                                &Event,
                                                &StatusBlock);
-            Status = IoCallDriver(DeviceObject, Irp);
-            if (Status == STATUS_PENDING)
+            if (Irp)
             {
-                /* Wait on the driver */
-                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = IoCallDriver(DeviceObject, Irp);
+                if (Status == STATUS_PENDING)
+                {
+                    /* Wait on the driver */
+                    KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                }
             }
 
+            /* Remove the flag */
+            ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
             /* Get rid of our reference to it */
-            ObDereferenceObject(DeviceObject);
-            
+            ObDereferenceObject(ShutdownEntry->DeviceObject);
+
             /* Free the shutdown entry and reset the event */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
             KeClearEvent(&Event);
@@ -184,15 +194,18 @@ IoShutdownSystem(IN ULONG Phase)
     }
     else if (Phase == 1)
     {
+        /* Acquire resource forever */
+        ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE);
+
         /* Shutdown disk file systems */
-        IopShutdownBaseFileSystems(&IopDiskFsListHead);
+        IopShutdownBaseFileSystems(&IopDiskFileSystemQueueHead);
 
         /* Shutdown cdrom file systems */
-        IopShutdownBaseFileSystems(&IopCdRomFsListHead);
+        IopShutdownBaseFileSystems(&IopCdRomFileSystemQueueHead);
 
         /* Shutdown tape filesystems */
-        IopShutdownBaseFileSystems(&IopTapeFsListHead);
-        
+        IopShutdownBaseFileSystems(&IopTapeFileSystemQueueHead);
+
         /* Loop last-chance shutdown notifications */
         ListEntry = ExInterlockedRemoveHeadList(&LastChanceShutdownListHead,
                                                 &ShutdownListLock);
@@ -214,16 +227,22 @@ IoShutdownSystem(IN ULONG Phase)
                                                NULL,
                                                &Event,
                                                &StatusBlock);
-            Status = IoCallDriver(DeviceObject, Irp);
-            if (Status == STATUS_PENDING)
+            if (Irp)
             {
-                /* Wait on the driver */
-                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                Status = IoCallDriver(DeviceObject, Irp);
+                if (Status == STATUS_PENDING)
+                {
+                    /* Wait on the driver */
+                    KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+                }
             }
 
+            /* Remove the flag */
+            ShutdownEntry->DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
             /* Get rid of our reference to it */
-            ObDereferenceObject(DeviceObject);
-            
+            ObDereferenceObject(ShutdownEntry->DeviceObject);
+
             /* Free the shutdown entry and reset the event */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
             KeClearEvent(&Event);
@@ -352,71 +371,22 @@ NTAPI
 IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
 {
     PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject;
-    PDEVICE_OBJECT AttachedDeviceObject, LowestDeviceObject;
-    PEXTENDED_DEVOBJ_EXTENSION ThisExtension, DeviceExtension;
-    PDEVICE_NODE DeviceNode;
-    BOOLEAN SafeToUnload = TRUE;
-
-    /* Check if removal is pending */
-    ThisExtension = IoGetDevObjExtension(DeviceObject);
-    if (ThisExtension->ExtensionFlags & DOE_REMOVE_PENDING)
-    {
-        /* Get the PDO, extension, and node */
-        LowestDeviceObject = IopGetLowestDevice(DeviceObject);
-        DeviceExtension = IoGetDevObjExtension(LowestDeviceObject);
-        DeviceNode = DeviceExtension->DeviceNode;
-
-        /* The PDO needs a device node */
-        ASSERT(DeviceNode != NULL);
-
-        /* Loop all attached objects */
-        AttachedDeviceObject = LowestDeviceObject;
-        while (AttachedDeviceObject)
-        {
-            /* Make sure they're dereferenced */
-            if (AttachedDeviceObject->ReferenceCount) return;
-            AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
-        }
-
-        /* Loop all attached objects */
-        AttachedDeviceObject = LowestDeviceObject;
-        while (AttachedDeviceObject)
-        {
-            /* Get the device extension */
-            DeviceExtension = IoGetDevObjExtension(AttachedDeviceObject);
-
-            /* Remove the pending flag and set processed */
-            DeviceExtension->ExtensionFlags &= ~DOE_REMOVE_PENDING;
-            DeviceExtension->ExtensionFlags |= DOE_REMOVE_PROCESSED;
-            AttachedDeviceObject = AttachedDeviceObject->AttachedDevice;
-        }
-
-        /*
-         * FIXME: TODO HPOUSSIN
-         * We need to parse/lock the device node, and if we have any pending
-         * surprise removals, query all relationships and send IRP_MN_REMOVE_
-         * _DEVICE to the devices related...
-         */
-        return;
-    }
+    PEXTENDED_DEVOBJ_EXTENSION ThisExtension = IoGetDevObjExtension(DeviceObject);
 
     /* Check if deletion is pending */
     if (ThisExtension->ExtensionFlags & DOE_DELETE_PENDING)
     {
-        /* Make sure unload is pending */
-        if (!(ThisExtension->ExtensionFlags & DOE_UNLOAD_PENDING) ||
-            (DriverObject->Flags & DRVO_UNLOAD_INVOKED))
+        if (DeviceObject->AttachedDevice)
         {
-            /* We can't unload anymore */
-            SafeToUnload = FALSE;
+            DPRINT("Device object is in the middle of a device stack\n");
+            return;
         }
 
-        /*
-         * Check if we have an attached device and fail if we're attached
-         * and still have a reference count.
-         */
-        AttachedDeviceObject = DeviceObject->AttachedDevice;
-        if ((AttachedDeviceObject) && (DeviceObject->ReferenceCount)) return;
+        if (DeviceObject->ReferenceCount)
+        {
+            DPRINT("Device object still has %d references\n", DeviceObject->ReferenceCount);
+            return;
+        }
 
         /* Check if we have a Security Descriptor */
         if (DeviceObject->SecurityDescriptor)
@@ -430,44 +400,42 @@ IopUnloadDevice(IN PDEVICE_OBJECT DeviceObject)
 
         /* Dereference the keep-alive */
         ObDereferenceObject(DeviceObject);
+    }
 
-        /* If we're not unloading, stop here */
-        if (!SafeToUnload) return;
+    /* We can't unload a non-PnP driver here */
+    if (DriverObject->Flags & DRVO_LEGACY_DRIVER)
+    {
+        DPRINT("Not a PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+        return;
     }
 
-    /* Loop all the device objects */
-    DeviceObject = DriverObject->DeviceObject;
-    while (DeviceObject)
+    /* Return if we've already called unload (maybe we're in it?) */
+    if (DriverObject->Flags & DRVO_UNLOAD_INVOKED) return;
+
+    /* We can't unload unless there's an unload handler */
+    if (!DriverObject->DriverUnload)
     {
-        /*
-         * Make sure we're not attached, having a reference count
-         * or already deleting
-         */
-        if ((DeviceObject->ReferenceCount) ||
-             (DeviceObject->AttachedDevice) ||
-             (IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
-              (DOE_DELETE_PENDING | DOE_REMOVE_PENDING)))
-        {
-            /* We're not safe to unload, quit */
-            return;
-        }
+        DPRINT1("No DriverUnload function on PnP driver! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+        return;
+    }
 
-        /* Check the next device */
-        DeviceObject = DeviceObject->NextDevice;
+    /* Bail if there are still devices present */
+    if (DriverObject->DeviceObject)
+    {
+        DPRINT("Devices still present! '%wZ' will not be unloaded!\n", &DriverObject->DriverName);
+        return;
     }
 
+    DPRINT1("Unloading driver '%wZ' (automatic)\n", &DriverObject->DriverName);
+
     /* Set the unload invoked flag */
     DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
 
     /* Unload it */
-    if (DriverObject->DriverUnload) DriverObject->DriverUnload(DriverObject);
+    DriverObject->DriverUnload(DriverObject);
 
     /* Make object temporary so it can be deleted */
     ObMakeTemporaryObject(DriverObject);
-
-    /* Dereference once more, referenced at driver object creation */
-    ObDereferenceObject(DriverObject);
-
 }
 
 VOID
@@ -479,18 +447,15 @@ IopDereferenceDeviceObject(IN PDEVICE_OBJECT DeviceObject,
     ASSERT(DeviceObject->ReferenceCount);
 
     /* Dereference the device */
-    DeviceObject->ReferenceCount--;
+    InterlockedDecrement(&DeviceObject->ReferenceCount);
 
     /*
      * Check if we can unload it and it's safe to unload (or if we're forcing
      * an unload, which is OK too).
      */
+    ASSERT(!ForceUnload);
     if (!(DeviceObject->ReferenceCount) &&
-        ((ForceUnload) || (IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
-                           (DOE_UNLOAD_PENDING |
-                            DOE_DELETE_PENDING |
-                            DOE_REMOVE_PENDING |
-                            DOE_REMOVE_PROCESSED))))
+        (IoGetDevObjExtension(DeviceObject)->ExtensionFlags & DOE_DELETE_PENDING))
     {
         /* Unload it */
         IopUnloadDevice(DeviceObject);
@@ -671,7 +636,6 @@ IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
 {
     NTSTATUS Status;
     IO_STACK_LOCATION Stack = {0};
-    IO_STATUS_BLOCK IoStatusBlock;
     PDEVICE_RELATIONS DeviceRelations;
     PDEVICE_OBJECT DeviceObject = NULL;
 
@@ -682,19 +646,17 @@ IopGetRelatedTargetDevice(IN PFILE_OBJECT FileObject,
     if (!DeviceObject) return STATUS_NO_SUCH_DEVICE;
 
     /* Define input parameters */
+    Stack.MajorFunction = IRP_MJ_PNP;
+    Stack.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
     Stack.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
     Stack.FileObject = FileObject;
 
     /* Call the driver to query all relations (IRP_MJ_PNP) */
-    Status = IopInitiatePnpIrp(DeviceObject,
-                               &IoStatusBlock,
-                               IRP_MN_QUERY_DEVICE_RELATIONS,
-                               &Stack);
+    Status = IopSynchronousCall(DeviceObject,
+                                &Stack,
+                                (PVOID)&DeviceRelations);
     if (!NT_SUCCESS(Status)) return Status;
 
-    /* Get returned pointer to DEVICE_RELATIONS */
-    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
-
     /* Make sure it's not NULL and contains only one object */
     ASSERT(DeviceRelations);
     ASSERT(DeviceRelations->Count == 1);
@@ -933,7 +895,7 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
     /* Set the Type and Size. Question: why is Size 0 on Windows? */
     DeviceObjectExtension->Type = IO_TYPE_DEVICE_OBJECT_EXTENSION;
     DeviceObjectExtension->Size = 0;
-    
+
     /* Initialize with Power Manager */
     PoInitializeDeviceObject(DeviceObjectExtension);
 
@@ -965,8 +927,8 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
         Status = IopCreateVpb(CreatedDeviceObject);
         if (!NT_SUCCESS(Status))
         {
-            /* Reference the device object and fail */
-            ObDereferenceObject(DeviceObject);
+            /* Dereference the device object and fail */
+            ObDereferenceObject(CreatedDeviceObject);
             return Status;
         }
 
@@ -1025,7 +987,7 @@ IoCreateDevice(IN PDRIVER_OBJECT DriverObject,
     ASSERT((DriverObject->Flags & DRVO_UNLOAD_INVOKED) == 0);
     CreatedDeviceObject->DriverObject = DriverObject;
     IopEditDeviceList(DriverObject, CreatedDeviceObject, IopAdd);
-    
+
     /* Link with the power manager */
     if (CreatedDeviceObject->Vpb) PoVolumeDevice(CreatedDeviceObject);
 
@@ -1073,6 +1035,9 @@ IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject)
     /* Set the pending delete flag */
     IoGetDevObjExtension(DeviceObject)->ExtensionFlags |= DOE_DELETE_PENDING;
 
+    /* Unlink with the power manager */
+    if (DeviceObject->Vpb) PoRemoveVolumeDevice(DeviceObject);
+
     /* Check if the device object can be unloaded */
     if (!DeviceObject->ReferenceCount) IopUnloadDevice(DeviceObject);
 }
@@ -1098,8 +1063,7 @@ IoDetachDevice(IN PDEVICE_OBJECT TargetDevice)
     TargetDevice->AttachedDevice = NULL;
 
     /* Check if it's ok to delete this device */
-    if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags &
-        (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) &&
+    if ((IoGetDevObjExtension(TargetDevice)->ExtensionFlags & DOE_DELETE_PENDING) &&
         !(TargetDevice->ReferenceCount))
     {
         /* It is, do it */
@@ -1447,7 +1411,7 @@ IoRegisterLastChanceShutdownNotification(IN PDEVICE_OBJECT DeviceObject)
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
-    
+
     /* Reference it so it doesn't go away */
     ObReferenceObject(DeviceObject);
 
@@ -1478,7 +1442,7 @@ IoRegisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
 
     /* Set the DO */
     Entry->DeviceObject = DeviceObject;
-    
+
     /* Reference it so it doesn't go away */
     ObReferenceObject(DeviceObject);
 
@@ -1503,6 +1467,9 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
     PLIST_ENTRY NextEntry;
     KIRQL OldIrql;
 
+    /* Remove the flag */
+    DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
+
     /* Acquire the shutdown lock and loop the shutdown list */
     KeAcquireSpinLock(&ShutdownListLock, &OldIrql);
     NextEntry = ShutdownListHead.Flink;
@@ -1522,7 +1489,7 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
 
             /* Free the entry */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
-            
+
             /* Get rid of our reference to it */
             ObDereferenceObject(DeviceObject);
         }
@@ -1549,7 +1516,7 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
 
             /* Free the entry */
             ExFreePoolWithTag(ShutdownEntry, TAG_SHUTDOWN_ENTRY);
-            
+
             /* Get rid of our reference to it */
             ObDereferenceObject(DeviceObject);
         }
@@ -1560,9 +1527,6 @@ IoUnregisterShutdownNotification(PDEVICE_OBJECT DeviceObject)
 
     /* Release the shutdown lock */
     KeReleaseSpinLock(&ShutdownListLock, OldIrql);
-
-    /* Now remove the flag */
-    DeviceObject->Flags &= ~DO_SHUTDOWN_REGISTERED;
 }
 
 /*
@@ -1734,4 +1698,15 @@ IoStartPacket(IN PDEVICE_OBJECT DeviceObject,
     KeLowerIrql(OldIrql);
 }
 
+#if defined (_WIN64)
+ULONG
+NTAPI
+IoWMIDeviceObjectToProviderId(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    UNIMPLEMENTED;
+    return 0;
+}
+#endif
+
 /* EOF */