- Get rid of ASSERT_IRQL, deprecated since long ago
[reactos.git] / reactos / ntoskrnl / po / power.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/po/power.c
5 * PURPOSE: Power Manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 extern ULONG ExpInitialiationPhase;
19
20 typedef struct _REQUEST_POWER_ITEM
21 {
22 PREQUEST_POWER_COMPLETE CompletionRoutine;
23 POWER_STATE PowerState;
24 PVOID Context;
25 } REQUEST_POWER_ITEM, *PREQUEST_POWER_ITEM;
26
27 PDEVICE_NODE PopSystemPowerDeviceNode = NULL;
28 BOOLEAN PopAcpiPresent = FALSE;
29
30 /* PRIVATE FUNCTIONS *********************************************************/
31
32 static
33 NTSTATUS
34 NTAPI
35 PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject,
36 IN PIRP Irp,
37 IN PVOID Context)
38 {
39 PIO_STACK_LOCATION Stack;
40 PREQUEST_POWER_ITEM RequestPowerItem;
41
42 Stack = IoGetNextIrpStackLocation(Irp);
43 RequestPowerItem = (PREQUEST_POWER_ITEM)Context;
44
45 RequestPowerItem->CompletionRoutine(DeviceObject,
46 Stack->MinorFunction,
47 RequestPowerItem->PowerState,
48 RequestPowerItem->Context,
49 &Irp->IoStatus);
50
51 ExFreePool(&Irp->IoStatus);
52 ExFreePool(Context);
53
54 return STATUS_SUCCESS;
55 }
56
57 VOID
58 NTAPI
59 PopCleanupPowerState(IN PPOWER_STATE PowerState)
60 {
61 //UNIMPLEMENTED;
62 }
63
64 NTSTATUS
65 NTAPI
66 PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState)
67 {
68 IO_STATUS_BLOCK IoStatusBlock;
69 PDEVICE_OBJECT DeviceObject;
70 PIO_STACK_LOCATION IrpSp;
71 PDEVICE_OBJECT Fdo;
72 NTSTATUS Status;
73 KEVENT Event;
74 PIRP Irp;
75
76 if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED;
77
78 Status = IopGetSystemPowerDeviceObject(&DeviceObject);
79 if (!NT_SUCCESS(Status))
80 {
81 DPRINT1("No system power driver available\n");
82 return STATUS_UNSUCCESSFUL;
83 }
84
85 Fdo = IoGetAttachedDeviceReference(DeviceObject);
86
87 if (Fdo == DeviceObject)
88 {
89 DPRINT("An FDO was not attached\n");
90 return STATUS_UNSUCCESSFUL;
91 }
92
93 KeInitializeEvent(&Event,
94 NotificationEvent,
95 FALSE);
96
97 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER,
98 Fdo,
99 NULL,
100 0,
101 NULL,
102 &Event,
103 &IoStatusBlock);
104
105 IrpSp = IoGetNextIrpStackLocation(Irp);
106 IrpSp->MinorFunction = IRP_MN_SET_POWER;
107 IrpSp->Parameters.Power.Type = SystemPowerState;
108 IrpSp->Parameters.Power.State.SystemState = PowerState;
109
110 DPRINT("Calling ACPI driver");
111 Status = PoCallDriver(Fdo, Irp);
112 if (Status == STATUS_PENDING)
113 {
114 KeWaitForSingleObject(&Event,
115 Executive,
116 KernelMode,
117 FALSE,
118 NULL);
119 Status = IoStatusBlock.Status;
120 }
121
122 ObDereferenceObject(Fdo);
123
124 return Status;
125 }
126
127 BOOLEAN
128 NTAPI
129 PoInitSystem(IN ULONG BootPhase,
130 IN BOOLEAN HaveAcpiTable)
131 {
132 PVOID NotificationEntry;
133 PCHAR CommandLine;
134 BOOLEAN ForceAcpiDisable = FALSE;
135
136 /* Check if this is phase 1 init */
137 if (BootPhase == 1)
138 {
139 /* Registry power button notification */
140 IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
141 0, /* The registry has not been initialized yet */
142 (PVOID)&GUID_DEVICE_SYS_BUTTON,
143 IopRootDeviceNode->
144 PhysicalDeviceObject->DriverObject,
145 PopAddRemoveSysCapsCallback,
146 NULL,
147 &NotificationEntry);
148 return TRUE;
149 }
150
151 /* Get the Command Line */
152 CommandLine = KeLoaderBlock->LoadOptions;
153
154 /* Upcase it */
155 _strupr(CommandLine);
156
157 /* Check for ACPI disable */
158 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE;
159
160 if (ForceAcpiDisable)
161 {
162 /* Set the ACPI State to False if it's been forced that way */
163 PopAcpiPresent = FALSE;
164 }
165 else
166 {
167 /* Otherwise check the LoaderBlock's Flag */
168 PopAcpiPresent = HaveAcpiTable;
169 }
170
171 return TRUE;
172 }
173
174 VOID
175 NTAPI
176 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState)
177 {
178 DPRINT1("PerfIdle function: %p\n", PowerState);
179 }
180
181 VOID
182 NTAPI
183 PopPerfIdleDpc(IN PKDPC Dpc,
184 IN PVOID DeferredContext,
185 IN PVOID SystemArgument1,
186 IN PVOID SystemArgument2)
187 {
188 /* Call the Perf Idle function */
189 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState);
190 }
191
192 VOID
193 FASTCALL
194 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState)
195 {
196 /* FIXME: Extremly naive implementation */
197 HalProcessorIdle();
198 }
199
200 VOID
201 NTAPI
202 PoInitializePrcb(IN PKPRCB Prcb)
203 {
204 /* Initialize the Power State */
205 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
206 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF;
207 Prcb->PowerState.CurrentThrottle = 100;
208 Prcb->PowerState.CurrentThrottleIndex = 0;
209 Prcb->PowerState.IdleFunction = PopIdle0;
210
211 /* Initialize the Perf DPC and Timer */
212 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb);
213 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number);
214 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer);
215 }
216
217 /* PUBLIC FUNCTIONS **********************************************************/
218
219 /*
220 * @implemented
221 */
222 NTSTATUS
223 NTAPI
224 PoCallDriver(IN PDEVICE_OBJECT DeviceObject,
225 IN OUT PIRP Irp)
226 {
227 NTSTATUS Status;
228
229 /* Forward to Io -- FIXME! */
230 Status = IoCallDriver(DeviceObject, Irp);
231
232 /* Return status */
233 return Status;
234 }
235
236 /*
237 * @unimplemented
238 */
239 PULONG
240 NTAPI
241 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject,
242 IN ULONG ConservationIdleTime,
243 IN ULONG PerformanceIdleTime,
244 IN DEVICE_POWER_STATE State)
245 {
246 UNIMPLEMENTED;
247 return NULL;
248 }
249
250 /*
251 * @unimplemented
252 */
253 PVOID
254 NTAPI
255 PoRegisterSystemState(IN PVOID StateHandle,
256 IN EXECUTION_STATE Flags)
257 {
258 UNIMPLEMENTED;
259 return NULL;
260 }
261
262 /*
263 * @implemented
264 */
265 NTSTATUS
266 NTAPI
267 PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject,
268 IN UCHAR MinorFunction,
269 IN POWER_STATE PowerState,
270 IN PREQUEST_POWER_COMPLETE CompletionFunction,
271 IN PVOID Context,
272 OUT PIRP *pIrp OPTIONAL)
273 {
274 PDEVICE_OBJECT TopDeviceObject;
275 PIO_STACK_LOCATION Stack;
276 PIRP Irp;
277 PIO_STATUS_BLOCK IoStatusBlock;
278 PREQUEST_POWER_ITEM RequestPowerItem;
279 NTSTATUS Status;
280
281 if (MinorFunction != IRP_MN_QUERY_POWER
282 && MinorFunction != IRP_MN_SET_POWER
283 && MinorFunction != IRP_MN_WAIT_WAKE)
284 return STATUS_INVALID_PARAMETER_2;
285
286 RequestPowerItem = ExAllocatePool(NonPagedPool, sizeof(REQUEST_POWER_ITEM));
287 if (!RequestPowerItem)
288 return STATUS_INSUFFICIENT_RESOURCES;
289 IoStatusBlock = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
290 if (!IoStatusBlock)
291 {
292 ExFreePool(RequestPowerItem);
293 return STATUS_INSUFFICIENT_RESOURCES;
294 }
295
296 /* Always call the top of the device stack */
297 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
298
299 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
300 TopDeviceObject,
301 NULL,
302 0,
303 NULL,
304 NULL,
305 IoStatusBlock);
306 if (!Irp)
307 {
308 ExFreePool(RequestPowerItem);
309 ExFreePool(IoStatusBlock);
310 return STATUS_INSUFFICIENT_RESOURCES;
311 }
312
313 /* POWER IRPs are always initialized with a status code of
314 STATUS_NOT_IMPLEMENTED */
315 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
316 Irp->IoStatus.Information = 0;
317
318 Stack = IoGetNextIrpStackLocation(Irp);
319 Stack->MinorFunction = MinorFunction;
320 if (MinorFunction == IRP_MN_WAIT_WAKE)
321 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState;
322 else
323 Stack->Parameters.WaitWake.PowerState = PowerState.DeviceState;
324
325 RequestPowerItem->CompletionRoutine = CompletionFunction;
326 RequestPowerItem->PowerState = PowerState;
327 RequestPowerItem->Context = Context;
328
329 if (pIrp != NULL)
330 *pIrp = Irp;
331
332 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, RequestPowerItem, TRUE, TRUE, TRUE);
333 Status = IoCallDriver(TopDeviceObject, Irp);
334
335 /* Always return STATUS_PENDING. The completion routine
336 * will call CompletionFunction and complete the Irp.
337 */
338 return STATUS_PENDING;
339 }
340
341 /*
342 * @unimplemented
343 */
344 POWER_STATE
345 NTAPI
346 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject,
347 IN POWER_STATE_TYPE Type,
348 IN POWER_STATE State)
349 {
350 POWER_STATE ps;
351
352 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
353
354 ps.SystemState = PowerSystemWorking; // Fully on
355 ps.DeviceState = PowerDeviceD0; // Fully on
356
357 return ps;
358 }
359
360 /*
361 * @unimplemented
362 */
363 VOID
364 NTAPI
365 PoSetSystemState(IN EXECUTION_STATE Flags)
366 {
367 UNIMPLEMENTED;
368 }
369
370 /*
371 * @unimplemented
372 */
373 VOID
374 NTAPI
375 PoStartNextPowerIrp(IN PIRP Irp)
376 {
377 UNIMPLEMENTED;
378 }
379
380 /*
381 * @unimplemented
382 */
383 VOID
384 NTAPI
385 PoUnregisterSystemState(IN PVOID StateHandle)
386 {
387 UNIMPLEMENTED;
388 }
389
390 /*
391 * @unimplemented
392 */
393 NTSTATUS
394 NTAPI
395 PoQueueShutdownWorkItem(IN PWORK_QUEUE_ITEM WorkItem)
396 {
397 PAGED_CODE();
398
399 UNIMPLEMENTED;
400 return STATUS_NOT_IMPLEMENTED;
401 }
402
403 /*
404 * @unimplemented
405 */
406 NTSTATUS
407 NTAPI
408 NtInitiatePowerAction (IN POWER_ACTION SystemAction,
409 IN SYSTEM_POWER_STATE MinSystemState,
410 IN ULONG Flags,
411 IN BOOLEAN Asynchronous)
412 {
413 UNIMPLEMENTED;
414 return STATUS_NOT_IMPLEMENTED;
415 }
416
417 /*
418 * @unimplemented
419 */
420 NTSTATUS
421 NTAPI
422 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
423 IN PVOID InputBuffer OPTIONAL,
424 IN ULONG InputBufferLength,
425 OUT PVOID OutputBuffer OPTIONAL,
426 IN ULONG OutputBufferLength)
427 {
428 NTSTATUS Status;
429
430 PAGED_CODE();
431
432 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%x, "
433 "InputBufferLength 0x%x, OutputBuffer 0x%x, OutputBufferLength 0x%x)\n",
434 PowerInformationLevel,
435 InputBuffer, InputBufferLength,
436 OutputBuffer, OutputBufferLength);
437
438 switch (PowerInformationLevel)
439 {
440 case SystemBatteryState:
441 {
442 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
443
444 if (InputBuffer != NULL)
445 return STATUS_INVALID_PARAMETER;
446 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
447 return STATUS_BUFFER_TOO_SMALL;
448
449 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
450 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE));
451 BatteryState->EstimatedTime = (ULONG)-1;
452
453 Status = STATUS_SUCCESS;
454 break;
455 }
456 case SystemPowerCapabilities:
457 {
458 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer;
459
460 if (InputBuffer != NULL)
461 return STATUS_INVALID_PARAMETER;
462 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES))
463 return STATUS_BUFFER_TOO_SMALL;
464
465 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */
466 RtlZeroMemory(PowerCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
467 //PowerCapabilities->SystemBatteriesPresent = 0;
468
469 Status = STATUS_SUCCESS;
470 break;
471 }
472
473 default:
474 Status = STATUS_NOT_IMPLEMENTED;
475 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n",
476 PowerInformationLevel);
477 break;
478 }
479
480 return Status;
481 }
482
483 NTSTATUS
484 NTAPI
485 NtGetDevicePowerState(IN HANDLE Device,
486 IN PDEVICE_POWER_STATE PowerState)
487 {
488 UNIMPLEMENTED;
489 return STATUS_NOT_IMPLEMENTED;
490 }
491
492 BOOLEAN
493 NTAPI
494 NtIsSystemResumeAutomatic(VOID)
495 {
496 UNIMPLEMENTED;
497 return FALSE;
498 }
499
500 NTSTATUS
501 NTAPI
502 NtRequestWakeupLatency(IN LATENCY_TIME Latency)
503 {
504 UNIMPLEMENTED;
505 return STATUS_NOT_IMPLEMENTED;
506 }
507
508 NTSTATUS
509 NTAPI
510 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags,
511 OUT EXECUTION_STATE *PreviousFlags)
512 {
513 UNIMPLEMENTED;
514 return STATUS_NOT_IMPLEMENTED;
515 }