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... ============================================================================== --- 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); + } }
/*