📄 power.c
字号:
PIrp->IoStatus.Status = status;
PoStartNextPowerIrp(PIrp);
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
return status;
}
}
}
break;
}
case DevicePowerState:
SerialDbgPrintEx(SERPNPPOWER, "DevicePowerState\n");
break;
default:
SerialDbgPrintEx(SERPNPPOWER, "UNKNOWN PowerState\n");
status = STATUS_SUCCESS;
goto PowerExit;
}
//
// If we are already in the requested state, just pass the IRP down
//
if (pDevExt->PowerState
== pIrpStack->Parameters.Power.State.DeviceState) {
SerialDbgPrintEx(SERPNPPOWER, "Already in requested power state\n");
status = STATUS_SUCCESS;
break;
}
switch (pIrpStack->Parameters.Power.State.DeviceState) {
case PowerDeviceD0:
SerialDbgPrintEx(SERPNPPOWER, "Going to power state D0\n");
return SerialSetPowerD0(PDevObj, PIrp);
case PowerDeviceD1:
case PowerDeviceD2:
case PowerDeviceD3:
SerialDbgPrintEx(SERPNPPOWER, "Going to power state D3\n");
return SerialSetPowerD3(PDevObj, PIrp);
default:
break;
}
break;
case IRP_MN_QUERY_POWER:
SerialDbgPrintEx (SERPNPPOWER, "Got IRP_MN_QUERY_POWER Irp\n");
//
// Check if we have a wait-wake pending and if so,
// ensure we don't power down too far.
//
if (pDevExt->PendingWakeIrp != NULL || pDevExt->SendWaitWake) {
if (pIrpStack->Parameters.Power.Type == DevicePowerState
&& pIrpStack->Parameters.Power.State.DeviceState
> pDevExt->DeviceWake) {
status = PIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
PoStartNextPowerIrp(PIrp);
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
return status;
}
}
//
// If no wait-wake, always successful
//
PIrp->IoStatus.Status = STATUS_SUCCESS;
status = STATUS_SUCCESS;
PoStartNextPowerIrp(PIrp);
IoSkipCurrentIrpStackLocation(PIrp);
return SerialPoCallDriver(pDevExt, pLowerDevObj, PIrp);
} // switch (pIrpStack->MinorFunction)
PowerExit:;
PoStartNextPowerIrp(PIrp);
//
// Pass to the lower driver
//
IoSkipCurrentIrpStackLocation(PIrp);
status = SerialPoCallDriver(pDevExt, pLowerDevObj, PIrp);
return status;
}
NTSTATUS
SerialSetPowerD0(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This routine Decides if we need to pass the power Irp down the stack
or not. It then either sets up a completion handler to finish the
initialization or calls the completion handler directly.
Arguments:
PDevObj - Pointer to the devobj we are changing power state on
PIrp - Pointer to the IRP for the current request
Return Value:
Return status of either PoCallDriver of the call to the initialization
routine.
--*/
{
PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
NTSTATUS status;
// PIO_WORKITEM pWorkItem;
PAGED_CODE();
SerialDbgPrintEx(SERTRACECALLS, "In SerialSetPowerD0\n");
SerialDbgPrintEx(SERPNPPOWER, "SetPowerD0 has IRP %x\n", PIrp);
ASSERT(pDevExt->LowerDeviceObject);
//
// Set up completion to init device when it is on
//
KeClearEvent(&pDevExt->PowerD0Event);
IoCopyCurrentIrpStackLocationToNext(PIrp);
IoSetCompletionRoutine(PIrp, SerialSyncCompletion, &pDevExt->PowerD0Event,
TRUE, TRUE, TRUE);
SerialDbgPrintEx(SERPNPPOWER, "Calling next driver\n");
status = PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
if (status == STATUS_PENDING) {
SerialDbgPrintEx(SERPNPPOWER, "Waiting for next driver\n");
KeWaitForSingleObject (&pDevExt->PowerD0Event, Executive, KernelMode,
FALSE, NULL);
} else {
if (!NT_SUCCESS(status)) {
PIrp->IoStatus.Status = status;
PoStartNextPowerIrp(PIrp);
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
// SerialClearAccept(pDevExt,SERIAL_PNPACCEPT_POWER_DOWN);
return status;
}
}
if (!NT_SUCCESS(PIrp->IoStatus.Status)) {
status = PIrp->IoStatus.Status;
PoStartNextPowerIrp(PIrp);
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
// SerialClearAccept(pDevExt, SERIAL_PNPACCEPT_POWER_DOWN);
return status;
}
else
{
status = PIrp->IoStatus.Status;
}
//
// Restore the device
//
pDevExt->PowerState = PowerDeviceD0;
//
// Theoretically we could change states in the middle of processing
// the restore which would result in a bad PKINTERRUPT being used
// in SerialRestoreDeviceState().
//
if (pDevExt->PNPState == SERIAL_PNP_STARTED) {
SerialRestoreDeviceState(pDevExt);
}
//
// Now that we are powered up, call PoSetPowerState
//
PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
pIrpStack->Parameters.Power.State);
PoStartNextPowerIrp(PIrp);
SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
// pWorkItem = IoAllocateWorkItem(PDevObj);
// IoQueueWorkItem(pWorkItem, SerialPowerD0WorkerRoutine, DelayedWorkQueue, pWorkItem);
SerialDbgPrintEx(SERTRACECALLS, "Leaving SerialSetPowerD0\n");
return status;
}
/*VOID
SerialPowerD0WorkerRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID pWorkItem)
{
PSERIAL_DEVICE_EXTENSION pDevExt = DeviceObject->DeviceExtension;
SerialUnstallIrps(pDevExt);
SerialClearAccept(pDevExt, SERIAL_PNPACCEPT_POWER_DOWN);
IoFreeWorkItem(pWorkItem);
} */
NTSTATUS
SerialGotoPowerState(IN PDEVICE_OBJECT PDevObj,
IN PSERIAL_DEVICE_EXTENSION PDevExt,
IN DEVICE_POWER_STATE DevPowerState)
/*++
Routine Description:
This routine causes the driver to request the stack go to a particular
power state.
Arguments:
PDevObj - Pointer to the device object for this device
PDevExt - Pointer to the device extension we are working from
DevPowerState - the power state we wish to go to
Return Value:
The function value is the final status of the call
--*/
{
KEVENT gotoPowEvent;
NTSTATUS status;
POWER_STATE powerState;
PAGED_CODE();
SerialDbgPrintEx(SERTRACECALLS, "In SerialGotoPowerState\n");
powerState.DeviceState = DevPowerState;
KeInitializeEvent(&gotoPowEvent, SynchronizationEvent, FALSE);
status = PoRequestPowerIrp(PDevObj, IRP_MN_SET_POWER, powerState,
SerialSystemPowerCompletion, &gotoPowEvent,
NULL);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&gotoPowEvent, Executive, KernelMode, FALSE, NULL);
status = STATUS_SUCCESS;
}
#if DBG
if (!NT_SUCCESS(status)) {
SerialDbgPrintEx(SERPNPPOWER, "SerialGotoPowerState FAILED\n");
}
#endif
SerialDbgPrintEx(SERTRACECALLS, "Leaving SerialGotoPowerState\n");
return status;
}
NTSTATUS
SerialSetPowerD3(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This routine handles the SET_POWER minor function.
Arguments:
PDevObj - Pointer to the device object for this device
PIrp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
KIRQL oldIrql;
PAGED_CODE();
SerialDbgPrintEx(SERDIAG3, "In SerialSetPowerD3\n");
// SerialSetAccept(pDevExt,SERIAL_PNPACCEPT_POWER_DOWN);
//
// Send the wait wake now, just in time
//
if (pDevExt->SendWaitWake) {
SerialSendWaitWake(pDevExt);
}
//
// Before we power down, call PoSetPowerState
//
PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
pIrpStack->Parameters.Power.State);
//
// If the device is not closed, disable interrupts and allow the fifo's
// to flush.
//
if (pDevExt->DeviceIsOpened == TRUE) {
LARGE_INTEGER charTime;
SetDeviceIsOpened(pDevExt, FALSE, TRUE);
charTime.QuadPart = -SerialGetCharTime(pDevExt).QuadPart;
//
// Shut down the chip
//
SerialDisableUART(pDevExt);
//
// Drain the device
//
SerialDrainUART(pDevExt, &charTime);
//
// Save the device state
//
SerialSaveDeviceState(pDevExt);
}
else
{
SetDeviceIsOpened(pDevExt, FALSE, FALSE);
}
//
// If the device is not open, we don't need to save the state;
// we can just reset the device on power-up
//
PIrp->IoStatus.Status = STATUS_SUCCESS;
pDevExt->PowerState = PowerDeviceD3;
//
// For what we are doing, we don't need a completion routine
// since we don't race on the power requests.
//
PIrp->IoStatus.Status = STATUS_SUCCESS;
PoStartNextPowerIrp(PIrp);
IoSkipCurrentIrpStackLocation(PIrp);
return SerialPoCallDriver(pDevExt, pDevExt->LowerDeviceObject, PIrp);
}
NTSTATUS
SerialSendWaitWake(PSERIAL_DEVICE_EXTENSION PDevExt)
/*++
Routine Description:
This routine causes a waitwake IRP to be sent
Arguments:
PDevExt - Pointer to the device extension for this device
Return Value:
STATUS_INVALID_DEVICE_STATE if one is already pending, else result
of call to PoRequestPowerIrp.
--*/
{
NTSTATUS status;
PIRP pIrp;
POWER_STATE powerState;
PAGED_CODE();
//
// Make sure one isn't pending already -- serial will only handle one at
// a time.
//
if (PDevExt->PendingWakeIrp != NULL) {
return STATUS_INVALID_DEVICE_STATE;
}
//
// Make sure we are capable of waking the machine
//
if (PDevExt->SystemWake <= PowerSystemWorking) {
return STATUS_INVALID_DEVICE_STATE;
}
if (PDevExt->DeviceWake == PowerDeviceUnspecified) {
return STATUS_INVALID_DEVICE_STATE;
}
//
// Send IRP to request wait wake and add a pending irp flag
//
//
InterlockedIncrement(&PDevExt->PendingIRPCnt);
powerState.SystemState = PDevExt->SystemWake;
status = PoRequestPowerIrp(PDevExt->Pdo, IRP_MN_WAIT_WAKE,
powerState, SerialWakeCompletion, PDevExt, &pIrp);
if (status == STATUS_PENDING) {
status = STATUS_SUCCESS;
PDevExt->PendingWakeIrp = pIrp;
} else if (!NT_SUCCESS(status)) {
SerialIRPEpilogue(PDevExt);
}
return status;
}
VOID
SerialWakeCompletion(IN PDEVICE_OBJECT PDevObj, IN UCHAR MinorFunction,
IN POWER_STATE PowerState, IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus)
/*++
Routine Description:
This routine handles completion of the waitwake IRP.
Arguments:
PDevObj - Pointer to the device object for this device
MinorFunction - Minor function previously supplied to PoRequestPowerIrp
PowerState - PowerState previously supplied to PoRequestPowerIrp
Context - a pointer to the device extension
IoStatus - current/final status of the waitwake IRP
Return Value:
The function value is the final status of attempting to process the
waitwake.
--*/
{
NTSTATUS status;
PSERIAL_DEVICE_EXTENSION pDevExt = (PSERIAL_DEVICE_EXTENSION)Context;
POWER_STATE powerState;
status = IoStatus->Status;
if (NT_SUCCESS(status)) {
//
// A wakeup has occurred -- powerup our stack
//
powerState.DeviceState = PowerDeviceD0;
PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_SET_POWER, powerState, NULL,
NULL, NULL);
}
pDevExt->PendingWakeIrp = NULL;
SerialIRPEpilogue(pDevExt);
return;
}
VOID
SetDeviceIsOpened(IN PSERIAL_DEVICE_EXTENSION PDevExt, IN BOOLEAN DeviceIsOpened, IN BOOLEAN Reopen)
{
KIRQL oldIrql;
BOOLEAN currentState;
KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
PDevExt->DeviceIsOpened = DeviceIsOpened;
PDevExt->DeviceState.Reopen = Reopen;
KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -