Author: cgutman
Date: Thu May 26 22:09:02 2011
New Revision: 51942

URL: http://svn.reactos.org/svn/reactos?rev=51942&view=rev
Log:
[NTOSKRNL]
- Implement the kernel backend of graceful device removal/ejection

Modified:
    trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c

Modified: trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c?rev=51942&r1=51941&r2=51942&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/pnpmgr/pnpmgr.c [iso-8859-1] Thu May 26 22:09:02 
2011
@@ -125,6 +125,20 @@
    return STATUS_SUCCESS;
 }
 
+NTSTATUS
+NTAPI
+IopSendEject(IN PDEVICE_OBJECT DeviceObject)
+{
+    IO_STACK_LOCATION Stack;
+    PVOID Dummy;
+    
+    RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
+    Stack.MajorFunction = IRP_MJ_PNP;
+    Stack.MinorFunction = IRP_MN_EJECT;
+    
+    return IopSynchronousCall(DeviceObject, &Stack, &Dummy); 
+}
+
 VOID
 NTAPI
 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
@@ -138,6 +152,20 @@
     
     /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
     IopSynchronousCall(DeviceObject, &Stack, &Dummy);
+}
+
+NTSTATUS
+NTAPI
+IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
+{
+    IO_STACK_LOCATION Stack;
+    PVOID Dummy;
+    
+    RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
+    Stack.MajorFunction = IRP_MJ_PNP;
+    Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
+    
+    return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
 }
 
 VOID
@@ -3687,14 +3715,221 @@
    return Status;
 }
 
+NTSTATUS
+NTAPI
+IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject)
+{
+    PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
+    IO_STACK_LOCATION Stack;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PDEVICE_RELATIONS DeviceRelations;
+    NTSTATUS Status;
+    ULONG i;
+    
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
+                              &DeviceNode->InstancePath);
+    
+    if (IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
+    {
+        DPRINT1("Removal vetoed by failing the query remove request\n");
+        
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
+                                  &DeviceNode->InstancePath);
+        
+        return STATUS_UNSUCCESSFUL;
+    }
+    
+    Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
+    
+    Status = IopInitiatePnpIrp(DeviceObject,
+                               &IoStatusBlock,
+                               IRP_MN_QUERY_DEVICE_RELATIONS,
+                               &Stack);
+    if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
+    {
+        DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
+        return Status;
+    }
+    
+    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+    
+    if (DeviceRelations)
+    {
+        for (i = 0; i < DeviceRelations->Count; i++)
+        {
+            PDEVICE_NODE RelationsDeviceNode = 
IopGetDeviceNode(DeviceRelations->Objects[i]);
+            
+            IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
+                                      &RelationsDeviceNode->InstancePath);
+            
+            if (IopQueryRemoveDevice(DeviceRelations->Objects[i]) != 
STATUS_SUCCESS)
+            {
+                DPRINT1("Device removal vetoed by failing a dependent query 
remove request\n");
+                
+                IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
+                                          &RelationsDeviceNode->InstancePath);
+                
+                Status = STATUS_UNSUCCESSFUL;
+                
+                goto cleanup;
+            }
+            else
+            {
+                IopSendRemoveDevice(DeviceRelations->Objects[i]);
+                
+                IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
+                                          &RelationsDeviceNode->InstancePath);
+                
+                ObDereferenceObject(DeviceRelations->Objects[i]);
+                
+                DeviceRelations->Objects[i] = NULL;
+            }
+        }
+        
+        ExFreePool(DeviceRelations);
+        
+        DeviceRelations = NULL;
+    }
+    
+    Status = STATUS_SUCCESS;
+    
+cleanup:
+    if (DeviceRelations)
+    {
+        for (i = 0; i < DeviceRelations->Count; i++)
+        {
+            if (DeviceRelations->Objects[i])
+            {
+                ObDereferenceObject(DeviceRelations->Objects[i]);
+            }
+        }
+        
+        ExFreePool(DeviceRelations);
+    }
+
+    return Status;
+}
+
 /*
- * @unimplemented
+ * @implemented
  */
 VOID
 NTAPI
 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
 {
-   UNIMPLEMENTED;
+    PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
+    PDEVICE_RELATIONS DeviceRelations;
+    IO_STATUS_BLOCK IoStatusBlock;
+    IO_STACK_LOCATION Stack;
+    DEVICE_CAPABILITIES Capabilities;
+    NTSTATUS Status;
+    ULONG i;
+    
+    IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
+                              &DeviceNode->InstancePath);
+    
+    if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != 
STATUS_SUCCESS)
+    {
+       IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                                 &DeviceNode->InstancePath);
+       return;
+    }
+    
+    Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
+    
+    Status = IopInitiatePnpIrp(PhysicalDeviceObject,
+                               &IoStatusBlock,
+                               IRP_MN_QUERY_DEVICE_RELATIONS,
+                               &Stack);
+    if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
+    {
+        DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                                  &DeviceNode->InstancePath);
+        return;
+    }
+    
+    DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
+    
+    if (DeviceRelations)
+    {
+        for (i = 0; i < DeviceRelations->Count; i++)
+        {
+            PDEVICE_NODE RelationsDeviceNode = 
IopGetDeviceNode(DeviceRelations->Objects[i]);
+            
+            IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
+                                      &RelationsDeviceNode->InstancePath);
+            
+            if (IopQueryRemoveDevice(DeviceRelations->Objects[i]) != 
STATUS_SUCCESS)
+            {
+                DPRINT1("Device removal vetoed by failing a query remove 
request (ejection relations)\n");
+                
+                IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
+                                          &RelationsDeviceNode->InstancePath);
+            
+                goto cleanup;
+            }
+            else
+            {
+                IopSendRemoveDevice(DeviceRelations->Objects[i]);
+                
+                IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
+                                          &RelationsDeviceNode->InstancePath);
+                
+                ObDereferenceObject(DeviceRelations->Objects[i]);
+                
+                DeviceRelations->Objects[i] = NULL;
+            }
+        }
+        
+        ExFreePool(DeviceRelations);
+        
+        DeviceRelations = NULL;
+    }
+    
+    if (IopPrepareDeviceForRemoval(PhysicalDeviceObject) != STATUS_SUCCESS)
+    {
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                                  &DeviceNode->InstancePath);
+        return;
+    }
+    
+    if (Capabilities.EjectSupported)
+    {
+        if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
+        {
+            IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                                      &DeviceNode->InstancePath);
+
+            return;
+        }
+    }
+    else
+    {
+        DeviceNode->Flags |= DNF_DISABLED;
+    }
+    
+cleanup:
+    if (DeviceRelations)
+    {
+        for (i = 0; i < DeviceRelations->Count; i++)
+        {
+            if (DeviceRelations->Objects[i])
+            {
+                ObDereferenceObject(DeviceRelations->Objects[i]);
+            }
+        }
+        
+        ExFreePool(DeviceRelations);
+
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
+                                  &DeviceNode->InstancePath);
+    }
+    else
+    {
+        IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
+                                  &DeviceNode->InstancePath);
+    }
 }
 
 /*


Reply via email to