/*++
*******************************************************************************
* Copyright (c) 1990-98 Digi International Inc., All Rights Reserved			*
* 																				*
* This software contains proprietary and confidential information of Digi		*
* International Inc.  By accepting transfer of this copy, Recipient agrees		*
* to retain this software in confidence, to prevent disclosure to others,		*
* and to make no use of this software other than that for which it was			*
* delivered.  This is an unpublished copyrighted work of Digi International		*
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly		*
* prohibited.																	*
* 																				*
* Restricted Rights Legend														*
*																				*
* Use, duplication, or disclosure by the Government is subject to				*
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in			*
* Technical Data and Computer Software clause at DFARS 252.227-7031 or			*
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -			*
* Restricted Rights at 48 CFR 52.227-19, as applicable.							*
*																				*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343			*
*																				*
*******************************************************************************

Module Name:

   power.c

Abstract:

   This module contains handler routines for IRP_MJ_POWER requests.

Author:

   Michael Zarns

--*/


#include "Digilib.h"    // defines NT5_BUILD

#if NT5_BUILD

#include "pnp.h"



NTSTATUS
PnpPowerFdo(
	PPNP_FDO_EXTENSION		pfdoExtension, 
	PIRP					pIrp
	)
/*++

Description:

	Dispatch routine for all adapter FDO related Power requests.

Parameters:

	pExt
		Device extension for our FDO which describes the adapter.
	
	pIrp
		Request.

	pIos
		Parameters passed along with Irp.

Return Value:

	STATUS_SUCCESS, or some error value.  If failing the request, do not forward to 
	lower driver!

--*/
{
	PIO_STACK_LOCATION	pIos	= IoGetCurrentIrpStackLocation( pIrp );
	ULONG const			Minor	= pIos->MinorFunction;
	NTSTATUS			Status	= STATUS_SUCCESS;

	DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: %s, pfdoExtension 0x%08x, pIrp 0x%08x\n", 
																DigiGetPowerIrpName(Minor),
																pfdoExtension, pIrp ) );

	switch ( Minor )
	{
		case IRP_MN_SET_POWER:			
			switch ( pIos->Parameters.Power.Type )
			{
				case SystemPowerState:

					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo:  SystemPowerState, %s\n", 
										DigiGetPowerSystemState(pIos->Parameters.Power.State.SystemState) ) )
					
					switch ( pIos->Parameters.Power.State.SystemState )
					{
						case PowerSystemWorking:
						{
							if ( pfdoExtension->PowerState != PowerDeviceD0 )
							{
								// Transition from power off to power on.  Startup card
								POWER_STATE NewState;
								ASSERT( pfdoExtension->PowerState == PowerDeviceD3 );// We only use two power states!
								NewState.DeviceState = pfdoExtension->PowerState = PowerDeviceD0;
								// NOTE: DigiPowerComplete forwards (and completes) the Irp, don't do it here!
								Status = PoRequestPowerIrp( pfdoExtension->pPdo, IRP_MN_SET_POWER, NewState, DigiPowerComplete, pIrp, NULL );
							}
							else
							{
								PoStartNextPowerIrp( pIrp );
								DsPnpIoCompleteRequest( pIrp, Status, 0 );
							}
							break;
						}

						case PowerSystemSleeping1:
						case PowerSystemSleeping2:
						case PowerSystemSleeping3:
						case PowerSystemHibernate:
						{
							// Transition from power on to power off.  Shutdown card.
							if ( pfdoExtension->PowerState == PowerDeviceD0 )
							{
								POWER_STATE NewState;
								NewState.DeviceState = pfdoExtension->PowerState = PowerDeviceD3;
								// NOTE: dxbPowerComplete forwards the Irp, don't do it here!
								Status = PoRequestPowerIrp( pfdoExtension->pPdo, IRP_MN_SET_POWER, NewState, DigiPowerComplete, pIrp, NULL );
							}
							else
							{
								PoStartNextPowerIrp( pIrp );
								DsPnpIoCompleteRequest( pIrp, Status, 0 );
							}
							break;
						}

						case PowerSystemShutdown:
							Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
							break;

						default:
							DigiDump( DEBUG_DIGIPNP, ( "*** DsPnp!PnpPowerFdo: Invalid PowerSystem state 0x%x! ***\n", pIos->Parameters.Power.State.SystemState ) );
							Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
							break;
					}
					break;

				case DevicePowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: DevicePowerState, %s\n", DigiGetPowerDeviceState(pIos->Parameters.Power.State.DeviceState) ) )
					switch ( pIos->Parameters.Power.State.DeviceState )
					{
						case PowerDeviceD0:
							Status = DigiPowerForwardIrpWait( pfdoExtension->pNextDeviceObject, pIrp );
							(void)PnpFdoStartDevice( pfdoExtension, NULL, NULL );	
							PoStartNextPowerIrp( pIrp );
							DsPnpIoCompleteRequest( pIrp, Status, 0 );
							break;

						case PowerDeviceD1:
						case PowerDeviceD2:
						case PowerDeviceD3:
							(void)PnpFdoStopDevice( pfdoExtension, NULL, NULL );
							Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
							break;

						default:
							Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
							break;
					}
					break;

				default:
					DigiDump( DEBUG_DIGIPNP, ( "*** DsPnp!PnpPowerFdo: Invalid Power.Type 0x%x! ***\n", pIos->Parameters.Power.Type ) );
					Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
					break;
			}
			break;

		case IRP_MN_QUERY_POWER:
			switch ( pIos->Parameters.Power.Type )
			{
				case SystemPowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: SystemPowerState, %s\n", DigiGetPowerSystemState(pIos->Parameters.Power.State.SystemState) ) )
					break;

				case DevicePowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: DevicePowerState, %s\n", DigiGetPowerDeviceState(pIos->Parameters.Power.State.DeviceState) ) )
					break;
			}
			Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
			break;

		case IRP_MN_WAIT_WAKE:
		case IRP_MN_POWER_SEQUENCE:
		default:
			DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: Passing unhandled Power Irp %s on to PDO!\n", DigiGetPowerIrpName( Minor ) ) );
			Status = DigiPowerForwardIrp( pfdoExtension->pNextDeviceObject, pIrp );
			break;
	}

	if ( !NT_SUCCESS( Status ) )
	{
		DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerFdo: %s, returning status 0x%x\n", DigiGetPowerIrpName(Minor), Status ) );
	}
	return Status;

}


