xref: /reactos/ntoskrnl/po/power.c (revision 5c7ce447)
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)
7c2c66affSColin Finck  *                  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
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 
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 
127c2c66affSColin Finck static
128c2c66affSColin Finck NTSTATUS
129c2c66affSColin Finck NTAPI
130c2c66affSColin Finck PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
131c2c66affSColin Finck                              IN PIRP Irp,
132c2c66affSColin Finck                              IN PVOID Context)
133c2c66affSColin Finck {
134c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
135c2c66affSColin Finck     PREQUEST_POWER_COMPLETE CompletionRoutine;
136c2c66affSColin Finck     POWER_STATE PowerState;
137c2c66affSColin Finck 
138c2c66affSColin Finck     Stack = IoGetCurrentIrpStackLocation(Irp);
139c2c66affSColin Finck     CompletionRoutine = Context;
140c2c66affSColin Finck 
141c2c66affSColin Finck     PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3;
142c2c66affSColin Finck     CompletionRoutine(Stack->Parameters.Others.Argument1,
143c2c66affSColin Finck                       (UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2,
144c2c66affSColin Finck                       PowerState,
145c2c66affSColin Finck                       Stack->Parameters.Others.Argument4,
146c2c66affSColin Finck                       &Irp->IoStatus);
147c2c66affSColin Finck 
148c2c66affSColin Finck     IoSkipCurrentIrpStackLocation(Irp);
149c2c66affSColin Finck     IoFreeIrp(Irp);
150c2c66affSColin Finck     ObDereferenceObject(DeviceObject);
151c2c66affSColin Finck 
152c2c66affSColin Finck     return STATUS_MORE_PROCESSING_REQUIRED;
153c2c66affSColin Finck }
154c2c66affSColin Finck 
155c2c66affSColin Finck VOID
156c2c66affSColin Finck NTAPI
157c2c66affSColin Finck PopCleanupPowerState(IN PPOWER_STATE PowerState)
158c2c66affSColin Finck {
159c2c66affSColin Finck     //UNIMPLEMENTED;
160c2c66affSColin Finck }
161c2c66affSColin Finck 
162c2c66affSColin Finck NTSTATUS
163c2c66affSColin Finck PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
164c2c66affSColin Finck {
165c2c66affSColin Finck     KEVENT Event;
166c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
167c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp;
168c2c66affSColin Finck     PIRP Irp;
169c2c66affSColin Finck     NTSTATUS Status;
170c2c66affSColin Finck 
171c2c66affSColin Finck     KeInitializeEvent(&Event,
172c2c66affSColin Finck                       NotificationEvent,
173c2c66affSColin Finck                       FALSE);
174c2c66affSColin Finck 
175c2c66affSColin Finck     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
176c2c66affSColin Finck                                        DeviceObject,
177c2c66affSColin Finck                                        NULL,
178c2c66affSColin Finck                                        0,
179c2c66affSColin Finck                                        NULL,
180c2c66affSColin Finck                                        &Event,
181c2c66affSColin Finck                                        &IoStatusBlock);
182c2c66affSColin Finck     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
183c2c66affSColin Finck 
184c2c66affSColin Finck     IrpSp = IoGetNextIrpStackLocation(Irp);
185c2c66affSColin Finck     IrpSp->MinorFunction = IRP_MN_QUERY_POWER;
186c2c66affSColin Finck     IrpSp->Parameters.Power.Type = SystemPowerState;
187c2c66affSColin Finck     IrpSp->Parameters.Power.State.SystemState = SystemState;
188c2c66affSColin Finck     IrpSp->Parameters.Power.ShutdownType = PowerAction;
189c2c66affSColin Finck 
190c2c66affSColin Finck     Status = PoCallDriver(DeviceObject, Irp);
191c2c66affSColin Finck     if (Status == STATUS_PENDING)
192c2c66affSColin Finck     {
193c2c66affSColin Finck         KeWaitForSingleObject(&Event,
194c2c66affSColin Finck                               Executive,
195c2c66affSColin Finck                               KernelMode,
196c2c66affSColin Finck                               FALSE,
197c2c66affSColin Finck                               NULL);
198c2c66affSColin Finck         Status = IoStatusBlock.Status;
199c2c66affSColin Finck     }
200c2c66affSColin Finck 
201c2c66affSColin Finck     return Status;
202c2c66affSColin Finck }
203c2c66affSColin Finck 
204c2c66affSColin Finck NTSTATUS
205c2c66affSColin Finck PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction)
206c2c66affSColin Finck {
207c2c66affSColin Finck     KEVENT Event;
208c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
209c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp;
210c2c66affSColin Finck     PIRP Irp;
211c2c66affSColin Finck     NTSTATUS Status;
212c2c66affSColin Finck 
213c2c66affSColin Finck     KeInitializeEvent(&Event,
214c2c66affSColin Finck                       NotificationEvent,
215c2c66affSColin Finck                       FALSE);
216c2c66affSColin Finck 
217c2c66affSColin Finck     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
218c2c66affSColin Finck                                        DeviceObject,
219c2c66affSColin Finck                                        NULL,
220c2c66affSColin Finck                                        0,
221c2c66affSColin Finck                                        NULL,
222c2c66affSColin Finck                                        &Event,
223c2c66affSColin Finck                                        &IoStatusBlock);
224c2c66affSColin Finck     if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
225c2c66affSColin Finck 
226c2c66affSColin Finck     IrpSp = IoGetNextIrpStackLocation(Irp);
227c2c66affSColin Finck     IrpSp->MinorFunction = IRP_MN_SET_POWER;
228c2c66affSColin Finck     IrpSp->Parameters.Power.Type = SystemPowerState;
229c2c66affSColin Finck     IrpSp->Parameters.Power.State.SystemState = SystemState;
230c2c66affSColin Finck     IrpSp->Parameters.Power.ShutdownType = PowerAction;
231c2c66affSColin Finck 
232c2c66affSColin Finck     Status = PoCallDriver(DeviceObject, Irp);
233c2c66affSColin Finck     if (Status == STATUS_PENDING)
234c2c66affSColin Finck     {
235c2c66affSColin Finck         KeWaitForSingleObject(&Event,
236c2c66affSColin Finck                               Executive,
237c2c66affSColin Finck                               KernelMode,
238c2c66affSColin Finck                               FALSE,
239c2c66affSColin Finck                               NULL);
240c2c66affSColin Finck         Status = IoStatusBlock.Status;
241c2c66affSColin Finck     }
242c2c66affSColin Finck 
243c2c66affSColin Finck     return Status;
244c2c66affSColin Finck }
245c2c66affSColin Finck 
246c2c66affSColin Finck NTSTATUS
247c2c66affSColin Finck PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
248c2c66affSColin Finck                                  PVOID Context)
249c2c66affSColin Finck {
250c2c66affSColin Finck     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
251c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
252c2c66affSColin Finck     NTSTATUS Status;
253c2c66affSColin Finck 
254c2c66affSColin Finck     DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
255c2c66affSColin Finck 
256c2c66affSColin Finck     if (DeviceNode == IopRootDeviceNode)
257c2c66affSColin Finck         return STATUS_SUCCESS;
258c2c66affSColin Finck 
259c2c66affSColin Finck     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
260c2c66affSColin Finck         return STATUS_SUCCESS;
261c2c66affSColin Finck 
262c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
263c2c66affSColin Finck 
264c2c66affSColin Finck     Status = PopSendQuerySystemPowerState(TopDeviceObject,
265c2c66affSColin Finck                                           PowerStateContext->SystemPowerState,
266c2c66affSColin Finck                                           PowerStateContext->PowerAction);
267c2c66affSColin Finck     if (!NT_SUCCESS(Status))
268c2c66affSColin Finck     {
269c2c66affSColin Finck         DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath);
270c2c66affSColin Finck     }
271c2c66affSColin Finck     ObDereferenceObject(TopDeviceObject);
272c2c66affSColin Finck 
273c2c66affSColin Finck #if 0
274c2c66affSColin Finck     return Status;
275c2c66affSColin Finck #else
276c2c66affSColin Finck     return STATUS_SUCCESS;
277c2c66affSColin Finck #endif
278c2c66affSColin Finck }
279c2c66affSColin Finck 
280c2c66affSColin Finck NTSTATUS
281c2c66affSColin Finck PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode,
282c2c66affSColin Finck                                PVOID Context)
283c2c66affSColin Finck {
284c2c66affSColin Finck     PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context;
285c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
286c2c66affSColin Finck     NTSTATUS Status;
287c2c66affSColin Finck 
288c2c66affSColin Finck     DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context);
289c2c66affSColin Finck 
290c2c66affSColin Finck     if (DeviceNode == IopRootDeviceNode)
291c2c66affSColin Finck         return STATUS_SUCCESS;
292c2c66affSColin Finck 
293c2c66affSColin Finck     if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice)
294c2c66affSColin Finck         return STATUS_SUCCESS;
295c2c66affSColin Finck 
296c2c66affSColin Finck     if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
297c2c66affSColin Finck         return STATUS_SUCCESS;
298c2c66affSColin Finck 
299c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
300c2c66affSColin Finck     if (TopDeviceObject == PowerStateContext->PowerDevice)
301c2c66affSColin Finck     {
302c2c66affSColin Finck         ObDereferenceObject(TopDeviceObject);
303c2c66affSColin Finck         return STATUS_SUCCESS;
304c2c66affSColin Finck     }
305c2c66affSColin Finck 
306c2c66affSColin Finck     Status = PopSendSetSystemPowerState(TopDeviceObject,
307c2c66affSColin Finck                                         PowerStateContext->SystemPowerState,
308c2c66affSColin Finck                                         PowerStateContext->PowerAction);
309c2c66affSColin Finck     if (!NT_SUCCESS(Status))
310c2c66affSColin Finck     {
311c2c66affSColin Finck         DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath);
312c2c66affSColin Finck     }
313c2c66affSColin Finck 
314c2c66affSColin Finck     ObDereferenceObject(TopDeviceObject);
315c2c66affSColin Finck 
316c2c66affSColin Finck #if 0
317c2c66affSColin Finck     return Status;
318c2c66affSColin Finck #else
319c2c66affSColin Finck     return STATUS_SUCCESS;
320c2c66affSColin Finck #endif
321c2c66affSColin Finck }
322c2c66affSColin Finck 
323c2c66affSColin Finck NTSTATUS
324c2c66affSColin Finck NTAPI
325c2c66affSColin Finck PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction)
326c2c66affSColin Finck {
327c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject;
328c2c66affSColin Finck     PDEVICE_OBJECT Fdo;
329c2c66affSColin Finck     NTSTATUS Status;
330c2c66affSColin Finck     DEVICETREE_TRAVERSE_CONTEXT Context;
331c2c66affSColin Finck     POWER_STATE_TRAVERSE_CONTEXT PowerContext;
332c2c66affSColin Finck 
333c2c66affSColin Finck     Status = IopGetSystemPowerDeviceObject(&DeviceObject);
334c2c66affSColin Finck     if (!NT_SUCCESS(Status))
335c2c66affSColin Finck     {
336c2c66affSColin Finck         DPRINT1("No system power driver available\n");
337c2c66affSColin Finck         Fdo = NULL;
338c2c66affSColin Finck     }
339c2c66affSColin Finck     else
340c2c66affSColin Finck     {
341c2c66affSColin Finck         Fdo = IoGetAttachedDeviceReference(DeviceObject);
342c2c66affSColin Finck         if (Fdo == DeviceObject)
343c2c66affSColin Finck         {
344c2c66affSColin Finck             DPRINT("An FDO was not attached\n");
345c2c66affSColin Finck             return STATUS_UNSUCCESSFUL;
346c2c66affSColin Finck         }
347c2c66affSColin Finck     }
348c2c66affSColin Finck 
349c2c66affSColin Finck     /* Set up context */
350c2c66affSColin Finck     PowerContext.PowerAction = PowerAction;
351c2c66affSColin Finck     PowerContext.SystemPowerState = PowerState;
352c2c66affSColin Finck     PowerContext.PowerDevice = Fdo;
353c2c66affSColin Finck 
354c2c66affSColin Finck     /* Query for system power change */
355c2c66affSColin Finck     IopInitDeviceTreeTraverseContext(&Context,
356c2c66affSColin Finck                                      IopRootDeviceNode,
357c2c66affSColin Finck                                      PopQuerySystemPowerStateTraverse,
358c2c66affSColin Finck                                      &PowerContext);
359c2c66affSColin Finck 
360c2c66affSColin Finck     Status = IopTraverseDeviceTree(&Context);
361c2c66affSColin Finck     if (!NT_SUCCESS(Status))
362c2c66affSColin Finck     {
363c2c66affSColin Finck         DPRINT1("Query system power state failed; changing state anyway\n");
364c2c66affSColin Finck     }
365c2c66affSColin Finck 
366c2c66affSColin Finck     /* Set system power change */
367c2c66affSColin Finck     IopInitDeviceTreeTraverseContext(&Context,
368c2c66affSColin Finck                                      IopRootDeviceNode,
369c2c66affSColin Finck                                      PopSetSystemPowerStateTraverse,
370c2c66affSColin Finck                                      &PowerContext);
371c2c66affSColin Finck 
372c2c66affSColin Finck     IopTraverseDeviceTree(&Context);
373c2c66affSColin Finck 
374c2c66affSColin Finck     if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
375c2c66affSColin Finck 
376c2c66affSColin Finck     if (Fdo != NULL)
377c2c66affSColin Finck     {
378c2c66affSColin Finck         if (PowerAction != PowerActionShutdownReset)
379c2c66affSColin Finck             PopSendSetSystemPowerState(Fdo, PowerState, PowerAction);
380c2c66affSColin Finck 
381c2c66affSColin Finck         ObDereferenceObject(Fdo);
382c2c66affSColin Finck     }
383c2c66affSColin Finck 
384c2c66affSColin Finck     return Status;
385c2c66affSColin Finck }
386c2c66affSColin Finck 
387*5c7ce447SVictor Perevertkin CODE_SEG("INIT")
388c2c66affSColin Finck BOOLEAN
389c2c66affSColin Finck NTAPI
390c2c66affSColin Finck PoInitSystem(IN ULONG BootPhase)
391c2c66affSColin Finck {
392c2c66affSColin Finck     PVOID NotificationEntry;
393c2c66affSColin Finck     PCHAR CommandLine;
394c2c66affSColin Finck     BOOLEAN ForceAcpiDisable = FALSE;
395c2c66affSColin Finck 
396c2c66affSColin Finck     /* Check if this is phase 1 init */
397c2c66affSColin Finck     if (BootPhase == 1)
398c2c66affSColin Finck     {
399c2c66affSColin Finck         /* Register power button notification */
400c2c66affSColin Finck         IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
401c2c66affSColin Finck                                        PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
402c2c66affSColin Finck                                        (PVOID)&GUID_DEVICE_SYS_BUTTON,
403c2c66affSColin Finck                                        IopRootDeviceNode->
404c2c66affSColin Finck                                        PhysicalDeviceObject->DriverObject,
405c2c66affSColin Finck                                        PopAddRemoveSysCapsCallback,
406c2c66affSColin Finck                                        NULL,
407c2c66affSColin Finck                                        &NotificationEntry);
408c2c66affSColin Finck 
409c2c66affSColin Finck         /* Register lid notification */
410c2c66affSColin Finck         IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
411c2c66affSColin Finck                                        PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
412c2c66affSColin Finck                                        (PVOID)&GUID_DEVICE_LID,
413c2c66affSColin Finck                                        IopRootDeviceNode->
414c2c66affSColin Finck                                        PhysicalDeviceObject->DriverObject,
415c2c66affSColin Finck                                        PopAddRemoveSysCapsCallback,
416c2c66affSColin Finck                                        NULL,
417c2c66affSColin Finck                                        &NotificationEntry);
418c2c66affSColin Finck         return TRUE;
419c2c66affSColin Finck     }
420c2c66affSColin Finck 
421626aaf22SEric Kohl     /* Initialize the power capabilities */
422626aaf22SEric Kohl     RtlZeroMemory(&PopCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
423626aaf22SEric Kohl 
424c2c66affSColin Finck     /* Get the Command Line */
425c2c66affSColin Finck     CommandLine = KeLoaderBlock->LoadOptions;
426c2c66affSColin Finck 
427c2c66affSColin Finck     /* Upcase it */
428c2c66affSColin Finck     _strupr(CommandLine);
429c2c66affSColin Finck 
430c2c66affSColin Finck     /* Check for ACPI disable */
431c2c66affSColin Finck     if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
432c2c66affSColin Finck 
433c2c66affSColin Finck     if (ForceAcpiDisable)
434c2c66affSColin Finck     {
435c2c66affSColin Finck         /* Set the ACPI State to False if it's been forced that way */
436c2c66affSColin Finck         PopAcpiPresent = FALSE;
437c2c66affSColin Finck     }
438c2c66affSColin Finck     else
439c2c66affSColin Finck     {
440c2c66affSColin Finck         /* Otherwise check if the LoaderBlock has a ACPI Table  */
441c2c66affSColin Finck         PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE;
442c2c66affSColin Finck     }
443c2c66affSColin Finck 
444626aaf22SEric Kohl     /* Enable shutdown by power button */
445626aaf22SEric Kohl     if (PopAcpiPresent)
446626aaf22SEric Kohl         PopCapabilities.SystemS5 = TRUE;
447c2c66affSColin Finck 
448c2c66affSColin Finck     /* Initialize volume support */
449c2c66affSColin Finck     InitializeListHead(&PopVolumeDevices);
450c2c66affSColin Finck     KeInitializeGuardedMutex(&PopVolumeLock);
451c2c66affSColin Finck 
452c2c66affSColin Finck     /* Initialize support for dope */
453c2c66affSColin Finck     KeInitializeSpinLock(&PopDopeGlobalLock);
454c2c66affSColin Finck 
455c2c66affSColin Finck     /* Initialize support for shutdown waits and work-items */
456c2c66affSColin Finck     PopInitShutdownList();
457c2c66affSColin Finck 
458c2c66affSColin Finck     return TRUE;
459c2c66affSColin Finck }
460c2c66affSColin Finck 
461c2c66affSColin Finck VOID
462c2c66affSColin Finck NTAPI
463c2c66affSColin Finck PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
464c2c66affSColin Finck {
465c2c66affSColin Finck     DPRINT1("PerfIdle function: %p\n", PowerState);
466c2c66affSColin Finck }
467c2c66affSColin Finck 
468c2c66affSColin Finck VOID
469c2c66affSColin Finck NTAPI
470c2c66affSColin Finck PopPerfIdleDpc(IN PKDPC Dpc,
471c2c66affSColin Finck                IN PVOID DeferredContext,
472c2c66affSColin Finck                IN PVOID SystemArgument1,
473c2c66affSColin Finck                IN PVOID SystemArgument2)
474c2c66affSColin Finck {
475c2c66affSColin Finck     /* Call the Perf Idle function */
476c2c66affSColin Finck     PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
477c2c66affSColin Finck }
478c2c66affSColin Finck 
479c2c66affSColin Finck VOID
480c2c66affSColin Finck FASTCALL
481c2c66affSColin Finck PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
482c2c66affSColin Finck {
483c2c66affSColin Finck     /* FIXME: Extremly naive implementation */
484c2c66affSColin Finck     HalProcessorIdle();
485c2c66affSColin Finck }
486c2c66affSColin Finck 
487*5c7ce447SVictor Perevertkin CODE_SEG("INIT")
488c2c66affSColin Finck VOID
489c2c66affSColin Finck NTAPI
490c2c66affSColin Finck PoInitializePrcb(IN PKPRCB Prcb)
491c2c66affSColin Finck {
492c2c66affSColin Finck     /* Initialize the Power State */
493c2c66affSColin Finck     RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
494c2c66affSColin Finck     Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
495c2c66affSColin Finck     Prcb->PowerState.CurrentThrottle = 100;
496c2c66affSColin Finck     Prcb->PowerState.CurrentThrottleIndex = 0;
497c2c66affSColin Finck     Prcb->PowerState.IdleFunction = PopIdle0;
498c2c66affSColin Finck 
499c2c66affSColin Finck     /* Initialize the Perf DPC and Timer */
500c2c66affSColin Finck     KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
501c2c66affSColin Finck     KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
502c2c66affSColin Finck     KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
503c2c66affSColin Finck }
504c2c66affSColin Finck 
505c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
506c2c66affSColin Finck 
507c2c66affSColin Finck /*
508c2c66affSColin Finck  * @unimplemented
509c2c66affSColin Finck  */
510c2c66affSColin Finck NTSTATUS
511c2c66affSColin Finck NTAPI
512c2c66affSColin Finck PoCancelDeviceNotify(IN PVOID NotifyBlock)
513c2c66affSColin Finck {
514c2c66affSColin Finck     UNIMPLEMENTED;
515c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
516c2c66affSColin Finck }
517c2c66affSColin Finck 
518c2c66affSColin Finck /*
519c2c66affSColin Finck  * @unimplemented
520c2c66affSColin Finck  */
521c2c66affSColin Finck NTSTATUS
522c2c66affSColin Finck NTAPI
523c2c66affSColin Finck PoRegisterDeviceNotify(OUT PVOID Unknown0,
524c2c66affSColin Finck                        IN ULONG Unknown1,
525c2c66affSColin Finck                        IN ULONG Unknown2,
526c2c66affSColin Finck                        IN ULONG Unknown3,
527c2c66affSColin Finck                        IN PVOID Unknown4,
528c2c66affSColin Finck                        IN PVOID Unknown5)
529c2c66affSColin Finck {
530c2c66affSColin Finck     UNIMPLEMENTED;
531c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
532c2c66affSColin Finck }
533c2c66affSColin Finck 
534c2c66affSColin Finck /*
535c2c66affSColin Finck  * @unimplemented
536c2c66affSColin Finck  */
537c2c66affSColin Finck VOID
538c2c66affSColin Finck NTAPI
539c2c66affSColin Finck PoShutdownBugCheck(IN BOOLEAN LogError,
540c2c66affSColin Finck                    IN ULONG BugCheckCode,
541c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter1,
542c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter2,
543c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter3,
544c2c66affSColin Finck                    IN ULONG_PTR BugCheckParameter4)
545c2c66affSColin Finck {
546c2c66affSColin Finck     DPRINT1("PoShutdownBugCheck called\n");
547c2c66affSColin Finck 
548c2c66affSColin Finck     /* FIXME: Log error if requested */
549c2c66affSColin Finck     /* FIXME: Initiate a shutdown */
550c2c66affSColin Finck 
551c2c66affSColin Finck     /* Bugcheck the system */
552c2c66affSColin Finck     KeBugCheckEx(BugCheckCode,
553c2c66affSColin Finck                  BugCheckParameter1,
554c2c66affSColin Finck                  BugCheckParameter2,
555c2c66affSColin Finck                  BugCheckParameter3,
556c2c66affSColin Finck                  BugCheckParameter4);
557c2c66affSColin Finck }
558c2c66affSColin Finck 
559c2c66affSColin Finck /*
560c2c66affSColin Finck  * @unimplemented
561c2c66affSColin Finck  */
562c2c66affSColin Finck VOID
563c2c66affSColin Finck NTAPI
564c2c66affSColin Finck PoSetHiberRange(IN PVOID HiberContext,
565c2c66affSColin Finck                 IN ULONG Flags,
566c2c66affSColin Finck                 IN OUT PVOID StartPage,
567c2c66affSColin Finck                 IN ULONG Length,
568c2c66affSColin Finck                 IN ULONG PageTag)
569c2c66affSColin Finck {
570c2c66affSColin Finck     UNIMPLEMENTED;
571c2c66affSColin Finck     return;
572c2c66affSColin Finck }
573c2c66affSColin Finck 
574c2c66affSColin Finck /*
575c2c66affSColin Finck  * @implemented
576c2c66affSColin Finck  */
57734f4b218SThomas Faber _IRQL_requires_max_(DISPATCH_LEVEL)
578c2c66affSColin Finck NTSTATUS
579c2c66affSColin Finck NTAPI
58034f4b218SThomas Faber PoCallDriver(
58134f4b218SThomas Faber     _In_ PDEVICE_OBJECT DeviceObject,
58234f4b218SThomas Faber     _Inout_ __drv_aliasesMem PIRP Irp)
583c2c66affSColin Finck {
58434f4b218SThomas Faber     PIO_STACK_LOCATION NextStack;
585c2c66affSColin Finck 
58634f4b218SThomas Faber     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
587c2c66affSColin Finck 
58834f4b218SThomas Faber     ASSERT(DeviceObject);
58934f4b218SThomas Faber     ASSERT(Irp);
59034f4b218SThomas Faber 
59134f4b218SThomas Faber     NextStack = IoGetNextIrpStackLocation(Irp);
59234f4b218SThomas Faber     ASSERT(NextStack->MajorFunction == IRP_MJ_POWER);
59334f4b218SThomas Faber 
59434f4b218SThomas Faber     /* Set DeviceObject for PopPresentIrp */
59534f4b218SThomas Faber     NextStack->DeviceObject = DeviceObject;
59634f4b218SThomas Faber 
59734f4b218SThomas Faber     /* Only QUERY_POWER and SET_POWER use special handling */
59834f4b218SThomas Faber     if (NextStack->MinorFunction != IRP_MN_SET_POWER &&
59934f4b218SThomas Faber         NextStack->MinorFunction != IRP_MN_QUERY_POWER)
60034f4b218SThomas Faber     {
60134f4b218SThomas Faber         return IoCallDriver(DeviceObject, Irp);
60234f4b218SThomas Faber     }
60334f4b218SThomas Faber 
60434f4b218SThomas Faber     /* Call the next driver, either directly or at PASSIVE_LEVEL */
60534f4b218SThomas Faber     return PopPresentIrp(NextStack, Irp);
606c2c66affSColin Finck }
607c2c66affSColin Finck 
608c2c66affSColin Finck /*
609c2c66affSColin Finck  * @unimplemented
610c2c66affSColin Finck  */
611c2c66affSColin Finck PULONG
612c2c66affSColin Finck NTAPI
613c2c66affSColin Finck PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
614c2c66affSColin Finck                                  IN ULONG ConservationIdleTime,
615c2c66affSColin Finck                                  IN ULONG PerformanceIdleTime,
616c2c66affSColin Finck                                  IN DEVICE_POWER_STATE State)
617c2c66affSColin Finck {
618c2c66affSColin Finck     UNIMPLEMENTED;
619c2c66affSColin Finck     return NULL;
620c2c66affSColin Finck }
621c2c66affSColin Finck 
622c2c66affSColin Finck /*
623c2c66affSColin Finck  * @unimplemented
624c2c66affSColin Finck  */
625c2c66affSColin Finck PVOID
626c2c66affSColin Finck NTAPI
627c2c66affSColin Finck PoRegisterSystemState(IN PVOID StateHandle,
628c2c66affSColin Finck                       IN EXECUTION_STATE Flags)
629c2c66affSColin Finck {
630c2c66affSColin Finck     UNIMPLEMENTED;
631c2c66affSColin Finck     return NULL;
632c2c66affSColin Finck }
633c2c66affSColin Finck 
634c2c66affSColin Finck /*
635c2c66affSColin Finck  * @implemented
636c2c66affSColin Finck  */
637c2c66affSColin Finck NTSTATUS
638c2c66affSColin Finck NTAPI
639c2c66affSColin Finck PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
640c2c66affSColin Finck                   IN UCHAR MinorFunction,
641c2c66affSColin Finck                   IN POWER_STATE PowerState,
642c2c66affSColin Finck                   IN PREQUEST_POWER_COMPLETE CompletionFunction,
643c2c66affSColin Finck                   IN PVOID Context,
644c2c66affSColin Finck                   OUT PIRP *pIrp OPTIONAL)
645c2c66affSColin Finck {
646c2c66affSColin Finck     PDEVICE_OBJECT TopDeviceObject;
647c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
648c2c66affSColin Finck     PIRP Irp;
649c2c66affSColin Finck 
650c2c66affSColin Finck     if (MinorFunction != IRP_MN_QUERY_POWER
651c2c66affSColin Finck         && MinorFunction != IRP_MN_SET_POWER
652c2c66affSColin Finck         && MinorFunction != IRP_MN_WAIT_WAKE)
653c2c66affSColin Finck         return STATUS_INVALID_PARAMETER_2;
654c2c66affSColin Finck 
655c2c66affSColin Finck     /* Always call the top of the device stack */
656c2c66affSColin Finck     TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
657c2c66affSColin Finck 
658c2c66affSColin Finck     Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE);
659c2c66affSColin Finck     if (!Irp)
660c2c66affSColin Finck     {
661c2c66affSColin Finck         ObDereferenceObject(TopDeviceObject);
662c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
663c2c66affSColin Finck     }
664c2c66affSColin Finck 
665c2c66affSColin Finck     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
666c2c66affSColin Finck     Irp->IoStatus.Information = 0;
667c2c66affSColin Finck 
668c2c66affSColin Finck     IoSetNextIrpStackLocation(Irp);
669c2c66affSColin Finck 
670c2c66affSColin Finck     Stack = IoGetNextIrpStackLocation(Irp);
671c2c66affSColin Finck     Stack->Parameters.Others.Argument1 = DeviceObject;
672c2c66affSColin Finck     Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction;
673c2c66affSColin Finck     Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState;
674c2c66affSColin Finck     Stack->Parameters.Others.Argument4 = Context;
675c2c66affSColin Finck     Stack->DeviceObject = TopDeviceObject;
676c2c66affSColin Finck     IoSetNextIrpStackLocation(Irp);
677c2c66affSColin Finck 
678c2c66affSColin Finck     Stack = IoGetNextIrpStackLocation(Irp);
679c2c66affSColin Finck     Stack->MajorFunction = IRP_MJ_POWER;
680c2c66affSColin Finck     Stack->MinorFunction = MinorFunction;
681c2c66affSColin Finck     if (MinorFunction == IRP_MN_WAIT_WAKE)
682c2c66affSColin Finck     {
683c2c66affSColin Finck         Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
684c2c66affSColin Finck     }
685c2c66affSColin Finck     else
686c2c66affSColin Finck     {
687c2c66affSColin Finck         Stack->Parameters.Power.Type = DevicePowerState;
688c2c66affSColin Finck         Stack->Parameters.Power.State = PowerState;
689c2c66affSColin Finck     }
690c2c66affSColin Finck 
691c2c66affSColin Finck     if (pIrp != NULL)
692c2c66affSColin Finck         *pIrp = Irp;
693c2c66affSColin Finck 
694c2c66affSColin Finck     IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE);
695c2c66affSColin Finck     PoCallDriver(TopDeviceObject, Irp);
696c2c66affSColin Finck 
697c2c66affSColin Finck     /* Always return STATUS_PENDING. The completion routine
698c2c66affSColin Finck      * will call CompletionFunction and complete the Irp.
699c2c66affSColin Finck      */
700c2c66affSColin Finck     return STATUS_PENDING;
701c2c66affSColin Finck }
702c2c66affSColin Finck 
703c2c66affSColin Finck /*
704c2c66affSColin Finck  * @unimplemented
705c2c66affSColin Finck  */
706c2c66affSColin Finck POWER_STATE
707c2c66affSColin Finck NTAPI
708c2c66affSColin Finck PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
709c2c66affSColin Finck                 IN POWER_STATE_TYPE Type,
710c2c66affSColin Finck                 IN POWER_STATE State)
711c2c66affSColin Finck {
712c2c66affSColin Finck     POWER_STATE ps;
713c2c66affSColin Finck 
714c2c66affSColin Finck     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
715c2c66affSColin Finck 
716c2c66affSColin Finck     ps.SystemState = PowerSystemWorking;  // Fully on
717c2c66affSColin Finck     ps.DeviceState = PowerDeviceD0;       // Fully on
718c2c66affSColin Finck 
719c2c66affSColin Finck     return ps;
720c2c66affSColin Finck }
721c2c66affSColin Finck 
722c2c66affSColin Finck /*
723c2c66affSColin Finck  * @unimplemented
724c2c66affSColin Finck  */
725c2c66affSColin Finck VOID
726c2c66affSColin Finck NTAPI
727c2c66affSColin Finck PoSetSystemState(IN EXECUTION_STATE Flags)
728c2c66affSColin Finck {
729c2c66affSColin Finck     UNIMPLEMENTED;
730c2c66affSColin Finck }
731c2c66affSColin Finck 
732c2c66affSColin Finck /*
733c2c66affSColin Finck  * @unimplemented
734c2c66affSColin Finck  */
735c2c66affSColin Finck VOID
736c2c66affSColin Finck NTAPI
737c2c66affSColin Finck PoStartNextPowerIrp(IN PIRP Irp)
738c2c66affSColin Finck {
7391539fb14SMark Jansen     UNIMPLEMENTED_ONCE;
740c2c66affSColin Finck }
741c2c66affSColin Finck 
742c2c66affSColin Finck /*
743c2c66affSColin Finck  * @unimplemented
744c2c66affSColin Finck  */
745c2c66affSColin Finck VOID
746c2c66affSColin Finck NTAPI
747c2c66affSColin Finck PoUnregisterSystemState(IN PVOID StateHandle)
748c2c66affSColin Finck {
749c2c66affSColin Finck     UNIMPLEMENTED;
750c2c66affSColin Finck }
751c2c66affSColin Finck 
752c2c66affSColin Finck /*
753c2c66affSColin Finck  * @unimplemented
754c2c66affSColin Finck  */
755c2c66affSColin Finck NTSTATUS
756c2c66affSColin Finck NTAPI
757c2c66affSColin Finck NtInitiatePowerAction(IN POWER_ACTION SystemAction,
758c2c66affSColin Finck                       IN SYSTEM_POWER_STATE MinSystemState,
759c2c66affSColin Finck                       IN ULONG Flags,
760c2c66affSColin Finck                       IN BOOLEAN Asynchronous)
761c2c66affSColin Finck {
762c2c66affSColin Finck     UNIMPLEMENTED;
763c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
764c2c66affSColin Finck }
765c2c66affSColin Finck 
766c2c66affSColin Finck /*
767c2c66affSColin Finck  * @unimplemented
768c2c66affSColin Finck  */
769c2c66affSColin Finck NTSTATUS
770c2c66affSColin Finck NTAPI
771c2c66affSColin Finck NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
772c2c66affSColin Finck                    IN PVOID InputBuffer  OPTIONAL,
773c2c66affSColin Finck                    IN ULONG InputBufferLength,
774c2c66affSColin Finck                    OUT PVOID OutputBuffer  OPTIONAL,
775c2c66affSColin Finck                    IN ULONG OutputBufferLength)
776c2c66affSColin Finck {
777c2c66affSColin Finck     NTSTATUS Status;
778c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
779c2c66affSColin Finck 
780c2c66affSColin Finck     PAGED_CODE();
781c2c66affSColin Finck 
782c2c66affSColin Finck     DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, "
783c2c66affSColin Finck            "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n",
784c2c66affSColin Finck            PowerInformationLevel,
785c2c66affSColin Finck            InputBuffer, InputBufferLength,
786c2c66affSColin Finck            OutputBuffer, OutputBufferLength);
787c2c66affSColin Finck 
788c2c66affSColin Finck     if (PreviousMode != KernelMode)
789c2c66affSColin Finck     {
790c2c66affSColin Finck         _SEH2_TRY
791c2c66affSColin Finck         {
792c2c66affSColin Finck             ProbeForRead(InputBuffer, InputBufferLength, 1);
793c2c66affSColin Finck             ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));
794c2c66affSColin Finck         }
795c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
796c2c66affSColin Finck         {
797c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
798c2c66affSColin Finck         }
799c2c66affSColin Finck         _SEH2_END;
800c2c66affSColin Finck     }
801c2c66affSColin Finck 
802c2c66affSColin Finck     switch (PowerInformationLevel)
803c2c66affSColin Finck     {
804c2c66affSColin Finck         case SystemBatteryState:
805c2c66affSColin Finck         {
806c2c66affSColin Finck             PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
807c2c66affSColin Finck 
808c2c66affSColin Finck             if (InputBuffer != NULL)
809c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
810c2c66affSColin Finck             if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
811c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
812c2c66affSColin Finck 
813c2c66affSColin Finck             _SEH2_TRY
814c2c66affSColin Finck             {
815c2c66affSColin Finck                 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
816c2c66affSColin Finck                 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
817cfe54aa4SEric Kohl                 BatteryState->EstimatedTime = MAXULONG;
818cfe54aa4SEric Kohl //                BatteryState->AcOnLine = TRUE;
819c2c66affSColin Finck 
820c2c66affSColin Finck                 Status = STATUS_SUCCESS;
821c2c66affSColin Finck             }
822c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
823c2c66affSColin Finck             {
824c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
825c2c66affSColin Finck             }
826c2c66affSColin Finck             _SEH2_END;
827c2c66affSColin Finck 
828c2c66affSColin Finck             break;
829c2c66affSColin Finck         }
830c2c66affSColin Finck 
831c2c66affSColin Finck         case SystemPowerCapabilities:
832c2c66affSColin Finck         {
833c2c66affSColin Finck             PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
834c2c66affSColin Finck 
835c2c66affSColin Finck             if (InputBuffer != NULL)
836c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
837c2c66affSColin Finck             if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
838c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
839c2c66affSColin Finck 
840c2c66affSColin Finck             _SEH2_TRY
841c2c66affSColin Finck             {
842626aaf22SEric Kohl                 RtlCopyMemory(PowerCapabilities,
843626aaf22SEric Kohl                               &PopCapabilities,
844626aaf22SEric Kohl                               sizeof(SYSTEM_POWER_CAPABILITIES));
845c2c66affSColin Finck 
846c2c66affSColin Finck                 Status = STATUS_SUCCESS;
847c2c66affSColin Finck             }
848c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
849c2c66affSColin Finck             {
850c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
851c2c66affSColin Finck             }
852c2c66affSColin Finck             _SEH2_END;
853c2c66affSColin Finck 
854c2c66affSColin Finck             break;
855c2c66affSColin Finck         }
856c2c66affSColin Finck 
857c2c66affSColin Finck         case ProcessorInformation:
858c2c66affSColin Finck         {
859c2c66affSColin Finck             PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer;
860c2c66affSColin Finck 
861c2c66affSColin Finck             if (InputBuffer != NULL)
862c2c66affSColin Finck                 return STATUS_INVALID_PARAMETER;
863c2c66affSColin Finck             if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION))
864c2c66affSColin Finck                 return STATUS_BUFFER_TOO_SMALL;
865c2c66affSColin Finck 
8664c78b2c3SStanislav Motylkov             /* FIXME: return structures for all processors */
8674c78b2c3SStanislav Motylkov 
868c2c66affSColin Finck             _SEH2_TRY
869c2c66affSColin Finck             {
8704c78b2c3SStanislav Motylkov                 /* FIXME: some values are hardcoded */
871c2c66affSColin Finck                 PowerInformation->Number = 0;
872c2c66affSColin Finck                 PowerInformation->MaxMhz = 1000;
8734c78b2c3SStanislav Motylkov                 PowerInformation->CurrentMhz = KeGetCurrentPrcb()->MHz;
874c2c66affSColin Finck                 PowerInformation->MhzLimit = 1000;
875c2c66affSColin Finck                 PowerInformation->MaxIdleState = 0;
876c2c66affSColin Finck                 PowerInformation->CurrentIdleState = 0;
877c2c66affSColin Finck 
878c2c66affSColin Finck                 Status = STATUS_SUCCESS;
879c2c66affSColin Finck             }
880c2c66affSColin Finck             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
881c2c66affSColin Finck             {
882c2c66affSColin Finck                 Status = _SEH2_GetExceptionCode();
883c2c66affSColin Finck             }
884c2c66affSColin Finck             _SEH2_END;
885c2c66affSColin Finck 
886c2c66affSColin Finck             break;
887c2c66affSColin Finck         }
888c2c66affSColin Finck 
889c2c66affSColin Finck         default:
890c2c66affSColin Finck             Status = STATUS_NOT_IMPLEMENTED;
891c2c66affSColin Finck             DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
892c2c66affSColin Finck                     PowerInformationLevel);
893c2c66affSColin Finck             break;
894c2c66affSColin Finck     }
895c2c66affSColin Finck 
896c2c66affSColin Finck     return Status;
897c2c66affSColin Finck }
898c2c66affSColin Finck 
899c2c66affSColin Finck NTSTATUS
900c2c66affSColin Finck NTAPI
901c2c66affSColin Finck NtGetDevicePowerState(IN HANDLE Device,
902c2c66affSColin Finck                       IN PDEVICE_POWER_STATE PowerState)
903c2c66affSColin Finck {
904c2c66affSColin Finck     UNIMPLEMENTED;
905c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
906c2c66affSColin Finck }
907c2c66affSColin Finck 
908c2c66affSColin Finck BOOLEAN
909c2c66affSColin Finck NTAPI
910c2c66affSColin Finck NtIsSystemResumeAutomatic(VOID)
911c2c66affSColin Finck {
912c2c66affSColin Finck     UNIMPLEMENTED;
913c2c66affSColin Finck     return FALSE;
914c2c66affSColin Finck }
915c2c66affSColin Finck 
916c2c66affSColin Finck NTSTATUS
917c2c66affSColin Finck NTAPI
918c2c66affSColin Finck NtRequestWakeupLatency(IN LATENCY_TIME Latency)
919c2c66affSColin Finck {
920c2c66affSColin Finck     UNIMPLEMENTED;
921c2c66affSColin Finck     return STATUS_NOT_IMPLEMENTED;
922c2c66affSColin Finck }
923c2c66affSColin Finck 
924c2c66affSColin Finck NTSTATUS
925c2c66affSColin Finck NTAPI
926c2c66affSColin Finck NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
927c2c66affSColin Finck                           OUT EXECUTION_STATE *PreviousFlags)
928c2c66affSColin Finck {
929c2c66affSColin Finck     PKTHREAD Thread = KeGetCurrentThread();
930c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
931c2c66affSColin Finck     EXECUTION_STATE PreviousState;
932c2c66affSColin Finck     PAGED_CODE();
933c2c66affSColin Finck 
934c2c66affSColin Finck     /* Validate flags */
935c2c66affSColin Finck     if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT))
936c2c66affSColin Finck     {
937c2c66affSColin Finck         /* Fail the request */
938c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
939c2c66affSColin Finck     }
940c2c66affSColin Finck 
941c2c66affSColin Finck     /* Check for user parameters */
942c2c66affSColin Finck     if (PreviousMode != KernelMode)
943c2c66affSColin Finck     {
944c2c66affSColin Finck         /* Protect the probes */
945c2c66affSColin Finck         _SEH2_TRY
946c2c66affSColin Finck         {
947c2c66affSColin Finck             /* Check if the pointer is valid */
948c2c66affSColin Finck             ProbeForWriteUlong(PreviousFlags);
949c2c66affSColin Finck         }
950c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
951c2c66affSColin Finck         {
952c2c66affSColin Finck             /* It isn't -- fail */
953c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
954c2c66affSColin Finck         }
955c2c66affSColin Finck         _SEH2_END;
956c2c66affSColin Finck     }
957c2c66affSColin Finck 
958c2c66affSColin Finck     /* Save the previous state, always masking in the continous flag */
959c2c66affSColin Finck     PreviousState = Thread->PowerState | ES_CONTINUOUS;
960c2c66affSColin Finck 
961c2c66affSColin Finck     /* Check if we need to update the power state */
962c2c66affSColin Finck     if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags;
963c2c66affSColin Finck 
964c2c66affSColin Finck     /* Protect the write back to user mode */
965c2c66affSColin Finck     _SEH2_TRY
966c2c66affSColin Finck     {
967c2c66affSColin Finck         /* Return the previous flags */
968c2c66affSColin Finck         *PreviousFlags = PreviousState;
969c2c66affSColin Finck     }
970c2c66affSColin Finck     _SEH2_EXCEPT(ExSystemExceptionFilter())
971c2c66affSColin Finck     {
972c2c66affSColin Finck         /* Something's wrong, fail */
973c2c66affSColin Finck         _SEH2_YIELD(return _SEH2_GetExceptionCode());
974c2c66affSColin Finck     }
975c2c66affSColin Finck     _SEH2_END;
976c2c66affSColin Finck 
977c2c66affSColin Finck     /* All is good */
978c2c66affSColin Finck     return STATUS_SUCCESS;
979c2c66affSColin Finck }
980c2c66affSColin Finck 
981c2c66affSColin Finck NTSTATUS
982c2c66affSColin Finck NTAPI
983c2c66affSColin Finck NtSetSystemPowerState(IN POWER_ACTION SystemAction,
984c2c66affSColin Finck                       IN SYSTEM_POWER_STATE MinSystemState,
985c2c66affSColin Finck                       IN ULONG Flags)
986c2c66affSColin Finck {
987c2c66affSColin Finck     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
988c2c66affSColin Finck     POP_POWER_ACTION Action = {0};
989c2c66affSColin Finck     NTSTATUS Status;
990c2c66affSColin Finck     ULONG Dummy;
991c2c66affSColin Finck 
992c2c66affSColin Finck     /* Check for invalid parameter combinations */
993c2c66affSColin Finck     if ((MinSystemState >= PowerSystemMaximum) ||
994c2c66affSColin Finck         (MinSystemState <= PowerSystemUnspecified) ||
995c2c66affSColin Finck         (SystemAction > PowerActionWarmEject) ||
996c2c66affSColin Finck         (SystemAction < PowerActionReserved) ||
997c2c66affSColin Finck         (Flags & ~(POWER_ACTION_QUERY_ALLOWED  |
998c2c66affSColin Finck                    POWER_ACTION_UI_ALLOWED     |
999c2c66affSColin Finck                    POWER_ACTION_OVERRIDE_APPS  |
1000c2c66affSColin Finck                    POWER_ACTION_LIGHTEST_FIRST |
1001c2c66affSColin Finck                    POWER_ACTION_LOCK_CONSOLE   |
1002c2c66affSColin Finck                    POWER_ACTION_DISABLE_WAKES  |
1003c2c66affSColin Finck                    POWER_ACTION_CRITICAL)))
1004c2c66affSColin Finck     {
1005c2c66affSColin Finck         DPRINT1("NtSetSystemPowerState: Bad parameters!\n");
1006c2c66affSColin Finck         DPRINT1("                       SystemAction: 0x%x\n", SystemAction);
1007c2c66affSColin Finck         DPRINT1("                       MinSystemState: 0x%x\n", MinSystemState);
1008c2c66affSColin Finck         DPRINT1("                       Flags: 0x%x\n", Flags);
1009c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
1010c2c66affSColin Finck     }
1011c2c66affSColin Finck 
1012c2c66affSColin Finck     /* Check for user caller */
1013c2c66affSColin Finck     if (PreviousMode != KernelMode)
1014c2c66affSColin Finck     {
1015c2c66affSColin Finck         /* Check for shutdown permission */
1016c2c66affSColin Finck         if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode))
1017c2c66affSColin Finck         {
1018c2c66affSColin Finck             /* Not granted */
1019c2c66affSColin Finck             DPRINT1("ERROR: Privilege not held for shutdown\n");
1020c2c66affSColin Finck             return STATUS_PRIVILEGE_NOT_HELD;
1021c2c66affSColin Finck         }
1022c2c66affSColin Finck 
1023c2c66affSColin Finck         /* Do it as a kernel-mode caller for consistency with system state */
1024c2c66affSColin Finck         return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags);
1025c2c66affSColin Finck     }
1026c2c66affSColin Finck 
1027c2c66affSColin Finck     /* Read policy settings (partial shutdown vs. full shutdown) */
1028c2c66affSColin Finck     if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy();
1029c2c66affSColin Finck 
1030c2c66affSColin Finck     /* Disable lazy flushing of registry */
1031c2c66affSColin Finck     DPRINT("Stopping lazy flush\n");
1032c2c66affSColin Finck     CmSetLazyFlushState(FALSE);
1033c2c66affSColin Finck 
1034c2c66affSColin Finck     /* Setup the power action */
1035c2c66affSColin Finck     Action.Action = SystemAction;
1036c2c66affSColin Finck     Action.Flags = Flags;
1037c2c66affSColin Finck 
1038c2c66affSColin Finck     /* Notify callbacks */
1039c2c66affSColin Finck     DPRINT("Notifying callbacks\n");
1040c2c66affSColin Finck     ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL);
1041c2c66affSColin Finck 
1042c2c66affSColin Finck     /* Swap in any worker thread stacks */
1043c2c66affSColin Finck     DPRINT("Swapping worker threads\n");
1044c2c66affSColin Finck     ExSwapinWorkerThreads(FALSE);
1045c2c66affSColin Finck 
1046c2c66affSColin Finck     /* Make our action global */
1047c2c66affSColin Finck     PopAction = Action;
1048c2c66affSColin Finck 
1049c2c66affSColin Finck     /* Start power loop */
1050c2c66affSColin Finck     Status = STATUS_CANCELLED;
1051c2c66affSColin Finck     while (TRUE)
1052c2c66affSColin Finck     {
1053c2c66affSColin Finck         /* Break out if there's nothing to do */
1054c2c66affSColin Finck         if (Action.Action == PowerActionNone) break;
1055c2c66affSColin Finck 
1056c2c66affSColin Finck         /* Check for first-pass or restart */
1057c2c66affSColin Finck         if (Status == STATUS_CANCELLED)
1058c2c66affSColin Finck         {
1059c2c66affSColin Finck             /* Check for shutdown action */
1060c2c66affSColin Finck             if ((PopAction.Action == PowerActionShutdown) ||
1061c2c66affSColin Finck                 (PopAction.Action == PowerActionShutdownReset) ||
1062c2c66affSColin Finck                 (PopAction.Action == PowerActionShutdownOff))
1063c2c66affSColin Finck             {
1064c2c66affSColin Finck                 /* Set the action */
1065c2c66affSColin Finck                 PopAction.Shutdown = TRUE;
1066c2c66affSColin Finck             }
1067c2c66affSColin Finck 
1068c2c66affSColin Finck             /* Now we are good to go */
1069c2c66affSColin Finck             Status = STATUS_SUCCESS;
1070c2c66affSColin Finck         }
1071c2c66affSColin Finck 
1072c2c66affSColin Finck         /* Check if we're still in an invalid status */
1073c2c66affSColin Finck         if (!NT_SUCCESS(Status)) break;
1074c2c66affSColin Finck 
1075c2c66affSColin Finck #ifndef NEWCC
1076c2c66affSColin Finck         /* Flush dirty cache pages */
1077c7ad200fSPierre Schweitzer         /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */
1078c7ad200fSPierre Schweitzer         CcRosFlushDirtyPages(-1, &Dummy, FALSE, FALSE); //HACK: We really should wait here!
1079c2c66affSColin Finck #else
1080c2c66affSColin Finck         Dummy = 0;
1081c2c66affSColin Finck #endif
1082c2c66affSColin Finck 
1083c2c66affSColin Finck         /* Flush all volumes and the registry */
1084c2c66affSColin Finck         DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy);
1085c2c66affSColin Finck         PopFlushVolumes(PopAction.Shutdown);
1086c2c66affSColin Finck 
1087c2c66affSColin Finck         /* Set IRP for drivers */
1088c2c66affSColin Finck         PopAction.IrpMinor = IRP_MN_SET_POWER;
1089c2c66affSColin Finck         if (PopAction.Shutdown)
1090c2c66affSColin Finck         {
1091c2c66affSColin Finck             DPRINT("Queueing shutdown thread\n");
1092c2c66affSColin Finck             /* Check if we are running in the system context */
1093c2c66affSColin Finck             if (PsGetCurrentProcess() != PsInitialSystemProcess)
1094c2c66affSColin Finck             {
1095c2c66affSColin Finck                 /* We're not, so use a worker thread for shutdown */
1096c2c66affSColin Finck                 ExInitializeWorkItem(&PopShutdownWorkItem,
1097c2c66affSColin Finck                                      &PopGracefulShutdown,
1098c2c66affSColin Finck                                      NULL);
1099c2c66affSColin Finck 
1100c2c66affSColin Finck                 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue);
1101c2c66affSColin Finck 
1102c2c66affSColin Finck                 /* Spend us -- when we wake up, the system is good to go down */
1103c2c66affSColin Finck                 KeSuspendThread(KeGetCurrentThread());
1104c2c66affSColin Finck                 Status = STATUS_SYSTEM_SHUTDOWN;
1105c2c66affSColin Finck                 goto Exit;
1106c2c66affSColin Finck 
1107c2c66affSColin Finck             }
1108c2c66affSColin Finck             else
1109c2c66affSColin Finck             {
1110c2c66affSColin Finck                 /* Do the shutdown inline */
1111c2c66affSColin Finck                 PopGracefulShutdown(NULL);
1112c2c66affSColin Finck             }
1113c2c66affSColin Finck         }
1114c2c66affSColin Finck 
1115c2c66affSColin Finck         /* You should not have made it this far */
11167d6bda16SSerge Gautherie         // ASSERTMSG("System is still up and running?!\n", FALSE);
1117c2c66affSColin Finck         DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action);
1118c2c66affSColin Finck         break;
1119c2c66affSColin Finck     }
1120c2c66affSColin Finck 
1121c2c66affSColin Finck Exit:
1122c2c66affSColin Finck     /* We're done, return */
1123c2c66affSColin Finck     return Status;
1124c2c66affSColin Finck }
1125