#ifndef _APPLEFAN_H
#define _APPLEFAN_H
#include <IOKit/IOService.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/i2c/PPCI2CInterface.h>
__BEGIN_DECLS
#include <kern/thread_call.h>
__END_DECLS
#ifdef DLOG
#undef DLOG
#endif
#ifdef APPLEFAN_DEBUG
#define DLOG(fmt, args...) kprintf(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
#define kConfigReg1 0x00
#define kConfigReg2 0x01
#define kExtTempReg 0x06
#define kLocalTempReg 0x0A
#define kRemoteTempReg 0x0B
#define kFanCharReg 0x20
#define kSpeedCfgReg 0x22
#define kFanFilterReg 0x23
#define kLocTminTrange 0x24
#define kRmtTminTrange 0x25
#define kMonitorEnable 0x01
#define kINTEnable 0x02
#define kTACHModeSelect 0x04
#define kPWMInvertEnable 0x08
#define kFanFaultEnable 0x10
#define kPWMModeSelectMask 0x60 // mask for this field
#define kPWMModeRemote 0x00 // remote temp drives fan speed
#define kPWMModeFastest 0x60 // faster of local,remote drives fan speed
#define kAutoEnable 0x80
#define kPWMOutputEnable 0x01
#define kTACHInputEnable 0x04
#define kLocTempINTEnable 0x10
#define kRmtTempINTEnable 0x20
#define kSWReset 0x80
#define kRemoteExtMask 0x07
#define kRemoteExtShift 5
#define kLocalExtMask 0xC0
#define kSpinUpTimeMask 0x07
#define kSpinUp200MS 0x00
#define kSpinUp400MS 0x01
#define kSpinUp600MS 0x02
#define kSpinUp800MS 0x03
#define kSpinUp1000MS 0x04
#define kSpinUp2000MS 0x05 // power-on default
#define kSpinUp4000MS 0x06
#define kSpinUp8000MS 0x07
#define kPWMFreqMask 0x38
#define kPWMFreq11Hz 0x00
#define kPWMFreq15Hz 0x08
#define kPWMFreq23Hz 0x10
#define kPWMFreq31Hz 0x18 // power-on default
#define kPWMFreq37Hz 0x20
#define kPWMFreq46Hz 0x28
#define kPWMFreq62Hz 0x30
#define kPWMFreq93Hz 0x38
#define kSpeedRangeMask 0xC0
#define kSpeedRange2647 0x00
#define kSpeedRange1324 0x40 // power-on default
#define kSpeedRange662 0x80
#define kSpeedRange331 0xC0
#define kDutyCycleOff 0x00
#define kDutyCycle07 0x01
#define kDutyCycle14 0x02
#define kDutyCycle20 0x03
#define kDutyCycle27 0x04
#define kDutyCycle33 0x05
#define kDutyCycle40 0x06
#define kDutyCycle47 0x07
#define kDutyCycle53 0x08
#define kDutyCycle60 0x09
#define kDutyCycle67 0x0A
#define kDutyCycle73 0x0B
#define kDutyCycle80 0x0C
#define kDutyCycle87 0x0D
#define kDutyCycle93 0x0E
#define kDutyCycleFull 0x0F
#define kFilterEnable 0x01
#define kSampleRateMask 0x1C
#define kSampleRate87_5Hz 0x00
#define kSampleRate175Hz 0x04
#define kSampleRate350Hz 0x08
#define kSampleRate700Hz 0x0C
#define kSampleRate1_4KHz 0x10 // power-on default
#define kSampleRate2_8KHz 0x14
#define kSampleRate5_6KHz 0x18
#define kSampleRate11_2KHz 0x1C
#define kRampRateMask 0x60
#define kRampRate1 0x00
#define kRampRate2 0x20
#define kRampRate4 0x40 // power-on default
#define kRampRate8 0x60
#define kSpinUpDisable 0x80
#define kTminMask 0xF8
#define kTrangeMask 0x07
#define kDefaultParamsKey "default-params"
#define kFanPollingPeriodKey "fan-polling-period"
#define kFanSpeedTableKey "fan-speed-table"
#define kSpeedupDelayKey "fan-speedup-delay"
#define kSlowdownDelayKey "fan-slowdown-delay"
#define kHysteresisTempKey "fan-hysteresis-temp"
#define kFanCurrentSpeedKey "fan-current-speed"
#define kCPUCurrentTempKey "cpu-current-temp"
#define kGetTempSymbol "platform-getTemp"
#define kForceUpdateSymbol "force-update"
#define sec2ms(nSeconds) (1000*nSeconds)
#define temp2str(myTemp, myString) \
sprintf(myString, "%d", myTemp >> 8);
#define kNumRetries 10
#define kTempMaxDelta 20
typedef struct {
UInt8 config1;
UInt8 config2;
UInt8 fan_char;
UInt8 speed_cfg;
UInt8 fan_filter;
UInt8 loc_tmin_trange;
UInt8 rmt_tmin_trange;
} adm1030_regs_t;
enum {
kPowerOff,
kPowerOn,
kNumPowerStates
};
#define kNumFanSpeeds 16
typedef SInt16 fan_speed_table_t[kNumFanSpeeds];
#define kADM1030Compatible "adm1030"
class AppleFan : public IOService
{
OSDeclareDefaultStructors(AppleFan)
private:
PPCI2CInterface *I2C_iface; IOService *cpu_thermo; UInt32 fThermoPHandle;
UInt8 fI2CBus; UInt8 fI2CAddr;
adm1030_regs_t fSavedRegs;
fan_speed_table_t fSpeedTable;
UInt64 fSpeedupDelay; UInt64 fSlowdownDelay;
SInt16 fHysteresisTemp;
AbsoluteTime fLastTransition;
UInt64 fPollingPeriod;
UInt8 fLastFanSpeed;
SInt16 fLastRmtTemp;
AbsoluteTime fWakeTime;
unsigned long fCurrentPowerState;
thread_call_t timerCallout;
const OSSymbol *pollingPeriodKey;
const OSSymbol *speedTableKey;
const OSSymbol *speedupDelayKey;
const OSSymbol *slowdownDelayKey;
const OSSymbol *hysteresisTempKey;
const OSSymbol *getTempSymbol;
#ifdef APPLEFAN_DEBUG
const OSSymbol *currentSpeedKey;
const OSSymbol *currentCPUTempKey;
const OSSymbol *forceUpdateKey;
#endif
bool initParms(IOService *provider);
bool initHW(IOService *provider);
bool getRemoteTemp(SInt16 *rmt_temp);
bool getCPUTemp(SInt16 *cpu_temp);
void doUpdate(bool first);
void setFanSpeed(UInt8 speed, SInt16 cpu_temp, bool first);
void setADM1030SpeedMagically(UInt8 desiredSpeed, SInt16 rmt_temp);
void doSleep(void);
void doWake(void);
void doRestart(void);
void setRestartMode(void);
bool saveADM1030State(adm1030_regs_t *);
void restoreADM1030State(adm1030_regs_t *);
bool doI2COpen(void);
void doI2CClose(void);
bool doI2CRead(UInt8 sub, UInt8 *bytes, UInt16 len);
bool doI2CWrite(UInt8 sub, UInt8 *bytes, UInt16 len);
#ifdef APPLEFAN_DEBUG
void publishSpeedTable(void);
void publishPollingPeriod(void);
void publishDelays(void);
void publishHysteresisTemp(void);
void publishCurrentSpeed(void);
void publishCurrentCPUTemp(void);
#endif
public:
#ifdef APPLEFAN_DEBUG
virtual IOReturn setProperties(OSObject *properties);
#endif
void parseDict(OSDictionary *props);
virtual IOReturn powerStateWillChangeTo(IOPMPowerFlags flags,
unsigned long stateNumber, IOService *whatDevice);
virtual IOReturn setPowerState(unsigned long powerStateOrdinal,
IOService *whatDevice);
virtual IOReturn powerStateDidChangeTo(IOPMPowerFlags flags,
unsigned long stateNumber, IOService *whatDevice);
virtual IOService *probe(IOService *provider, SInt32 *score);
virtual bool init(OSDictionary *dict);
virtual void free(void);
virtual bool start(IOService *provider);
virtual void stop(IOService *provider);
static void timerEventOccured( void * self );
static IOReturn sPMNotify(void *target, void *refCon,
long unsigned int messageType, IOService *provider,
void *messageArg, vm_size_t argSize);
};
#endif