xref: /reactos/ntoskrnl/po/power.c (revision 4b051b91)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/po/power.c
5c2c66affSColin Finck  * PURPOSE:         Power Manager
6c2c66affSColin Finck  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
7*4b051b91SSerge Gautherie  *                  Hervé Poussineau (hpoussin@reactos.com)
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck /* INCLUDES ******************************************************************/
11c2c66affSColin Finck 
12c2c66affSColin Finck #include <ntoskrnl.h>
13c2c66affSColin Finck #define NDEBUG
14c2c66affSColin Finck #include <debug.h>
15c2c66affSColin Finck 
16c2c66affSColin Finck /* GLOBALS *******************************************************************/
17c2c66affSColin Finck 
18c2c66affSColin Finck typedef struct _POWER_STATE_TRAVERSE_CONTEXT
19c2c66affSColin Finck {
20c2c66affSColin Finck     SYSTEM_POWER_STATE SystemPowerState;
21c2c66affSColin Finck     POWER_ACTION PowerAction;
22c2c66affSColin Finck     PDEVICE_OBJECT PowerDevice;
23c2c66affSColin Finck } POWER_STATE_TRAVERSE_CONTEXT, *PPOWER_STATE_TRAVERSE_CONTEXT;
24c2c66affSColin Finck 
25c2c66affSColin Finck PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
26c2c66affSColin Finck BOOLEAN PopAcpiPresent = FALSE;
27c2c66affSColin Finck POP_POWER_ACTION PopAction;
28c2c66affSColin Finck WORK_QUEUE_ITEM PopShutdownWorkItem;
29626aaf22SEric Kohl SYSTEM_POWER_CAPABILITIES PopCapabilities;
30c2c66affSColin Finck 
31c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
32c2c66affSColin Finck 
3334f4b218SThomas Faber static WORKER_THREAD_ROUTINE PopPassivePowerCall;
3434f4b218SThomas Faber _Use_decl_annotations_
3534f4b218SThomas Faber static
3634f4b218SThomas Faber VOID
3734f4b218SThomas Faber NTAPI
PopPassivePowerCall(PVOID Parameter)3834f4b218SThomas Faber PopPassivePowerCall(
3934f4b218SThomas Faber     PVOID Parameter)
4034f4b218SThomas Faber {
4134f4b218SThomas Faber     PIRP Irp = Parameter;
4234f4b218SThomas Faber     PIO_STACK_LOCATION IoStack;
4334f4b218SThomas Faber 
4434f4b218SThomas Faber     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
4534f4b218SThomas Faber 
4634f4b218SThomas Faber     _Analysis_assume_(Irp != NULL);
4734f4b218SThomas Faber     IoStack = IoGetNextIrpStackLocation(Irp);
4834f4b218SThomas Faber 
4934f4b218SThomas Faber     (VOID)IoCallDriver(IoStack->DeviceObject, Irp);
5034f4b218SThomas Faber }
5134f4b218SThomas Faber 
_IRQL_requires_max_(DISPATCH_LEVEL)5234f4b218SThomas Faber _IRQL_requires_max_(DISPATCH_LEVEL)
5334f4b218SThomas Faber _IRQL_requires_same_
5434f4b218SThomas Faber static
5534f4b218SThomas Faber NTSTATUS
5634f4b218SThomas Faber PopPresentIrp(
5734f4b218SThomas Faber     _In_ PIO_STACK_LOCATION NextStack,
5834f4b218SThomas Faber     _In_ PIRP Irp)
5934f4b218SThomas Faber {
6034f4b218SThomas Faber     NTSTATUS Status;
6134f4b218SThomas Faber     BOOLEAN CallAtPassiveLevel;
6234f4b218SThomas Faber     PDEVICE_OBJECT DeviceObject;
6334f4b218SThomas Faber     PWORK_QUEUE_ITEM WorkQueueItem;
6434f4b218SThomas Faber 
6534f4b218SThomas Faber     ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
6634f4b218SThomas Faber 
6734f4b218SThomas Faber     DeviceObject = NextStack->DeviceObject;
6834f4b218SThomas Faber 
6934f4b218SThomas Faber     /* Determine whether the IRP must be handled at PASSIVE_LEVEL.
7034f4b218SThomas Faber      * Only SET_POWER to working state can happen at raised IRQL. */
7134f4b218SThomas Faber     CallAtPassiveLevel = TRUE;
7234f4b218SThomas Faber     if ((NextStack->MinorFunction == IRP_MN_SET_POWER) &&
7334f4b218SThomas Faber         !(DeviceObject->Flags & DO_POWER_PAGABLE))
7434f4b218SThomas Faber     {
7534f4b218SThomas Faber         if (NextStack->Parameters.Power.Type == DevicePowerState &&
7634f4b218SThomas Faber             NextStack->Parameters.Power.State.DeviceState == PowerDeviceD0)
7734f4b218SThomas Faber         {
7834f4b218SThomas Faber             CallAtPassiveLevel = FALSE;
7934f4b218SThomas Faber         }
8034f4b218SThomas Faber         if (NextStack->Parameters.Power.Type == SystemPowerState &&
8134f4b218SThomas Faber             NextStack->Parameters.Power.State.SystemState == PowerSystemWorking)
8234f4b218SThomas Faber         {
8334f4b218SThomas Faber             CallAtPassiveLevel = FALSE;
8434f4b218SThomas Faber         }
8534f4b218SThomas Faber     }
8634f4b218SThomas Faber 
8734f4b218SThomas Faber     if (CallAtPassiveLevel)
8834f4b218SThomas Faber     {
8934f4b218SThomas Faber         /* We need to fit a work item into the DriverContext below */
9034f4b218SThomas Faber         C_ASSERT(sizeof(Irp->Tail.Overlay.DriverContext) >= sizeof(WORK_QUEUE_ITEM));
9134f4b218SThomas Faber 
9234f4b218SThomas Faber         if (KeGetCurrentIrql() == PASSIVE_LEVEL)
9334f4b218SThomas Faber         {
9434f4b218SThomas Faber             /* Already at passive, call next driver directly */
9534f4b218SThomas Faber             return IoCallDriver(DeviceObject, Irp);
9634f4b218SThomas Faber         }
9734f4b218SThomas Faber 
9834f4b218SThomas Faber         /* Need to schedule a work item and return pending */
9934f4b218SThomas Faber         NextStack->Control |= SL_PENDING_RETURNED;
10034f4b218SThomas Faber 
10134f4b218SThomas Faber         WorkQueueItem = (PWORK_QUEUE_ITEM)&Irp->Tail.Overlay.DriverContext;
10234f4b218SThomas Faber         ExInitializeWorkItem(WorkQueueItem,
10334f4b218SThomas Faber                              PopPassivePowerCall,
10434f4b218SThomas Faber                              Irp);
10534f4b218SThomas Faber         ExQueueWorkItem(WorkQueueItem, DelayedWorkQueue);
10634f4b218SThomas Faber 
10734f4b218SThomas Faber         return STATUS_PENDING;
10834f4b218SThomas Faber     }
10934f4b218SThomas Faber 
11034f4b218SThomas Faber     /* Direct call. Raise IRQL in debug to catch invalid paged memory access. */
11134f4b218SThomas Faber #if DBG
11234f4b218SThomas Faber     {
11334f4b218SThomas Faber     KIRQL OldIrql;
11434f4b218SThomas Faber     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
11534f4b218SThomas Faber #endif
11634f4b218SThomas Faber 
11734f4b218SThomas Faber     Status = IoCallDriver(DeviceObject, Irp);
11834f4b218SThomas Faber 
11934f4b218SThomas Faber #if DBG
12034f4b218SThomas Faber     KeLowerIrql(OldIrql);
12134f4b218SThomas Faber     }
12234f4b218SThomas Faber #endif
12334f4b218SThomas Faber 
12434f4b218SThomas Faber     return Status;
12534f4b218SThomas Faber }
12634f4b218SThomas Faber 
12721930311SDmitry Borisov static IO_COMPLETION_ROUTINE PopRequestPowerIrpCompletion;
12821930311SDmitry Borisov 
129c2c66affSColin Finck static
130c2c66affSColin Finck NTSTATUS
131c2c66affSColin Finck NTAPI
13221930311SDmitry Borisov PopRequestPowerIrpCompletion(
13321930311SDmitry Borisov     _In_ PDEVICE_OBJECT DeviceObject,
13421930311SDmitry Borisov     _In_ PIRP Irp,
13521930311SDmitry Borisov     _In_reads_opt_(_Inexpressible_("varies")) PVOID Context)
136c2c66affSColin Finck {
137c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
138c2c66affSColin Finck     PREQUEST_POWER_COMPLETE CompletionRoutine;
139c2c66affSColin Finck     POWER_STATE PowerState;
140c2c66affSColin Finck 
141c2c66affSColin Finck     Stack = IoGetCurrentIrpStackLocation(Irp);
142c2c66affSColin Finck     CompletionRoutine = Context;
143c2c66affSColin Finck 
144c2c66affSColin Finck     PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3;
14521930311SDmitry Borisov 
14621930311SDmitry Borisov     if (CompletionRoutine)
14721930311SDmitry Borisov     {
148c2c66affSColin Finck         CompletionRoutine(Stack->Parameters.Others.Argument1,
149c2c66affSColin Finck                           (UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2,
150c2c66affSColin Finck                           PowerState,
151c2c66affSColin Finck                           Stack->Parameters.Others.Argument4,
152c2c66affSColin Finck                           &Irp->IoStatus);
15321930311SDmitry Borisov     }
154c2c66affSColin Finck 
155c2c66affSColin Finck     IoSkipCurrentIrpStackLocation(Irp);
156c2c66affSColin Finck     IoFreeIrp(Irp);
157c2c66affSColin Finck     ObDereferenceObject(DeviceObject);
158c2c66affSColin Finck 
159c2c66affSColin Finck     return STATUS_MORE_PROCESSING_REQUIRED;
160c2c66affSColin Finck }
161c2c66affSColin Finck 
162c2c66affSColin Finck VOID
163c2c66affSColin Finck NTAPI
PopCleanupPowerState(IN PPOWER_STATE PowerState)164c2c66affSColin Finck PopCleanupPowerState(IN PPOWER_STATE PowerState)
165c2c66affSColin Finck {
166c2c66affSColin Finck     //UNIMPLEMENTED;
167c2c66affSColin Finck }
168c2c66affSColin Finck 
169c2c66affSColin Finck NTSTATUS
PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject,SYSTEM_POWER_STATE SystemState,POWER_ACTION PowerAction)170c2c66affSColin Finck PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
171c2c66affSColin Finck {
172c2c66affSColin Finck     KEVENT Event;
173c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
174c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp;
175c2c66affSColin Finck     PIRP Irp;
176c2c66affSColin Finck     NTSTATUS Status;
177c2c66affSColin Finck 
178c2c66affSColin Finck     KeInitializeEvent(&Event,
179c2c66affSColin Finck                       NotificationEvent,
180c2c66affSColin Finck                       FALSE);
181c2c66affSColin Finck 
182c2c66affSColin Finck     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
183c2c66affSColin Finck                                        DeviceObject,
184c2c66affSColin Finck                                        NULL,
185c2c66affSColin Finck                                        0,
186c2c66affSColin Finck                                        NULL,
187c2c66affSColin Finck                                        &Event,
188c2c66affSColin Finck                                        &IoStatusBlock);
189c2c66affSColin Finck     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
190c2c66affSColin Finck 
191c2c66affSColin Finck     IrpSp = IoGetNextIrpStackLocation(Irp);
192c2c66affSColin Finck     IrpSp->MinorFunction = IRP_MN_QUERY_POWER;
193c2c66affSColin Finck     IrpSp->Parameters.Power.Type = SystemPowerState;
194c2c66affSColin Finck     IrpSp->Parameters.Power.State.SystemState = SystemState;
195c2c66affSColin Finck     IrpSp->Parameters.Power.ShutdownType = PowerAction;
196c2c66affSColin Finck 
197c2c66affSColin Finck     Status = PoCallDriver(DeviceObject, Irp);
198c2c66affSColin Finck     if (Status == STATUS_PENDING)
199c2c66affSColin Finck     {
200c2c66affSColin Finck         KeWaitForSingleObject(&Event,
201c2c66affSColin Finck                               Executive,
202c2c66affSColin Finck                               KernelMode,
203c2c66affSColin Finck                               FALSE,
204c2c66affSColin Finck                               NULL);
205c2c66affSColin Finck         Status = IoStatusBlock.Status;
206c2c66affSColin Finck     }
207c2c66affSColin Finck 
208c2c66affSColin Finck     return Status;
209c2c66affSColin Finck }
210c2c66affSColin Finck 
211c2c66affSColin Finck NTSTATUS
PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject,SYSTEM_POWER_STATE SystemState,POWER_ACTION PowerAction)212c2c66affSColin Finck PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
213c2c66affSColin Finck {
214c2c66affSColin Finck     KEVENT Event;
215c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
216c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp;
217c2c66affSColin Finck     PIRP Irp;
218c2c66affSColin Finck     NTSTATUS Status;
219c2c66affSColin Finck 
220c2c66affSColin Finck     KeInitializeEvent(&Event,
221c2c66affSColin Finck                       NotificationEvent,
222c2c66affSColin Finck                       FALSE);
223c2c66affSColin Finck 
224c2c66affSColin Finck     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
225c2c66affSColin Finck                                        DeviceObject,
226c2c66affSColin Finck                                        NULL,
227c2c66affSColin Finck                                        0,
228c2c66affSColin Finck                                        NULL,
229c2c66affSColin Finck                                        &Event,
230c2c66affSColin Finck                                        &IoStatusBlock);
231c2c66affSColin Finck     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
232c2c66affSColin Finck 
233c2c66affSColin Finck     IrpSp = IoGetNextIrpStackLocation(Irp);
234c2c66affSColin Finck     IrpSp->MinorFunction = IRP_MN_SET_POWER;
235c2c66affSColin Finck     IrpSp->Parameters.Power.Type = SystemPowerState;
236c2c66affSColin Finck     IrpSp->Parameters.Power.State.SystemState = SystemState;
237c2c66affSColin Finck     IrpSp->Parameters.Power.ShutdownType = PowerAction;
238c2c66affSColin Finck 
239c2c66affSColin Finck     Status = PoCallDriver(DeviceObject, Irp);
240c2c66affSColin Finck     if (Status == STATUS_PENDING)
241c2c66affSColin Finck     {
242c2c66affSColin Finck         KeWaitForSingleObject(&Event,
243c2c66affSColin Finck                               Executive,
244c2c66affSColin Finck                               KernelMode,
245c2c66affSColin Finck                               FALSE,
246c2c66affSColin Finck                               NULL);
247c2c66affSColin Finck         Status = IoStatusBlock.Status;
248c2c66affSColin Finck     }
249c2c66affSColin Finck 
250c2c66affSColin Finck     return Status;
251c2c66affSColin Finck }
252c2c66affSColin Finck 
253c2c66affSColin Finck NTSTATUS
PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,PVOID Context)254c2c66affSColin Finck PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
255c2c66affSColin Finck                                  PVOID Context)
256c2c66affSColin Finck {
257c2c66affSColin Finck     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
258c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
259c2c66affSColin Finck     NTSTATUS Status;
260c2c66affSColin Finck 
261c2c66affSColin Finck     DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
262c2c66affSColin Finck 
263c2c66affSColin Finck     if (DeviceNode == IopRootDeviceNode)
264c2c66affSColin Finck         return STATUS_SUCCESS;
265c2c66affSColin Finck 
266c2c66affSColin Finck     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
267c2c66affSColin Finck         return STATUS_SUCCESS;
268c2c66affSColin Finck 
269c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
270c2c66affSColin Finck 
271c2c66affSColin Finck     Status = PopSendQuerySystemPowerState(TopDeviceObject,
272c2c66affSColin Finck                                           PowerStateContext->SystemPowerState,
273c2c66affSColin Finck                                           PowerStateContext->PowerAction);
274c2c66affSColin Finck     if (!NT_SUCCESS(Status))
275c2c66affSColin Finck     {
276c2c66affSColin Finck         DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
277c2c66affSColin Finck     }
278c2c66affSColin Finck     ObDereferenceObject(TopDeviceObject);
279c2c66affSColin Finck 
280c2c66affSColin Finck #if 0
281c2c66affSColin Finck     return Status;
282c2c66affSColin Finck #else
283c2c66affSColin Finck     return STATUS_SUCCESS;
284c2c66affSColin Finck #endif
285c2c66affSColin Finck }
286c2c66affSColin Finck 
287c2c66affSColin Finck NTSTATUS
PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,PVOID Context)288c2c66affSColin Finck PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
289c2c66affSColin Finck                                PVOID Context)
290c2c66affSColin Finck {
291c2c66affSColin Finck     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
292c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
293c2c66affSColin Finck     NTSTATUS Status;
294c2c66affSColin Finck 
295c2c66affSColin Finck     DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
296c2c66affSColin Finck 
297c2c66affSColin Finck     if (DeviceNode == IopRootDeviceNode)
298c2c66affSColin Finck         return STATUS_SUCCESS;
299c2c66affSColin Finck 
300c2c66affSColin Finck     if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
301c2c66affSColin Finck         return STATUS_SUCCESS;
302c2c66affSColin Finck 
303c2c66affSColin Finck     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
304c2c66affSColin Finck         return STATUS_SUCCESS;
305c2c66affSColin Finck 
306c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
307c2c66affSColin Finck     if (TopDeviceObject == PowerStateContext->PowerDevice)
308c2c66affSColin Finck     {
309c2c66affSColin Finck         ObDereferenceObject(TopDeviceObject);
310c2c66affSColin Finck         return STATUS_SUCCESS;
311c2c66affSColin Finck     }
312c2c66affSColin Finck 
313c2c66affSColin Finck     Status = PopSendSetSystemPowerState(TopDeviceObject,
314c2c66affSColin Finck                                         PowerStateContext->SystemPowerState,
315c2c66affSColin Finck                                         PowerStateContext->PowerAction);
316c2c66affSColin Finck     if (!NT_SUCCESS(Status))
317c2c66affSColin Finck     {
318c2c66affSColin Finck         DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
319c2c66affSColin Finck     }
320c2c66affSColin Finck 
321c2c66affSColin Finck     ObDereferenceObject(TopDeviceObject);
322c2c66affSColin Finck 
323c2c66affSColin Finck #if 0
324c2c66affSColin Finck     return Status;
325c2c66affSColin Finck #else
326c2c66affSColin Finck     return STATUS_SUCCESS;
327c2c66affSColin Finck #endif
328c2c66affSColin Finck }
329c2c66affSColin Finck 
330c2c66affSColin Finck NTSTATUS
331c2c66affSColin Finck NTAPI
PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState,POWER_ACTION PowerAction)332c2c66affSColin Finck PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
333c2c66affSColin Finck {
334c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject;
335c2c66affSColin Finck     PDEVICE_OBJECT Fdo;
336c2c66affSColin Finck     NTSTATUS Status;
337c2c66affSColin Finck     DEVICETREE_TRAVERSE_CONTEXT Context;
338c2c66affSColin Finck     POWER_STATE_TRAVERSE_CONTEXT PowerContext;
339c2c66affSColin Finck 
340c2c66affSColin Finck     Status = IopGetSystemPowerDeviceObject(&DeviceObject);
341c2c66affSColin Finck     if (!NT_SUCCESS(Status))
342c2c66affSColin Finck     {
343c2c66affSColin Finck         DPRINT1("No system power driver available\n");
344c2c66affSColin Finck         Fdo = NULL;
345c2c66affSColin Finck     }
346c2c66affSColin Finck     else
347c2c66affSColin Finck     {
348c2c66affSColin Finck         Fdo = IoGetAttachedDeviceReference(DeviceObject);
349c2c66affSColin Finck         if (Fdo == DeviceObject)
350c2c66affSColin Finck         {
351c2c66affSColin Finck             DPRINT("An FDO was not attached\n");
352c2c66affSColin Finck             return STATUS_UNSUCCESSFUL;
353c2c66affSColin Finck         }
354c2c66affSColin Finck     }
355c2c66affSColin Finck 
356c2c66affSColin Finck     /* Set up context */
357c2c66affSColin Finck     PowerContext.PowerAction = PowerAction;
358c2c66affSColin Finck     PowerContext.SystemPowerState = PowerState;
359c2c66affSColin Finck     PowerContext.PowerDevice = Fdo;
360c2c66affSColin Finck 
361c2c66affSColin Finck     /* Query for system power change */
362c2c66affSColin Finck     IopInitDeviceTreeTraverseContext(&Context,
363c2c66affSColin Finck                                      IopRootDeviceNode,
364c2c66affSColin Finck                                      PopQuerySystemPowerStateTraverse,
365c2c66affSColin Finck                                      &PowerContext);
366c2c66affSColin Finck 
367c2c66affSColin Finck     Status = IopTraverseDeviceTree(&Context);
368c2c66affSColin Finck     if (!NT_SUCCESS(Status))
369c2c66affSColin Finck     {
370c2c66affSColin Finck         DPRINT1("Query system power state failed; changing state anyway\n");
371c2c66affSColin Finck     }
372c2c66affSColin Finck 
373c2c66affSColin Finck     /* Set system power change */
374c2c66affSColin Finck     IopInitDeviceTreeTraverseContext(&Context,
375c2c66affSColin Finck                                      IopRootDeviceNode,
376c2c66affSColin Finck                                      PopSetSystemPowerStateTraverse,
377c2c66affSColin Finck                                      &PowerContext);
378c2c66affSColin Finck 
379c2c66affSColin Finck     IopTraverseDeviceTree(&Context);
380c2c66affSColin Finck 
381c2c66affSColin Finck     if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
382c2c66affSColin Finck 
383c2c66affSColin Finck     if (Fdo != NULL)
384c2c66affSColin Finck     {
385c2c66affSColin Finck         if (PowerAction != PowerActionShutdownReset)
386c2c66affSColin Finck             PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
387c2c66affSColin Finck 
388c2c66affSColin Finck         ObDereferenceObject(Fdo);
389c2c66affSColin Finck     }
390c2c66affSColin Finck 
391c2c66affSColin Finck     return Status;
392c2c66affSColin Finck }
393c2c66affSColin Finck 
3945c7ce447SVictor Perevertkin CODE_SEG("INIT")
395c2c66affSColin Finck BOOLEAN
396c2c66affSColin Finck NTAPI
PoInitSystem(IN ULONG BootPhase)397c2c66affSColin Finck PoInitSystem(IN ULONG BootPhase)
398c2c66affSColin Finck {
399c2c66affSColin Finck     PVOID NotificationEntry;
400c2c66affSColin Finck     PCHAR CommandLine;
401c2c66affSColin Finck     BOOLEAN ForceAcpiDisable = FALSE;
402c2c66affSColin Finck 
403c2c66affSColin Finck     /* Check if this is phase 1 init */
404c2c66affSColin Finck     if (BootPhase == 1)
405c2c66affSColin Finck     {
40607d38cd4SJérôme Gardou         NTSTATUS Status;
407c2c66affSColin Finck         /* Register power button notification */
40807d38cd4SJérôme Gardou         Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
409c2c66affSColin Finck                                                 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
410c2c66affSColin Finck                                                 (PVOID)&GUID_DEVICE_SYS_BUTTON,
41107d38cd4SJérôme Gardou                                                 IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
412c2c66affSColin Finck                                                 PopAddRemoveSysCapsCallback,
413dff8b93eSHervé Poussineau                                                 (PVOID)(ULONG_PTR)PolicyDeviceSystemButton,
414c2c66affSColin Finck                                                 &NotificationEntry);
41507d38cd4SJérôme Gardou         if (!NT_SUCCESS(Status))
41607d38cd4SJérôme Gardou             return FALSE;
417c2c66affSColin Finck 
418c2c66affSColin Finck         /* Register lid notification */
41907d38cd4SJérôme Gardou         Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
420c2c66affSColin Finck                                                 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
421c2c66affSColin Finck                                                 (PVOID)&GUID_DEVICE_LID,
42207d38cd4SJérôme Gardou                                                 IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
423c2c66affSColin Finck                                                 PopAddRemoveSysCapsCallback,
424dff8b93eSHervé Poussineau                                                 (PVOID)(ULONG_PTR)PolicyDeviceSystemButton,
425c2c66affSColin Finck                                                 &NotificationEntry);
4269e43518dSHervé Poussineau         if (!NT_SUCCESS(Status))
4279e43518dSHervé Poussineau             return FALSE;
4289e43518dSHervé Poussineau 
4299e43518dSHervé Poussineau         /* Register battery notification */
4309e43518dSHervé Poussineau         Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
4319e43518dSHervé Poussineau                                                 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
4329e43518dSHervé Poussineau                                                 (PVOID)&GUID_DEVICE_BATTERY,
4339e43518dSHervé Poussineau                                                 IopRootDeviceNode->PhysicalDeviceObject->DriverObject,
4349e43518dSHervé Poussineau                                                 PopAddRemoveSysCapsCallback,
4359e43518dSHervé Poussineau                                                 (PVOID)(ULONG_PTR)PolicyDeviceBattery,
4369e43518dSHervé Poussineau                                                 &NotificationEntry);
4379e43518dSHervé Poussineau 
43807d38cd4SJérôme Gardou         return NT_SUCCESS(Status);
439c2c66affSColin Finck     }
440c2c66affSColin Finck 
441626aaf22SEric Kohl     /* Initialize the power capabilities */
442626aaf22SEric Kohl     RtlZeroMemory(&PopCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
443626aaf22SEric Kohl 
444c2c66affSColin Finck     /* Get the Command Line */
445c2c66affSColin Finck     CommandLine = KeLoaderBlock->LoadOptions;
446c2c66affSColin Finck 
447c2c66affSColin Finck     /* Upcase it */
448c2c66affSColin Finck     _strupr(CommandLine);
449c2c66affSColin Finck 
450c2c66affSColin Finck     /* Check for ACPI disable */
451c2c66affSColin Finck     if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
452c2c66affSColin Finck 
453c2c66affSColin Finck     if (ForceAcpiDisable)
454c2c66affSColin Finck     {
455c2c66affSColin Finck         /* Set the ACPI State to False if it's been forced that way */
456c2c66affSColin Finck         PopAcpiPresent = FALSE;
457c2c66affSColin Finck     }
458c2c66affSColin Finck     else
459c2c66affSColin Finck     {
460c2c66affSColin Finck         /* Otherwise check if the LoaderBlock has a ACPI Table  */
461c2c66affSColin Finck         PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
462c2c66affSColin Finck     }
463c2c66affSColin Finck 
464626aaf22SEric Kohl     /* Enable shutdown by power button */
465626aaf22SEric Kohl     if (PopAcpiPresent)
466626aaf22SEric Kohl         PopCapabilities.SystemS5 = TRUE;
467c2c66affSColin Finck 
468c2c66affSColin Finck     /* Initialize volume support */
469c2c66affSColin Finck     InitializeListHead(&PopVolumeDevices);
470c2c66affSColin Finck     KeInitializeGuardedMutex(&PopVolumeLock);
471c2c66affSColin Finck 
472c2c66affSColin Finck     /* Initialize support for dope */
473c2c66affSColin Finck     KeInitializeSpinLock(&PopDopeGlobalLock);
474c2c66affSColin Finck 
475c2c66affSColin Finck     /* Initialize support for shutdown waits and work-items */
476c2c66affSColin Finck     PopInitShutdownList();
477c2c66affSColin Finck 
478c2c66affSColin Finck     return TRUE;
479c2c66affSColin Finck }
480c2c66affSColin Finck 
481c2c66affSColin Finck VOID
482c2c66affSColin Finck NTAPI
PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)483c2c66affSColin Finck PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
484c2c66affSColin Finck {
485c2c66affSColin Finck     DPRINT1("PerfIdle function: %p\n", PowerState);
486c2c66affSColin Finck }
487c2c66affSColin Finck 
488c2c66affSColin Finck VOID
489c2c66affSColin Finck NTAPI
PopPerfIdleDpc(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)490c2c66affSColin Finck PopPerfIdleDpc(IN PKDPC Dpc,
491c2c66affSColin Finck                IN PVOID DeferredContext,
492c2c66affSColin Finck                IN PVOID SystemArgument1,
493c2c66affSColin Finck                IN PVOID SystemArgument2)
494c2c66affSColin Finck {
495c2c66affSColin Finck     /* Call the Perf Idle function */
496c2c66affSColin Finck     PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
497c2c66affSColin Finck }
498c2c66affSColin Finck 
499c2c66affSColin Finck VOID
500c2c66affSColin Finck FASTCALL
PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)501c2c66affSColin Finck PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
502c2c66affSColin Finck {
503c2c66affSColin Finck     /* FIXME: Extremly naive implementation */
504c2c66affSColin Finck     HalProcessorIdle();
505c2c66affSColin Finck }
506c2c66affSColin Finck 
5075c7ce447SVictor Perevertkin CODE_SEG("INIT")
508c2c66affSColin Finck VOID
509c2c66affSColin Finck NTAPI
PoInitializePrcb(IN PKPRCB Prcb)510c2c66affSColin Finck PoInitializePrcb(IN PKPRCB Prcb)
511c2c66affSColin Finck {
512c2c66affSColin Finck     /* Initialize the Power State */
513c2c66affSColin Finck     RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
514c2c66affSColin Finck     Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
515c2c66affSColin Finck     Prcb->PowerState.CurrentThrottle = 100;
516c2c66affSColin Finck     Prcb->PowerState.CurrentThrottleIndex = 0;
517c2c66affSColin Finck     Prcb->PowerState.IdleFunction = PopIdle0;
518c2c66affSColin Finck 
519c2c66affSColin Finck     /* Initialize the Perf DPC and Timer */
520c2c66affSColin Finck     KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
521c2c66affSColin Finck     KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
522c2c66affSColin Finck     KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
523c2c66affSColin Finck }
524c2c66affSColin Finck 
525c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
526c2c66affSColin Finck 
527c2c66affSColin Finck /*
528c2c66affSColin Finck  * @unimplemented
529c2c66affSColin Finck  */
530c2c66affSColin Finck NTSTATUS
531c2c66affSColin Finck NTAPI
PoCancelDeviceNotify(IN PVOID NotifyBlock)532c2c66affSColin Finck PoCancelDeviceNotify(IN PVOID NotifyBlock)
533c2c66affSColin Finck {
534c2c66affSColin Finck     UNIMPLEMENTED;
535c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
536c2c66affSColin Finck }
537c2c66affSColin Finck 
538c2c66affSColin Finck /*
539c2c66affSColin Finck  * @unimplemented
540c2c66affSColin Finck  */
541c2c66affSColin Finck NTSTATUS
542c2c66affSColin Finck NTAPI
PoRegisterDeviceNotify(OUT PVOID Unknown0,IN ULONG Unknown1,IN ULONG Unknown2,IN ULONG Unknown3,IN PVOID Unknown4,IN PVOID Unknown5)543c2c66affSColin Finck PoRegisterDeviceNotify(OUT PVOID Unknown0,
544c2c66affSColin Finck                        IN ULONG Unknown1,
545c2c66affSColin Finck                        IN ULONG Unknown2,
546c2c66affSColin Finck                        IN ULONG Unknown3,
547c2c66affSColin Finck                        IN PVOID Unknown4,
548c2c66affSColin Finck                        IN PVOID Unknown5)
549c2c66affSColin Finck {
550c2c66affSColin Finck     UNIMPLEMENTED;
551c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
552c2c66affSColin Finck }
553c2c66affSColin Finck 
554c2c66affSColin Finck /*
555c2c66affSColin Finck  * @unimplemented
556c2c66affSColin Finck  */
557c2c66affSColin Finck VOID
558c2c66affSColin Finck NTAPI
PoShutdownBugCheck(IN BOOLEAN LogError,IN ULONG BugCheckCode,IN ULONG_PTR BugCheckParameter1,IN ULONG_PTR BugCheckParameter2,IN ULONG_PTR BugCheckParameter3,IN ULONG_PTR BugCheckParameter4)559c2c66affSColin Finck PoShutdownBugCheck(IN BOOLEAN LogError,
560c2c66affSColin Finck                    IN ULONG BugCheckCode,
561c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter1,
562c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter2,
563c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter3,
564c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter4)
565c2c66affSColin Finck {
566c2c66affSColin Finck     DPRINT1("PoShutdownBugCheck called\n");
567c2c66affSColin Finck 
568c2c66affSColin Finck     /* FIXME: Log error if requested */
569c2c66affSColin Finck     /* FIXME: Initiate a shutdown */
570c2c66affSColin Finck 
571c2c66affSColin Finck     /* Bugcheck the system */
572c2c66affSColin Finck     KeBugCheckEx(BugCheckCode,
573c2c66affSColin Finck                  BugCheckParameter1,
574c2c66affSColin Finck                  BugCheckParameter2,
575c2c66affSColin Finck                  BugCheckParameter3,
576c2c66affSColin Finck                  BugCheckParameter4);
577c2c66affSColin Finck }
578c2c66affSColin Finck 
579c2c66affSColin Finck /*
580c2c66affSColin Finck  * @unimplemented
581c2c66affSColin Finck  */
582c2c66affSColin Finck VOID
583c2c66affSColin Finck NTAPI
PoSetHiberRange(IN PVOID HiberContext,IN ULONG Flags,IN OUT PVOID StartPage,IN ULONG Length,IN ULONG PageTag)584c2c66affSColin Finck PoSetHiberRange(IN PVOID HiberContext,
585c2c66affSColin Finck                 IN ULONG Flags,
586c2c66affSColin Finck                 IN OUT PVOID StartPage,
587c2c66affSColin Finck                 IN ULONG Length,
588c2c66affSColin Finck                 IN ULONG PageTag)
589c2c66affSColin Finck {
590c2c66affSColin Finck     UNIMPLEMENTED;
591c2c66affSColin Finck     return;
592c2c66affSColin Finck }
593c2c66affSColin Finck 
594c2c66affSColin Finck /*
595c2c66affSColin Finck  * @implemented
596c2c66affSColin Finck  */
_IRQL_requires_max_(DISPATCH_LEVEL)59734f4b218SThomas Faber _IRQL_requires_max_(DISPATCH_LEVEL)
598c2c66affSColin Finck NTSTATUS
599c2c66affSColin Finck NTAPI
60034f4b218SThomas Faber PoCallDriver(
60134f4b218SThomas Faber     _In_ PDEVICE_OBJECT DeviceObject,
60234f4b218SThomas Faber     _Inout_ __drv_aliasesMem PIRP Irp)
603c2c66affSColin Finck {
60434f4b218SThomas Faber     PIO_STACK_LOCATION NextStack;
605c2c66affSColin Finck 
60634f4b218SThomas Faber     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
607c2c66affSColin Finck 
60834f4b218SThomas Faber     ASSERT(DeviceObject);
60934f4b218SThomas Faber     ASSERT(Irp);
61034f4b218SThomas Faber 
61134f4b218SThomas Faber     NextStack = IoGetNextIrpStackLocation(Irp);
61234f4b218SThomas Faber     ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
61334f4b218SThomas Faber 
61434f4b218SThomas Faber     /* Set DeviceObject for PopPresentIrp */
61534f4b218SThomas Faber     NextStack->DeviceObject = DeviceObject;
61634f4b218SThomas Faber 
61734f4b218SThomas Faber     /* Only QUERY_POWER and SET_POWER use special handling */
61834f4b218SThomas Faber     if (NextStack->MinorFunction != IRP_MN_SET_POWER &&
61934f4b218SThomas Faber         NextStack->MinorFunction != IRP_MN_QUERY_POWER)
62034f4b218SThomas Faber     {
62134f4b218SThomas Faber         return IoCallDriver(DeviceObject, Irp);
62234f4b218SThomas Faber     }
62334f4b218SThomas Faber 
62434f4b218SThomas Faber     /* Call the next driver, either directly or at PASSIVE_LEVEL */
62534f4b218SThomas Faber     return PopPresentIrp(NextStack, Irp);
626c2c66affSColin Finck }
627c2c66affSColin Finck 
628c2c66affSColin Finck /*
629c2c66affSColin Finck  * @unimplemented
630c2c66affSColin Finck  */
631c2c66affSColin Finck PULONG
632c2c66affSColin Finck NTAPI
PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,IN ULONG ConservationIdleTime,IN ULONG PerformanceIdleTime,IN DEVICE_POWER_STATE State)633c2c66affSColin Finck PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
634c2c66affSColin Finck                                  IN ULONG ConservationIdleTime,
635c2c66affSColin Finck                                  IN ULONG PerformanceIdleTime,
636c2c66affSColin Finck                                  IN DEVICE_POWER_STATE State)
637c2c66affSColin Finck {
638c2c66affSColin Finck     UNIMPLEMENTED;
639c2c66affSColin Finck     return NULL;
640c2c66affSColin Finck }
641c2c66affSColin Finck 
642c2c66affSColin Finck /*
643c2c66affSColin Finck  * @unimplemented
644c2c66affSColin Finck  */
645c2c66affSColin Finck PVOID
646c2c66affSColin Finck NTAPI
PoRegisterSystemState(IN PVOID StateHandle,IN EXECUTION_STATE Flags)647c2c66affSColin Finck PoRegisterSystemState(IN PVOID StateHandle,
648c2c66affSColin Finck                       IN EXECUTION_STATE Flags)
649c2c66affSColin Finck {
650c2c66affSColin Finck     UNIMPLEMENTED;
651c2c66affSColin Finck     return NULL;
652c2c66affSColin Finck }
653c2c66affSColin Finck 
654c2c66affSColin Finck /*
655c2c66affSColin Finck  * @implemented
656c2c66affSColin Finck  */
657c2c66affSColin Finck NTSTATUS
658c2c66affSColin Finck NTAPI
PoRequestPowerIrp(_In_ PDEVICE_OBJECT DeviceObject,_In_ UCHAR MinorFunction,_In_ POWER_STATE PowerState,_In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction,_In_opt_ __drv_aliasesMem PVOID Context,_Outptr_opt_ PIRP * pIrp)65921930311SDmitry Borisov PoRequestPowerIrp(
66021930311SDmitry Borisov     _In_ PDEVICE_OBJECT DeviceObject,
66121930311SDmitry Borisov     _In_ UCHAR MinorFunction,
66221930311SDmitry Borisov     _In_ POWER_STATE PowerState,
66321930311SDmitry Borisov     _In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction,
66421930311SDmitry Borisov     _In_opt_ __drv_aliasesMem PVOID Context,
66521930311SDmitry Borisov     _Outptr_opt_ PIRP *pIrp)
666c2c66affSColin Finck {
667c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
668c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
669c2c66affSColin Finck     PIRP Irp;
670c2c66affSColin Finck 
671c2c66affSColin Finck     if (MinorFunction != IRP_MN_QUERY_POWER
672c2c66affSColin Finck         && MinorFunction != IRP_MN_SET_POWER
673c2c66affSColin Finck         && MinorFunction != IRP_MN_WAIT_WAKE)
674c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
675c2c66affSColin Finck 
676c2c66affSColin Finck     /* Always call the top of the device stack */
677c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
678c2c66affSColin Finck 
679c2c66affSColin Finck     Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
680c2c66affSColin Finck     if (!Irp)
681c2c66affSColin Finck     {
682c2c66affSColin Finck         ObDereferenceObject(TopDeviceObject);
683c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
684c2c66affSColin Finck     }
685c2c66affSColin Finck 
686c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
687c2c66affSColin Finck     Irp->IoStatus.Information = 0;
688c2c66affSColin Finck 
689c2c66affSColin Finck     IoSetNextIrpStackLocation(Irp);
690c2c66affSColin Finck 
691c2c66affSColin Finck     Stack = IoGetNextIrpStackLocation(Irp);
692c2c66affSColin Finck     Stack->Parameters.Others.Argument1 = DeviceObject;
693c2c66affSColin Finck     Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
694c2c66affSColin Finck     Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
695c2c66affSColin Finck     Stack->Parameters.Others.Argument4 = Context;
696c2c66affSColin Finck     Stack->DeviceObject = TopDeviceObject;
697c2c66affSColin Finck     IoSetNextIrpStackLocation(Irp);
698c2c66affSColin Finck 
699c2c66affSColin Finck     Stack = IoGetNextIrpStackLocation(Irp);
700c2c66affSColin Finck     Stack->MajorFunction = IRP_MJ_POWER;
701c2c66affSColin Finck     Stack->MinorFunction = MinorFunction;
702c2c66affSColin Finck     if (MinorFunction == IRP_MN_WAIT_WAKE)
703c2c66affSColin Finck     {
704c2c66affSColin Finck         Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
705c2c66affSColin Finck     }
706c2c66affSColin Finck     else
707c2c66affSColin Finck     {
708c2c66affSColin Finck         Stack->Parameters.Power.Type = DevicePowerState;
709c2c66affSColin Finck         Stack->Parameters.Power.State = PowerState;
710c2c66affSColin Finck     }
711c2c66affSColin Finck 
712c2c66affSColin Finck     if (pIrp != NULL)
713c2c66affSColin Finck         *pIrp = Irp;
714c2c66affSColin Finck 
715c2c66affSColin Finck     IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
716c2c66affSColin Finck     PoCallDriver(TopDeviceObject, Irp);
717c2c66affSColin Finck 
718c2c66affSColin Finck     /* Always return STATUS_PENDING. The completion routine
719c2c66affSColin Finck      * will call CompletionFunction and complete the Irp.
720c2c66affSColin Finck      */
721c2c66affSColin Finck     return STATUS_PENDING;
722c2c66affSColin Finck }
723c2c66affSColin Finck 
724c2c66affSColin Finck /*
725c2c66affSColin Finck  * @unimplemented
726c2c66affSColin Finck  */
727c2c66affSColin Finck POWER_STATE
728c2c66affSColin Finck NTAPI
PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,IN POWER_STATE_TYPE Type,IN POWER_STATE State)729c2c66affSColin Finck PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
730c2c66affSColin Finck                 IN POWER_STATE_TYPE Type,
731c2c66affSColin Finck                 IN POWER_STATE State)
732c2c66affSColin Finck {
733c2c66affSColin Finck     POWER_STATE ps;
734c2c66affSColin Finck 
735c2c66affSColin Finck     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
736c2c66affSColin Finck 
737c2c66affSColin Finck     ps.SystemState = PowerSystemWorking;  // Fully on
738c2c66affSColin Finck     ps.DeviceState = PowerDeviceD0;       // Fully on
739c2c66affSColin Finck 
740c2c66affSColin Finck     return ps;
741c2c66affSColin Finck }
742c2c66affSColin Finck 
743c2c66affSColin Finck /*
744c2c66affSColin Finck  * @unimplemented
745c2c66affSColin Finck  */
746c2c66affSColin Finck VOID
747c2c66affSColin Finck NTAPI
PoSetSystemState(IN EXECUTION_STATE Flags)748c2c66affSColin Finck PoSetSystemState(IN EXECUTION_STATE Flags)
749c2c66affSColin Finck {
750c2c66affSColin Finck     UNIMPLEMENTED;
751c2c66affSColin Finck }
752c2c66affSColin Finck 
753c2c66affSColin Finck /*
754c2c66affSColin Finck  * @unimplemented
755c2c66affSColin Finck  */
756c2c66affSColin Finck VOID
757c2c66affSColin Finck NTAPI
PoStartNextPowerIrp(IN PIRP Irp)758c2c66affSColin Finck PoStartNextPowerIrp(IN PIRP Irp)
759c2c66affSColin Finck {
7601539fb14SMark Jansen     UNIMPLEMENTED_ONCE;
761c2c66affSColin Finck }
762c2c66affSColin Finck 
763c2c66affSColin Finck /*
764c2c66affSColin Finck  * @unimplemented
765c2c66affSColin Finck  */
766c2c66affSColin Finck VOID
767c2c66affSColin Finck NTAPI
PoUnregisterSystemState(IN PVOID StateHandle)768c2c66affSColin Finck PoUnregisterSystemState(IN PVOID StateHandle)
769c2c66affSColin Finck {
770c2c66affSColin Finck     UNIMPLEMENTED;
771c2c66affSColin Finck }
772c2c66affSColin Finck 
773c2c66affSColin Finck /*
774c2c66affSColin Finck  * @unimplemented
775c2c66affSColin Finck  */
776c2c66affSColin Finck NTSTATUS
777c2c66affSColin Finck NTAPI
NtInitiatePowerAction(IN POWER_ACTION SystemAction,IN SYSTEM_POWER_STATE MinSystemState,IN ULONG Flags,IN BOOLEAN Asynchronous)778c2c66affSColin Finck NtInitiatePowerAction(IN POWER_ACTION SystemAction,
779c2c66affSColin Finck                       IN SYSTEM_POWER_STATE MinSystemState,
780c2c66affSColin Finck                       IN ULONG Flags,
781c2c66affSColin Finck                       IN BOOLEAN Asynchronous)
782c2c66affSColin Finck {
783c2c66affSColin Finck     UNIMPLEMENTED;
784c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
785c2c66affSColin Finck }
786c2c66affSColin Finck 
787c2c66affSColin Finck /*
788c2c66affSColin Finck  * @unimplemented
789c2c66affSColin Finck  */
790c2c66affSColin Finck NTSTATUS
791c2c66affSColin Finck NTAPI
NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,IN PVOID InputBuffer OPTIONAL,IN ULONG InputBufferLength,OUT PVOID OutputBuffer OPTIONAL,IN ULONG OutputBufferLength)792c2c66affSColin Finck NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
793c2c66affSColin Finck                    IN PVOID InputBuffer  OPTIONAL,
794c2c66affSColin Finck                    IN ULONG InputBufferLength,
795c2c66affSColin Finck                    OUT PVOID OutputBuffer  OPTIONAL,
796c2c66affSColin Finck                    IN ULONG OutputBufferLength)
797c2c66affSColin Finck {
798c2c66affSColin Finck     NTSTATUS Status;
799c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
800c2c66affSColin Finck 
801c2c66affSColin Finck     PAGED_CODE();
802c2c66affSColin Finck 
803c2c66affSColin Finck     DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
804c2c66affSColin Finck            "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
805c2c66affSColin Finck            PowerInformationLevel,
806c2c66affSColin Finck            InputBuffer, InputBufferLength,
807c2c66affSColin Finck            OutputBuffer, OutputBufferLength);
808c2c66affSColin Finck 
809c2c66affSColin Finck     if (PreviousMode != KernelMode)
810c2c66affSColin Finck     {
811c2c66affSColin Finck         _SEH2_TRY
812c2c66affSColin Finck         {
813c2c66affSColin Finck             ProbeForRead(InputBuffer, InputBufferLength, 1);
814c2c66affSColin Finck             ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));
815c2c66affSColin Finck         }
816c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
817c2c66affSColin Finck         {
818c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
819c2c66affSColin Finck         }
820c2c66affSColin Finck         _SEH2_END;
821c2c66affSColin Finck     }
822c2c66affSColin Finck 
823c2c66affSColin Finck     switch (PowerInformationLevel)
824c2c66affSColin Finck     {
825c2c66affSColin Finck         case SystemBatteryState:
826c2c66affSColin Finck         {
827c2c66affSColin Finck             PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
828c2c66affSColin Finck 
829c2c66affSColin Finck             if (InputBuffer != NULL)
830c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
831c2c66affSColin Finck             if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
832c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
833c2c66affSColin Finck 
834c2c66affSColin Finck             _SEH2_TRY
835c2c66affSColin Finck             {
836*4b051b91SSerge Gautherie                 /* Just zero the struct */
837*4b051b91SSerge Gautherie                 RtlZeroMemory(BatteryState, sizeof(*BatteryState));
838cfe54aa4SEric Kohl                 BatteryState->EstimatedTime = MAXULONG;
8399e43518dSHervé Poussineau                 BatteryState->BatteryPresent = PopCapabilities.SystemBatteriesPresent;
840cfe54aa4SEric Kohl //                BatteryState->AcOnLine = TRUE;
8419e43518dSHervé Poussineau //                BatteryState->MaxCapacity = ;
8429e43518dSHervé Poussineau //                BatteryState->RemainingCapacity = ;
843c2c66affSColin Finck 
844c2c66affSColin Finck                 Status = STATUS_SUCCESS;
845c2c66affSColin Finck             }
846c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
847c2c66affSColin Finck             {
848c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
849c2c66affSColin Finck             }
850c2c66affSColin Finck             _SEH2_END;
851c2c66affSColin Finck 
852c2c66affSColin Finck             break;
853c2c66affSColin Finck         }
854c2c66affSColin Finck 
855c2c66affSColin Finck         case SystemPowerCapabilities:
856c2c66affSColin Finck         {
857c2c66affSColin Finck             PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
858c2c66affSColin Finck 
859c2c66affSColin Finck             if (InputBuffer != NULL)
860c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
861c2c66affSColin Finck             if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
862c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
863c2c66affSColin Finck 
864c2c66affSColin Finck             _SEH2_TRY
865c2c66affSColin Finck             {
866626aaf22SEric Kohl                 RtlCopyMemory(PowerCapabilities,
867626aaf22SEric Kohl                               &PopCapabilities,
868626aaf22SEric Kohl                               sizeof(SYSTEM_POWER_CAPABILITIES));
869c2c66affSColin Finck 
870c2c66affSColin Finck                 Status = STATUS_SUCCESS;
871c2c66affSColin Finck             }
872c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
873c2c66affSColin Finck             {
874c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
875c2c66affSColin Finck             }
876c2c66affSColin Finck             _SEH2_END;
877c2c66affSColin Finck 
878c2c66affSColin Finck             break;
879c2c66affSColin Finck         }
880c2c66affSColin Finck 
881c2c66affSColin Finck         case ProcessorInformation:
882c2c66affSColin Finck         {
883c2c66affSColin Finck             PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer;
884c2c66affSColin Finck 
885c2c66affSColin Finck             if (InputBuffer != NULL)
886c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
887c2c66affSColin Finck             if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION))
888c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
889c2c66affSColin Finck 
8904c78b2c3SStanislav Motylkov             /* FIXME: return structures for all processors */
8914c78b2c3SStanislav Motylkov 
892c2c66affSColin Finck             _SEH2_TRY
893c2c66affSColin Finck             {
8944c78b2c3SStanislav Motylkov                 /* FIXME: some values are hardcoded */
895c2c66affSColin Finck                 PowerInformation->Number = 0;
896c2c66affSColin Finck                 PowerInformation->MaxMhz = 1000;
8974c78b2c3SStanislav Motylkov                 PowerInformation->CurrentMhz = KeGetCurrentPrcb()->MHz;
898c2c66affSColin Finck                 PowerInformation->MhzLimit = 1000;
899c2c66affSColin Finck                 PowerInformation->MaxIdleState = 0;
900c2c66affSColin Finck                 PowerInformation->CurrentIdleState = 0;
901c2c66affSColin Finck 
902c2c66affSColin Finck                 Status = STATUS_SUCCESS;
903c2c66affSColin Finck             }
904c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
905c2c66affSColin Finck             {
906c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
907c2c66affSColin Finck             }
908c2c66affSColin Finck             _SEH2_END;
909c2c66affSColin Finck 
910c2c66affSColin Finck             break;
911c2c66affSColin Finck         }
912c2c66affSColin Finck 
913c2c66affSColin Finck         default:
914c2c66affSColin Finck             Status = STATUS_NOT_IMPLEMENTED;
915c2c66affSColin Finck             DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
916c2c66affSColin Finck                     PowerInformationLevel);
917c2c66affSColin Finck             break;
918c2c66affSColin Finck     }
919c2c66affSColin Finck 
920c2c66affSColin Finck     return Status;
921c2c66affSColin Finck }
922c2c66affSColin Finck 
923c2c66affSColin Finck NTSTATUS
924c2c66affSColin Finck NTAPI
NtGetDevicePowerState(IN HANDLE Device,IN PDEVICE_POWER_STATE PowerState)925c2c66affSColin Finck NtGetDevicePowerState(IN HANDLE Device,
926c2c66affSColin Finck                       IN PDEVICE_POWER_STATE PowerState)
927c2c66affSColin Finck {
928c2c66affSColin Finck     UNIMPLEMENTED;
929c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
930c2c66affSColin Finck }
931c2c66affSColin Finck 
932c2c66affSColin Finck BOOLEAN
933c2c66affSColin Finck NTAPI
NtIsSystemResumeAutomatic(VOID)934c2c66affSColin Finck NtIsSystemResumeAutomatic(VOID)
935c2c66affSColin Finck {
936c2c66affSColin Finck     UNIMPLEMENTED;
937c2c66affSColin Finck     return FALSE;
938c2c66affSColin Finck }
939c2c66affSColin Finck 
940c2c66affSColin Finck NTSTATUS
941c2c66affSColin Finck NTAPI
NtRequestWakeupLatency(IN LATENCY_TIME Latency)942c2c66affSColin Finck NtRequestWakeupLatency(IN LATENCY_TIME Latency)
943c2c66affSColin Finck {
944c2c66affSColin Finck     UNIMPLEMENTED;
945c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
946c2c66affSColin Finck }
947c2c66affSColin Finck 
948c2c66affSColin Finck NTSTATUS
949c2c66affSColin Finck NTAPI
NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,OUT EXECUTION_STATE * PreviousFlags)950c2c66affSColin Finck NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
951c2c66affSColin Finck                           OUT EXECUTION_STATE *PreviousFlags)
952c2c66affSColin Finck {
953c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
954c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
955c2c66affSColin Finck     EXECUTION_STATE PreviousState;
956c2c66affSColin Finck     PAGED_CODE();
957c2c66affSColin Finck 
958c2c66affSColin Finck     /* Validate flags */
959c2c66affSColin Finck     if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
960c2c66affSColin Finck     {
961c2c66affSColin Finck         /* Fail the request */
962c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
963c2c66affSColin Finck     }
964c2c66affSColin Finck 
965c2c66affSColin Finck     /* Check for user parameters */
966c2c66affSColin Finck     if (PreviousMode != KernelMode)
967c2c66affSColin Finck     {
968c2c66affSColin Finck         /* Protect the probes */
969c2c66affSColin Finck         _SEH2_TRY
970c2c66affSColin Finck         {
971c2c66affSColin Finck             /* Check if the pointer is valid */
972c2c66affSColin Finck             ProbeForWriteUlong(PreviousFlags);
973c2c66affSColin Finck         }
974c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
975c2c66affSColin Finck         {
976c2c66affSColin Finck             /* It isn't -- fail */
977c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
978c2c66affSColin Finck         }
979c2c66affSColin Finck         _SEH2_END;
980c2c66affSColin Finck     }
981c2c66affSColin Finck 
982c2c66affSColin Finck     /* Save the previous state, always masking in the continous flag */
983c2c66affSColin Finck     PreviousState = Thread->PowerState | ES_CONTINUOUS;
984c2c66affSColin Finck 
985c2c66affSColin Finck     /* Check if we need to update the power state */
986c2c66affSColin Finck     if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
987c2c66affSColin Finck 
988c2c66affSColin Finck     /* Protect the write back to user mode */
989c2c66affSColin Finck     _SEH2_TRY
990c2c66affSColin Finck     {
991c2c66affSColin Finck         /* Return the previous flags */
992c2c66affSColin Finck         *PreviousFlags = PreviousState;
993c2c66affSColin Finck     }
994c2c66affSColin Finck     _SEH2_EXCEPT(ExSystemExceptionFilter())
995c2c66affSColin Finck     {
996c2c66affSColin Finck         /* Something's wrong, fail */
997c2c66affSColin Finck         _SEH2_YIELD(return _SEH2_GetExceptionCode());
998c2c66affSColin Finck     }
999c2c66affSColin Finck     _SEH2_END;
1000c2c66affSColin Finck 
1001c2c66affSColin Finck     /* All is good */
1002c2c66affSColin Finck     return STATUS_SUCCESS;
1003c2c66affSColin Finck }
1004c2c66affSColin Finck 
1005c2c66affSColin Finck NTSTATUS
1006c2c66affSColin Finck NTAPI
NtSetSystemPowerState(IN POWER_ACTION SystemAction,IN SYSTEM_POWER_STATE MinSystemState,IN ULONG Flags)1007c2c66affSColin Finck NtSetSystemPowerState(IN POWER_ACTION SystemAction,
1008c2c66affSColin Finck                       IN SYSTEM_POWER_STATE MinSystemState,
1009c2c66affSColin Finck                       IN ULONG Flags)
1010c2c66affSColin Finck {
1011c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1012c2c66affSColin Finck     POP_POWER_ACTION Action = {0};
1013c2c66affSColin Finck     NTSTATUS Status;
1014c2c66affSColin Finck     ULONG Dummy;
1015c2c66affSColin Finck 
1016c2c66affSColin Finck     /* Check for invalid parameter combinations */
1017c2c66affSColin Finck     if ((MinSystemState >= PowerSystemMaximum) ||
1018c2c66affSColin Finck         (MinSystemState <= PowerSystemUnspecified) ||
1019c2c66affSColin Finck         (SystemAction > PowerActionWarmEject) ||
1020c2c66affSColin Finck         (SystemAction < PowerActionReserved) ||
1021c2c66affSColin Finck         (Flags & ~(POWER_ACTION_QUERY_ALLOWED  |
1022c2c66affSColin Finck                    POWER_ACTION_UI_ALLOWED     |
1023c2c66affSColin Finck                    POWER_ACTION_OVERRIDE_APPS  |
1024c2c66affSColin Finck                    POWER_ACTION_LIGHTEST_FIRST |
1025c2c66affSColin Finck                    POWER_ACTION_LOCK_CONSOLE   |
1026c2c66affSColin Finck                    POWER_ACTION_DISABLE_WAKES  |
1027c2c66affSColin Finck                    POWER_ACTION_CRITICAL)))
1028c2c66affSColin Finck     {
1029c2c66affSColin Finck         DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
1030c2c66affSColin Finck         DPRINT1("                       SystemAction: 0x%x\n", SystemAction);
1031c2c66affSColin Finck         DPRINT1("                       MinSystemState: 0x%x\n", MinSystemState);
1032c2c66affSColin Finck         DPRINT1("                       Flags: 0x%x\n", Flags);
1033c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
1034c2c66affSColin Finck     }
1035c2c66affSColin Finck 
1036c2c66affSColin Finck     /* Check for user caller */
1037c2c66affSColin Finck     if (PreviousMode != KernelMode)
1038c2c66affSColin Finck     {
1039c2c66affSColin Finck         /* Check for shutdown permission */
1040c2c66affSColin Finck         if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
1041c2c66affSColin Finck         {
1042c2c66affSColin Finck             /* Not granted */
1043c2c66affSColin Finck             DPRINT1("ERROR: Privilege not held for shutdown\n");
1044c2c66affSColin Finck             return STATUS_PRIVILEGE_NOT_HELD;
1045c2c66affSColin Finck         }
1046c2c66affSColin Finck 
1047c2c66affSColin Finck         /* Do it as a kernel-mode caller for consistency with system state */
1048c2c66affSColin Finck         return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags);
1049c2c66affSColin Finck     }
1050c2c66affSColin Finck 
1051c2c66affSColin Finck     /* Read policy settings (partial shutdown vs. full shutdown) */
1052c2c66affSColin Finck     if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
1053c2c66affSColin Finck 
1054c2c66affSColin Finck     /* Disable lazy flushing of registry */
1055c2c66affSColin Finck     DPRINT("Stopping lazy flush\n");
1056c2c66affSColin Finck     CmSetLazyFlushState(FALSE);
1057c2c66affSColin Finck 
1058c2c66affSColin Finck     /* Setup the power action */
1059c2c66affSColin Finck     Action.Action = SystemAction;
1060c2c66affSColin Finck     Action.Flags = Flags;
1061c2c66affSColin Finck 
1062c2c66affSColin Finck     /* Notify callbacks */
1063c2c66affSColin Finck     DPRINT("Notifying callbacks\n");
1064c2c66affSColin Finck     ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
1065c2c66affSColin Finck 
1066c2c66affSColin Finck     /* Swap in any worker thread stacks */
1067c2c66affSColin Finck     DPRINT("Swapping worker threads\n");
1068c2c66affSColin Finck     ExSwapinWorkerThreads(FALSE);
1069c2c66affSColin Finck 
1070c2c66affSColin Finck     /* Make our action global */
1071c2c66affSColin Finck     PopAction = Action;
1072c2c66affSColin Finck 
1073c2c66affSColin Finck     /* Start power loop */
1074c2c66affSColin Finck     Status = STATUS_CANCELLED;
1075c2c66affSColin Finck     while (TRUE)
1076c2c66affSColin Finck     {
1077c2c66affSColin Finck         /* Break out if there's nothing to do */
1078c2c66affSColin Finck         if (Action.Action == PowerActionNone) break;
1079c2c66affSColin Finck 
1080c2c66affSColin Finck         /* Check for first-pass or restart */
1081c2c66affSColin Finck         if (Status == STATUS_CANCELLED)
1082c2c66affSColin Finck         {
1083c2c66affSColin Finck             /* Check for shutdown action */
1084c2c66affSColin Finck             if ((PopAction.Action == PowerActionShutdown) ||
1085c2c66affSColin Finck                 (PopAction.Action == PowerActionShutdownReset) ||
1086c2c66affSColin Finck                 (PopAction.Action == PowerActionShutdownOff))
1087c2c66affSColin Finck             {
1088c2c66affSColin Finck                 /* Set the action */
1089c2c66affSColin Finck                 PopAction.Shutdown = TRUE;
1090c2c66affSColin Finck             }
1091c2c66affSColin Finck 
1092c2c66affSColin Finck             /* Now we are good to go */
1093c2c66affSColin Finck             Status = STATUS_SUCCESS;
1094c2c66affSColin Finck         }
1095c2c66affSColin Finck 
1096c2c66affSColin Finck         /* Check if we're still in an invalid status */
1097c2c66affSColin Finck         if (!NT_SUCCESS(Status)) break;
1098c2c66affSColin Finck 
109948e1c859SJérôme Gardou         /* Flush all volumes and the registry */
110048e1c859SJérôme Gardou         DPRINT("Flushing volumes\n");
110148e1c859SJérôme Gardou         PopFlushVolumes(PopAction.Shutdown);
110248e1c859SJérôme Gardou 
1103c2c66affSColin Finck #ifndef NEWCC
1104c2c66affSColin Finck         /* Flush dirty cache pages */
1105c7ad200fSPierre Schweitzer         /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */
110648e1c859SJérôme Gardou         CcRosFlushDirtyPages(MAXULONG, &Dummy, TRUE, FALSE);
110748e1c859SJérôme Gardou         DPRINT("Cache flushed %lu pages\n", Dummy);
1108c2c66affSColin Finck #else
1109c2c66affSColin Finck         Dummy = 0;
1110c2c66affSColin Finck #endif
1111c2c66affSColin Finck 
1112c2c66affSColin Finck         /* Set IRP for drivers */
1113c2c66affSColin Finck         PopAction.IrpMinor = IRP_MN_SET_POWER;
1114c2c66affSColin Finck         if (PopAction.Shutdown)
1115c2c66affSColin Finck         {
1116c2c66affSColin Finck             DPRINT("Queueing shutdown thread\n");
1117c2c66affSColin Finck             /* Check if we are running in the system context */
1118c2c66affSColin Finck             if (PsGetCurrentProcess() != PsInitialSystemProcess)
1119c2c66affSColin Finck             {
1120c2c66affSColin Finck                 /* We're not, so use a worker thread for shutdown */
1121c2c66affSColin Finck                 ExInitializeWorkItem(&PopShutdownWorkItem,
1122c2c66affSColin Finck                                      &PopGracefulShutdown,
1123c2c66affSColin Finck                                      NULL);
1124c2c66affSColin Finck 
1125c2c66affSColin Finck                 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
1126c2c66affSColin Finck 
1127c2c66affSColin Finck                 /* Spend us -- when we wake up, the system is good to go down */
1128c2c66affSColin Finck                 KeSuspendThread(KeGetCurrentThread());
1129c2c66affSColin Finck                 Status = STATUS_SYSTEM_SHUTDOWN;
1130c2c66affSColin Finck                 goto Exit;
1131c2c66affSColin Finck 
1132c2c66affSColin Finck             }
1133c2c66affSColin Finck             else
1134c2c66affSColin Finck             {
1135c2c66affSColin Finck                 /* Do the shutdown inline */
1136c2c66affSColin Finck                 PopGracefulShutdown(NULL);
1137c2c66affSColin Finck             }
1138c2c66affSColin Finck         }
1139c2c66affSColin Finck 
1140c2c66affSColin Finck         /* You should not have made it this far */
11417d6bda16SSerge Gautherie         // ASSERTMSG("System is still up and running?!\n", FALSE);
1142c2c66affSColin Finck         DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action);
1143c2c66affSColin Finck         break;
1144c2c66affSColin Finck     }
1145c2c66affSColin Finck 
1146c2c66affSColin Finck Exit:
1147c2c66affSColin Finck     /* We're done, return */
1148c2c66affSColin Finck     return Status;
1149c2c66affSColin Finck }
1150