Apple16X50UARTSyncPower.cpp   [plain text]


/*
 * Copyright (c) 2004-2006 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@
 */


#include "Apple16X50UARTSync.h"


/****** From iokit/IOKit/pwr_mgt/IOPMpowerState.h for reference (see ourPowerStates below) ******

struct IOPMPowerState
{
    unsigned long	version;				// version number of this struct

    IOPMPowerFlags	capabilityFlags;			// bits that describe the capability
    IOPMPowerFlags	outputPowerCharacter;			// description (to power domain children)
    IOPMPowerFlags	inputPowerRequirement;			// description (to power domain parent)

    unsigned long	staticPower;				// average consumption in milliwatts
    unsigned long	unbudgetedPower;			// additional consumption from separate power supply (mw)
    unsigned long	powerToAttain;				// additional power to attain this state from next lower state (in mw)

    unsigned long	timeToAttain;				// (microseconds)
    unsigned long	settleUpTime;				// (microseconds)
    unsigned long	timeToLower;				// (microseconds)
    unsigned long	settleDownTime;				// (microseconds)

    unsigned long	powerDomainBudget;			// power in mw a domain in this state can deliver to its children
};

*************************************************************************************************/
enum {
    kACPI_Settle_time = 500	// guess 500 microseconds
};

enum {			// just two power states supported, on and off.
    kACPI_PowerStateOff = 0,
    kACPI_PowerStateOn,
    kACPI_PowerStateCount
};

static IOPMPowerState gOurPowerStates[kACPI_PowerStateCount] =
{
    {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, IOPMDeviceUsable | IOPMMaxPerformance, IOPMPowerOn, IOPMPowerOn, 50, 0, 0,
	kACPI_Settle_time, kACPI_Settle_time, kACPI_Settle_time, kACPI_Settle_time, 0}
};

#pragma mark -- Class overrides

/****************************************************************************************************/
//
//		Method:		Apple16X50UARTSync::registerWithPolicyMaker
//
//		Inputs:		policyMaker - the power policy maker
//
//		Outputs:	Return code - various
//
//		Desc:		Initialize the driver for power management and register
//				ourselves with policy-maker. Called by superclass - not by
//				Power Management
//
/****************************************************************************************************/

bool Apple16X50UARTSync::initForPM(IOService *provider)
{
    IOReturn	rc;

    PMinit();                   				// Initialize superclass variables
    provider->joinPMtree(this); 				// Attach into the power management hierarchy
    if (pm_vars == NULL) {					// Did it work
        return false;
    }

    // Initialize power management support state.
    
    // if async on/off might need two of these
    fPowerThreadCall = thread_call_allocate(handleSetPowerState,
					    (thread_call_param_t) this );

    if (fPowerThreadCall == NULL) {		// check early, check often
	return false;
    }

    // We've done the PMinit, so we're the policy mgr.  Register w/ourselves as the driver (yuck)
    rc = registerPowerDriver(this, gOurPowerStates, kACPI_PowerStateCount);
    if (rc) {
        return false;
    }

    return true;

}/* end registerWithPolicyMaker */

    

/****************************************************************************************************/
//
//		Method:		Apple16X50UARTSync::setPowerState
//
//		Inputs:		powerStateOrdinal - the state being set
//
//		Outputs:	Return code - IOPMAckImplied or IOPMNoSuchState
//
//		Desc:		Power state is being set
//
/****************************************************************************************************/

IOReturn Apple16X50UARTSync::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice)
{
    bool ok;
    UInt32 counter = 0;

//	IOLog("Apple16X50UARTSync::setPowerState (%ld) - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n",powerStateOrdinal);
    	
    retain();				// paranoia is your friend, make sure we're not freed
	
    fWaitForGatedCmd = true;		// could do this async, but let's be sync initially
    
    ok = thread_call_enter1(fPowerThreadCall, (void *)powerStateOrdinal);     // schedule work on workloop
	
    if (ok) {				// if thread was already pending ...
	release();			// don't need/want the retain, so undo it
    }

    while (fWaitForGatedCmd) {		// we're being sync for now, wait for it to finish
	IOSleep(2);			// it should be very fast
	counter++;
    }
    
//	IOLog("Apple16X50UARTSync::setPowerState - <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
    return IOPMAckImplied;		// we're done
    
}/* end setPowerState */



