388 lines
11 KiB
C
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;
|
||
|
}
|
||
|
|