/*
 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 2004 Apple Computer, Inc.  All rights reserved.
 *
 *  File: $Id: PowerMac8_1_SystemFansCtrlLoop.cpp,v 1.3 2004/08/31 02:36:22 dirty Exp $
 *
 */



#include "IOPlatformPluginSymbols.h"
#include "IOPlatformPlugin.h"
#include "PowerMac8_1_SystemFansCtrlLoop.h"


OSDefineMetaClassAndStructors( PowerMac8_1_SystemFansCtrlLoop, SMU_Neo2_PIDCtrlLoop )

IOReturn PowerMac8_1_SystemFansCtrlLoop::initPlatformCtrlLoop(const OSDictionary *dict)
	{
	IOReturn							result;

	result = SMU_Neo2_PIDCtrlLoop::initPlatformCtrlLoop( dict );

	cpuFanCtrlLoop = NULL;

	OSArray*							linearFactors;
	OSDictionary*						factorDict;
	OSData*								factorData;

	linearFactors = OSDynamicCast( OSArray, dict->getObject( "linear-factors" ) );

	factorDict = OSDynamicCast( OSDictionary, linearFactors->getObject( 0 ) );

	factorData = OSDynamicCast( OSData, factorDict->getObject( "scaling" ) );
	scalingFactorA = *( SInt16 * ) factorData->getBytesNoCopy();

	factorData = OSDynamicCast( OSData, factorDict->getObject( "offset" ) );
	constantB = *( SInt16 * ) factorData->getBytesNoCopy();

	factorDict = OSDynamicCast( OSDictionary, linearFactors->getObject( 1 ) );

	factorData = OSDynamicCast( OSData, factorDict->getObject( "scaling" ) );
	scalingFactorE = *( SInt16 * ) factorData->getBytesNoCopy();

	factorData = OSDynamicCast( OSData, factorDict->getObject( "offset" ) );
	constantF = *( SInt16 * ) factorData->getBytesNoCopy();

	linkedCtrlLoopID = OSDynamicCast( OSNumber, dict->getObject( "linked-ctrlloop-id" ) );
	linkedCtrlLoopID->retain();

	return( result );
	}


ControlValue PowerMac8_1_SystemFansCtrlLoop::calculateNewTarget( void ) const
	{
	ControlValue								newTarget;

	newTarget = SMU_Neo2_PIDCtrlLoop::calculateNewTarget();

	if ( linkedControl )
		{
		// Apply any hard limits.

		newTarget = min( newTarget, linkedControlOutputMax );
		newTarget = max( newTarget, linkedControlOutputMin );
		}

	return( newTarget );
	}


void PowerMac8_1_SystemFansCtrlLoop::sendNewTarget( ControlValue newTarget )
	{
	targetValue = newTarget;

	if ( linkedControl &&
		( ( ctrlloopState == kIOPCtrlLoopFirstAdjustment ) || ( ctrlloopState == kIOPCtrlLoopDidWake ) ||
		( newTarget != linkedControl->getTargetValue() ) ) )
		{
		if ( linkedControl->sendTargetValue( newTarget ) )
			{
			linkedControl->setTargetValue( newTarget );
			ctrlloopState = kIOPCtrlLoopAllRegistered;
			}
		else
			{
			CTRLLOOP_DLOG( "PowerMac8_1_SystemFansCtrlLoop::sendNewTarget failed to send target value to linked control\n" );
			}
		}

	ControlValue						scaledNewTarget;
	ControlValue						pinnedScaledNewTarget;
	ControlValue						scaledCPUFanTarget = 0;
	ControlValue						cpuFanTarget = 0;

	// Try and find the PowerMac8_1_CPUFanCtrlLoop here...

	if ( !cpuFanCtrlLoop )
		{
		if ( ( cpuFanCtrlLoop = OSDynamicCast( PowerMac8_1_CPUFanCtrlLoop, platformPlugin->lookupCtrlLoopByID( linkedCtrlLoopID ) ) ) != NULL )
			{
			linkedCtrlLoopID->release();
			linkedCtrlLoopID = NULL;
			}
		}

	long long							mx;

	mx = ( newTarget * scalingFactorA );
	scaledNewTarget = ( mx >> 12 ) + constantB;

	if ( cpuFanCtrlLoop != NULL )
		{
		// Scale cpuFanTarget linearly by scalingFactor (4.12 signed) and constant (16.0 signed).

		cpuFanTarget = cpuFanCtrlLoop->getCtrlLoopTarget();

		mx = ( cpuFanTarget * scalingFactorE );
		scaledCPUFanTarget = ( mx >> 12 ) + constantF;
		}

	pinnedScaledNewTarget = max( ( SInt16 ) scaledNewTarget, ( SInt16 ) scaledCPUFanTarget );

	pinnedScaledNewTarget = min( ( SInt16 ) pinnedScaledNewTarget, ( SInt16 ) outputMax );
	pinnedScaledNewTarget = max( ( SInt16 ) pinnedScaledNewTarget, ( SInt16 ) outputMin );

	if ( ( ctrlloopState == kIOPCtrlLoopFirstAdjustment ) || ( ctrlloopState == kIOPCtrlLoopDidWake ) ||
		( pinnedScaledNewTarget != outputControl->getTargetValue() ) )
		{
		if ( outputControl->sendTargetValue( pinnedScaledNewTarget ) )
			{
			outputControl->setTargetValue( pinnedScaledNewTarget );
			ctrlloopState = kIOPCtrlLoopAllRegistered;
			}
		else
			{
			CTRLLOOP_DLOG( "PowerMac8_1_SystemFansCtrlLoop::sendNewTarget failed to send target value to first control\n" );
			}
		}
	}


ControlValue PowerMac8_1_SystemFansCtrlLoop::getCtrlLoopTarget( void ) const
	{
	return( targetValue );
	}
