windows-nt/Source/XPSP1/NT/printscan/wia/kernel/usbscan/power.c
2020-09-26 16:20:57 +08:00

388 lines
11 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
power.c
Abstract:
Author:
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"));
//
// Check arguments.
//
if( (NULL == pDeviceObject)
|| (NULL == pDeviceObject->DeviceExtension)
|| (NULL == pIrp) )
{
DebugTrace(TRACE_ERROR,("USPower: ERROR!! Invalid parameter passed.\n"));
Status = STATUS_INVALID_PARAMETER;
DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving.. Status = %x.\n", Status));
return Status;
}
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\n"));
//
// find the device power state equivalent to the given system state
//
DebugTrace(TRACE_STATUS,("USPower: Set Power, SystemPowerState (%d)\n",
pIrpStack -> Parameters.Power.State.SystemState));
if (pIrpStack -> Parameters.Power.State.SystemState == PowerSystemWorking) {
powerState.DeviceState = PowerDeviceD0;
} else if (/* pde ->EnabledForWakeup */ FALSE) {
DebugTrace(TRACE_STATUS,("USPower: USBSCAN always enabled for wakeup\n"));
powerState.DeviceState = pde ->
DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState];
} else {
//
// wakeup not enabled, just go in to the 'OFF' state.
//
powerState.DeviceState = PowerDeviceD3;
} //irpStack->Parameters.Power.State.SystemState
//
// are we already in this state?
//
if (powerState.DeviceState != pde -> CurrentDevicePowerState) {
//
// No, request that we be put into this state
//
DebugTrace(TRACE_STATUS,("USPower: Requesting powerstate %d\n",
powerState.DeviceState));
IoMarkIrpPending(pIrp);
pde -> pPowerIrp = pIrp;
Status = PoRequestPowerIrp(pde -> pPhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
USPoRequestCompletion,
pDeviceObject,
NULL);
if (!NT_SUCCESS(Status)) {
//
// Allocation failed, we must complete the IRP
// ourselves.
//
PoStartNextPowerIrp(pIrp);
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
USDecrementIoCount(pDeviceObject);
}
//
// We marked the IRP pending, so we must return
// STATUS_PENDING (our caller will examine
// Irp->IoStatus.Status)
//
Status = STATUS_PENDING;
} else {
//
// Yes, just pass it on
//
IoCopyCurrentIrpStackLocationToNext(pIrp);
PoStartNextPowerIrp(pIrp);
Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
}
break;
case DevicePowerState:
DebugTrace(TRACE_STATUS,("USPower: DevicePowerState\n"));
Status = USSetDevicePowerState(pDeviceObject,
pIrpStack -> Parameters.Power.State.DeviceState,
&hookIt);
IoCopyCurrentIrpStackLocationToNext(pIrp);
if (hookIt) {
DebugTrace(TRACE_STATUS,("USPower: Set PowerIrp Completion Routine\n"));
IoSetCompletionRoutine(pIrp,
USPowerIrpComplete,
// always pass FDO to completion routine
pDeviceObject,
hookIt,
hookIt,
hookIt);
}
PoStartNextPowerIrp(pIrp);
Status = PoCallDriver(pde ->pStackDeviceObject, pIrp);
if (!hookIt) {
USDecrementIoCount(pDeviceObject);
}
break;
} /* case irpStack->Parameters.Power.Type */
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
DebugTrace(TRACE_STATUS,("USPower: IRP_MN_QUERY_POWER\n"));
IoCopyCurrentIrpStackLocationToNext(pIrp);
PoStartNextPowerIrp(pIrp);
Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
break; /* IRP_MN_QUERY_POWER */
default:
DebugTrace(TRACE_STATUS,("USPower: Unknown power message (%x)\n",pIrpStack->MinorFunction));
IoCopyCurrentIrpStackLocationToNext(pIrp);
PoStartNextPowerIrp(pIrp);
Status = PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
} /* pIrpStack -> MinorFunction */
DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving... Status = 0x%x\n", Status));
return Status;
}
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"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
pIrp = pde -> pPowerIrp;
Status = pIoStatus -> Status;
IoCopyCurrentIrpStackLocationToNext(pIrp);
PoStartNextPowerIrp(pIrp);
PoCallDriver(pde -> pStackDeviceObject, pIrp);
USDecrementIoCount(pDeviceObject);
DebugTrace(TRACE_PROC_LEAVE,("USPoRequestCompletion: Leaving... Status = 0x%x\n", Status));
return Status;
}
USPowerIrpComplete(
IN PDEVICE_OBJECT pPdo,
IN PIRP pIrp,
IN PDEVICE_OBJECT pDeviceObject
)
/*++
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;
PIO_STACK_LOCATION pIrpStack;
DebugTrace(TRACE_PROC_ENTER,("USPowerIrpComplete: Enter...\n"));
pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension;
Status = STATUS_SUCCESS;
if (pIrp -> PendingReturned) {
IoMarkIrpPending(pIrp);
}
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);
pde -> AcceptingRequests = TRUE;
pde -> CurrentDevicePowerState = PowerDeviceD0;
pIrp -> IoStatus.Status = Status;
USDecrementIoCount(pDeviceObject);
DebugTrace(TRACE_PROC_LEAVE,("USPowerIrpComplete: Leaving... Status = 0x%x\n", Status));
return Status;
}
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;
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 (DeviceState) {
DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD3 (OFF)\n"));
} else {
DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD1/D2 (SUSPEND)\n"));
}
#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));
}
DebugTrace(TRACE_PROC_LEAVE,("USSetDevicePowerState: Leaving... Status = 0x%x\n", Status));
return Status;
}