//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1998 - 1999
//
//  File:       power.c
//
//--------------------------------------------------------------------------

#include "pch.h"

VOID
PowerStateCallback(
    IN  PVOID CallbackContext,
    IN  PVOID Argument1,
    IN  PVOID Argument2
    )
{
    ULONG_PTR   action = (ULONG_PTR)Argument1;
    ULONG_PTR   state  = (ULONG_PTR)Argument2;

    UNREFERENCED_PARAMETER(CallbackContext);

    if( PO_CB_AC_STATUS == action ) {

        //
        // AC <-> DC Transition has occurred
        // state == TRUE if on AC, else FALSE.
        //
        PowerStateIsAC = (BOOLEAN)state;
        // DbgPrint("PowerState is now %s\n",PowerStateIsAC?"AC":"Battery");
    }

    return;
}


NTSTATUS
PptPowerComplete (
                  IN PDEVICE_OBJECT       pDeviceObject,
                  IN PIRP                 pIrp,
                  IN PFDO_EXTENSION    Fdx
                  )

/*++
      
Routine Description:
      
    This routine handles all IRP_MJ_POWER IRPs.
  
Arguments:
  
    pDeviceObject           - represents the port device
  
    pIrp                    - PNP irp
  
    Fdx               - Device Extension
  
Return Value:
  
    Status
  
--*/
{
    POWER_STATE_TYPE    powerType;
    POWER_STATE         powerState;
    PIO_STACK_LOCATION  pIrpStack;
    
    UNREFERENCED_PARAMETER( pDeviceObject );

    if( pIrp->PendingReturned ) {
        IoMarkIrpPending( pIrp );
    }

    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    
    powerType = pIrpStack->Parameters.Power.Type;
    powerState = pIrpStack->Parameters.Power.State;
    
    switch (pIrpStack->MinorFunction) {
        
    case IRP_MN_QUERY_POWER:
        
        ASSERTMSG ("Invalid power completion minor code: Query Power\n", FALSE);
        break;
        
    case IRP_MN_SET_POWER:
        
        DD((PCE)Fdx,DDT,"Power - Setting %s state to %d\n", 
               ( (powerType == SystemPowerState) ?  "System" : "Device" ), powerState.SystemState);
        
        switch (powerType) {
        case DevicePowerState:
            if (Fdx->DeviceState < powerState.DeviceState) {
                //
                // Powering down
                //
                
                ASSERTMSG ("Invalid power completion Device Down\n", FALSE);
                
            } else if (powerState.DeviceState < Fdx->DeviceState) {
                //
                // Powering Up
                //
                PoSetPowerState (Fdx->DeviceObject, powerType, powerState);
                
                if (PowerDeviceD0 == Fdx->DeviceState) {
                    
                    //
                    // Do the power on stuff here.
                    //
                    
                }
                Fdx->DeviceState = powerState.DeviceState;
            }
            break;
            
        case SystemPowerState:
            
            if (Fdx->SystemState < powerState.SystemState) {
                //
                // Powering down
                //
                
                ASSERTMSG ("Invalid power completion System Down\n", FALSE);
                
            } else if (powerState.SystemState < Fdx->SystemState) {
                //
                // Powering Up
                //
                if (PowerSystemWorking == powerState.SystemState) {
                    
                    //
                    // Do the system start up stuff here.
                    //
                    
                    powerState.DeviceState = PowerDeviceD0;
                    PoRequestPowerIrp (Fdx->DeviceObject,
                                       IRP_MN_SET_POWER,
                                       powerState,
                                       NULL, // no completion function
                                       NULL, // and no context
                                       NULL);
                }
                
                Fdx->SystemState = powerState.SystemState;
            }
            break;
        }
        
        
        break;
        
    default:
        ASSERTMSG ("Power Complete: Bad Power State", FALSE);
    }
    
    PoStartNextPowerIrp (pIrp);
    
    return STATUS_SUCCESS;
}


NTSTATUS
PptFdoPower (
    IN PDEVICE_OBJECT pDeviceObject,
    IN PIRP           pIrp
    )
/*++
      
Routine Description:
      
    This routine handles all IRP_MJ_POWER IRPs.
      
Arguments:
      
    pDeviceObject           - represents the port device
      
    pIrp                    - PNP irp
      
Return Value:
      
    Status
      
--*/
{
    POWER_STATE_TYPE    powerType;
    POWER_STATE         powerState;
    PIO_STACK_LOCATION  pIrpStack;
    NTSTATUS            status;
    PFDO_EXTENSION      fdx;
    BOOLEAN             hookit   = FALSE;
    BOOLEAN             bogusIrp = FALSE;
    
    //
    // WORKWORK.  THIS CODE DOESN'T DO MUCH...NEED TO CHECK OUT FULL POWER FUNCTIONALITY.
    //
    
    fdx = pDeviceObject->DeviceExtension;
    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    
    status = PptAcquireRemoveLock(&fdx->RemoveLock, pIrp);
    if( !NT_SUCCESS(status) ) {
        PoStartNextPowerIrp(pIrp);
        return P4CompleteRequest( pIrp, status, pIrp->IoStatus.Information );
    }

    powerType = pIrpStack->Parameters.Power.Type;
    powerState = pIrpStack->Parameters.Power.State;
    
    switch (pIrpStack->MinorFunction) {
        
    case IRP_MN_QUERY_POWER:
        
        status = STATUS_SUCCESS;
        break;
        
    case IRP_MN_SET_POWER:
        
        DD((PCE)fdx,DDT,"Power - Setting %s state to %d\n",
               ( (powerType == SystemPowerState) ?  "System" : "Device" ), powerState.SystemState);
        
        status = STATUS_SUCCESS;

        switch (powerType) {
        case DevicePowerState:
            if (fdx->DeviceState < powerState.DeviceState) {
                //
                // Powering down
                //
                
                PoSetPowerState (fdx->DeviceObject, powerType, powerState);
                
                if (PowerDeviceD0 == fdx->DeviceState) {
                    
                    //
                    // Do the power on stuff here.
                    //
                    
                }
                fdx->DeviceState = powerState.DeviceState;
                
            } else if (powerState.DeviceState < fdx->DeviceState) {
                //
                // Powering Up
                //
                hookit = TRUE;

            }
            
            break;
            
        case SystemPowerState:
            
            if (fdx->SystemState < powerState.SystemState) {
                //
                // Powering down
                //
                if (PowerSystemWorking == fdx->SystemState) {
                    
                    //
                    // Do the system shut down stuff here.
                    //
                    
                }
                
                powerState.DeviceState = PowerDeviceD3;
                PoRequestPowerIrp (fdx->DeviceObject,
                                   IRP_MN_SET_POWER,
                                   powerState,
                                   NULL, // no completion function
                                   NULL, // and no context
                                   NULL);
                fdx->SystemState = powerState.SystemState;
                
            } else if (powerState.SystemState < fdx->SystemState) {
                //
                // Powering Up
                //
                hookit = TRUE;
            }
            break;
        }
        
        break;
        
    default:
        bogusIrp = TRUE;
        status = STATUS_NOT_SUPPORTED;
    }
    
    IoCopyCurrentIrpStackLocationToNext (pIrp);
    
    if (!NT_SUCCESS (status)) {

        PoStartNextPowerIrp (pIrp);

        if( bogusIrp ) {
            status = PoCallDriver( fdx->ParentDeviceObject, pIrp );
        } else {
            P4CompleteRequest( pIrp, status, pIrp->IoStatus.Information );
        }
        
    } else if (hookit) {
        
        IoSetCompletionRoutine( pIrp, PptPowerComplete, fdx, TRUE, TRUE, TRUE );
        status = PoCallDriver (fdx->ParentDeviceObject, pIrp);
        
    } else {

        PoStartNextPowerIrp (pIrp);
        status = PoCallDriver (fdx->ParentDeviceObject, pIrp);

    }
    
    PptReleaseRemoveLock(&fdx->RemoveLock, pIrp);

    return status;
}