NTSTATUS
PnpPowerPdo(
	PDEVICE_OBJECT	pDeviceObject, 
	PIRP			pIrp
	)
/*++

Description:

	Dispatch routine for all adapter PDO related Power requests.

Parameters:

	pExt
		Device extension for our PDO which describes the adapter.
	
	pIrp
		Request.

	pIos
		Parameters passed along with Irp.

Return Value:

	STATUS_SUCCESS, or some error value.

--*/
{
	PIO_STACK_LOCATION	pIos			= IoGetCurrentIrpStackLocation( pIrp );
	ULONG const			Minor			= pIos->MinorFunction;
	NTSTATUS			Status			= STATUS_NOT_SUPPORTED;
	PPNP_PDO_EXTENSION	ppdoExtension	= pDeviceObject->DeviceExtension;

	DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: %s, ppdoExtension 0x%08x, pIrp 0x%08x\n",
											DigiGetPowerIrpName(Minor), ppdoExtension, pIrp ) );

	switch ( Minor )
	{
		case IRP_MN_SET_POWER:
		{
			switch ( pIos->Parameters.Power.Type )
			{
				case SystemPowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!DnpPowerPdo: SetPower: SystemPowerState, %s\n", DigiGetPowerSystemState(pIos->Parameters.Power.State.SystemState) ) )
					break;

				case DevicePowerState:
				{
					// We only support D0 and D3.  On and Off.  If any sleep state is requested, use D3==Off.
					const DEVICE_POWER_STATE Requested = pIos->Parameters.Power.State.DeviceState;
					POWER_STATE NewState;
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: SetPower: DevicePowerState, %s\n", DigiGetPowerDeviceState(pIos->Parameters.Power.State.DeviceState) ) )
					NewState.DeviceState = Requested > PowerDeviceD0 ? PowerDeviceD3 : PowerDeviceD0;
					PoSetPowerState( ppdoExtension->pDeviceObject, DevicePowerState, NewState );
					break;
				}
			}
			Status = STATUS_SUCCESS;
			break;
		}

		case IRP_MN_QUERY_POWER:
			switch ( pIos->Parameters.Power.Type )
			{
				case SystemPowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: QueryPower: SystemPowerState, %s\n", DigiGetPowerSystemState(pIos->Parameters.Power.State.SystemState) ) )
					break;

				case DevicePowerState:
					DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: QueryPower: DevicePowerState, %s\n", DigiGetPowerDeviceState(pIos->Parameters.Power.State.DeviceState) ) )
					break;
			}
			Status = STATUS_SUCCESS;
			break;

		case IRP_MN_POWER_SEQUENCE:
			Status = STATUS_NOT_IMPLEMENTED;
			break;

		case IRP_MN_WAIT_WAKE:
		default:
			Status = STATUS_NOT_SUPPORTED;
			DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: Ignoring unhandled Power Irp %s (0x%x)!\n", DigiGetPowerIrpName( Minor ), Minor ) );
			break;
	}

	if ( !NT_SUCCESS( Status ) )
	{
		DigiDump( DEBUG_DIGIPNP, ( "DsPnp!PnpPowerPdo: %s, returning status 0x%x\n", DigiGetPowerIrpName(Minor), Status ) );
	}
	PoStartNextPowerIrp( pIrp );
	DsPnpIoCompleteRequest( pIrp, Status, 0 );
	return Status;

}

#endif // NT5_BUILD
