/*
 * Copyright (c) 2002-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) 2002-2004 Apple Computer, Inc.  All rights reserved.
 *
 *  DRI: Dave Radcliffe
 *
 */


#ifndef _IOPLATFORMPLUGIN_H
#define _IOPLATFORMPLUGIN_H

#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOCPU.h>
//#include <IOKit/IOWorkLoop.h>
//#include <IOKit/IOCommandGate.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOMessage.h>

__BEGIN_DECLS
#include <kern/thread_call.h>
__END_DECLS

#include "IOPlatformPluginDefs.h"
#include "IOPlatformStateSensor.h"
#include "IOPlatformControl.h"
#include "IOPlatformCtrlLoop.h"

#ifdef DLOG
#undef DLOG
#endif

// Uncomment for debug info
//#define PLUGIN_DEBUG 1

#ifdef PLUGIN_DEBUG
#define DLOG(fmt, args...)  kprintf(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif

// compile in the PlatformConsole accessor in setProperties()
#define IMPLEMENT_SETPROPERTIES 1

/* internal power state */
enum {
	kIOPPluginSleeping,
	kIOPPluginRunning,
	kIOPPluginNumPowerStates
};

// setAggressiveness flags - UInt32
enum {
	kSetAggrUserAuto	= 0x80000000,				// setAggressiveness call generated automatically
	kSetAggrSourceMask	= ~kSetAggrUserAuto
};

// Maximum number of cpus we support
enum {
	kMaxCpus	= 16
};

/*!
    @class IOPlatformPlugin
    @abstract A class for monitor system functions such as power and thermal */
class IOPlatformPlugin : public IOService
{
    OSDeclareDefaultStructors(IOPlatformPlugin)	

private:

protected:

/* Messages from all sources are put into an IOPPluginEventData structure and
	processed under the protection of a command gate.  The parameter contents
	are keyed off the event type. */
typedef struct IOPPluginEventData
{
	UInt32				eventType;
	void*				param1;
	void*				param2;
	void*				param3;
	void*				param4;
};

typedef IOReturn ( *IOPPluginSyncHandler )( void * p1, void * p2, void * p3 );

/* Event types */
enum {
	IOPPluginEventSetAggressiveness	= 0,	// param1 = selector, param2 = newLevel
	IOPPluginEventSystemWillSleep	= 1,	// params all NULL
	IOPPluginEventSystemDidWake		= 2,	// params all NULL
	IOPPluginEventMessage			= 3,	// param1 = type, param2 = IOService * sender, param3 = dict
	IOPPluginEventPlatformFunction	= 4,	// params match callPlatformFunction() params
	IOPPluginEventSetProperties		= 5,	// param1 = OSObject * properties
	IOPPluginEventTimer				= 6,	// no params used
	IOPPluginEventSystemRestarting	= 7,	// params all NULL
	IOPPluginEventMisc				= 8		// param1, param2, param3 are parameters to (IOPPluginSyncHandler *) param4
};

/* message types */
enum {
	kIOPPluginMessageRegister			= 1,
	kIOPPluginMessageUnregister			= 2,
	kIOPPluginMessageLowThresholdHit	= 3,
	kIOPPluginMessageHighThresholdHit	= 4,
	kIOPPluginMessageCurrentValue		= 5,
	kIOPPluginMessageStateChanged		= 6,
	kIOPPluginMessagePowerMonitor		= 7,
	kIOPPluginMessageError				= 8,
	kIOPPluginMessageGetPlatformID		= 9
};

	/* This lock protects _ALL_ of the internal state and instance data within the plugin and provides serialization for all entry points */
	IORecursiveLock *	gate;

	/* the deadline timer thread callout */
	thread_call_t		timerCallout;

	/* a pointer to the root power domain, initialized in ::start() */
	IOPMrootDomain *	pmRootDomain;

	/* initializes all IOPlatformPluginFamily symbols */
	virtual void 		initSymbols( void );

	/* unsynchronized event dispatcher -- all unsynchronized entry points call through dispatchEvent(), which in turn aquires the gate lock and passes control to the synchronized event handler, handleEvent(). */
	virtual IOReturn	dispatchEvent(IOPPluginEventData *event);  /* BLOCKING */

	/* synchronized event handler -- processes events under protection of the gate lock */
	virtual IOReturn	handleEvent(IOPPluginEventData *event);

	/* the array of IOPlatformSensor objects */
	OSArray *			sensors;

