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