[NTOS:PO]
[reactos.git] / reactos / ntoskrnl / po / power.c
index 746fe7d..9b96b60 100644 (file)
 
 /* GLOBALS *******************************************************************/
 
-typedef struct _REQUEST_POWER_ITEM
-{
-    PREQUEST_POWER_COMPLETE CompletionRoutine;
-    POWER_STATE PowerState;
-    PVOID Context;
-    PDEVICE_OBJECT TopDeviceObject;
-} REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
-
 typedef struct _POWER_STATE_TRAVERSE_CONTEXT
 {
     SYSTEM_POWER_STATE SystemPowerState;
@@ -45,21 +37,22 @@ PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
                              IN PVOID Context)
 {
     PIO_STACK_LOCATION Stack;
-    PREQUEST_POWER_ITEM RequestPowerItem;
+    PREQUEST_POWER_COMPLETE CompletionRoutine;
+    POWER_STATE PowerState;
 
-    Stack = IoGetNextIrpStackLocation(Irp);
-    RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+    CompletionRoutine = Context;
 
-    RequestPowerItem->CompletionRoutine(DeviceObject,
-                                        Stack->MinorFunction,
-                                        RequestPowerItem->PowerState,
-                                        RequestPowerItem->Context,
-                                        &Irp->IoStatus);
+    PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3;
+    CompletionRoutine(Stack->Parameters.Others.Argument1,
+                      (UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2,
+                      PowerState,
+                      Stack->Parameters.Others.Argument4,
+                      &Irp->IoStatus);
 
+    IoSkipCurrentIrpStackLocation(Irp);
     IoFreeIrp(Irp);
-
-    ObDereferenceObject(RequestPowerItem->TopDeviceObject);
-    ExFreePool(Context);
+    ObDereferenceObject(DeviceObject);
 
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
@@ -160,6 +153,7 @@ PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
                                  PVOID Context)
 {
     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
+    PDEVICE_OBJECT TopDeviceObject;
     NTSTATUS Status;
 
     DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
@@ -170,13 +164,16 @@ PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
         return STATUS_SUCCESS;
 
-    Status = PopSendQuerySystemPowerState(DeviceNode->PhysicalDeviceObject,
+    TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
+
+    Status = PopSendQuerySystemPowerState(TopDeviceObject,
                                           PowerStateContext->SystemPowerState,
                                           PowerStateContext->PowerAction);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
     }
+    ObDereferenceObject(TopDeviceObject);
 
 #if 0
     return Status;
@@ -190,6 +187,7 @@ PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
                                PVOID Context)
 {
     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
+    PDEVICE_OBJECT TopDeviceObject;
     NTSTATUS Status;
 
     DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
@@ -203,7 +201,14 @@ PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
         return STATUS_SUCCESS;
 
-    Status = PopSendSetSystemPowerState(DeviceNode->PhysicalDeviceObject,
+    TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
+    if (TopDeviceObject == PowerStateContext->PowerDevice)
+    {
+        ObDereferenceObject(TopDeviceObject);
+        return STATUS_SUCCESS;
+    }
+
+    Status = PopSendSetSystemPowerState(TopDeviceObject,
                                         PowerStateContext->SystemPowerState,
                                         PowerStateContext->PowerAction);
     if (!NT_SUCCESS(Status))
@@ -211,6 +216,8 @@ PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
         DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
     }
 
+    ObDereferenceObject(TopDeviceObject);
+
 #if 0
     return Status;
 #else
@@ -521,57 +528,52 @@ PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
     PDEVICE_OBJECT TopDeviceObject;
     PIO_STACK_LOCATION Stack;
     PIRP Irp;
-    PREQUEST_POWER_ITEM RequestPowerItem;
 
     if (MinorFunction != IRP_MN_QUERY_POWER
         && MinorFunction != IRP_MN_SET_POWER
         && MinorFunction != IRP_MN_WAIT_WAKE)
         return STATUS_INVALID_PARAMETER_2;
 
-    RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
-    if (!RequestPowerItem)
-        return STATUS_INSUFFICIENT_RESOURCES;
-
     /* Always call the top of the device stack */
     TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
 
-    Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_POWER,
-                                        TopDeviceObject,
-                                        NULL,
-                                        0,
-                                        NULL,
-                                        NULL);
+    Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
     if (!Irp)
     {
         ObDereferenceObject(TopDeviceObject);
-        ExFreePool(RequestPowerItem);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    /* POWER IRPs are always initialized with a status code of
-       STATUS_NOT_IMPLEMENTED */
-    Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
     Irp->IoStatus.Information = 0;
 
+    IoSetNextIrpStackLocation(Irp);
+
     Stack = IoGetNextIrpStackLocation(Irp);
+    Stack->Parameters.Others.Argument1 = DeviceObject;
+    Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
+    Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
+    Stack->Parameters.Others.Argument4 = Context;
+    Stack->DeviceObject = TopDeviceObject;
+    IoSetNextIrpStackLocation(Irp);
+
+    Stack = IoGetNextIrpStackLocation(Irp);
+    Stack->MajorFunction = IRP_MJ_POWER;
     Stack->MinorFunction = MinorFunction;
     if (MinorFunction == IRP_MN_WAIT_WAKE)
+    {
         Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
+    }
     else
     {
         Stack->Parameters.Power.Type = DevicePowerState;
         Stack->Parameters.Power.State = PowerState;
     }
 
-    RequestPowerItem->CompletionRoutine = CompletionFunction;
-    RequestPowerItem->PowerState = PowerState;
-    RequestPowerItem->Context = Context;
-    RequestPowerItem->TopDeviceObject = TopDeviceObject;
-
     if (pIrp != NULL)
         *pIrp = Irp;
 
-    IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
+    IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
     PoCallDriver(TopDeviceObject, Irp);
 
     /* Always return STATUS_PENDING. The completion routine
@@ -634,10 +636,10 @@ PoUnregisterSystemState(IN PVOID StateHandle)
  */
 NTSTATUS
 NTAPI
-NtInitiatePowerAction (IN POWER_ACTION SystemAction,
-                       IN SYSTEM_POWER_STATE MinSystemState,
-                       IN ULONG Flags,
-                       IN BOOLEAN Asynchronous)
+NtInitiatePowerAction(IN POWER_ACTION SystemAction,
+                      IN SYSTEM_POWER_STATE MinSystemState,
+                      IN ULONG Flags,
+                      IN BOOLEAN Asynchronous)
 {
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
@@ -655,6 +657,7 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
                    IN ULONG OutputBufferLength)
 {
     NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
 
     PAGED_CODE();
 
@@ -664,6 +667,20 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
            InputBuffer, InputBufferLength,
            OutputBuffer, OutputBufferLength);
 
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForRead(InputBuffer, InputBufferLength, 1);
+            ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
     switch (PowerInformationLevel)
     {
         case SystemBatteryState:
@@ -675,11 +692,20 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
             if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
                 return STATUS_BUFFER_TOO_SMALL;
 
-            /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
-            RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
-            BatteryState->EstimatedTime = MAXULONG;
+            _SEH2_TRY
+            {
+                /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
+                RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
+                BatteryState->EstimatedTime = MAXULONG;
+
+                Status = STATUS_SUCCESS;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
 
-            Status = STATUS_SUCCESS;
             break;
         }
 
@@ -692,11 +718,49 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
             if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
                 return STATUS_BUFFER_TOO_SMALL;
 
-            /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
-            RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
-            //PowerCapabilities->SystemBatteriesPresent = 0;
+            _SEH2_TRY
+            {
+                /* Just zero the struct (and thus set PowerCapabilities->SystemBatteriesPresent = FALSE) */
+                RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
+                //PowerCapabilities->SystemBatteriesPresent = 0;
+
+                Status = STATUS_SUCCESS;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            break;
+        }
+
+        case ProcessorInformation:
+        {
+            PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer;
+
+            if (InputBuffer != NULL)
+                return STATUS_INVALID_PARAMETER;
+            if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION))
+                return STATUS_BUFFER_TOO_SMALL;
+
+            _SEH2_TRY
+            {
+                PowerInformation->Number = 0;
+                PowerInformation->MaxMhz = 1000;
+                PowerInformation->CurrentMhz = 1000;
+                PowerInformation->MhzLimit = 1000;
+                PowerInformation->MaxIdleState = 0;
+                PowerInformation->CurrentIdleState = 0;
+
+                Status = STATUS_SUCCESS;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
 
-            Status = STATUS_SUCCESS;
             break;
         }