	/* an array of pointers to the IOPlatformSensor::infoDict dictionaries of all registered sensors.  This array is published in the I/O registry */
	OSArray *			sensorInfoDicts;

	/* the array of IOPlatformControl objects */
	OSArray *			controls;

	/* an array of pointers to the IOPlatformControl::infoDict dictionaries of all registered controls.  This array is published in the I/O registry */
	OSArray *			controlInfoDicts;

	/* the array of IOPlatformCtrlLoop objects */
	OSArray *			ctrlLoops;

	/* an array of pointers to the IOPlatformCtrlLoop::infoDict dictionaries of all control loops.  This array is published in the I/O registry */
	OSArray *			ctrlLoopInfoDicts;
	
	/* simple array of references to registered cpus */
	IOCPU				*cpus[kMaxCpus];

	/* a flag to record whether or not the environment dictionary has changed during the current pass through handleEvent().  This flag is cleared after every invocation of handleEvent().  If it is set during a pass, then all the control loops are notified of the environment change and allowed a chance to react immediately */
	bool				envChanged;

	int					pluginPowerState;

/*!	@var envInfo The platform plugin maintains environmental information about the condition of the system, including clamshell state, user preferences and failure state.  This information is accessed by IOPlatformCtrlLoops  so that they can correctly choose their metastate. */
	OSDictionary *envInfo;

/*!
	@function probeConfig
	@abstract The platform plugin calls this method at system startup time to determine the machine configuration, i.e. uniprocessor, dual processor, etc.  The returned value is an index into the ConfigArray array in the machine's thermal profile.  The default implementation returns 0.  Subclasses should override this method with code capable of determining the machine's config.  */
	virtual UInt8 probeConfig( void );

/*!	@var machineConfig
	@abstract The platform plugin caches the results of a getConfig() call in this variable.  getConfig() should only be called from IOPlatformPlugin::start a single time, all subsequent need of the machine configuration index should use the contents of this variable. */
	UInt8 machineConfig;

/*!
	@function initThermalProfile
	@abstract Parse thermal profile data and set up all internal data structures.  This prepares the platform plugin to accept registration and power management messages, and starts a control registration timer that will trigger a failure mechanism if a control doesn't register. */
	virtual bool initThermalProfile(IOService *nub);

/*!
	@function setTimeout
	@abstract Check for outstanding deadlines with all the ctrl loops, and set a timer callback if necessary. */
	void setTimeout( const AbsoluteTime now );

/*!
	@function timerHandler
	@abstract serialized timer callback handler */
	void timerHandler( const AbsoluteTime now );

/*!
	@function sleepHandler
	@abstract serialized sleep notification handler */
	virtual IOReturn sleepHandler(void);

/*!
	@function wakeHandler
	@abstract serialized wake notification handler */
	virtual IOReturn wakeHandler(void);

/*!
	@function restartHandler
	@abstract serialized restart notification handler */
	virtual IOReturn restartHandler(void);

/*!
	@function messageHandler
	@abstract serialized message() notification handler */
	IOReturn messageHandler(UInt32 type, IOService *sender, OSDictionary *dict);

/*!
	@function setAggressivenessHandler
	@abstract serialized setAggressiveness() handler */
	IOReturn setAggressivenessHandler(unsigned long selector, unsigned long newLevel);

/*!
	@function registerHandler
	@abstract handles registration messages */
	IOReturn registrationHandler( IOService *sender, OSDictionary *dict );

/*!
	@function setPropertiesHandler
	@abstract handles setProperties calls */
	IOReturn setPropertiesHandler( OSObject * properties );

/*!
	@function environmentChanged
	@abstract Notify the ctrl loops that the environment dict has changed */
	virtual void		environmentChanged( void );

	virtual bool initControls( const OSArray * controlDicts );
	virtual bool initSensors( const OSArray * sensorDicts );
	virtual bool initCtrlLoops( const OSArray * ctrlLoopDicts );
	virtual bool validOnConfig( const OSArray * validConfigs );

/*!
	@function registerChassisSwitchNotifier
	@abstract Register for clamshell notifications */
	virtual void registerChassisSwitchNotifier( void );

/*!
	@function pollChassisSwitch
	@abstract Poll the clamshell switch */
	virtual OSBoolean *pollChassisSwitch( void );

public:

	virtual UInt8 getConfig( void );

/*!
	@function lookupSensorByID
	@abstract Search the list of known sensors and return the first one with the given ID
	@param sensorID The Sensor ID of the desired sensor */
	virtual IOPlatformSensor * lookupSensorByID( const OSNumber * sensorID ) const;

/*!
	@function lookupControlByID
	@abstract Search the list of known controls and return the first one with the given ID
	@param ctrlID The Control ID of the desired controller */
	virtual IOPlatformControl * lookupControlByID( const OSNumber * controlID ) const;

/*!
	@function lookupCtrlLoopByID
	@abstract Search the list of control loops and return the first one with the given ID
	@param ctrlLoopID The Control Loop ID of the desired Control Loop */
	virtual IOPlatformCtrlLoop * lookupCtrlLoopByID( const OSNumber * ctrlLoopID ) const;

/*!
	@function lookupCpuByID
	@abstract Search the list of known cpus and return the one with the given ID
	@param cpuID The cpu-id number of the desired cpu */
	virtual IOCPU * lookupCpuByID( const UInt32 cpuID ) const;

/*!
	@function lookupSensorByKey
	@abstract Search the list of known sensors and return the first one whose Desc_Key matches the given key */
	virtual IOPlatformSensor * lookupSensorByKey( const OSString * sensorKey ) const;
	virtual IOPlatformSensor * lookupSensorByKey( const char * sensorDesc ) const;

/*!
	@function lookupControlByKey
	@abstract Search the list of known controls and return the first one whose Desc_Key matches the given key */
	virtual IOPlatformControl * lookupControlByKey( const OSString * controlKey ) const;
	virtual IOPlatformControl * lookupControlByKey( const char * controlDesc ) const;

/*!
	@function setEnv
	@abstract environmental dictionary accessors with OSDictionary semantics */
	virtual bool		setEnv(const OSString *aKey, const OSMetaClassBase *anObject);
	virtual bool		setEnv(const char *aKey, const OSMetaClassBase *anObject);
	virtual bool		setEnv(const OSSymbol *aKey, const OSMetaClassBase *anObject);

	virtual bool 		setEnvArray( const OSSymbol * aKey, const OSObject * setter, bool setting );
	virtual bool		envArrayCondIsTrue( const OSSymbol *cond ) const;
	virtual bool		envArrayCondIsTrueForObject( const OSObject * obj, const OSSymbol *cond ) const;

/*!
	@function getEnv
	@abstract environmental dictionary getter with OSDictionary::getObject semanitics */
	virtual OSObject	*getEnv(const char *aKey) const;
	virtual OSObject	*getEnv(const OSString *aKey) const;
	virtual OSObject	*getEnv(const OSSymbol *aKey) const;

/*!
	@function matchPlatformFlags
	@abstract Perform a logical AND of the supplied flagsBits with the PlatformFlags (defined in the Thermal Profile). Return the result as a boolean. Bits are defined in IOPlatformPluginDefs.h (see IOPPluginEvnPlatformFlags) */
	virtual	bool		matchPlatformFlags( UInt32 flagsBits );

	virtual bool 		start(IOService *nub);
	virtual void		stop(IOService *nub);
	virtual IOService *	probe(IOService *nub, SInt32 *score);
	virtual bool		init(OSDictionary *dict);
	virtual void		free(void);

	virtual IOReturn	setPowerState(unsigned long whatState, IOService *policyMaker);
	static	IOReturn	sysPowerDownHandler(void *, void *, UInt32, IOService *, void *, vm_size_t);
    virtual IOReturn	message( UInt32 type, IOService * provider, void * argument = 0 );
    virtual IOReturn	setAggressiveness(unsigned long selector, unsigned long newLevel);
	virtual IOReturn	setProperties( OSObject * properties );

/*!
	@function timerEventOccured
	@abstract Timer callback routine, conforms to IOTimerEventSource::Action prototype */
    static void			timerEventOccured( void * self );

	virtual void		sleepSystem( void );

/*!
	@function coreDump
	@abstract Sends current state description to IOLog. */
	void 				coreDump(void);

};


class IOPlatformPluginThermalProfile : public IOService
{
	OSDeclareDefaultStructors( IOPlatformPluginThermalProfile );

protected:

						IOPlatformPlugin*			platformPlugin;

public:

		virtual			bool						start( IOService* nub );
		virtual			void						adjustThermalProfile( void );
		virtual			UInt8						getThermalConfig( void );
};


#endif // _IOPLATFORMPLUGIN_H
