#include <sys/cdefs.h>
__BEGIN_DECLS
#include <ppc/proc_reg.h>
#include <ppc/machine_routines.h>
#include <mach/mach_types.h>
extern vm_offset_t ml_io_map(vm_offset_t phys_addr, vm_size_t size);
__END_DECLS
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOKitKeys.h>
#include "MacRISC2.h"
#include <IOKit/pci/IOPCIDevice.h>
static unsigned long macRISC2Speed[] = { 0, 1 };
#include <IOKit/pwr_mgt/RootDomain.h>
#include "IOPMSlotsMacRISC2.h"
#include "IOPMUSBMacRISC2.h"
#include <IOKit/pwr_mgt/IOPMPagingPlexus.h>
#include <IOKit/pwr_mgt/IOPMPowerSource.h>
extern char *gIOMacRISC2PMTree;
#define super ApplePlatformExpert
OSDefineMetaClassAndStructors(MacRISC2PE, ApplePlatformExpert);
bool MacRISC2PE::start(IOService *provider)
{
long machineType;
OSData *tmpData;
IORegistryEntry *uniNRegEntry;
IORegistryEntry *powerMgtEntry;
UInt32 *primInfo;
UInt32 uniNArbCtrl, uniNBaseAddressTemp, uniNMPCIMemTimeout;
UInt32 stepType;
OSDictionary *propTable;
OSCollectionIterator *propIter;
OSString *propKey;
OSData *propVal;
SInt32 numFuncs, retval;
setChipSetType(kChipSetTypeCore2001);
provider_name = provider->getName();
machineType = kMacRISC2TypeUnknown;
doPlatformPowerMonitor = false;
if (provider_name != NULL) {
if (0 == strncmp(provider_name, "PowerMac", strlen("PowerMac")))
machineType = kMacRISC2TypePowerMac;
else if (0 == strncmp(provider_name, "RackMac", strlen("RackMac")))
machineType = kMacRISC2TypePowerMac;
else if (0 == strncmp(provider_name, "PowerBook", strlen("PowerBook")))
machineType = kMacRISC2TypePowerBook;
else if (0 == strncmp(provider_name, "iBook", strlen("iBook")))
machineType = kMacRISC2TypePowerBook;
else IOLog ("AppleMacRISC2PE - warning: unknown machineType\n");
}
isPortable = (machineType == kMacRISC2TypePowerBook);
setMachineType(machineType);
tmpData = OSDynamicCast(OSData, provider->getProperty("clock-frequency"));
if (tmpData == 0) return false;
macRISC2Speed[0] = *(unsigned long *)tmpData->getBytesNoCopy();
uniNRegEntry = provider->childFromPath("uni-n", gIODTPlane);
if (uniNRegEntry == 0) return false;
tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("reg"));
if (tmpData == 0) return false;
uniNBaseAddressTemp = ((unsigned long *)tmpData->getBytesNoCopy())[0];
uniNBaseAddress = (unsigned long *)ml_io_map(uniNBaseAddressTemp, 0x3200);
if (uniNBaseAddress == 0) return false;
uniNVersion = readUniNReg(kUniNVersion);
if (uniNVersion < kUniNVersion150)
{
uniNArbCtrl = readUniNReg(kUniNArbCtrl);
uniNArbCtrl &= ~kUniNArbCtrlQAckDelayMask;
if (uniNVersion < kUniNVersion107)
{
uniNArbCtrl |= kUniNArbCtrlQAckDelay105 << kUniNArbCtrlQAckDelayShift;
}
else
{
uniNArbCtrl |= kUniNArbCtrlQAckDelay << kUniNArbCtrlQAckDelayShift;
}
writeUniNReg(kUniNArbCtrl, uniNArbCtrl);
}
if ( ((uniNVersion >= kUniNVersion150) && (uniNVersion <= kUniNVersion200)) ||
(uniNVersion == kUniNVersionPangea) )
{
uniNMPCIMemTimeout = readUniNReg(kUniNMPCIMemTimeout);
uniNMPCIMemTimeout &= ~kUniNMPCIMemTimeoutMask;
uniNMPCIMemTimeout |= kUniNMPCIMemGrantTime;
writeUniNReg(kUniNMPCIMemTimeout, uniNMPCIMemTimeout);
}
numFuncs = 0;
if ( ((propTable = uniNRegEntry->dictionaryWithProperties()) == 0) ||
((propIter = OSCollectionIterator::withCollection(propTable)) == 0) ) {
if (propTable) propTable->release();
return(false);
}
while ((propKey = OSDynamicCast(OSString, propIter->getNextObject())) != 0) {
if (strncmp(kFunctionProvidedPrefix,
propKey->getCStringNoCopy(),
strlen(kFunctionProvidedPrefix)) == 0) {
propVal = OSDynamicCast(OSData, propTable->getObject(propKey));
if ((retval = parseProvidedFunction(propKey, propVal)) < 0) {
releaseResources();
numFuncs = 0;
break;
} else
numFuncs += retval;
}
}
if (propTable) { propTable->release(); propTable = 0; }
if (propIter) { propIter->release(); propIter = 0; }
if (fOnDemand) publishStrings(fOnDemand);
IOService *uniNServiceEntry = OSDynamicCast(IOService, uniNRegEntry);
if (uniNServiceEntry != NULL)
createNubs(this, uniNRegEntry->getChildIterator( gIODTPlane ));
powerMgtEntry = retrievePowerMgtEntry ();
if (powerMgtEntry == 0)
{
kprintf ("didn't find power mgt node\n");
return false;
}
tmpData = OSDynamicCast(OSData, powerMgtEntry->getProperty ("prim-info"));
if (tmpData != 0)
{
primInfo = (unsigned long *)tmpData->getBytesNoCopy();
if (primInfo != 0)
{
_pePMFeatures = primInfo[3];
_pePrivPMFeatures = primInfo[4];
_peNumBatteriesSupported = ((primInfo[6]>>16) & 0x000000FF);
kprintf ("Public PM Features: %0x.\n",_pePMFeatures);
kprintf ("Privat PM Features: %0x.\n",_pePrivPMFeatures);
kprintf ("Num Internal Batteries Supported: %0x.\n", _peNumBatteriesSupported);
}
}
mutex = IOLockAlloc();
if (mutex == NULL)
return false;
else
IOLockInit( mutex );
processorSpeedChangeFlags = kNoSpeedChange;
stepType = 0;
if (machineType == kMacRISC2TypePowerBook) {
OSIterator *childIterator;
IORegistryEntry *cpuEntry, *powerPCEntry;
OSData *cpuSpeedData, *stepTypeData;
cpuEntry = provider->childFromPath("cpus", gIODTPlane);
if ((childIterator = cpuEntry->getChildIterator (gIODTPlane)) != NULL) {
while ((powerPCEntry = (IORegistryEntry *)(childIterator->getNextObject ())) != NULL) {
if (!strncmp ("PowerPC", powerPCEntry->getName(gIODTPlane), strlen ("PowerPC"))) {
stepTypeData = OSDynamicCast( OSData, powerPCEntry->getProperty( "dynamic-power-step" ));
if (stepTypeData)
processorSpeedChangeFlags = kProcessorBasedSpeedChange | kProcessorFast |
kL3CacheEnabled | kL2CacheEnabled;
else { stepTypeData = OSDynamicCast( OSData, powerPCEntry->getProperty( "force-reduced-speed" ));
cpuSpeedData = OSDynamicCast( OSData, powerPCEntry->getProperty( "max-clock-frequency" ));
if (stepTypeData && cpuSpeedData) {
UInt32 newCPUSpeed, newNum;
doPlatformPowerMonitor = true;
processorSpeedChangeFlags = kDisableL3SpeedChange | kL3CacheEnabled | kL2CacheEnabled;
if (stepTypeData->getLength() > 0)
stepType = *(UInt32 *) stepTypeData->getBytesNoCopy();
newCPUSpeed = *(UInt32 *) cpuSpeedData->getBytesNoCopy();
if (newCPUSpeed != gPEClockFrequencyInfo.cpu_clock_rate_hz) {
if ((_pePrivPMFeatures & (1 << 17)) != 0)
processorSpeedChangeFlags |= kPMUBasedSpeedChange;
processorSpeedChangeFlags |= kEnvironmentalSpeedChange;
newNum = newCPUSpeed / (gPEClockFrequencyInfo.cpu_clock_rate_hz /
gPEClockFrequencyInfo.bus_to_cpu_rate_num);
gPEClockFrequencyInfo.bus_to_cpu_rate_num = newNum; gPEClockFrequencyInfo.cpu_clock_rate_hz = newCPUSpeed; }
} else if ((_pePrivPMFeatures & (1 << 17)) != 0)
processorSpeedChangeFlags = kPMUBasedSpeedChange | kProcessorFast |
kL3CacheEnabled | kL2CacheEnabled;
}
break;
}
}
childIterator->release();
}
}
if (doPlatformPowerMonitor) {
powerMonWeakCharger.bitsSet = kIOPMACInstalled | kIOPMACnoChargeCapability;
powerMonWeakCharger.bitsClear = 0;
powerMonWeakCharger.bitsMask = powerMonWeakCharger.bitsSet | powerMonWeakCharger.bitsClear;
powerMonBatteryWarning.bitsSet = kIOPMRawLowBattery;
powerMonBatteryWarning.bitsClear = 0;
powerMonBatteryWarning.bitsMask = powerMonBatteryWarning.bitsSet | powerMonBatteryWarning.bitsClear;
powerMonBatteryDepleted.bitsSet = kIOPMBatteryDepleted;
powerMonBatteryDepleted.bitsClear = 0;
powerMonBatteryDepleted.bitsMask = powerMonBatteryDepleted.bitsSet | powerMonBatteryDepleted.bitsClear;
powerMonBatteryNotInstalled.bitsSet = 0;
powerMonBatteryNotInstalled.bitsClear = kIOPMBatteryInstalled;
powerMonBatteryNotInstalled.bitsMask = powerMonBatteryNotInstalled.bitsSet | powerMonBatteryNotInstalled.bitsClear;
if ((stepType & 1) == 0) {
powerMonClamshellClosed.bitsSet = kIOPMClosedClamshell;
powerMonClamshellClosed.bitsClear = 0;
powerMonClamshellClosed.bitsMask = powerMonClamshellClosed.bitsSet | powerMonClamshellClosed.bitsClear;
} else { powerMonClamshellClosed.bitsMask = powerMonClamshellClosed.bitsSet = 0xFFFFFFFF;
powerMonClamshellClosed.bitsClear = 0;
}
powerMonForceLowPower.bitsSet = kIOPMForceLowSpeed;
powerMonForceLowPower.bitsClear = 0;
powerMonForceLowPower.bitsMask = powerMonForceLowPower.bitsSet | powerMonForceLowPower.bitsClear;
} else { powerMonWeakCharger.bitsMask = powerMonWeakCharger.bitsSet = 0xFFFFFFFF;
powerMonWeakCharger.bitsClear = 0;
powerMonBatteryWarning.bitsMask = powerMonBatteryWarning.bitsSet = 0xFFFFFFFF;
powerMonBatteryWarning.bitsClear = 0;
powerMonBatteryDepleted.bitsMask = powerMonBatteryDepleted.bitsSet = 0xFFFFFFFF;
powerMonBatteryDepleted.bitsClear = 0;
powerMonBatteryNotInstalled.bitsMask = powerMonBatteryNotInstalled.bitsSet = 0xFFFFFFFF;
powerMonBatteryNotInstalled.bitsClear = 0;
powerMonClamshellClosed.bitsMask = powerMonClamshellClosed.bitsSet = 0xFFFFFFFF;
powerMonClamshellClosed.bitsClear = 0;
powerMonForceLowPower.bitsMask = 0xFFFFFFFF;
powerMonForceLowPower.bitsSet = powerMonForceLowPower.bitsClear = 0; }
return super::start(provider);
}
IORegistryEntry * MacRISC2PE::retrievePowerMgtEntry (void)
{
IORegistryEntry * theEntry = 0;
IORegistryEntry * anObj = 0;
IORegistryIterator * iter;
OSString * powerMgtNodeName;
iter = IORegistryIterator::iterateOver (IORegistryEntry::getPlane(kIODeviceTreePlane), kIORegistryIterateRecursively);
if (iter)
{
powerMgtNodeName = OSString::withCString("power-mgt");
anObj = iter->getNextObject ();
while (anObj)
{
if (anObj->compareName(powerMgtNodeName))
{
theEntry = anObj;
break;
}
anObj = iter->getNextObject();
}
powerMgtNodeName->release();
iter->release ();
}
return theEntry;
}
bool MacRISC2PE::platformAdjustService(IOService *service)
{
const OSSymbol *tmpSymbol, *keySymbol;
bool result;
if (IODTMatchNubWithKeys(service, "open-pic"))
{
keySymbol = OSSymbol::withCStringNoCopy("InterruptControllerName");
tmpSymbol = IODTInterruptControllerName(service);
result = service->setProperty(keySymbol, tmpSymbol);
return true;
}
if (!strcmp(service->getName(), "programmer-switch"))
{
service->setProperty("mask_NMI", service);
return true;
}
if (!strcmp(service->getName(), "pmu"))
{
OSArray *tmpArray;
OSCollectionIterator *extIntList;
IORegistryEntry *extInt;
OSObject *extIntControllerName;
OSObject *extIntControllerData;
service->setProperty("no-nvram", service);
extIntList = IODTFindMatchingEntries(getProvider(), kIODTRecursive, "'extint-gpio1'");
extInt = (IORegistryEntry *)extIntList->getNextObject();
tmpArray = (OSArray *)extInt->getProperty(gIOInterruptControllersKey);
extIntControllerName = tmpArray->getObject(0);
tmpArray = (OSArray *)extInt->getProperty(gIOInterruptSpecifiersKey);
extIntControllerData = tmpArray->getObject(0);
tmpArray = (OSArray *)service->getProperty(gIOInterruptControllersKey);
tmpArray->replaceObject(4, extIntControllerName);
tmpArray = (OSArray *)service->getProperty(gIOInterruptSpecifiersKey);
tmpArray->replaceObject(4, extIntControllerData);
extIntList->release();
return true;
}
if (!strcmp(service->getName(), "via-pmu"))
{
service->setProperty("BusSpeedCorrect", this);
return true;
}
if ((uniNVersion == kUniNVersion150) && IODTMatchNubWithKeys(service, "('pci', 'uni-north')") &&
(service->childFromPath("mac-io", gIODTPlane) != NULL)) {
service->setProperty ("DisableRDG", true);
return true;
}
if (((uniNVersion >= kUniNVersion150) && (uniNVersion <= kUniNVersion200) || (uniNVersion == kUniNVersionPangea)) &&
(!strcmp(service->getName(gIODTPlane), "firewire")) &&
IODTMatchNubWithKeys(service->getParentEntry(gIODTPlane), "('pci', 'uni-north')")) {
char data;
data = 0x08; service->setProperty (kIOPCICacheLineSize, &data, 1);
data = 0x40; service->setProperty (kIOPCITimerLatency, &data, 1);
return true;
}
if ((uniNVersion == kUniNVersion200) &&
IODTMatchNubWithKeys(service, "('ethernet', 'gmac')") &&
IODTMatchNubWithKeys(service->getParentEntry(gIODTPlane), "('pci', 'uni-north')")) {
char data;
long cacheSize;
OSData *cacheData;
data = 0x08; cacheData = OSDynamicCast( OSData, service->getProperty( "cache-line-size" ) );
if (cacheData) {
cacheSize = *(long *)cacheData->getBytesNoCopy();
data = (cacheSize >> 2);
}
service->setProperty (kIOPCICacheLineSize, &data, 1);
data = 0x20; service->setProperty (kIOPCITimerLatency, &data, 1);
return true;
}
if (!strcmp(service->getName(), "usb") &&
(0 == strncmp(provider_name, "PowerBook4,", strlen("PowerBook4,"))) &&
IODTMatchNubWithKeys(service->getParentEntry(gIODTPlane), "('pci', 'uni-north')")) {
OSData *regProp;
IOPCIAddressSpace *pciAddress;
UInt32 ports;
if( (regProp = (OSData *) service->getProperty("reg"))) {
pciAddress = (IOPCIAddressSpace *) regProp->getBytesNoCopy();
if (pciAddress->s.deviceNum == 0x18) {
if(!((OSData *) service->getProperty(kAAPLSuspendablePorts))) {
ports = 4;
service->setProperty (kAAPLSuspendablePorts, &ports, sizeof(UInt32));
}
return true;
}
}
}
return true;
}
IOReturn MacRISC2PE::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
OSData *func;
if (functionName == gGetDefaultBusSpeedsKey)
{
getDefaultBusSpeeds((long *)param1, (unsigned long **)param2);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableUniNEthernetClock"))
{
enableUniNEthernetClock((bool)param1, (IOService *)param2);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableFireWireClock")) {
enableUniNFireWireClock((bool)param1, (IOService *)param2);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableFireWireCablePower")) {
enableUniNFireWireCablePower((bool)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("AccessUniN15PerformanceRegister"))
{
return accessUniN15PerformanceRegister((bool)param1, (long)param2, (unsigned long *)param3);
}
if (functionName->isEqualTo("PlatformIsPortable")) {
*(bool *) param1 = isPortable;
return kIOReturnSuccess;
}
if (functionName->isEqualTo("PlatformPowerMonitor")) {
return platformPowerMonitor ((UInt32 *) param1);
}
if (fOnDemand && (func = OSDynamicCast(OSData, fOnDemand->getObject(functionName))) != 0) {
if (performFunction(func, param1, param2, param3, param4))
return kIOReturnSuccess;
else
return kIOReturnError;
}
return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
}
unsigned long MacRISC2PE::readUniNReg(unsigned long offset)
{
return uniNBaseAddress[offset / 4];
}
void MacRISC2PE::writeUniNReg(unsigned long offset, unsigned long data)
{
uniNBaseAddress[offset / 4] = data;
eieio();
}
void MacRISC2PE::getDefaultBusSpeeds(long *numSpeeds, unsigned long **speedList)
{
if ((numSpeeds == 0) || (speedList == 0)) return;
*numSpeeds = 1;
*speedList = macRISC2Speed;
}
void MacRISC2PE::enableUniNEthernetClock(bool enable, IOService *nub)
{
unsigned long regTemp;
if (enable)
configureUniNPCIDevice(nub);
if (mutex != NULL)
IOLockLock(mutex);
regTemp = readUniNReg(kUniNClockControl);
if (enable)
{
regTemp |= kUniNEthernetClockEnable;
}
else
{
regTemp &= ~kUniNEthernetClockEnable;
}
writeUniNReg(kUniNClockControl, regTemp);
if (mutex != NULL)
IOLockUnlock(mutex);
}
void MacRISC2PE::enableUniNFireWireClock(bool enable, IOService *nub)
{
unsigned long regTemp;
if (enable)
configureUniNPCIDevice(nub);
if (mutex != NULL)
IOLockLock(mutex);
regTemp = readUniNReg(kUniNClockControl);
if (enable)
{
regTemp |= kUniNFirewireClockEnable;
}
else
{
regTemp &= ~kUniNFirewireClockEnable;
}
writeUniNReg(kUniNClockControl, regTemp);
if (mutex != NULL)
IOLockUnlock(mutex);
}
void MacRISC2PE::enableUniNFireWireCablePower(bool enable)
{
if(getMachineType() == kMacRISC2TypePowerBook)
{
IOService *keyLargo;
keyLargo = waitForService(serviceMatching("KeyLargo"));
if(keyLargo)
{
UInt32 gpioOffset = 0x73;
keyLargo->callPlatformFunction(OSSymbol::withCString("keyLargo_writeRegUInt8"),
true, (void *)&gpioOffset, (void *)(enable ? 0:4), 0, 0);
}
}
}
void MacRISC2PE::configureUniNPCIDevice (IOService *nub)
{
OSData *cacheData, *latencyData;
IOPCIDevice *provider;
if (nub) provider = OSDynamicCast(IOPCIDevice, nub);
else provider = NULL;
if (provider) {
cacheData = (OSData *)provider->getProperty (kIOPCICacheLineSize);
latencyData = (OSData *)provider->getProperty (kIOPCITimerLatency);
if (cacheData || latencyData) {
UInt32 configData;
configData = provider->configRead32 (kIOPCIConfigCacheLineSize);
if (cacheData)
configData = (configData & 0xFFFFFF00) | *(char *) cacheData->getBytesNoCopy();
if (latencyData)
configData = (configData & 0xFFFF00FF) | ((*(char *) latencyData->getBytesNoCopy()) << 8);
provider->configWrite32 (kIOPCIConfigCacheLineSize, configData);
}
}
return;
}
enum
{
kMCMonitorModeControl = 0,
kMCCommand,
kMCPerformanceMonitor0,
kMCPerformanceMonitor1,
kMCPerformanceMonitor2,
kMCPerformanceMonitor3
};
IOReturn MacRISC2PE::accessUniN15PerformanceRegister(bool write, long regNumber, unsigned long *data)
{
unsigned long offset;
if (uniNVersion < kUniNVersion150) return kIOReturnUnsupported;
switch (regNumber)
{
case kMCMonitorModeControl : offset = kUniNMMCR; break;
case kMCCommand : offset = kUniNMCMDR; break;
case kMCPerformanceMonitor0 : offset = kUniNMPMC1; break;
case kMCPerformanceMonitor1 : offset = kUniNMPMC2; break;
case kMCPerformanceMonitor2 : offset = kUniNMPMC3; break;
case kMCPerformanceMonitor3 : offset = kUniNMPMC4; break;
default : return kIOReturnBadArgument;
}
if (data == 0) return kIOReturnBadArgument;
if (write)
{
writeUniNReg(offset, *data);
}
else
{
*data = readUniNReg(offset);
}
return kIOReturnSuccess;
}
IOReturn MacRISC2PE::platformPowerMonitor(UInt32 *powerFlags)
{
IOReturn result;
if (doPlatformPowerMonitor) {
if (((*powerFlags & powerMonWeakCharger.bitsMask) ==
(powerMonWeakCharger.bitsMask & powerMonWeakCharger.bitsSet & ~powerMonWeakCharger.bitsClear)) ||
((*powerFlags & powerMonBatteryWarning.bitsMask) ==
(powerMonBatteryWarning.bitsMask & powerMonBatteryWarning.bitsSet & ~powerMonBatteryWarning.bitsClear)) ||
((*powerFlags & powerMonBatteryDepleted.bitsMask) ==
(powerMonBatteryDepleted.bitsMask & powerMonBatteryDepleted.bitsSet & ~powerMonBatteryDepleted.bitsClear)) ||
((*powerFlags & powerMonBatteryNotInstalled.bitsMask) ==
(powerMonBatteryNotInstalled.bitsMask & powerMonBatteryNotInstalled.bitsSet & ~powerMonBatteryNotInstalled.bitsClear))) {
*powerFlags |= (powerMonForceLowPower.bitsMask & powerMonForceLowPower.bitsSet);
if (processorSpeedChangeFlags & kL3CacheEnabled) {
if (!macRISC2CPU)
macRISC2CPU = waitForService (serviceMatching("MacRISC2CPU"));
if (macRISC2CPU) {
processorSpeedChangeFlags &= ~kClamshellClosedSpeedChange;
macRISC2CPU->setAggressiveness (kPMSetProcessorSpeed, 1); }
}
} else if ((*powerFlags & powerMonClamshellClosed.bitsMask) ==
(powerMonClamshellClosed.bitsMask & powerMonClamshellClosed.bitsSet & ~powerMonClamshellClosed.bitsClear)) {
*powerFlags |= (powerMonForceLowPower.bitsMask & powerMonForceLowPower.bitsSet);
if (!(processorSpeedChangeFlags & kL3CacheEnabled)) {
if (!macRISC2CPU)
macRISC2CPU = waitForService (serviceMatching("MacRISC2CPU"));
if (macRISC2CPU) {
if (processorSpeedChangeFlags & kPMUBasedSpeedChange) {
processorSpeedChangeFlags &= ~kPMUBasedSpeedChange;
macRISC2CPU->setAggressiveness (kPMSetProcessorSpeed, 0); processorSpeedChangeFlags |= kPMUBasedSpeedChange;
}
}
}
processorSpeedChangeFlags |= kClamshellClosedSpeedChange; } else {
*powerFlags &= ~(powerMonForceLowPower.bitsMask & powerMonForceLowPower.bitsClear);
processorSpeedChangeFlags &= ~kClamshellClosedSpeedChange;
}
result = kIOReturnSuccess;
} else
result = kIOReturnUnsupported;
return result;
}
void MacRISC2PE::PMInstantiatePowerDomains ( void )
{
OSString * errorStr = new OSString;
OSObject * obj;
IOPMUSBMacRISC2 * usbMacRISC2;
obj = OSUnserializeXML (gIOMacRISC2PMTree, &errorStr);
if( 0 == (thePowerTree = ( OSArray * ) obj) )
{
kprintf ("error parsing power tree: %s", errorStr->getCStringNoCopy());
}
getProvider()->setProperty ("powertreedesc", thePowerTree);
#if CREATE_PLEXUS
plexus = new IOPMPagingPlexus;
if ( plexus ) {
plexus->init();
plexus->attach(this);
plexus->start(this);
}
#endif
root = IOPMrootDomain::construct();
root->attach(this);
root->start(this);
if ( plexus ) {
root->addPowerChild(plexus);
}
root->setSleepSupported(kRootDomainSleepSupported);
if (NULL == root)
{
kprintf ("PMInstantiatePowerDomains - null ROOT\n");
return;
}
PMRegisterDevice (NULL, root);
usbMacRISC2 = new IOPMUSBMacRISC2;
if (usbMacRISC2)
{
usbMacRISC2->init ();
usbMacRISC2->attach (this);
usbMacRISC2->start (this);
PMRegisterDevice (root, usbMacRISC2);
if ( plexus ) {
plexus->addPowerChild (usbMacRISC2);
}
}
slotsMacRISC2 = new IOPMSlotsMacRISC2;
if (slotsMacRISC2)
{
slotsMacRISC2->init ();
slotsMacRISC2->attach (this);
slotsMacRISC2->start (this);
PMRegisterDevice (root, slotsMacRISC2);
if ( plexus ) {
plexus->addPowerChild (slotsMacRISC2);
}
}
if (processorSpeedChangeFlags != kNoSpeedChange) {
root->publishFeature("Reduce Processor Speed");
if (processorSpeedChangeFlags & kProcessorBasedSpeedChange) {
root->publishFeature("Dynamic Power Step");
}
}
return;
}
extern const IORegistryPlane * gIOPowerPlane;
void MacRISC2PE::PMRegisterDevice(IOService * theNub, IOService * theDevice)
{
bool nodeFound = false;
IOReturn err = -1;
OSData * propertyPtr = 0;
const char * theProperty;
if (mutex != NULL)
IOLockLock(mutex);
multipleParentKeyValue = NULL;
numInstancesRegistered = 0;
nodeFound = CheckSubTree (thePowerTree, theNub, theDevice, NULL);
if (0 == numInstancesRegistered)
{
while( theNub && (!theNub->inPlane(gIOPowerPlane)))
theNub = theNub->getProvider();
}
if (mutex != NULL)
IOLockUnlock(mutex);
if ( NULL != theNub )
err = theNub->addPowerChild (theDevice);
if ((err != IOPMNoErr) && (0 == numInstancesRegistered) && (theDevice != root)) {
root->addPowerChild (theDevice);
if ( plexus ) {
plexus->addPowerChild (theDevice);
}
}
propertyPtr = OSDynamicCast(OSData,theDevice->getProperty("AAPL,slot-name"));
if ( propertyPtr ) {
theProperty = (const char *) propertyPtr->getBytesNoCopy();
if ( strncmp("SLOT-",theProperty,5) == 0 ) {
slotsMacRISC2->addPowerChild (theDevice);
}
}
}
void MacRISC2PE::publishStrings(OSCollection *strings)
{
OSCollectionIterator *strIter;
OSSymbol *key;
if (!strings) return;
strIter = OSCollectionIterator::withCollection(strings);
if (strIter){
while ((key = OSDynamicCast(OSSymbol, strIter->getNextObject())) != 0)
publishResource(key, this);
strIter->release();
}
}
void MacRISC2PE::releaseResources(void)
{
UInt32 i;
if (fOnDemand) {
fOnDemand->release();
fOnDemand = 0;
}
for (i=0; i<kListNumLists; i++) {
if (fFuncList[i]) {
fFuncList[i]->release();
fFuncList[i] = 0;
}
}
return;
}
SInt32 MacRISC2PE::parseProvidedFunction(OSString *key, OSData *value)
{
SInt32 numFuncs;
UInt32 wordsLeft, phandle, flags, cmdCount, cmdLen, maskLen, valueLen;
UInt32 *quadlet;
OSData *cmd;
const OSSymbol *aKey;
char funcNameWithPrefix[160], funcName[128];
const char *myFunc;
bool processingCmdList;
processingCmdList = false;
numFuncs = 0;
cmd = 0;
cmdCount = 0;
wordsLeft = value->getLength() / sizeof(UInt32);
quadlet = (UInt32 *)value->getBytesNoCopy();
if (quadlet == 0) return(-1);
while (wordsLeft >= 3) { if (processingCmdList)
processingCmdList = (cmdCount != 0);
else {
numFuncs++;
phandle = *quadlet++;
flags = *quadlet++;
wordsLeft -= 2;
}
if (!flags) return(-1);
switch (*quadlet) {
case kCommandCommandList:
DLOG ("parseProvidedFunction got command kCommandCommandList,");
processingCmdList = true;
cmd = OSData::withBytes ((void *)&phandle, sizeof(UInt32));
cmdLen = 1 + kCommandCommandListLength;
cmd->appendBytes((void *)quadlet, cmdLen * sizeof(UInt32));
quadlet++;
cmdCount = *quadlet++;
wordsLeft -= cmdLen;
DLOG (" cmdCount = %ld\n", cmdCount);
break;
case kCommandWriteReg32:
DLOG ("parseProvidedFunction got command kCommandWriteReg32\n");
if (wordsLeft < kCommandWriteReg32Length) return(-1);
if (processingCmdList)
cmdCount--;
else
cmd = OSData::withBytes ((void *)&phandle, sizeof(UInt32));
cmdLen = 1 + kCommandWriteReg32Length;
cmd->appendBytes((void *)quadlet, cmdLen * sizeof(UInt32));
quadlet += cmdLen;
wordsLeft -= cmdLen;
break;
case kCommandConfigRead:
DLOG ("parseProvidedFunction got command kCommandConfigRead\n");
if (wordsLeft < kCommandConfigReadLength) return(-1);
if (processingCmdList)
cmdCount--;
else
cmd = OSData::withBytes ((void *)&phandle, sizeof(UInt32));
cmdLen = 1 + kCommandConfigReadLength;
cmd->appendBytes((void *)quadlet, cmdLen * sizeof(UInt32));
quadlet += cmdLen;
wordsLeft -= cmdLen;
break;
case kCommandConfigRMW:
DLOG ("parseProvidedFunction got command kCommandConfigRMW\n");
if (wordsLeft < kCommandConfigRMWLength) return(-1);
if (processingCmdList)
cmdCount--;
else
cmd = OSData::withBytes ((void *)&phandle, sizeof(UInt32));
maskLen = quadlet[2]; valueLen = quadlet[3]; cmdLen = 1 + kCommandConfigRMWLength + (maskLen / sizeof(UInt32)) + (valueLen / sizeof(UInt32));
cmd->appendBytes((void *)quadlet, cmdLen * sizeof (UInt32));
quadlet += cmdLen;
wordsLeft -= cmdLen;
break;
default:
DLOG("MacRISC2PE got unsupported command\n" \
"\tphandle = %08lx\n" \
"\t flags = %08lx\n" \
"\tcommand = %08lx\n", phandle, flags, *quadlet);
return(-1);
}
if (!cmd) return(-1);
if (!processingCmdList || (wordsLeft < 3)) {
if (flags & kFlagOnInit) ADD_OBJ_TO_SET(cmd, fFuncList[kListOnInit]);
if (flags & kFlagOnTerm) ADD_OBJ_TO_SET(cmd, fFuncList[kListOnTerm]);
if (flags & kFlagOnDemand) {
myFunc = key->getCStringNoCopy() + strlen(kFunctionProvidedPrefix);
sprintf(funcName, "%s-%08lx", myFunc, phandle);
sprintf(funcNameWithPrefix, "%s%s", kFunctionRequiredPrefix,
funcName);
if ((aKey = OSSymbol::withCString(funcNameWithPrefix)) == 0)
return(-1);
DLOG ("parseProvidedFunction registering demand function '%s\n", funcNameWithPrefix);
if (fOnDemand) {
if (!fOnDemand->setObject(aKey,cmd))
return(-1);
} else
if ((fOnDemand = OSDictionary::withObjects(
&(const OSObject *)cmd, &aKey, 1, 1)) == 0)
return(-1);
}
cmd->release();
}
}
return(numFuncs);
}
bool MacRISC2PE::performFunctionList(const OSSet *funcList)
{
bool ret;
OSCollectionIterator *iter;
const OSData *aFunc;
if (funcList == 0) return(false);
iter = OSCollectionIterator::withCollection(funcList);
if (iter == 0) return(false);
ret = true;
while((aFunc = OSDynamicCast(OSData, iter->getNextObject())) != 0)
if (!performFunction(aFunc, (void *)1, (void *)0, (void *)0, (void *)0)) ret = false;
iter->release();
return(ret);
}
bool MacRISC2PE::performFunction(const OSData *func, void *param1 = 0,
void *param2 = 0, void *param3 = 0, void *param4 = 0)
{
UInt32 *quadlet, pHandle, offset, data, value, valueLen, mask, maskLen, writeLen, wordsLeft, cmdCount;
SInt32 lastCmd;
bool processingCmdList;
IOPCIDevice *nub;
if (func == 0) return(false);
processingCmdList = false;
cmdCount = 0;
wordsLeft = func->getLength() / sizeof(UInt32);
data = 0;
nub = NULL;
lastCmd = -1;
quadlet = (UInt32 *)func->getBytesNoCopy();
if (quadlet == 0) return(-1);
while (wordsLeft >= 2) { if (processingCmdList)
processingCmdList = (cmdCount != 0);
else {
pHandle = *quadlet++;
wordsLeft--;
}
switch (*quadlet) {
case kCommandCommandList:
DLOG ("MacRISC2PE::performFunction got command kCommandCommandList,");
processingCmdList = true;
quadlet++;
cmdCount = *quadlet++;
wordsLeft -= (1 + kCommandCommandListLength);
DLOG (" cmdCount = %ld\n", cmdCount);
break;
case kCommandWriteReg32:
DLOG ("MacRISC2PE::performFunction command kCommandWriteReg32\n");
if (processingCmdList)
cmdCount--;
quadlet++;
offset = *quadlet++;
value = *quadlet++;
mask = *quadlet++;
wordsLeft -= (1 + kCommandWriteReg32Length);
if (mask != 0xFFFFFFFF) {
data = readUniNReg (offset);
data &= mask;
data |= value;
} else data = value;
DLOG ("MacRISC2PE::performFunction - writing data 0x%lx to Uni-N register offset 0x%lx\n", data, offset);
writeUniNReg(offset, data);
break;
case kCommandConfigRead:
DLOG ("MacRISC2PE::performFunction command kCommandConfigRead\n");
if (processingCmdList)
cmdCount--;
quadlet++;
offset = *quadlet++;
valueLen = *quadlet++;
wordsLeft -= (1 + kCommandConfigReadLength);
if (valueLen != 4) {
IOLog ("MacRISC2PE::performFunction config reads cannot handle anything other than 4 bytes, found length %ld\n", valueLen);
return false;
}
if (!nub) {
if (!pHandle) {
IOLog ("MacRISC2PE::performFunction config read requires pHandle to locate nub\n");
return false;
}
nub = findNubForPHandle (pHandle);
if (!nub) {
IOLog ("MacRISC2PE::performFunction config read cannot find nub for pHandle 0x%08lx\n", pHandle);
return false;
}
}
data = nub->configRead32 (offset);
DLOG ("MacRISC2PE::performFunction config read 0x%lx at offset 0x%lx\n", data, offset);
if (param1)
*(UInt32 *)param1 = data;
lastCmd = kCommandConfigRead;
break;
case kCommandConfigRMW:
DLOG ("MacRISC2PE::performFunction command kCommandConfigRMW\n");
if (processingCmdList)
cmdCount--;
if (lastCmd != kCommandConfigRead) {
IOLog ("MacRISC2PE::performFunction - config modify/write requires prior read\n");
return false;
}
quadlet++;
offset = *quadlet++;
maskLen = *quadlet++;
valueLen = *quadlet++;
writeLen = *quadlet++;
wordsLeft -= (1 + kCommandConfigRMWLength + (maskLen / sizeof(UInt32)) + (valueLen / sizeof(UInt32)));
if (writeLen != 4) {
IOLog ("MacRISC2PE::performFunction config read/modify/write cannot handle anything other than 4 bytes, found length %ld\n", writeLen);
return false;
}
mask = *quadlet++;
value = *quadlet++;
DLOG("\nMacRISC2PE::performFunction config read/modify/write offset = %08lx maskLen = %08lx dataLen = %08lx writeLen = %08lx, mask = %08lx, data = %08lx\n",
offset, maskLen, valueLen, writeLen, mask, value);
if (!nub) {
if (!pHandle) {
IOLog ("MacRISC2PE::performFunction config read/modify/write requires pHandle to locate nub\n");
return false;
}
nub = findNubForPHandle (pHandle);
if (!nub) {
IOLog ("MacRISC2PE::performFunction config read/modify/write cannot find nub for pHandle 0x%08lx\n", pHandle);
return false;
}
}
data &= mask;
data |= value;
DLOG ("MacRISC2PE::performFunction config write data 0x%lx to offset 0x%lx\n", data, offset);
nub->configWrite32 (offset, data);
break;
default:
IOLog("MacRISC2PE::performFunction got unsupported command %08lx\n", *quadlet);
return(false);
}
}
return(true);
}
IOPCIDevice* MacRISC2PE::findNubForPHandle( UInt32 pHandleValue )
{
IORegistryIterator* iterator;
IORegistryEntry* matchingEntry = NULL;
iterator = IORegistryIterator::iterateOver( gIODTPlane, kIORegistryIterateRecursively );
if ( iterator == NULL )
return( NULL );
while ( ( matchingEntry = iterator->getNextObject() ) != NULL ) {
OSData* property;
if ( ( property = OSDynamicCast( OSData, matchingEntry->getProperty( "AAPL,phandle" ) ) ) != NULL )
if ( pHandleValue == *( ( UInt32 * ) property->getBytesNoCopy() ) )
break;
}
iterator->release();
DLOG ("MacRISC2PE::findNubForPHandle - found matchingEntry '%s'\n", matchingEntry->getName());
return( OSDynamicCast (IOPCIDevice, matchingEntry));
}