#pragma mark -- Support and private Methods

//---------------------------------------------------------------------------
// handleSetPowerState()
//
// param0 - the object
// param1 - unsigned long, new power state ordinal
//---------------------------------------------------------------------------
//static
void Apple16X50UARTSync::handleSetPowerState(thread_call_param_t param0, thread_call_param_t param1 )
{
    Apple16X50UARTSync *self = OSDynamicCast(Apple16X50UARTSync, (const OSMetaClassBase *)param0);
    UInt32 on_off = (UInt32)param1;		// new power state
    
    if (self && self->CommandGate) {
	self->CommandGate->runAction(&(self->setPowerStateGated), (void *)on_off, (void *)0, (void *)0, (void *)0);
	self->release();		// offset the retain in setPowerState()
    }
}

//---------------------------------------------------------------------------
// setPowerState()
//
// owner = the object
// arg0 = boolean, true=power on, false=power off
//---------------------------------------------------------------------------
// static
IOReturn Apple16X50UARTSync::setPowerStateGated(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
    Apple16X50UARTSync *self = OSDynamicCast(Apple16X50UARTSync, (const OSMetaClassBase *)owner);
    UInt32 newState = (UInt32)arg0;		// new power state to go to
    
    // sleep -> save UART settings
    // wake -> restore UART settings
    // assumptions: not powering off no need to fully reprogram the chip
    if (self && self->portOpened && self->fCurrentPowerState != newState) 
	{
		if (newState) 
		{
			self->restoreUART();
			self->setStateGated(PD_RS232_S_CAR, PD_RS232_S_CAR);
		}
		else 
		{
			self->saveUART();
			self->setStateGated(0, PD_RS232_S_CAR);
		}
    }
    
    self->fCurrentPowerState = newState;
    self->fWaitForGatedCmd = false;	    // release caller (power thread)
    return kIOReturnSuccess;
}


/****************************************************************************************************/
//
//		Method:		Apple16X50UARTSync::maxCapabilityForDomainState
//
//		Inputs:		domainState - current state
//
//		Outputs:	Return code - maximum state
//
//		Desc:		Returns the maximum state of card power, which would be
//		  		power on without any attempt to manager power
//
/****************************************************************************************************/

unsigned long Apple16X50UARTSync::maxCapabilityForDomainState(IOPMPowerFlags domainState)
{
    if (domainState & IOPMPowerOn ) {
        return kACPI_PowerStateCount - 1;
    }

    return 0;

}/* end maxCapabilityForDomainState */

/****************************************************************************************************/
//
//		Method:		Apple16X50UARTSync::initialPowerStateForDomainState
//
//		Inputs:		domainState - current state
//
//		Outputs:	Return code - initial state
//
//		Desc:		The power domain may be changing state.	If power is on in the new
//				state, that will not affect our state at all. If domain power is off,
//				we can attain only our lowest state, which is off
//
/****************************************************************************************************/

unsigned long Apple16X50UARTSync::initialPowerStateForDomainState(IOPMPowerFlags domainState)
{
    if (domainState & IOPMPowerOn) {
        return kACPI_PowerStateCount - 1;
    }
    return 0;

}/* end initialPowerStateForDomainState */

/****************************************************************************************************/
//
//		Method:		Apple16X50UARTSync::powerStateForDomainState
//
//		Inputs:		domainState - current state
//
//		Outputs:	Return code - power state
//
//		Desc:		The power domain may be changing state.	If power is on in the new
//				state, that will not affect our state at all. If domain power is off,
//				we can attain only our lowest state, which is off
//
/****************************************************************************************************/

unsigned long Apple16X50UARTSync::powerStateForDomainState(IOPMPowerFlags domainState )
{

    if (domainState & IOPMPowerOn) {
        return 1;						// This should answer What If?
    }
    return 0;

}/* end powerStateForDomainState */