You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
908 lines
22 KiB
908 lines
22 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
power.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that handles the power IRPs for the serial
|
|
driver.
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
//#pragma alloc_text(PAGEMX0, MoxaGotoPowerState)
|
|
//#pragma alloc_text(PAGEMX0, MoxaPowerDispatch)
|
|
//#pragma alloc_text(PAGEMX0, MoxaSetPowerD0)
|
|
//#pragma alloc_text(PAGEMX0, MoxaSetPowerD3)
|
|
//#pragma alloc_text(PAGEMX0, MoxaSaveDeviceState)
|
|
//#pragma alloc_text(PAGEMX0, MoxaRestoreDeviceState)
|
|
//#pragma alloc_text(PAGEMX0, MoxaSendWaitWake)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaSystemPowerCompletion(IN PDEVICE_OBJECT PDevObj, UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState, IN PVOID Context,
|
|
PIO_STATUS_BLOCK IoStatus)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the completion routine for PoRequestPowerIrp calls
|
|
in this module.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object the irp is completing for
|
|
|
|
MinorFunction - IRP_MN_XXXX value requested
|
|
|
|
PowerState - Power state request was made of
|
|
|
|
Context - Event to set or NULL if no setting required
|
|
|
|
IoStatus - Status block from request
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
|
|
--*/
|
|
{
|
|
if (Context != NULL) {
|
|
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, 0);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MoxaSaveDeviceState(IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine saves the device state of the UART
|
|
|
|
Arguments:
|
|
|
|
PDevExt - Pointer to the device extension for the devobj to save the state
|
|
for.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_STATE pDevState = &PDevExt->DeviceState;
|
|
KIRQL oldIrql;
|
|
|
|
// PAGED_CODE();
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Entering MoxaSaveDeviceState\n"));
|
|
|
|
|
|
MoxaKillAllReadsOrWrites(
|
|
PDevExt->DeviceObject,
|
|
&PDevExt->WriteQueue,
|
|
&PDevExt->CurrentWriteIrp
|
|
);
|
|
|
|
MoxaKillAllReadsOrWrites(
|
|
PDevExt->DeviceObject,
|
|
&PDevExt->ReadQueue,
|
|
&PDevExt->CurrentReadIrp
|
|
);
|
|
|
|
//
|
|
// Clean out the Tx/Rx queue
|
|
//
|
|
KeAcquireSpinLock(
|
|
&PDevExt->ControlLock,
|
|
&oldIrql
|
|
);
|
|
|
|
PDevExt->TotalCharsQueued = 0;
|
|
|
|
MoxaFunc( // flush input/output queue
|
|
PDevExt->PortOfs,
|
|
FC_FlushQueue,
|
|
2
|
|
);
|
|
|
|
KeReleaseSpinLock(
|
|
&PDevExt->ControlLock,
|
|
oldIrql
|
|
);
|
|
|
|
//
|
|
// Read necessary registers direct
|
|
//
|
|
|
|
pDevState->HostState = *(PUSHORT)(PDevExt->PortOfs + HostStat);
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Leaving MoxaSaveDeviceState\n"));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
MoxaRestoreDeviceState(IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine restores the device state of the UART
|
|
|
|
Arguments:
|
|
|
|
PDevExt - Pointer to the device extension for the devobj to restore the
|
|
state for.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_STATE pDevState = &PDevExt->DeviceState;
|
|
SHORT divisor;
|
|
USHORT max;
|
|
|
|
|
|
|
|
// PAGED_CODE();
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Enter MoxaRestoreDeviceState\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------ PDevExt: %x\n", PDevExt));
|
|
|
|
if (PDevExt->DeviceState.Reopen == TRUE) {
|
|
|
|
USHORT arg,i;
|
|
|
|
//MoxaFunc1(PDevExt->PortOfs, FC_ChannelReset, Magic_code);
|
|
//
|
|
// Restore Host Stat
|
|
//
|
|
|
|
*(PUSHORT)(PDevExt->PortOfs + HostStat) = pDevState->HostState;
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetDataMode, PDevExt->DataMode);
|
|
|
|
MoxaGetDivisorFromBaud(
|
|
PDevExt->ClockType,
|
|
PDevExt->CurrentBaud,
|
|
&divisor
|
|
);
|
|
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetBaud, divisor);
|
|
|
|
*(PUSHORT)(PDevExt->PortOfs+ Tx_trigger) = (USHORT)MoxaTxLowWater;
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetTxFIFOCnt, PDevExt->TxFifoAmount);
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetRxFIFOTrig,PDevExt->RxFifoTrigger);
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetLineIrq,Magic_code);
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetXoffLimit, (USHORT)PDevExt->HandFlow.XoffLimit);
|
|
MoxaFunc1(PDevExt->PortOfs, FC_SetFlowRepl, (USHORT)PDevExt->HandFlow.FlowReplace);
|
|
|
|
|
|
arg = (MoxaFlagBit[PDevExt->PortNo] & 3);
|
|
MoxaFunc1(
|
|
PDevExt->PortOfs,
|
|
FC_LineControl,
|
|
arg
|
|
);
|
|
|
|
for (i=0; i<sizeof(SERIAL_CHARS); i++)
|
|
(PDevExt->PortOfs + FuncArg)[i] = ((PUCHAR)&PDevExt->SpecialChars)[i];
|
|
*(PDevExt->PortOfs + FuncCode) = FC_SetChars;
|
|
MoxaWaitFinish1(PDevExt->PortOfs);
|
|
|
|
PDevExt->ModemStatus = *(PUSHORT)(PDevExt->PortOfs + FlagStat) >> 4;
|
|
|
|
if (PDevExt->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
arg = CTS_FlowCtl;
|
|
|
|
if (PDevExt->HandFlow.FlowReplace & SERIAL_RTS_HANDSHAKE)
|
|
arg |= RTS_FlowCtl;
|
|
|
|
if (PDevExt->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
arg |= Tx_FlowCtl;
|
|
|
|
if (PDevExt->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
|
|
arg |= Rx_FlowCtl;
|
|
|
|
MoxaFunc1(PDevExt->PortOfs,FC_SetFlowCtl, arg);
|
|
if (MoxaFlagBit[PDevExt->PortNo] & 4)
|
|
MoxaFunc1(PDevExt->PortOfs,FC_SetXoffState,Magic_code);
|
|
MoxaFunc1(PDevExt->PortOfs, FC_EnableCH, Magic_code);
|
|
|
|
|
|
if (PDevExt->NumberNeededForRead)
|
|
MoxaKdPrint (MX_DBG_TRACE, ("NumberNeededForRead=%d\n",PDevExt->NumberNeededForRead));
|
|
|
|
PDevExt->DeviceState.Reopen = FALSE;
|
|
|
|
}
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Exit restore\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaPowerDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a dispatch routine for the IRPs that come to the driver with the
|
|
IRP_MJ_POWER major code (power IRPs).
|
|
|
|
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
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
|
|
PDEVICE_OBJECT pPdo = pDevExt->Pdo;
|
|
BOOLEAN acceptingIRPs;
|
|
|
|
// PAGED_CODE();
|
|
if (pDevExt->ControlDevice) { // Control Device
|
|
|
|
PoStartNextPowerIrp(PIrp);
|
|
status = STATUS_CANCELLED;
|
|
PIrp->IoStatus.Information = 0L;
|
|
PIrp->IoStatus.Status = status;
|
|
IoCompleteRequest(
|
|
PIrp,
|
|
0
|
|
);
|
|
return status;
|
|
}
|
|
|
|
|
|
if ((status = MoxaIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
|
|
PoStartNextPowerIrp(PIrp);
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
|
|
switch (pIrpStack->MinorFunction) {
|
|
|
|
case IRP_MN_WAIT_WAKE:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got IRP_MN_WAIT_WAKE Irp\n"));
|
|
break;
|
|
|
|
|
|
case IRP_MN_POWER_SEQUENCE:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Got IRP_MN_POWER_SEQUENCE Irp\n"));
|
|
break;
|
|
|
|
|
|
case IRP_MN_SET_POWER:
|
|
MoxaKdPrint (MX_DBG_TRACE,("Got IRP_MN_SET_POWER Irp\n"));
|
|
|
|
//
|
|
// Perform different ops if it was system or device
|
|
//
|
|
|
|
switch (pIrpStack->Parameters.Power.Type) {
|
|
case SystemPowerState: {
|
|
POWER_STATE powerState;
|
|
|
|
//
|
|
// They asked for a system power state change
|
|
//
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------: SystemPowerState\n"));
|
|
|
|
//
|
|
// We will only service this if we are policy owner -- we
|
|
// don't need to lock on this value since we only service
|
|
// one power request at a time.
|
|
//
|
|
|
|
if (pDevExt->OwnsPowerPolicy != TRUE) {
|
|
status = STATUS_SUCCESS;
|
|
goto PowerExit;
|
|
}
|
|
|
|
|
|
switch (pIrpStack->Parameters.Power.State.SystemState) {
|
|
case PowerSystemUnspecified:
|
|
powerState.DeviceState = PowerDeviceUnspecified;
|
|
break;
|
|
|
|
case PowerSystemWorking:
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
break;
|
|
|
|
case PowerSystemSleeping1:
|
|
case PowerSystemSleeping2:
|
|
case PowerSystemSleeping3:
|
|
case PowerSystemHibernate:
|
|
case PowerSystemShutdown:
|
|
case PowerSystemMaximum:
|
|
powerState.DeviceState = PowerDeviceD3;
|
|
break;
|
|
|
|
default:
|
|
status = STATUS_SUCCESS;
|
|
goto PowerExit;
|
|
break;
|
|
}
|
|
|
|
|
|
PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
|
|
pIrpStack->Parameters.Power.State);
|
|
|
|
//
|
|
// Send IRP to change device state
|
|
//
|
|
|
|
PoRequestPowerIrp(pPdo, IRP_MN_SET_POWER, powerState, NULL, NULL,
|
|
NULL);
|
|
|
|
goto PowerExit;
|
|
}
|
|
|
|
case DevicePowerState:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------: DevicePowerState\n"));
|
|
break;
|
|
|
|
default:
|
|
MoxaKdPrint (MX_DBG_TRACE, ("------: UNKNOWN PowerState\n"));
|
|
goto PowerExit;
|
|
}
|
|
|
|
|
|
//
|
|
// If we are already in the requested state, just pass the IRP down
|
|
//
|
|
|
|
if (pDevExt->PowerState
|
|
== pIrpStack->Parameters.Power.State.DeviceState) {
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Already in requested power state\n")
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
switch (pIrpStack->Parameters.Power.State.DeviceState) {
|
|
|
|
case PowerDeviceD0:
|
|
MoxaKdPrint (MX_DBG_TRACE,("Going to power state D0\n"));
|
|
return MoxaSetPowerD0(PDevObj, PIrp);
|
|
|
|
case PowerDeviceD1:
|
|
case PowerDeviceD2:
|
|
case PowerDeviceD3:
|
|
MoxaKdPrint (MX_DBG_TRACE,("Going to power state D3\n"));
|
|
return MoxaSetPowerD3(PDevObj, PIrp);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MN_QUERY_POWER:
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("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) {
|
|
if (pIrpStack->Parameters.Power.Type == SystemPowerState
|
|
&& pIrpStack->Parameters.Power.State.SystemState
|
|
> pDevExt->SystemWake) {
|
|
status = PIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
|
PoStartNextPowerIrp(PIrp);
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If no wait-wake, always successful
|
|
//
|
|
|
|
PIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
PoStartNextPowerIrp(PIrp);
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
return MoxaPoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
} // switch (pIrpStack->MinorFunction)
|
|
|
|
|
|
PowerExit:;
|
|
|
|
PoStartNextPowerIrp(PIrp);
|
|
|
|
|
|
//
|
|
// Pass to the lower driver
|
|
//
|
|
IoSkipCurrentIrpStackLocation(PIrp);
|
|
status = MoxaPoCallDriver(pDevExt, pLowerDevObj, PIrp);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaSetPowerD0(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.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
NTSTATUS status;
|
|
ULONG boardReady = 0;
|
|
KEVENT event;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
// PAGED_CODE();
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("In MoxaSetPowerD0\n"));
|
|
MoxaKdPrint (MX_DBG_TRACE, ("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, MoxaSyncCompletion, &pDevExt->PowerD0Event,
|
|
TRUE, TRUE, TRUE);
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Calling next driver\n"));
|
|
|
|
status = PoCallDriver(pDevExt->LowerDeviceObject, PIrp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Waiting for next driver\n"));
|
|
KeWaitForSingleObject (&pDevExt->PowerD0Event, Executive, KernelMode,
|
|
FALSE, NULL);
|
|
} else {
|
|
if (!NT_SUCCESS(status)) {
|
|
PIrp->IoStatus.Status = status;
|
|
PoStartNextPowerIrp(PIrp);
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(PIrp->IoStatus.Status)) {
|
|
PoStartNextPowerIrp(PIrp);
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
return PIrp->IoStatus.Status;
|
|
}
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Get board ready ...\n"));
|
|
|
|
status = MoxaIoSyncIoctlEx(IOCTL_MOXA_INTERNAL_BOARD_READY, TRUE,
|
|
pDevExt->LowerDeviceObject, &event, &IoStatusBlock,
|
|
NULL, 0, &boardReady,
|
|
sizeof(boardReady));
|
|
MoxaKdPrint(MX_DBG_TRACE,("status=%x,boardReady=%x\n",status,boardReady));
|
|
|
|
if (NT_SUCCESS(status) && boardReady) {
|
|
|
|
//
|
|
// Restore the device
|
|
//
|
|
|
|
//
|
|
// Theoretically we could change states in the middle of processing
|
|
// the restore which would result in a bad PKINTERRUPT being used
|
|
// in MoxaRestoreDeviceState().
|
|
//
|
|
|
|
if (pDevExt->PNPState == SERIAL_PNP_STARTED) {
|
|
MoxaRestoreDeviceState(pDevExt);
|
|
}
|
|
pDevExt->PowerState = PowerDeviceD0;
|
|
MoxaGlobalData->BoardReady[pDevExt->BoardNo] = TRUE;
|
|
}
|
|
else
|
|
MoxaGlobalData->BoardReady[pDevExt->BoardNo] = FALSE;
|
|
|
|
|
|
//
|
|
// Now that we are powered up, call PoSetPowerState
|
|
//
|
|
|
|
PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
|
|
pIrpStack->Parameters.Power.State);
|
|
|
|
PoStartNextPowerIrp(PIrp);
|
|
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Leaving MoxaSetPowerD0\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaGotoPowerState(IN PDEVICE_OBJECT PDevObj,
|
|
IN PMOXA_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();
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("In MoxaGotoPowerState\n"));
|
|
|
|
powerState.DeviceState = DevPowerState;
|
|
|
|
KeInitializeEvent(&gotoPowEvent, SynchronizationEvent, FALSE);
|
|
|
|
status = PoRequestPowerIrp(PDevObj, IRP_MN_SET_POWER, powerState,
|
|
MoxaSystemPowerCompletion, &gotoPowEvent,
|
|
NULL);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
KeWaitForSingleObject(&gotoPowEvent, Executive, KernelMode, FALSE, NULL);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
#if DBG
|
|
if (!NT_SUCCESS(status)) {
|
|
MoxaKdPrint (MX_DBG_TRACE,("MoxaGotoPowerState FAILED\n"));
|
|
}
|
|
#endif
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Leaving MoxaGotoPowerState\n"));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaSetPowerD3(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;
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
|
|
// PAGED_CODE();
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("In MoxaSetPowerD3\n"));
|
|
|
|
//
|
|
// Before we power down, call PoSetPowerState
|
|
//
|
|
|
|
PoSetPowerState(PDevObj, pIrpStack->Parameters.Power.Type,
|
|
pIrpStack->Parameters.Power.State);
|
|
|
|
pDevExt->PowerState = PowerDeviceD3;
|
|
//
|
|
// If the device is not closed, disable interrupts and allow the fifo's
|
|
// to flush.
|
|
//
|
|
|
|
if (pDevExt->DeviceIsOpened == TRUE) {
|
|
LARGE_INTEGER charTime;
|
|
|
|
pDevExt->DeviceState.Reopen = TRUE;
|
|
|
|
//
|
|
// Save the device state
|
|
//
|
|
MoxaSaveDeviceState(pDevExt);
|
|
MoxaFunc1(pDevExt->PortOfs, FC_DisableCH, Magic_code);
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Port Disabled\n"));
|
|
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
|
|
|
|
//
|
|
// 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 MoxaPoCallDriver(pDevExt, pDevExt->LowerDeviceObject, PIrp);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaSendWaitWake(PMOXA_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;
|
|
}
|
|
|
|
//
|
|
// 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, MoxaWakeCompletion, PDevExt, &pIrp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
status = STATUS_SUCCESS;
|
|
PDevExt->PendingWakeIrp = pIrp;
|
|
} else if (!NT_SUCCESS(status)) {
|
|
MoxaIRPEpilogue(PDevExt);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MoxaWakeCompletion(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;
|
|
PMOXA_DEVICE_EXTENSION pDevExt = (PMOXA_DEVICE_EXTENSION)Context;
|
|
POWER_STATE powerState;
|
|
|
|
status = IoStatus->Status;
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
NTSTATUS tmpStatus;
|
|
PIRP pIrp;
|
|
PKEVENT pEvent;
|
|
|
|
//
|
|
// A wakeup has occurred -- powerup our stack
|
|
//
|
|
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
|
|
pEvent = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
|
|
|
|
if (pEvent == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto ErrorExitWakeCompletion;
|
|
}
|
|
|
|
KeInitializeEvent(pEvent, SynchronizationEvent, FALSE);
|
|
|
|
tmpStatus = PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_SET_POWER, powerState,
|
|
MoxaSystemPowerCompletion, pEvent,
|
|
NULL);
|
|
|
|
if (tmpStatus == STATUS_PENDING) {
|
|
KeWaitForSingleObject(pEvent, Executive, KernelMode, FALSE, NULL);
|
|
tmpStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExFreePool(pEvent);
|
|
|
|
if (!NT_SUCCESS(tmpStatus)) {
|
|
status = tmpStatus;
|
|
goto ErrorExitWakeCompletion;
|
|
}
|
|
|
|
//
|
|
// Send another WaitWake Irp
|
|
//
|
|
|
|
powerState.SystemState = pDevExt->SystemWake;
|
|
|
|
tmpStatus = PoRequestPowerIrp(pDevExt->Pdo, IRP_MN_WAIT_WAKE,
|
|
powerState, MoxaWakeCompletion,
|
|
pDevExt, &pIrp);
|
|
|
|
if (tmpStatus == STATUS_PENDING) {
|
|
pDevExt->PendingWakeIrp = pIrp;
|
|
goto ExitWakeCompletion;
|
|
}
|
|
|
|
status = tmpStatus;
|
|
}
|
|
|
|
ErrorExitWakeCompletion:;
|
|
pDevExt->PendingWakeIrp = NULL;
|
|
MoxaIRPEpilogue(pDevExt);
|
|
|
|
ExitWakeCompletion:;
|
|
return status;
|
|
}
|
|
|