Leaked source code of windows server 2003
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.
 
 
 
 
 
 

597 lines
19 KiB

/*++
Copyright (C) Microsoft Corporation, 1999 - 2001
Module Name:
power.c
Abstract:
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include <stdio.h>
#include "stddef.h"
#include "wdm.h"
#include "usbscan.h"
#include "usbd_api.h"
#include "private.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, USPower)
#endif
NTSTATUS
USPower(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Process the Power IRPs sent to the PDO for this device.
Arguments:
pDeviceObject - pointer to the functional device object (FDO) for this device.
pIrp - pointer to an I/O Request Packet
Return Value:
NT status code
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PIO_STACK_LOCATION pIrpStack;
BOOLEAN hookIt = FALSE;
POWER_STATE powerState;
PAGED_CODE();
DebugTrace(TRACE_PROC_ENTER,("USPower: Enter... \n"));
USIncrementIoCount(pDeviceObject);
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
Status = STATUS_SUCCESS;
switch (pIrpStack -> MinorFunction) {
case IRP_MN_SET_POWER:
{
DebugTrace(TRACE_STATUS,("USPower: IRP_MN_SET_POWER\n"));
switch (pIrpStack -> Parameters.Power.Type) {
case SystemPowerState:
{
DebugTrace(TRACE_STATUS,("USPower: SystemPowerState (0x%x)\n",pIrpStack->Parameters.Power.State.SystemState));
//
// Let lower layer know S IRP, we'll catch on the way up.
//
IoMarkIrpPending(pIrp);
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,
USSystemPowerIrpComplete,
// always pass FDO to completion routine
pDeviceObject,
TRUE,
TRUE,
TRUE);
PoCallDriver(pde ->pStackDeviceObject, pIrp);
Status = STATUS_PENDING;
goto USPower_return;
} // case SystemPowerState:
case DevicePowerState:
{
DebugTrace(TRACE_STATUS,("USPower: DevicePowerState\n"));
Status = USSetDevicePowerState(pDeviceObject,
pIrpStack -> Parameters.Power.State.DeviceState,
&hookIt);
if (hookIt) {
DebugTrace(TRACE_STATUS,("USPower: Set PowerIrp Completion Routine\n"));
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,
USDevicePowerIrpComplete,
// always pass FDO to completion routine
pDeviceObject,
hookIt,
hookIt,
hookIt);
} else {
PoStartNextPowerIrp(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
}
Status = PoCallDriver(pde ->pStackDeviceObject, pIrp);
if (!hookIt) {
USDecrementIoCount(pDeviceObject);
}
goto USPower_return;
} // case DevicePowerState:
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
} // case IRP_MN_SET_POWER:
case IRP_MN_QUERY_POWER:
{
DebugTrace(TRACE_STATUS,("USPower: IRP_MN_QUERY_POWER\n"));
if(PowerDeviceD3 == pde -> DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState]){
//
// We're going down to D3 state, which we can't wake from. Cancel WaitWakeIRP.
//
USDisarmWake(pde);
} // if(PowerDeviceD3 == pde -> DeviceCapabilities.DeviceState[irpStack->Parameters.Power.State.SystemState])
PoStartNextPowerIrp(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
break; /* IRP_MN_QUERY_POWER */
} // case IRP_MN_QUERY_POWER:
case IRP_MN_WAIT_WAKE:
{
LONG oldWakeState;
DebugTrace(TRACE_STATUS,("USPower: IRP_MN_WAIT_WAKE\n"));
pde->pWakeIrp = pIrp;
//
// Now we're armed.
//
oldWakeState = InterlockedCompareExchange(&pde->WakeState,
WAKESTATE_ARMED,
WAKESTATE_WAITING);
if(WAKESTATE_WAITING_CANCELLED == oldWakeState){
//
// We got disarmed, finish up and complete the IRP
//
pde->WakeState = WAKESTATE_COMPLETING;
pIrp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(pIrp, IO_NO_INCREMENT );
Status = STATUS_CANCELLED;
USDecrementIoCount(pDeviceObject);
break;
} // if(WAKESTATE_WAITING_CANCELLED == oldWakeState)
// We went from WAITING to ARMED. Set a completion routine and forward
// the IRP. Note that our completion routine might complete the IRP
// asynchronously, so we mark the IRP pending
IoMarkIrpPending(pIrp);
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp,
USWaitWakeIoCompletionRoutine,
NULL,
TRUE,
TRUE,
TRUE );
PoCallDriver(pde->pStackDeviceObject, pIrp);
Status = STATUS_PENDING;
USDecrementIoCount(pDeviceObject);
break;
} // case IRP_MN_WAIT_WAKE:
default:
DebugTrace(TRACE_STATUS,("USPower: Unknown power message (%x)\n",pIrpStack->MinorFunction));
PoStartNextPowerIrp(pIrp);
IoSkipCurrentIrpStackLocation(pIrp);
Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
} /* pIrpStack -> MinorFunction */
USPower_return:
DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving... Status = 0x%x\n", Status));
return Status;
} // USPower()
NTSTATUS
USPoRequestCompletion(
IN PDEVICE_OBJECT pPdo,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PDEVICE_OBJECT pDeviceObject,
IN PIO_STATUS_BLOCK pIoStatus
)
/*++
Routine Description:
This routine is called when the port driver completes an IRP.
Arguments:
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PIRP pIrp;
DebugTrace(TRACE_PROC_ENTER,("USPoRequestCompletion: Enter...\n"));
//
// Initialize local.
//
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
pIrp = pde -> pPowerIrp;
Status = pIoStatus -> Status;
//
// Copy status from D IRP to S IRP.
//
pIrp->IoStatus.Status = pIoStatus->Status;
//
// Complete S IRP.
//
PoStartNextPowerIrp(pIrp);
IoCompleteRequest(pIrp, IO_NO_INCREMENT );
USDecrementIoCount(pDeviceObject);
DebugTrace(TRACE_PROC_LEAVE,("USPoRequestCompletion: Leaving... Status = 0x%x\n", Status));
return Status;
} // USPoRequestCompletion()
NTSTATUS
USDevicePowerIrpComplete(
IN PDEVICE_OBJECT pPdo,
IN PIRP pIrp,
IN PDEVICE_OBJECT pDeviceObject
)
/*++
Routine Description:
This routine is called when the port driver completes SetD0 IRP.
Arguments:
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PIO_STACK_LOCATION pIrpStack;
DebugTrace(TRACE_PROC_ENTER,("USDevicePowerIrpComplete: Enter...\n"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = STATUS_SUCCESS;
if (pIrp -> PendingReturned) {
IoMarkIrpPending(pIrp);
} // if (pIrp -> PendingReturned)
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
ASSERT(pIrpStack -> MajorFunction == IRP_MJ_POWER);
ASSERT(pIrpStack -> MinorFunction == IRP_MN_SET_POWER);
ASSERT(pIrpStack -> Parameters.Power.Type == DevicePowerState);
ASSERT(pIrpStack -> Parameters.Power.State.DeviceState == PowerDeviceD0);
//
// This completion is called only for D0 IRP.
//
pde->CurrentDevicePowerState = PowerDeviceD0;
pde->AcceptingRequests = TRUE;
//
// Now power is on. Rearm for wakeup.
//
USQueuePassiveLevelCallback(pde->pOwnDeviceObject, USPassiveLevelReArmCallbackWorker);
//
// Ready for next D IRP.
//
PoStartNextPowerIrp(pIrp);
//
// Leaving...
//
USDecrementIoCount(pDeviceObject);
DebugTrace(TRACE_PROC_LEAVE,("USDevicePowerIrpComplete: Leaving... Status = 0x%x\n", Status));
return Status;
} // USDevicePowerIrpComplete()
NTSTATUS
USSystemPowerIrpComplete(
IN PDEVICE_OBJECT pPdo,
IN PIRP pIrp,
IN PDEVICE_OBJECT pDeviceObject
)
/*++
Routine Description:
This routine is called when the port driver completes SetD0 IRP.
Arguments:
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
PIO_STACK_LOCATION pIrpStack;
POWER_STATE powerState;
DebugTrace(TRACE_PROC_ENTER,("USSystemPowerIrpComplete: Enter... IRP(0x%p)\n", pIrp));
//
// Initialize local.
//
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = pIrp->IoStatus.Status;
pIrpStack = IoGetCurrentIrpStackLocation (pIrp);
ASSERT(pIrpStack -> MajorFunction == IRP_MJ_POWER);
ASSERT(pIrpStack -> MinorFunction == IRP_MN_SET_POWER);
ASSERT(pIrpStack -> Parameters.Power.Type == SystemPowerState);
if(!NT_SUCCESS(Status)){
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: IRP failed (0x%x).\n", Status));
Status = STATUS_SUCCESS;
USDecrementIoCount(pDeviceObject);
goto USSystemPowerIrpComplete_return;
} // if(!NT_SUCCESS(Status))
//
// Now Request D IRP based on what we got.
//
if(TRUE == pde ->bEnabledForWakeup){
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: We have remote wakeup support, getting powerState from table.\n"));
//
// We support wakeup, we'll just follow device stated set by PDO.
//
powerState.DeviceState = pde -> DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState];
} else { // if(TRUE == pde ->EnabledForWakeup)
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: We don't have remote wakeup support.\n"));
//
// We don't support remote wake, we're in D0 only when PowerSystemWorking.
//
if(PowerSystemWorking == pIrpStack -> Parameters.Power.State.SystemState){
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: PowerSystemWorking is requested, powering up to D0.\n"));
powerState.DeviceState = PowerDeviceD0;
} else { // if(PowerSystemWorking == pIrpStack -> Parameters.Power.State.SystemState)
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: Going other than PowerSystemWorking, turning off the device to D3.\n"));
powerState.DeviceState = PowerDeviceD3;
}
} // else(TRUE == pde ->EnabledForWakeup)
//
// are we already in this state?
//
if(powerState.DeviceState != pde -> CurrentDevicePowerState){
//
// No, request that we be put into this state
//
DebugTrace(TRACE_STATUS,("USSystemPowerIrpComplete: Requesting DevicePowerState(0x%x).\n", powerState.DeviceState));
pde -> pPowerIrp = pIrp;
Status = PoRequestPowerIrp(pde -> pPhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USPoRequestCompletion,
pDeviceObject,
NULL);
if(NT_SUCCESS(Status)){
//
// D IRP is successfully requested. S IRP will be completed in D IRP completion routine together.
//
Status = STATUS_MORE_PROCESSING_REQUIRED;
} else { // if(NT_SUCCESS(Status))
DebugTrace(TRACE_WARNING,("USSystemPowerIrpComplete: WARNING!! DevicePowerState(0x%x) request failed..\n", powerState.DeviceState));
PoStartNextPowerIrp(pIrp);
Status = STATUS_SUCCESS;
USDecrementIoCount(pDeviceObject);
}
} else { // if(powerState.DeviceState != pde -> CurrentDevicePowerState)
//
// We're already in this device state, no need to issue D IRP.
//
PoStartNextPowerIrp(pIrp);
Status = STATUS_SUCCESS;
USDecrementIoCount(pDeviceObject);
} // else(powerState.DeviceState != pde -> CurrentDevicePowerState)
USSystemPowerIrpComplete_return:
DebugTrace(TRACE_PROC_LEAVE,("USSystemPowerIrpComplete: Leaving... Status = 0x%x\n", Status));
return Status;
} // USSystemPowerIrpComplete()
NTSTATUS
USSetDevicePowerState(
IN PDEVICE_OBJECT pDeviceObject,
IN DEVICE_POWER_STATE DeviceState,
IN PBOOLEAN pHookIt
)
/*++
Routine Description:
Arguments:
pDeviceObject - Pointer to the device object for the class device.
DeviceState - Device specific power state to set the device in to.
Return Value:
--*/
{
NTSTATUS Status;
PUSBSCAN_DEVICE_EXTENSION pde;
POWER_STATE PowerState;
DebugTrace(TRACE_PROC_ENTER,("USSetDevicePowerState: Enter...\n"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = STATUS_SUCCESS;
switch (DeviceState){
case PowerDeviceD3:
// ASSERT(pde -> AcceptingRequests);
// pde -> AcceptingRequests = FALSE;
// USCancelPipe(pDeviceObject, ALL_PIPE, TRUE);
// pde -> CurrentDevicePowerState = DeviceState;
// break;
case PowerDeviceD1:
case PowerDeviceD2:
#if DBG
if(PowerDeviceD3 == DeviceState){
DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD3 (OFF)\n"));
} else { // if(PowerDeviceD3 == DeviceState)
DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD1/D2 (SUSPEND)\n"));
} // else(PowerDeviceD3 == DeviceState)
#endif
USCancelPipe(pDeviceObject, NULL, ALL_PIPE, TRUE);
//
// power states D1,D2 translate to USB suspend
// D3 transltes to OFF
pde -> CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD0:
DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD0 (ON)\n"));
//
// finish the rest in the completion routine
//
*pHookIt = TRUE;
// pass on to PDO
break;
default:
DebugTrace(TRACE_WARNING,("USSetDevicePowerState: Bogus DeviceState = %x\n", DeviceState));
} // switch (DeviceState)
DebugTrace(TRACE_PROC_LEAVE,("USSetDevicePowerState: Leaving... Status = 0x%x\n", Status));
return Status;
} // USSetDevicePowerState()
NTSTATUS
USWaitWakeIoCompletionRoutine(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp,
PVOID pContext
)
{
PUSBSCAN_DEVICE_EXTENSION pde;
LONG oldWakeState;
NTSTATUS Status;
DebugTrace(TRACE_PROC_ENTER,("USWaitWakeIoCompletionRoutine: Enter...\n"));
//
// Initialize local.
//
pde = (PUSBSCAN_DEVICE_EXTENSION) pDeviceObject->DeviceExtension;
oldWakeState = 0;
Status = STATUS_SUCCESS;
// Advance the state to completing
oldWakeState = InterlockedExchange( &pde->WakeState, WAKESTATE_COMPLETING );
if(WAKESTATE_ARMED == oldWakeState){
// Normal case, IoCancelIrp isn�ft being called. Note that we already
// marked the IRP pending in our dispatch routine
Status = STATUS_SUCCESS;
goto USWaitWakeIoCompletionRoutine_return;
} else { // if(WAKESTATE_ARMED == oldWakeState)
if(WAKESTATE_ARMING_CANCELLED != oldWakeState){
DebugTrace(TRACE_ERROR,("USWaitWakeIoCompletionRoutine: ERROR!! wake IRP is completed but oldState(0x%x) isn't ARMED/CALCELLED.", oldWakeState));
} else { // if(WAKESTATE_ARMING_CANCELLED != oldWakeState)
DebugTrace(TRACE_STATUS,("USWaitWakeIoCompletionRoutine: WakeIRP is canceled.\n"));
}
// IoCancelIrp is being called RIGHT NOW. The disarm code will try
// to put back the WAKESTATE_ARMED state. It will then see our
// WAKESTATE_COMPLETED value, and complete the IRP itself!
Status = STATUS_MORE_PROCESSING_REQUIRED;
goto USWaitWakeIoCompletionRoutine_return;
} // else(WAKESTATE_ARMED == oldWakeState)
USWaitWakeIoCompletionRoutine_return:
DebugTrace(TRACE_PROC_LEAVE,("USWaitWakeIoCompletionRoutine: Leaving... Status = 0x%x\n", Status));
return Status;
} // USWaitWakeIoCompletionRoutine(