AppleTexasAudio.cpp [plain text]
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IORegistryEntry.h>
#include <IOKit/IOCommandGate.h>
#include <UserNotification/KUNCUserNotifications.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/audio/IOAudioEngine.h>
#include "AudioI2SHardwareConstants.h"
#include "AppleTexasAudio.h"
#include "AppleTexasEQPrefs.cpp"
#define super AppleOnboardAudio
OSDefineMetaClassAndStructors(AppleTexasAudio, AppleOnboardAudio)
EQPrefsPtr gEQPrefs = &theEQPrefs;
extern uid_t console_user;
#pragma mark +UNIX LIKE FUNCTIONS
bool AppleTexasAudio::init(OSDictionary *properties)
{
debugIOLog("+ AppleTexasAudio::init\n");
if (!super::init(properties))
return false;
gVolLeft = 0;
gVolRight = 0;
gVolMuteActive = false;
gModemSoundActive = false;
debugIOLog("- AppleTexasAudio::init\n");
return true;
}
void AppleTexasAudio::free()
{
IOWorkLoop *workLoop;
debugIOLog("+ AppleTexasAudio::free\n");
CLEAN_RELEASE(hdpnMuteRegMem);
CLEAN_RELEASE(ampMuteRegMem);
CLEAN_RELEASE(hwResetRegMem);
CLEAN_RELEASE(headphoneExtIntGpioMem);
CLEAN_RELEASE(dallasExtIntGpioMem);
CLEAN_RELEASE(audioI2SControl);
if (NULL != ioBaseAddressMemory) {
ioBaseAddressMemory->release();
}
if (NULL != ioClockBaseAddressMemory) {
ioClockBaseAddressMemory->release();
}
workLoop = getWorkLoop();
if (NULL != workLoop) {
if (NULL != headphoneIntEventSource && NULL != headphoneIntProvider)
workLoop->removeEventSource (headphoneIntEventSource);
if (NULL != dallasIntEventSource && NULL != dallasIntProvider)
workLoop->removeEventSource (dallasIntEventSource);
if (NULL != dallasHandlerTimer)
workLoop->removeEventSource (dallasHandlerTimer);
if (NULL != notifierHandlerTimer)
workLoop->removeEventSource (notifierHandlerTimer);
if ( NULL != deferHeadphoneHandlerTimer ) { workLoop->removeEventSource ( deferHeadphoneHandlerTimer ); } }
publishResource (gAppleAudioVideoJackStateKey, NULL);
CLEAN_RELEASE(headphoneIntEventSource);
CLEAN_RELEASE(dallasIntEventSource);
super::free();
debugIOLog("- AppleTexasAudio::free\n");
}
IOService* AppleTexasAudio::probe(IOService *provider, SInt32 *score)
{
IORegistryEntry *sound = 0;
debugIOLog("+ AppleTexasAudio::probe\n");
super::probe(provider, score);
*score = kIODefaultProbeScore;
sound = provider->childFromPath("sound", gIODTPlane);
if(sound) {
OSData *tmpData;
tmpData = OSDynamicCast(OSData, sound->getProperty(kModelPropName));
if(tmpData) {
if(tmpData->isEqualTo(kTexasModelName, sizeof(kTexasModelName) -1)) {
*score = *score+1;
debugIOLog("++ AppleTexasAudio::probe increasing score\n");
return(this);
} else {
debugIOLog ("++ AppleTexasAudio::probe, didn't find what we were looking for\n");
}
}
sound->release ();
}
debugIOLog("- AppleTexasAudio::probe\n");
return (0);
}
bool AppleTexasAudio::initHardware(IOService *provider)
{
bool myreturn = true;
DEBUG_IOLOG("+ AppleTexasAudio::initHardware\n");
super::initHardware(provider);
DEBUG_IOLOG("- AppleTexasAudio::initHardware\n");
return myreturn;
}
void AppleTexasAudio::timerCallback(OSObject *target, IOAudioDevice *device)
{
AppleTexasAudio * templateDriver;
templateDriver = OSDynamicCast (AppleTexasAudio, target);
if (templateDriver) {
templateDriver->checkStatus(false);
}
return;
}
void AppleTexasAudio::checkStatus(bool force)
{
}
#pragma mark +HARDWARE REGISTER MANIPULATION
void AppleTexasAudio::sndHWInitialize(IOService *provider)
{
IOReturn err;
IORegistryEntry *i2s;
IORegistryEntry *macio;
IORegistryEntry *gpio;
IORegistryEntry *i2c;
IORegistryEntry *deq;
IORegistryEntry *intSource;
IORegistryEntry *headphoneMute;
IORegistryEntry *ampMute;
IORegistryEntry *hardwareReset;
OSData *tmpData;
IOMemoryMap *map;
UInt32 *hdpnMuteGpioAddr;
UInt32 *ampMuteGpioAddr;
UInt32 *hwResetGpioAddr;
UInt32 *headphoneExtIntGpioAddr;
UInt32 *dallasExtIntGpioAddr;
UInt32 *i2cAddrPtr;
UInt32 *tmpPtr;
UInt32 loopCnt;
UInt32 myFrameRate;
UInt8 data[kBIQwidth]; UInt8 curValue;
bool hasInput;
DEBUG_IOLOG("+ AppleTexasAudio::sndHWInitialize\n");
ourProvider = provider;
hasInput = (bool) HasInput ();
savedNanos = 0;
myFrameRate = frameRate (0);
i2s = NULL;
macio = NULL;
gpio = NULL;
i2c = NULL;
i2s = ourProvider->getParentEntry (gIODTPlane);
FailIf (!i2s, Exit);
macio = i2s->getParentEntry (gIODTPlane);
FailIf (!macio, Exit);
gpio = macio->childFromPath (kGPIODTEntry, gIODTPlane);
FailIf (!gpio, Exit);
i2c = macio->childFromPath (kI2CDTEntry, gIODTPlane);
setProperty (kSpeakerConnectError, speakerConnectFailed);
tmpData = OSDynamicCast (OSData, macio->getProperty (kDeviceIDPropName));
FailIf (!tmpData, Exit);
deviceID = (UInt32)tmpData->getBytesNoCopy ();
deq = i2c->childFromPath (kDigitalEQDTEntry, gIODTPlane);
FailIf (!deq, Exit);
tmpData = OSDynamicCast (OSData, deq->getProperty (kI2CAddress));
deq->release ();
FailIf (!tmpData, Exit);
i2cAddrPtr = (UInt32*)tmpData->getBytesNoCopy ();
DEQAddress = *i2cAddrPtr;
DEQAddress = DEQAddress >> 1;
headphoneMute = FindEntryByProperty (gpio, kAudioGPIO, kHeadphoneAmpEntry);
FailIf (!headphoneMute, Exit);
tmpData = OSDynamicCast (OSData, headphoneMute->getProperty (kAAPLAddress));
FailIf (!tmpData, Exit);
hdpnMuteGpioAddr = (UInt32*)tmpData->getBytesNoCopy ();
tmpData = OSDynamicCast (OSData, headphoneMute->getProperty (kAudioGPIOActiveState));
tmpPtr = (UInt32*)tmpData->getBytesNoCopy ();
hdpnActiveState = *tmpPtr;
hdpnMuteRegMem = IODeviceMemory::withRange (*hdpnMuteGpioAddr, sizeof (UInt8));
map = hdpnMuteRegMem->map (0);
hdpnMuteGpio = (UInt8*)map->getVirtualAddress ();
intSource = 0;
intSource = FindEntryByProperty (gpio, kOneWireBus, kSpeakerID);
if (NULL != intSource) {
dallasIntProvider = OSDynamicCast (IOService, intSource);
FailIf (!dallasIntProvider, Exit);
tmpData = OSDynamicCast (OSData, intSource->getProperty (kAudioGPIOActiveState));
if (!tmpData) {
dallasInsertedActiveState = 1;
} else {
tmpPtr = (UInt32*)tmpData->getBytesNoCopy ();
dallasInsertedActiveState = *tmpPtr;
}
tmpData = OSDynamicCast (OSData, intSource->getProperty (kAAPLAddress));
FailIf (!tmpData, Exit);
dallasExtIntGpioAddr = (UInt32*)tmpData->getBytesNoCopy ();
dallasExtIntGpioMem = IODeviceMemory::withRange (*dallasExtIntGpioAddr, sizeof (UInt8));
map = dallasExtIntGpioMem->map (0);
dallasExtIntGpio = (UInt8*)map->getVirtualAddress ();
curValue = *dallasExtIntGpio;
curValue = curValue | (1 << 7);
*dallasExtIntGpio = curValue;
} else {
debugIOLog ("!!!!Couldn't find a dallas speaker interrupt source!!!!\n");
}
intSource = 0;
intSource = FindEntryByProperty (gpio, kAudioGPIO, kHeadphoneDetectInt);
if (!intSource)
intSource = FindEntryByProperty (gpio, kCompatible, kKWHeadphoneDetectInt);
FailIf (!intSource, Exit);
headphoneIntProvider = OSDynamicCast (IOService, intSource);
FailIf (!headphoneIntProvider, Exit);
tmpData = OSDynamicCast (OSData, intSource->getProperty (kVideoPropertyEntry));
debug2IOLog ("kVideoPropertyEntry = %p\n", tmpData);
if (NULL != tmpData) {
hasVideo = TRUE;
gAppleAudioVideoJackStateKey = OSSymbol::withCStringNoCopy ("AppleAudioVideoJackState");
debugIOLog ("has video in headphone\n");
}
tmpData = OSDynamicCast (OSData, intSource->getProperty (kAudioGPIOActiveState));
if (NULL == tmpData) {
headphoneInsertedActiveState = 1;
} else {
tmpPtr = (UInt32*)tmpData->getBytesNoCopy ();
headphoneInsertedActiveState = *tmpPtr;
}
tmpData = OSDynamicCast (OSData, intSource->getProperty (kAAPLAddress));
FailIf (!tmpData, Exit);
headphoneExtIntGpioAddr = (UInt32*)tmpData->getBytesNoCopy ();
headphoneExtIntGpioMem = IODeviceMemory::withRange (*headphoneExtIntGpioAddr, sizeof (UInt8));
map = headphoneExtIntGpioMem->map (0);
headphoneExtIntGpio = (UInt8*)map->getVirtualAddress ();
curValue = *headphoneExtIntGpio;
curValue = curValue | (1 << 7);
*headphoneExtIntGpio = curValue;
ampMute = FindEntryByProperty (gpio, kAudioGPIO, kAmpEntry);
FailIf (!ampMute, Exit);
tmpData = OSDynamicCast (OSData, ampMute->getProperty (kAAPLAddress));
FailIf (!tmpData, Exit);
ampMuteGpioAddr = (UInt32*)tmpData->getBytesNoCopy ();
tmpData = OSDynamicCast (OSData, ampMute->getProperty (kAudioGPIOActiveState));
tmpPtr = (UInt32*)tmpData->getBytesNoCopy ();
ampActiveState = *tmpPtr;
ampMuteRegMem = IODeviceMemory::withRange (*ampMuteGpioAddr, sizeof (UInt8));
map = ampMuteRegMem->map (0);
ampMuteGpio = (UInt8*)map->getVirtualAddress ();
hardwareReset = FindEntryByProperty (gpio, kAudioGPIO, kHWResetEntry);
FailIf (!hardwareReset, Exit);
tmpData = OSDynamicCast (OSData, hardwareReset->getProperty (kAAPLAddress));
FailIf (!tmpData, Exit);
hwResetGpioAddr = (UInt32*)tmpData->getBytesNoCopy ();
tmpData = OSDynamicCast (OSData, hardwareReset->getProperty (kAudioGPIOActiveState));
tmpPtr = (UInt32*)tmpData->getBytesNoCopy ();
hwResetActiveState = *tmpPtr;
hwResetRegMem = IODeviceMemory::withRange (*hwResetGpioAddr, sizeof (UInt8));
map = hwResetRegMem->map (0);
hwResetGpio = (UInt8*)map->getVirtualAddress ();
FailIf (!findAndAttachI2C (provider), Exit);
layoutID = GetDeviceID ();
debug2IOLog ("layoutID = %ld\n", layoutID);
ExcludeHPMuteRelease (layoutID);
i2sSerialFormat = ( kClockSource45MHz | ( 1 << kMClkDivisorShift ) | ( 1 << kSClkDivisorShift ) | kSClkMaster | kSerialFormat64x );
drc.compressionRatioNumerator = kDrcRatioNumerator;
drc.compressionRatioDenominator = kDrcRationDenominator;
drc.threshold = kDrcThresholdMax;
drc.maximumVolume = kDefaultMaximumVolume;
drc.enable = false;
data[0] = ( kNormalLoad << kFL ) | ( k64fs << kSC ) | TAS_I2S_MODE | ( TAS_WORD_LENGTH << kW0 );
TAS3001C_WriteRegister( kMainCtrlReg, data, kUPDATE_SHADOW );
data[0] = ( kDrcDisable << kEN ) | ( kCompression3to1 << kCR );
data[1] = kDefaultCompThld;
TAS3001C_WriteRegister( kDynamicRangeCtrlReg, data, kUPDATE_SHADOW );
for( loopCnt = 0; loopCnt < kVOLwidth; loopCnt++ ) data[loopCnt] = 0;
TAS3001C_WriteRegister( kVolumeCtrlReg, data, kUPDATE_SHADOW );
data[0] = 0x72; TAS3001C_WriteRegister( kTrebleCtrlReg, data, kUPDATE_SHADOW );
data[0] = 0x3E; TAS3001C_WriteRegister( kBassCtrlReg, data, kUPDATE_SHADOW );
data[0] = 0x10; data[1] = 0x00;
data[2] = 0x00;
TAS3001C_WriteRegister( kMixer1CtrlReg, data, kUPDATE_SHADOW );
data[0] = 0x00; data[1] = 0x00;
data[2] = 0x00;
TAS3001C_WriteRegister( kMixer2CtrlReg, data, kUPDATE_SHADOW );
for( loopCnt = 1; loopCnt < kBIQwidth; loopCnt++ ) data[loopCnt] = 0x00;
data[0] = 0x10;
TAS3001C_WriteRegister( kLeftBiquad0CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kLeftBiquad1CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kLeftBiquad2CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kLeftBiquad3CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kLeftBiquad4CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kLeftBiquad5CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad0CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad1CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad2CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad3CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad4CtrlReg, data, kUPDATE_SHADOW );
TAS3001C_WriteRegister( kRightBiquad5CtrlReg, data, kUPDATE_SHADOW );
map = provider->mapDeviceMemoryWithIndex (AppleDBDMAAudioDMAEngine::kDBDMADeviceIndex);
FailIf (!map, Exit);
AudioI2SInfo tempInfo;
tempInfo.map = map;
tempInfo.i2sSerialFormat = kSerialFormat64x;
audioI2SControl = AudioI2SControl::create(&tempInfo) ;
FailIf (NULL == audioI2SControl, Exit);
audioI2SControl->retain();
ClockSource clockSource;
UInt32 sclkDivisor;
UInt32 mclkDivisor;
UInt32 dataFormat; dataFormat = ( ( 2 << kNumChannelsInShift ) | kDataIn16 | ( 2 << kNumChannelsOutShift ) | kDataOut16 );
FailIf (FALSE == audioI2SControl->setSampleParameters (myFrameRate, 256, &clockSource, &mclkDivisor, &sclkDivisor, kSndIOFormatI2S64x), Exit);
audioI2SControl->setSerialFormatRegister (clockSource, mclkDivisor, sclkDivisor, kSndIOFormatI2S64x, dataFormat);
err = TAS3001C_Initialize( kFORCE_RESET_SETUP_TIME );
dallasDriver = NULL;
dallasDriverNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleDallasDriver"), (IOServiceNotificationHandler)&DallasDriverPublished, this);
if (NULL != dallasDriver)
dallasDriverNotifier->remove ();
Exit:
if (NULL != gpio)
gpio->release ();
if (NULL != i2c)
i2c->release ();
DEBUG_IOLOG("- AppleTexasAudio::sndHWInitialize\n");
return;
}
void AppleTexasAudio::sndHWPostDMAEngineInit (IOService *provider) {
IOWorkLoop *workLoop;
DEBUG_IOLOG("+ AppleTexasAudio::sndHWPostDMAEngineInit\n");
if (NULL != driverDMAEngine)
driverDMAEngine->setSampleLatencies (kTexasOutputSampleLatency, kTexasInputSampleLatency);
workLoop = getWorkLoop();
FailIf (NULL == workLoop, Exit);
if (NULL != headphoneIntProvider) {
headphoneIntEventSource = IOInterruptEventSource::interruptEventSource (this,
headphoneInterruptHandler,
headphoneIntProvider,
0);
FailIf (NULL == headphoneIntEventSource, Exit);
workLoop->addEventSource (headphoneIntEventSource);
}
if (NULL != dallasIntProvider) {
dallasHandlerTimer = IOTimerEventSource::timerEventSource (this, DallasInterruptHandlerTimer);
if (NULL != dallasHandlerTimer) {
workLoop->addEventSource (dallasHandlerTimer);
}
notifierHandlerTimer = IOTimerEventSource::timerEventSource (this, DisplaySpeakersNotFullyConnected);
if (NULL != notifierHandlerTimer) {
workLoop->addEventSource (notifierHandlerTimer);
}
deferHeadphoneHandlerTimer = IOTimerEventSource::timerEventSource (this, deferHeadphoneHandler); if (NULL != deferHeadphoneHandlerTimer) { workLoop->addEventSource (deferHeadphoneHandlerTimer); }
dallasIntEventSource = IOFilterInterruptEventSource::filterInterruptEventSource (this,
dallasInterruptHandler,
interruptFilter,
dallasIntProvider,
0);
FailIf (NULL == dallasIntEventSource, Exit);
workLoop->addEventSource (dallasIntEventSource);
if (NULL != outputSelector) {
outputSelector->addAvailableSelection(kIOAudioOutputPortSubTypeExternalSpeaker, "External speakers");
}
}
if ( TRUE == IsSpeakerConnected() ) {
if (NULL != dallasDriver) {
UInt8 bEEPROM[32];
Boolean result;
debugIOLog ("sndHWPostDMAEngineInit: About to get the speaker ID\n");
speakerID = 0;
familyID = 0;
result = dallasDriver->getSpeakerID (bEEPROM);
if (TRUE == result) {
dallasSpeakersProbed = TRUE;
familyID = bEEPROM[0];
speakerID = bEEPROM[1];
debug2IOLog ("speakerID = %ld\n", speakerID);
} else {
debugIOLog ("speakerID unknown, probe failed\n");
}
}
} else {
speakerID = 0;
familyID = 0;
dallasSpeakersProbed = FALSE;
}
if (FALSE == IsHeadphoneConnected ()) {
if ( NULL == dallasInterruptHandler ) { SetActiveOutput (kSndHWOutput2, kBiquadUntouched);
}
if (TRUE == hasVideo) {
publishResource (gAppleAudioVideoJackStateKey, kOSBooleanFalse);
}
if (NULL != dallasIntProvider) {
DallasInterruptHandlerTimer (this, 0);
} else {
DeviceInterruptService ();
}
} else {
if (NULL != headphoneIntProvider) {
deferHeadphoneHandler (this, deferHeadphoneHandlerTimer);
}
}
if (NULL == outVolRight && NULL != outVolLeft) {
lastRightVol = kOUT_OF_BOUNDS_VOLUME_VALUE;
lastLeftVol = outVolLeft->getIntValue ();
}
if (NULL != headphoneIntEventSource)
headphoneIntEventSource->enable ();
if (NULL != dallasIntEventSource)
dallasIntEventSource->enable ();
Exit:
DEBUG_IOLOG("- AppleTexasAudio::sndHWPostDMAEngineInit\n");
return;
}
UInt32 AppleTexasAudio::sndHWGetInSenseBits(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetInSenseBits\n");
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetInSenseBits\n");
return 0;
}
UInt32 AppleTexasAudio::sndHWGetRegister(UInt32 regNum)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetRegister\n");
UInt32 returnValue = 0;
return returnValue;
}
IOReturn AppleTexasAudio::sndHWSetRegister(UInt32 regNum, UInt32 val)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetRegister\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetRegister\n");
return(myReturn);
}
#pragma mark +HARDWARE IO ACTIVATION
UInt32 AppleTexasAudio::sndHWGetActiveOutputExclusive(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetActiveOutputExclusive\n");
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetActiveOutputExclusive\n");
return 0;
}
IOReturn AppleTexasAudio::sndHWSetActiveOutputExclusive(UInt32 outputPort )
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetActiveOutputExclusive\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetActiveOutputExclusive\n");
return(myReturn);
}
UInt32 AppleTexasAudio::sndHWGetActiveInputExclusive(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetActiveInputExclusive\n");
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetActiveInputExclusive\n");
return 0;
}
IOReturn AppleTexasAudio::sndHWSetActiveInputExclusive(UInt32 input )
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetActiveInputExclusive\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetActiveInputExclusive\n");
return(myReturn);
}
#pragma mark +CONTROL FUNCTIONS
bool AppleTexasAudio::sndHWGetSystemMute(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetSystemMute\n");
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetSystemMute\n");
return (gVolMuteActive);
}
IOReturn AppleTexasAudio::setModemSound(bool state) {
UInt8 data[3];
IOReturn myReturn = kIOReturnSuccess;
if(gModemSoundActive == state)
goto EXIT;
if(state) { data[0] = 0x10;
} else {
data[0] = 0x00;
}
data[1] = 0x00;
data[2] = 0x00;
myReturn = TAS3001C_WriteRegister( kMixer2CtrlReg, data, kUPDATE_HW );
gModemSoundActive = state;
EXIT:
return(myReturn);
}
IOReturn AppleTexasAudio::sndHWSetSystemMute(bool mutestate)
{
IOReturn result;
result = kIOReturnSuccess;
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetSystemMute\n");
if (true == mutestate) {
if (false == gVolMuteActive) {
gVolMuteActive = mutestate ;
result = SetVolumeCoefficients (0, 0);
}
} else {
gVolMuteActive = mutestate ;
result = SetVolumeCoefficients (volumeTable[(UInt32)gVolLeft], volumeTable[(UInt32)gVolRight]);
}
DEBUG_IOLOG ("- AppleTexasAudio::sndHWSetSystemMute\n");
return (result);
}
bool AppleTexasAudio::sndHWSetSystemVolume(UInt32 leftVolume, UInt32 rightVolume)
{
bool result;
result = false;
debug3IOLog ("+ AppleTexasAudio::sndHWSetSystemVolume (left: %ld, right %ld)\n", leftVolume, rightVolume);
gVolLeft = leftVolume;
gVolRight = rightVolume;
if (NULL != outVolLeft) {
lastLeftVol = gVolLeft;
}
if (NULL != outVolRight) {
lastRightVol = gVolRight;
}
result = SetVolumeCoefficients (volumeTable[(UInt32)gVolLeft], volumeTable[(UInt32)gVolRight]);
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetSystemVolume\n");
return (result == kIOReturnSuccess);
}
IOReturn AppleTexasAudio::sndHWSetSystemVolume(UInt32 value)
{
DEBUG2_IOLOG("+ AppleTexasAudio::sndHWSetSystemVolume (vol: %ld)\n", value);
IOReturn myReturn = kIOReturnError;
if( true == sndHWSetSystemVolume( value, value ))
{
myReturn = kIOReturnSuccess;
}
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetSystemVolume\n");
return(myReturn);
}
IOReturn AppleTexasAudio::sndHWSetPlayThrough(bool playthroughstate)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetPlayThrough\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetPlayThrough\n");
return(myReturn);
}
IOReturn AppleTexasAudio::sndHWSetSystemInputGain(UInt32 leftGain, UInt32 rightGain)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetPlayThrough\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetPlayThrough\n");
return(myReturn);
}
IOReturn AppleTexasAudio::AdjustControls (void) {
IOFixed mindBVol;
IOFixed maxdBVol;
Boolean mustUpdate;
FailIf (NULL == driverDMAEngine, Exit);
mustUpdate = FALSE;
mindBVol = volumedBTable[minVolume];
maxdBVol = volumedBTable[maxVolume];
if ((NULL == outVolMaster && TRUE == useMasterVolumeControl) ||
(NULL != outVolMaster && FALSE == useMasterVolumeControl) ||
(NULL != outVolLeft && outVolLeft->getMinValue () != minVolume) ||
(NULL != outVolLeft && outVolLeft->getMaxValue () != maxVolume) ||
(NULL != outVolRight && outVolRight->getMinValue () != minVolume) ||
(NULL != outVolRight && outVolRight->getMaxValue () != maxVolume)) {
mustUpdate = TRUE;
}
if (TRUE == mustUpdate) {
debug3IOLog ("AdjustControls: mindBVol = %lx, maxdBVol = %lx\n", mindBVol, maxdBVol);
driverDMAEngine->pauseAudioEngine ();
driverDMAEngine->beginConfigurationChange ();
if (TRUE == useMasterVolumeControl) {
if (NULL == outVolMaster) {
if (NULL != outVolLeft) {
lastLeftVol = outVolLeft->getIntValue ();
driverDMAEngine->removeDefaultAudioControl (outVolLeft);
outVolLeft = NULL;
}
if (NULL != outVolRight) {
lastRightVol = outVolRight->getIntValue ();
driverDMAEngine->removeDefaultAudioControl (outVolRight);
outVolRight = NULL;
}
outVolMaster = IOAudioLevelControl::createVolumeControl((lastLeftVol + lastRightVol) / 2, minVolume, maxVolume, mindBVol, maxdBVol,
kIOAudioControlChannelIDAll,
kIOAudioControlChannelNameAll,
kOutVolMaster,
kIOAudioControlUsageOutput);
if (NULL != outVolMaster) {
driverDMAEngine->addDefaultAudioControl(outVolMaster);
outVolMaster->setValueChangeHandler((IOAudioControl::IntValueChangeHandler)outputControlChangeHandler, this);
outVolMaster->flushValue ();
}
}
} else {
if (NULL == outVolLeft) {
if (lastLeftVol > kMAXIMUM_LEGAL_VOLUME_VALUE && NULL != outVolMaster) {
lastLeftVol = outVolMaster->getIntValue ();
}
outVolLeft = IOAudioLevelControl::createVolumeControl (lastLeftVol, kMinimumVolume, kMaximumVolume, mindBVol, maxdBVol,
kIOAudioControlChannelIDDefaultLeft,
kIOAudioControlChannelNameLeft,
kOutVolLeft,
kIOAudioControlUsageOutput);
if (NULL != outVolLeft) {
driverDMAEngine->addDefaultAudioControl (outVolLeft);
outVolLeft->setValueChangeHandler ((IOAudioControl::IntValueChangeHandler)outputControlChangeHandler, this);
}
}
if (NULL == outVolRight) {
if (lastRightVol > kMAXIMUM_LEGAL_VOLUME_VALUE && NULL != outVolMaster) {
lastRightVol = outVolMaster->getIntValue ();
}
outVolRight = IOAudioLevelControl::createVolumeControl (lastRightVol, kMinimumVolume, kMaximumVolume, mindBVol, maxdBVol,
kIOAudioControlChannelIDDefaultRight,
kIOAudioControlChannelNameRight,
kOutVolRight,
kIOAudioControlUsageOutput);
if (NULL != outVolRight) {
driverDMAEngine->addDefaultAudioControl (outVolRight);
outVolRight->setValueChangeHandler ((IOAudioControl::IntValueChangeHandler)outputControlChangeHandler, this);
}
}
if (NULL != outVolMaster) {
driverDMAEngine->removeDefaultAudioControl (outVolMaster);
outVolMaster = NULL;
}
if (NULL != outVolLeft && NULL != outVolRight) {
outVolLeft->flushValue ();
outVolRight->flushValue ();
}
}
if (NULL != outVolMaster) {
outVolMaster->setMinValue (minVolume);
outVolMaster->setMinDB (mindBVol);
outVolMaster->setMaxValue (maxVolume);
outVolMaster->setMaxDB (maxdBVol);
if (outVolMaster->getIntValue () > maxVolume) {
outVolMaster->setValue (maxVolume);
}
}
if (NULL != outVolLeft) {
outVolLeft->setMinValue (minVolume);
outVolLeft->setMinDB (mindBVol);
outVolLeft->setMaxValue (maxVolume);
outVolLeft->setMaxDB (maxdBVol);
if (outVolLeft->getIntValue () > maxVolume) {
outVolLeft->setValue (maxVolume);
}
}
if (NULL != outVolRight) {
outVolRight->setMinValue (minVolume);
outVolRight->setMinDB (mindBVol);
outVolRight->setMaxValue (maxVolume);
outVolRight->setMaxDB (maxdBVol);
if (outVolRight->getIntValue () > maxVolume) {
outVolRight->setValue (maxVolume);
}
}
driverDMAEngine->completeConfigurationChange ();
driverDMAEngine->resumeAudioEngine ();
}
Exit:
return kIOReturnSuccess;
}
#pragma mark +INDENTIFICATION
UInt32 AppleTexasAudio::sndHWGetType(void )
{
UInt32 returnValue;
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetType\n");
returnValue = kSndHWTypeTumbler;
DEBUG_IOLOG ("- AppleTexasAudio::sndHWGetType\n");
return returnValue ;
}
UInt32 AppleTexasAudio::sndHWGetManufacturer(void )
{
UInt32 returnValue;
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetManufacturer\n");
returnValue = kSndHWManfTI ;
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetManufacturer\n");
return returnValue ;
}
#pragma mark +DETECT ACTIVATION & DEACTIVATION
void AppleTexasAudio::setDeviceDetectionActive(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::setDeviceDetectionActive\n");
mCanPollStatus = true ;
DEBUG_IOLOG("- AppleTexasAudio::setDeviceDetectionActive\n");
return ;
}
void AppleTexasAudio::setDeviceDetectionInActive(void)
{
DEBUG_IOLOG("+ AppleTexasAudio::setDeviceDetectionInActive\n");
mCanPollStatus = false ;
DEBUG_IOLOG("- AppleTexasAudio::setDeviceDetectionInActive\n");
return ;
}
#pragma mark +POWER MANAGEMENT
IOReturn AppleTexasAudio::sndHWSetPowerState (IOAudioDevicePowerState theState) {
IOReturn result;
debug2IOLog ("+ AppleTexasAudio::sndHWSetPowerState (%d)\n", theState);
result = kIOReturnSuccess;
switch (theState) {
case kIOAudioDeviceActive:
if (kIOAudioDeviceIdle == previousPowerState) {
result = performDeviceIdleWake ();
} else {
result = performDeviceWake ();
}
completePowerStateChange ();
break;
case kIOAudioDeviceIdle:
result = performDeviceIdleSleep ();
break;
case kIOAudioDeviceSleep:
result = performDeviceSleep ();
break;
}
previousPowerState = theState;
debugIOLog ("- AppleTexasAudio::sndHWSetPowerState\n");
return result;
}
IOReturn AppleTexasAudio::performDeviceIdleSleep () {
IOService * keyLargo;
debugIOLog ("+ AppleTexasAudio::performDeviceIdleSleep\n");
keyLargo = NULL;
SetActiveOutput (kSndHWOutputNone, kBiquadUntouched);
GpioWrite (hwResetGpio, ASSERT_GPIO (hwResetActiveState));
IODelay (100);
keyLargo = IOService::waitForService (IOService::serviceMatching ("KeyLargo"));
if (NULL != keyLargo) {
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)false, (void *)0, 0, 0); break;
case kUseI2SCell1: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)false, (void *)1, 0, 0); break;
}
}
debugIOLog ("- AppleTexasAudio::performDeviceIdleSleep\n");
return kIOReturnSuccess;
}
IOReturn AppleTexasAudio::performDeviceIdleWake () {
IOService * keyLargo;
IOReturn err;
debugIOLog ("+ AppleTexasAudio::performDeviceIdleWake\n");
keyLargo = NULL;
keyLargo = IOService::waitForService (IOService::serviceMatching ("KeyLargo"));
if (NULL != keyLargo) {
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)true, (void *)0, 0, 0); break;
case kUseI2SCell1: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)true, (void *)1, 0, 0); break;
}
}
IODelay (100);
GpioWrite (hwResetGpio, NEGATE_GPIO (hwResetActiveState));
IOSleep (10);
err = TAS3001C_Initialize (kFORCE_RESET_SETUP_TIME);
if ( TRUE == IsSpeakerConnected() ) {
if (NULL != dallasDriver && FALSE == dallasSpeakersProbed) {
UInt8 bEEPROM[32];
Boolean result;
debugIOLog ("performDeviceIdleWake: About to get the speaker ID\n");
speakerID = 0;
familyID = 0;
dallasIntEventSource->disable ();
result = dallasDriver->getSpeakerID (bEEPROM);
dallasIntEventSource->enable ();
if (TRUE == result) {
dallasSpeakersProbed = TRUE;
familyID = bEEPROM[0];
speakerID = bEEPROM[1];
debug2IOLog ("speakerID = %ld\n", speakerID);
} else {
debugIOLog ("speakerID unknown, probe failed\n");
}
}
} else {
speakerID = 0;
familyID = 0;
dallasSpeakersProbed = FALSE;
}
if (FALSE == IsHeadphoneConnected ()) {
if ( NULL == dallasIntProvider ) { SetActiveOutput (kSndHWOutput2, kBiquadUntouched);
}
if (TRUE == hasVideo && FALSE != headphonesConnected) {
publishResource (gAppleAudioVideoJackStateKey, kOSBooleanFalse);
}
if (NULL != dallasIntProvider) {
DallasInterruptHandlerTimer (this, 0);
} else {
DeviceInterruptService ();
}
} else {
if (NULL != headphoneIntProvider) {
deferHeadphoneHandler (this, deferHeadphoneHandlerTimer);
}
}
debugIOLog ("- AppleTexasAudio::performDeviceIdleWake\n");
return err;
}
IOReturn AppleTexasAudio::performDeviceSleep () {
IOService * keyLargo;
debugIOLog ("+ AppleTexasAudio::performDeviceSleep\n");
keyLargo = NULL;
SetActiveOutput (kSndHWOutputNone, kBiquadUntouched);
GpioWrite (hwResetGpio, ASSERT_GPIO (hwResetActiveState));
keyLargo = IOService::waitForService (IOService::serviceMatching ("KeyLargo"));
if (NULL != keyLargo) {
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)false, (void *)0, 0, 0); break;
case kUseI2SCell1: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)false, (void *)1, 0, 0); break;
}
}
debugIOLog ("- AppleTexasAudio::performDeviceSleep\n");
return kIOReturnSuccess;
}
IOReturn AppleTexasAudio::performDeviceWake () {
IOService * keyLargo;
IOReturn err;
debugIOLog ("+ AppleTexasAudio::performDeviceWake\n");
SetActiveOutput (kSndHWOutputNone, kBiquadUntouched);
GpioWrite (hwResetGpio, ASSERT_GPIO (hwResetActiveState));
keyLargo = NULL;
keyLargo = IOService::waitForService (IOService::serviceMatching ("KeyLargo"));
if (NULL != keyLargo) {
switch ( i2SInterfaceNumber ) {
case kUseI2SCell0: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)true, (void *)0, 0, 0); break;
case kUseI2SCell1: keyLargo->callPlatformFunction (OSSymbol::withCString ("keyLargo_powerI2S"), false, (void *)true, (void *)1, 0, 0); break;
}
}
IODelay (100);
GpioWrite (hwResetGpio, NEGATE_GPIO (hwResetActiveState));
IOSleep (150);
err = TAS3001C_Initialize (kFORCE_RESET_SETUP_TIME);
if ( TRUE == IsSpeakerConnected() ) {
if (NULL != dallasDriver && FALSE == dallasSpeakersProbed && TRUE == IsSpeakerConnected ()) {
UInt8 bEEPROM[32];
Boolean result;
debugIOLog ("performDeviceWake: About to get the speaker ID\n");
speakerID = 0;
familyID = 0;
dallasIntEventSource->disable ();
result = dallasDriver->getSpeakerID (bEEPROM);
dallasIntEventSource->enable ();
if (TRUE == result) {
dallasSpeakersProbed = TRUE;
familyID = bEEPROM[0];
speakerID = bEEPROM[1];
debug2IOLog ("speakerID = %ld\n", speakerID);
} else {
debugIOLog ("speakerID unknown, probe failed\n");
}
}
} else {
speakerID = 0;
familyID = 0;
dallasSpeakersProbed = FALSE;
}
if (FALSE == IsHeadphoneConnected ()) {
if ( NULL == dallasIntProvider ) { SetActiveOutput (kSndHWOutput2, kBiquadUntouched);
}
if (TRUE == hasVideo && FALSE != headphonesConnected) {
publishResource (gAppleAudioVideoJackStateKey, kOSBooleanFalse);
}
if (NULL != dallasIntProvider) {
DallasInterruptHandlerTimer (this, 0);
} else {
DeviceInterruptService ();
}
} else {
if (NULL != headphoneIntProvider) {
deferHeadphoneHandler (this, deferHeadphoneHandlerTimer);
}
}
debugIOLog ("- AppleTexasAudio::performDeviceWake\n");
return err;
}
UInt32 AppleTexasAudio::sndHWGetConnectedDevices(
void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetConnectedDevices\n");
UInt32 returnValue = currentDevices;
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetConnectedDevices\n");
return returnValue ;
}
UInt32 AppleTexasAudio::sndHWGetProgOutput(
void)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWGetProgOutput\n");
DEBUG_IOLOG("- AppleTexasAudio::sndHWGetProgOutput\n");
return 0;
}
IOReturn AppleTexasAudio::sndHWSetProgOutput(
UInt32 outputBits)
{
DEBUG_IOLOG("+ AppleTexasAudio::sndHWSetProgOutput\n");
IOReturn myReturn = kIOReturnSuccess;
DEBUG_IOLOG("- AppleTexasAudio::sndHWSetProgOutput\n");
return(myReturn);
}
#pragma mark +INTERRUPT HANDLERS
Boolean AppleTexasAudio::IsSpeakerConnected (void) {
UInt8 dallasSenseContents;
Boolean connection;
connection = FALSE;
if (NULL != dallasIntProvider) {
dallasSenseContents = *(dallasExtIntGpio);
debug3IOLog ("dallasExtIntGpio = %p, dallasSenseContents = 0x%X\n", dallasExtIntGpio, dallasSenseContents);
if ((dallasSenseContents & (1 << 1)) == (dallasInsertedActiveState << 1)) {
debugIOLog ("gpio says dallas speakers are connected\n");
connection = TRUE;
} else {
debugIOLog ("gpio says dallas speakers are NOT connected\n");
connection = FALSE;
}
}
return connection;
}
void AppleTexasAudio::deferHeadphoneHandler (OSObject *owner, IOTimerEventSource *sender) {
AbsoluteTime fireTime;
UInt64 nanos;
AppleTexasAudio * device;
device = OSDynamicCast (AppleTexasAudio, owner);
FailIf (NULL == device, Exit);
if ( kIOAudioDeviceSleep != device->ourPowerState ) {
device->RealHeadphoneInterruptHandler (0, 0);
} else {
clock_get_uptime (&fireTime);
absolutetime_to_nanoseconds (fireTime, &nanos);
nanos += kDeferInsertionDelayNanos; if (NULL != device->deferHeadphoneHandlerTimer && NULL != sender) {
nanoseconds_to_absolutetime (nanos, &fireTime);
sender->cancelTimeout ();
sender->wakeAtTime (fireTime);
}
}
Exit:
return;
}
void AppleTexasAudio::DallasInterruptHandlerTimer (OSObject *owner, IOTimerEventSource *sender) {
AppleTexasAudio * device;
IOCommandGate * cg;
AbsoluteTime currTime;
OSNumber * activeOutput;
AbsoluteTime fireTime;
UInt64 nanos;
device = OSDynamicCast (AppleTexasAudio, owner);
FailIf (NULL == device, Exit);
if ( kIOAudioDeviceActive == device->ourPowerState ) {
device->dallasSpeakersConnected = device->IsSpeakerConnected ();
debug2IOLog ("dallas speakers connected = %d\n", (unsigned int)device->dallasSpeakersConnected);
if (TRUE == device->dallasSpeakersProbed && FALSE == device->dallasSpeakersConnected) {
device->dallasSpeakersProbed = FALSE;
}
if (FALSE == device->IsHeadphoneConnected ()) {
cg = device->getCommandGate ();
if (NULL != cg) {
cg->runAction (DeviceInterruptServiceAction);
}
device->SetActiveOutput (kSndHWOutput2, kBiquadUntouched);
clock_get_uptime (&currTime);
absolutetime_to_nanoseconds (currTime, &device->savedNanos);
if (TRUE == device->dallasSpeakersConnected) {
if (NULL != device->outputSelector) {
activeOutput = OSNumber::withNumber (kIOAudioOutputPortSubTypeExternalSpeaker, 32);
device->outputSelector->hardwareValueChanged (activeOutput);
}
} else {
if (NULL != device->outputSelector) {
activeOutput = OSNumber::withNumber (kIOAudioOutputPortSubTypeInternalSpeaker, 32);
device->outputSelector->hardwareValueChanged (activeOutput);
}
}
}
if (NULL != device->dallasIntEventSource) {
device->dallasIntEventSource->enable();
}
} else {
if (NULL != device->dallasHandlerTimer) {
clock_get_uptime (&fireTime);
absolutetime_to_nanoseconds (fireTime, &nanos);
nanos += kInsertionDelayNanos;
nanoseconds_to_absolutetime (nanos, &fireTime);
if ( NULL != sender ) {
sender->cancelTimeout ();
sender->wakeAtTime (fireTime);
}
}
}
Exit:
return;
}
void AppleTexasAudio::RealDallasInterruptHandler (IOInterruptEventSource *source, int count) {
AbsoluteTime fireTime;
UInt64 nanos;
if (NULL != dallasHandlerTimer) {
clock_get_uptime (&fireTime);
absolutetime_to_nanoseconds (fireTime, &nanos);
nanos += kInsertionDelayNanos;
nanoseconds_to_absolutetime (nanos, &fireTime);
dallasHandlerTimer->cancelTimeout ();
dallasHandlerTimer->wakeAtTime (fireTime);
}
return;
}
void AppleTexasAudio::dallasInterruptHandler(OSObject *owner, IOInterruptEventSource *source, int count) {
AbsoluteTime currTime;
UInt64 currNanos;
AppleTexasAudio * appleTexasAudio;
appleTexasAudio = OSDynamicCast (AppleTexasAudio, owner);
FailIf (!appleTexasAudio, Exit);
appleTexasAudio->dallasIntEventSource->disable();
clock_get_uptime (&currTime);
absolutetime_to_nanoseconds (currTime, &currNanos);
if ((currNanos - appleTexasAudio->savedNanos) > 10000000) {
appleTexasAudio->RealDallasInterruptHandler (source, count);
} else {
appleTexasAudio->dallasIntEventSource->enable();
}
Exit:
return;
}
bool AppleTexasAudio::interruptFilter(OSObject *owner, IOFilterInterruptEventSource *src)
{
AppleTexasAudio* self = (AppleTexasAudio*) owner;
self->dallasIntEventSource->disable();
return (true);
}
void AppleTexasAudio::DisplaySpeakersNotFullyConnected (OSObject *owner, IOTimerEventSource *sender) {
AppleTexasAudio * appleTexasAudio;
IOCommandGate * cg;
AbsoluteTime currTime;
UInt32 deviceID;
UInt8 bEEPROM[32];
Boolean result;
debugIOLog ("+ DisplaySpeakersNotFullyConnected\n");
appleTexasAudio = OSDynamicCast (AppleTexasAudio, owner);
FailIf (!appleTexasAudio, Exit);
if (0 == console_user) {
appleTexasAudio->notifierHandlerTimer->setTimeoutMS (kNotifyTimerDelay); } else {
if (appleTexasAudio->doneWaiting == FALSE) {
appleTexasAudio->notifierHandlerTimer->setTimeoutMS (kUserLoginDelay); appleTexasAudio->doneWaiting = TRUE;
} else {
deviceID = appleTexasAudio->GetDeviceMatch ();
if (kExternalSpeakersActive == deviceID) {
if (NULL != appleTexasAudio->dallasDriver) {
appleTexasAudio->dallasIntEventSource->disable ();
result = appleTexasAudio->dallasDriver->getSpeakerID (bEEPROM);
appleTexasAudio->dallasIntEventSource->enable ();
clock_get_uptime (&currTime);
absolutetime_to_nanoseconds (currTime, &appleTexasAudio->savedNanos);
if (FALSE == result && TRUE == appleTexasAudio->IsSpeakerConnected() ) { KUNCUserNotificationDisplayNotice (
0, 0, "", "", "/System/Library/Extensions/AppleOnboardAudio.kext", "HeaderOfDallasPartialInsert", "StringOfDallasPartialInsert",
"ButtonOfDallasPartialInsert");
IOLog ("The device plugged into the Apple speaker mini-jack cannot be recognized.\n");
IOLog ("Remove the plug from the jack. Then plug it back in and make sure it is fully inserted.\n");
} else {
appleTexasAudio->dallasIntEventSource->disable ();
cg = appleTexasAudio->getCommandGate ();
if (NULL != cg) {
cg->runAction (DeviceInterruptServiceAction);
}
appleTexasAudio->dallasIntEventSource->enable ();
clock_get_uptime (&currTime);
absolutetime_to_nanoseconds (currTime, &appleTexasAudio->savedNanos);
}
}
}
}
}
Exit:
debugIOLog ("- DisplaySpeakersNotFullyConnected\n");
return;
}
Boolean AppleTexasAudio::IsHeadphoneConnected (void) {
UInt8 headphoneSenseContents;
Boolean connection;
connection = FALSE;
if (NULL != headphoneIntEventSource) {
headphoneSenseContents = *headphoneExtIntGpio;
debug3IOLog ("headphoneExtIntGpio = %p, headphoneSenseContents = 0x%X\n", headphoneExtIntGpio, headphoneSenseContents);
if ((headphoneSenseContents & (1 << 1)) == (headphoneInsertedActiveState << 1)) {
debugIOLog ("Headphones are inserted\n");
connection = TRUE;
} else {
debugIOLog ("Headphones are not inserted\n");
connection = FALSE;
}
}
return connection;
}
IOReturn AppleTexasAudio::DeviceInterruptServiceAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
AppleTexasAudio * appleTexasAudio;
appleTexasAudio = OSDynamicCast (AppleTexasAudio, owner);
FailIf (!appleTexasAudio, Exit);
appleTexasAudio->DeviceInterruptService ();
Exit:
return kIOReturnSuccess;
}
void AppleTexasAudio::RealHeadphoneInterruptHandler (IOInterruptEventSource *source, int count) {
IOCommandGate * cg;
OSNumber * activeOutput;
SetActiveOutput (kSndHWOutputNone, kBiquadUntouched);
cg = getCommandGate ();
if (NULL != cg) {
cg->runAction (DeviceInterruptServiceAction);
}
headphonesConnected = IsHeadphoneConnected ();
if (TRUE == headphonesConnected) {
SetActiveOutput (kSndHWOutput1, kBiquadUntouched);
if (NULL != outputSelector) {
activeOutput = OSNumber::withNumber (kIOAudioOutputPortSubTypeHeadphones, 32);
outputSelector->hardwareValueChanged (activeOutput);
}
} else {
SetActiveOutput (kSndHWOutput2, kBiquadUntouched);
if (NULL != outputSelector) {
if (FALSE == IsSpeakerConnected()) {
activeOutput = OSNumber::withNumber (kIOAudioOutputPortSubTypeInternalSpeaker, 32);
} else {
activeOutput = OSNumber::withNumber (kIOAudioOutputPortSubTypeExternalSpeaker, 32);
}
outputSelector->hardwareValueChanged (activeOutput);
}
}
if (TRUE == hasVideo) {
publishResource (gAppleAudioVideoJackStateKey, headphonesConnected ? kOSBooleanTrue : kOSBooleanFalse);
}
}
void AppleTexasAudio::headphoneInterruptHandler (OSObject *owner, IOInterruptEventSource *source, int count) {
AppleTexasAudio * appleTexasAudio;
appleTexasAudio = OSDynamicCast (AppleTexasAudio, owner);
FailIf (!appleTexasAudio, Exit);
appleTexasAudio->deferHeadphoneHandler (appleTexasAudio, appleTexasAudio->deferHeadphoneHandlerTimer);
Exit:
return;
}
IOReturn AppleTexasAudio::performPowerStateChange(IOAudioDevicePowerState oldPowerState,
IOAudioDevicePowerState newPowerState,
UInt32 *microsecondsUntilComplete)
{
IOReturn result;
debug4IOLog ("+ AppleTexasAudio::performPowerStateChange (%d, %d) -- ourPowerState = %d\n", oldPowerState, newPowerState, ourPowerState);
if (NULL != theAudioPowerObject && NULL != microsecondsUntilComplete) {
*microsecondsUntilComplete = theAudioPowerObject->GetTimeToChangePowerState (ourPowerState, newPowerState);
}
result = IOAudioDevice::performPowerStateChange (oldPowerState, newPowerState, microsecondsUntilComplete);
if (NULL != theAudioPowerObject) {
switch (newPowerState) {
case kIOAudioDeviceSleep:
if (ourPowerState == kIOAudioDeviceActive) {
outputMuteChange (TRUE); theAudioPowerObject->setHardwarePowerOff ();
ourPowerState = newPowerState;
}
break;
case kIOAudioDeviceIdle:
if (ourPowerState == kIOAudioDeviceActive) {
outputMuteChange (TRUE); theAudioPowerObject->setHardwarePowerOff ();
ourPowerState = kIOAudioDeviceSleep;
} else if (ourPowerState == kIOAudioDeviceSleep && NULL != dallasDriver) {
outputMuteChange (TRUE); theAudioPowerObject->setHardwarePowerOn ();
ourPowerState = kIOAudioDeviceActive;
}
break;
case kIOAudioDeviceActive:
theAudioPowerObject->setHardwarePowerOn ();
if (NULL != outMute) {
outMute->flushValue (); }
ourPowerState = newPowerState;
break;
default:
break;
}
}
debug2IOLog ("- AppleTexasAudio::performPowerStateChange -- ourPowerState = %d\n", ourPowerState);
return result;
}
#pragma mark +DIRECT HARDWARE MANIPULATION
UInt8 * AppleTexasAudio::getGPIOAddress (UInt32 gpioSelector) {
UInt8 * gpioAddress;
gpioAddress = NULL;
switch (gpioSelector) {
case kHeadphoneMuteSel: gpioAddress = hdpnMuteGpio; break;
case kHeadphoneDetecteSel: gpioAddress = headphoneExtIntGpio; break;
case kAmplifierMuteSel: gpioAddress = ampMuteGpio; break;
case kSpeakerDetectSel: gpioAddress = dallasExtIntGpio; break;
case kCodecResetSel: gpioAddress = hwResetGpio; break;
}
if ( NULL == gpioAddress ) {
debug2IOLog ( "AppleTexasAudio::getGPIOAddress ( %d ) returns NULL\n", (unsigned int)gpioSelector );
}
return gpioAddress;
}
Boolean AppleTexasAudio::getGPIOActiveState (UInt32 gpioSelector) {
Boolean activeState;
activeState = NULL;
switch (gpioSelector) {
case kHeadphoneMuteSel: activeState = hdpnActiveState; break;
case kHeadphoneDetecteSel: activeState = headphoneInsertedActiveState; break;
case kAmplifierMuteSel: activeState = ampActiveState; break;
case kSpeakerDetectSel: activeState = dallasInsertedActiveState; break;
case kCodecResetSel: activeState = hwResetActiveState; break;
default:
debug2IOLog ( "AppleTexasAudio::getGPIOActiveState ( %d ) UNKNOWN\n", (unsigned int)gpioSelector );
break;
}
return activeState;
}
void AppleTexasAudio::setGPIOActiveState ( UInt32 selector, UInt8 gpioActiveState ) {
gpioActiveState = 0 == gpioActiveState ? FALSE : TRUE;
switch ( selector ) {
case kHeadphoneMuteSel: hdpnActiveState = gpioActiveState; break;
case kHeadphoneDetecteSel: headphoneInsertedActiveState = gpioActiveState; break;
case kAmplifierMuteSel: ampActiveState = gpioActiveState; break;
case kSpeakerDetectSel: dallasInsertedActiveState = gpioActiveState; break;
case kCodecResetSel: hwResetActiveState = gpioActiveState; break;
default:
debug3IOLog ( " AppleTexasAudio::setGPIOActiveState ( %d, %d ) UNKNOWN\n", (unsigned int)selector, gpioActiveState );
break;
}
return;
}
Boolean AppleTexasAudio::checkGpioAvailable ( UInt32 selector ) {
Boolean result = FALSE;
switch ( selector ) {
case kHeadphoneMuteSel: if ( NULL != hdpnMuteGpio ) { result = TRUE; } break;
case kHeadphoneDetecteSel: if ( NULL != headphoneExtIntGpio ) { result = TRUE; } break;
case kAmplifierMuteSel: if ( NULL != ampMuteGpio ) { result = TRUE; } break;
case kSpeakerDetectSel: if ( NULL != dallasExtIntGpio ) { result = TRUE; } break;
case kCodecResetSel: if ( NULL != hwResetGpio ) { result = TRUE; } break;
}
return result;
}
IOReturn AppleTexasAudio::readHWReg32 ( UInt32 selector, UInt32 * registerData ) {
IOReturn result = kIOReturnError;
if ( NULL != registerData ) {
result = kIOReturnSuccess;
switch ( selector ) {
case kI2sSerialFormatRegisterSelector: *registerData = audioI2SControl->GetSerialFormatReg(); break;
case kI2sDataWordFormatRegisterSelector: *registerData = audioI2SControl->GetDataWordSizesReg(); break;
case kFeatureControlRegister1Selector: *registerData = audioI2SControl->FCR1GetReg(); break;
case kFeatureControlRegister3Selector: *registerData = audioI2SControl->FCR3GetReg(); break;
case kI2s1SerialFormatRegisterSelector: *registerData = audioI2SControl->GetSerialFormatReg(); break;
case kI2s1DataWordFormatRegisterSelector: *registerData = audioI2SControl->GetDataWordSizesReg(); break;
default: result = kIOReturnError; break;
}
}
return result;
}
IOReturn AppleTexasAudio::writeHWReg32 ( UInt32 selector, UInt32 registerData ) {
IOReturn result = kIOReturnError;
result = kIOReturnSuccess;
switch ( selector ) {
case kI2sSerialFormatRegisterSelector: audioI2SControl->SetSerialFormatReg( registerData ); break;
case kI2sDataWordFormatRegisterSelector: audioI2SControl->SetDataWordSizesReg( registerData ); break;
case kFeatureControlRegister1Selector: audioI2SControl->Fcr1SetReg( registerData ); break;
case kFeatureControlRegister3Selector: audioI2SControl->Fcr3SetReg( registerData ); break;
case kI2s1SerialFormatRegisterSelector: audioI2SControl->SetSerialFormatReg( registerData ); break;
case kI2s1DataWordFormatRegisterSelector: audioI2SControl->SetFrameMatchReg( registerData ); break;
default: result = kIOReturnError; break;
}
return result;
}
IOReturn AppleTexasAudio::readCodecReg ( UInt32 selector, void * registerData, UInt32 * registerDataSize ) {
UInt32 codecCacheSize;
IOReturn err = kIOReturnError;
codecCacheSize = sizeof ( TAS3001C_ShadowReg );
if ( NULL != registerDataSize && NULL != registerData ) {
if ( codecCacheSize <= *registerDataSize && 0 != codecCacheSize && 0 == selector ) {
for ( UInt32 index = 0; index < codecCacheSize; index++ ) {
((UInt8*)registerData)[index] = ((UInt8*)&shadowRegs)[index];
}
err = kIOReturnSuccess;
if ( kIOReturnSuccess == err ) {
*registerDataSize = codecCacheSize;
}
}
}
return err;
}
IOReturn AppleTexasAudio::writeCodecReg ( UInt32 selector, void * registerData ) {
UInt32 codecRegSize;
IOReturn err = 0;
err = getCodecRegSize ( selector, &codecRegSize );
if ( kIOReturnSuccess == err ) {
err = TAS3001C_WriteRegister( (UInt8)selector, (UInt8*)registerData, kUPDATE_ALL );
}
return err;
}
UInt8 AppleTexasAudio::readGPIO (UInt32 selector) {
UInt8 * address;
UInt8 gpioValue;
gpioValue = NULL;
address = getGPIOAddress (selector);
if (NULL != address)
gpioValue = GpioReadByte (address);
return (gpioValue);
}
IOReturn AppleTexasAudio::getVolumePRAM ( UInt32 * pramDataPtr )
{
UInt8 curPRAMVol;
IODTPlatformExpert * platform;
IOReturn err = kIOReturnError;
curPRAMVol = 0;
if ( NULL != pramDataPtr ) {
platform = OSDynamicCast(IODTPlatformExpert,getPlatform());
if (platform) {
platform->readXPRAM((IOByteCount)kPRamVolumeAddr, &curPRAMVol, (IOByteCount)1);
*pramDataPtr = (UInt32)curPRAMVol;
err = kIOReturnSuccess;
}
}
return err;
}
IOReturn AppleTexasAudio::getDmaState ( UInt32 * dmaStatePtr )
{
IOReturn err = kIOReturnError;
if ( NULL != dmaStatePtr && NULL != driverDMAEngine ) {
*dmaStatePtr = (UInt32)driverDMAEngine->getDmaState();
err = kIOReturnSuccess;
}
return err;
}
IOReturn AppleTexasAudio::getStreamFormat ( IOAudioStreamFormat * streamFormatPtr )
{
IOReturn err = kIOReturnError;
if ( NULL != streamFormatPtr ) {
err = driverDMAEngine->getAudioStreamFormat( streamFormatPtr );
}
return err;
}
IOReturn AppleTexasAudio::readPowerState ( UInt32 selector, IOAudioDevicePowerState * powerState )
{
IOReturn err = kIOReturnError;
if ( NULL != powerState ) {
*powerState = ourPowerState;
err = kIOReturnSuccess;
}
return err;
}
IOReturn AppleTexasAudio::setPowerState ( UInt32 selector, IOAudioDevicePowerState powerState )
{
UInt32 microsecondsUntilComplete;
IOReturn err = kIOReturnError;
if ( NULL != powerState ) {
err = performPowerStateChange ( ourPowerState, powerState, µsecondsUntilComplete );
}
return err;
}
IOReturn AppleTexasAudio::setBiquadCoefficients ( UInt32 selector, void * biquadCoefficients, UInt32 coefficientSize )
{
IOReturn err;
IOReturn totalErr = kIOReturnError;
if ( kMaxBiquadWidth >= coefficientSize && NULL != biquadCoefficients && 0 == selector ) {
totalErr = kIOReturnSuccess;
for ( UInt32 index = 0; index < ( kTumblerNumBiquads * kTumblerMaxStreamCnt ); index ++ ) {
if ( kTumblerNumBiquads > index ) {
err = SndHWSetOutputBiquad ( kStreamFrontLeft, index, (FourDotTwenty*)biquadCoefficients );
} else {
err = SndHWSetOutputBiquad ( kStreamFrontRight, index - kTumblerNumBiquads, (FourDotTwenty*)biquadCoefficients );
}
(( EQFilterCoefficients*)biquadCoefficients)++;
if ( err ) { totalErr = err; }
}
}
return totalErr;
}
IOReturn AppleTexasAudio::getBiquadInformation ( UInt32 scalarArg1, void * outStructPtr, IOByteCount * outStructSizePtr )
{
#pragma unused ( scalarArg1 )
IOReturn result = kIOReturnError;
if ( NULL != outStructPtr && NULL != outStructSizePtr ) {
if ( *outStructSizePtr >= ( sizeof ( BiquadInfoList ) + ( sizeof ( UInt32 ) * ( kTumblerCoefficientsPerBiquad - 1 ) ) ) ) {
((BiquadInfoListPtr)outStructPtr)->numBiquad = kTumblerNumBiquads;
((BiquadInfoListPtr)outStructPtr)->numCoefficientsPerBiquad = kTumblerCoefficientsPerBiquad;
((BiquadInfoListPtr)outStructPtr)->biquadCoefficientBitWidth = kTumblerCoefficientBitWidth;
((BiquadInfoListPtr)outStructPtr)->coefficientIntegerBitWidth = kTumblerCoefficientIntegerBitWidth;
((BiquadInfoListPtr)outStructPtr)->coefficientFractionBitWidth = kTumblerCoefficientFractionBitWidth;
((BiquadInfoListPtr)outStructPtr)->coefficientOrder[0] = 'b0 ';
((BiquadInfoListPtr)outStructPtr)->coefficientOrder[1] = 'b1 ';
((BiquadInfoListPtr)outStructPtr)->coefficientOrder[2] = 'b2 ';
((BiquadInfoListPtr)outStructPtr)->coefficientOrder[3] = 'a1 ';
((BiquadInfoListPtr)outStructPtr)->coefficientOrder[4] = 'a2 ';
*outStructSizePtr = ( sizeof ( BiquadInfoList ) + ( sizeof ( UInt32 ) * ( kTumblerCoefficientsPerBiquad - 1 ) ) );
result = kIOReturnSuccess;
}
}
return result;
}
IOReturn AppleTexasAudio::getProcessingParameters ( UInt32 scalarArg1, void * outStructPtr, IOByteCount * outStructSizePtr )
{
UInt32 index;
IOReturn err = kIOReturnNotReadable;
if ( NULL != outStructPtr && NULL != outStructSizePtr ) {
if ( kMaxProcessingParamSize >= *outStructSizePtr ) {
for ( index = 0; index < ( kMaxProcessingParamSize / sizeof(UInt32) ); index++ ) {
((UInt32*)outStructPtr)[index] = mProcessingParams[index];
}
err = kIOReturnSuccess;
}
}
return (err);
}
IOReturn AppleTexasAudio::setProcessingParameters ( UInt32 scalarArg1, void * inStructPtr, UInt32 inStructSize )
{
EQPrefsElementPtr eqPrefs;
UInt32 index;
IOReturn err = kIOReturnNotReadable;
if ( NULL != inStructPtr && kMaxProcessingParamSize >= inStructSize ) {
disableLoadingEQFromFile = (bool)scalarArg1;
for ( index = 0; index < ( kMaxProcessingParamSize / sizeof(UInt32) ); index++ ) {
mProcessingParams[index] = ((UInt32*)inStructPtr)[index];
}
if ( disableLoadingEQFromFile ) {
SetUnityGainAllPass();
} else {
err = GetCustomEQCoefficients (layoutID, deviceID, speakerID, &eqPrefs);
if ( kIOReturnSuccess == err && NULL != eqPrefs ) {
DRCInfo localDRC;
localDRC.compressionRatioNumerator = eqPrefs->drcCompressionRatioNumerator;
localDRC.compressionRatioDenominator = eqPrefs->drcCompressionRatioDenominator;
localDRC.threshold = eqPrefs->drcThreshold;
localDRC.maximumVolume = eqPrefs->drcMaximumVolume;
localDRC.enable = (Boolean)((UInt32)(eqPrefs->drcEnable));
SndHWSetDRC ((DRCInfoPtr)&localDRC);
SndHWSetOutputBiquadGroup (eqPrefs->filterCount, eqPrefs->filter[0].coefficient);
} else {
SetUnityGainAllPass ();
}
}
err = kIOReturnSuccess;
}
return (err);
}
IOReturn AppleTexasAudio::invokeInternalFunction ( UInt32 functionSelector, void * inData ) {
switch ( functionSelector ) {
case kInvokeHeadphoneInterruptHandler:
RealHeadphoneInterruptHandler ( 0, 0 );
break;
case kInvokeSpeakerInterruptHandler:
RealDallasInterruptHandler ( 0, 0 );
break;
}
return kIOReturnSuccess;
}
void AppleTexasAudio::writeGPIO (UInt32 selector, UInt8 data) {
UInt8 * address;
UInt32 gpioValue;
gpioValue = NULL;
address = getGPIOAddress (selector);
if (NULL != address)
GpioWriteByte (address, data);
return;
}
UInt8 AppleTexasAudio::GpioGetDDR( UInt8* gpioAddress )
{
UInt8 gpioData;
Boolean result;
result = gpioDDR_INPUT;
if( NULL != gpioAddress )
{
gpioData = *gpioAddress;
if( 0 != ( gpioData & ( 1 << gpioDDR ) ) ) {
result = gpioDDR_OUTPUT;
}
#if DEBUGLOG
IOLog( "***** GPIO DDR RD 0x%8.0X = 0x%2.0X returns %d\n", (unsigned int)gpioAddress, gpioData, result );
#endif
}
return result;
}
UInt8 AppleTexasAudio::GpioReadByte( UInt8* gpioAddress )
{
UInt8 gpioData;
Boolean result;
result = 0;
gpioData = 0;
if( NULL != gpioAddress )
{
gpioData = *gpioAddress;
#if DEBUGLOG
IOLog( "GpioReadByte( 0x%8.0X ), *gpioAddress 0x%X\n", (unsigned int)gpioAddress, gpioData );
#endif
}
return gpioData;
}
void AppleTexasAudio::GpioWriteByte( UInt8* gpioAddress, UInt8 gpioData )
{
if( NULL != gpioAddress )
{
*gpioAddress = gpioData;
#if DEBUGLOG
IOLog( "GpioWrite( 0x%8.0X, 0x%2.0X )\n", (unsigned int)gpioAddress, gpioData);
#endif
}
}
Boolean AppleTexasAudio::GpioRead( UInt8* gpioAddress )
{
UInt8 gpioData;
Boolean result;
result = 0;
if( NULL != gpioAddress )
{
gpioData = *gpioAddress;
if( 0 != ( gpioData & ( 1 << gpioDATA ) ) ) {
result = 1;
}
#if DEBUGLOG
IOLog( "GpioRead( 0x%8.0X ) result %d, *gpioAddress 0x%2.0X\n", (unsigned int)gpioAddress, result, *gpioAddress );
#endif
}
return result;
}
void AppleTexasAudio::GpioWrite( UInt8* gpioAddress, UInt8 data )
{
UInt8 gpioData;
if( NULL != gpioAddress )
{
if( 0 == data )
gpioData = ( gpioDDR_OUTPUT << gpioDDR ) | ( 0 << gpioDATA );
else
gpioData = ( gpioDDR_OUTPUT << gpioDDR ) | ( 1 << gpioDATA );
*gpioAddress = gpioData;
#if DEBUGLOG
IOLog( "GpioWrite( 0x%8.0X, 0x%2.0X ), *gpioAddress 0x%2.0X\n", (unsigned int)gpioAddress, gpioData, *gpioAddress );
#endif
}
}
IOReturn AppleTexasAudio::readSpkrID ( UInt32 selector, UInt32 * speakerIDPtr ) {
UInt8 bEEPROM[32];
IOReturn result = kIOReturnError;
if ( NULL != speakerIDPtr ) {
for ( UInt32 index = 0; index < 4; index++ ) {
bEEPROM[index] = 0;
}
if ( selector ) {
if ( IsSpeakerConnected () && NULL != dallasDriver ) {
if ( dallasDriver->getSpeakerID (bEEPROM) ) {
*speakerIDPtr = ( IsSpeakerConnected () << kSpeakerID_Connected ) | ( bEEPROM[0] << kSpeakerID_Family ) | ( bEEPROM[1] << kSpeakerID_Type ) | ( bEEPROM[2] << kSpeakerID_SubType );
}
}
} else {
*speakerIDPtr = ( IsHeadphoneConnected () << kHeadphone_Connected ) | \
( IsSpeakerConnected () << kSpeakerID_Connected ) | \
( familyID << kSpeakerID_Family ) | \
( speakerID << kSpeakerID_Type ) | \
( 0 << kSpeakerID_SubType );
}
result = kIOReturnSuccess;
}
return result;
}
IOReturn AppleTexasAudio::getCodecRegSize ( UInt32 selector, UInt32 * codecRegSizePtr )
{
IOReturn err = kIOReturnError;
if ( NULL != codecRegSizePtr ) {
*codecRegSizePtr = 0;
err = kIOReturnSuccess;
switch( selector )
{
case kMainCtrlReg: *codecRegSizePtr = kMCRwidth; break;
case kDynamicRangeCtrlReg: *codecRegSizePtr = kDRCwidth; break;
case kVolumeCtrlReg: *codecRegSizePtr = kVOLwidth; break;
case kTrebleCtrlReg: *codecRegSizePtr = kTREwidth; break;
case kBassCtrlReg: *codecRegSizePtr = kBASwidth; break;
case kMixer1CtrlReg: *codecRegSizePtr = kMIXwidth; break;
case kMixer2CtrlReg: *codecRegSizePtr = kMIXwidth; break;
case kLeftBiquad0CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kLeftBiquad1CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kLeftBiquad2CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kLeftBiquad3CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kLeftBiquad4CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kLeftBiquad5CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad0CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad1CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad2CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad3CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad4CtrlReg: *codecRegSizePtr = kBIQwidth; break;
case kRightBiquad5CtrlReg: *codecRegSizePtr = kBIQwidth; break;
default: err = kIOReturnBadArgument; break;
}
if ( kIOReturnSuccess != err ) {
debug4IOLog ( "±AppleTexasAudio::getCodecRegSize ( %X, %X ) returns %X\n", (unsigned int)selector, (unsigned int)codecRegSizePtr, (unsigned int)err );
}
}
return err;
}
IOReturn AppleTexasAudio::InitEQSerialMode (UInt32 mode, Boolean restoreOnNormal)
{
IOReturn err;
UInt8 initData;
UInt8 previousData;
debug3IOLog ("AppleTexasAudio::InitEQSerialMode (%8lX, %d)\n", mode, restoreOnNormal);
initData = (kNormalLoad << kFL);
if (kSetFastLoadMode == mode)
initData = (kFastLoad << kFL);
err = TAS3001C_ReadRegister (kMainCtrlReg, &previousData);
initData |= (k64fs << kSC) | TAS_I2S_MODE | (TAS_WORD_LENGTH << kW0);
err = TAS3001C_WriteRegister (kMainCtrlReg, &initData, kUPDATE_ALL);
if (kRestoreOnNormal == restoreOnNormal && ((kFastLoad << kFL) == (kFastLoad << kFL) & previousData)) {
if ((kNormalLoad << kFL) == (initData & (kFastLoad << kFL))) {
TAS3001C_WriteRegister (kVolumeCtrlReg, (UInt8*)shadowRegs.sVOL, kUPDATE_HW);
TAS3001C_WriteRegister (kMixer1CtrlReg, (UInt8*)shadowRegs.sMX1, kUPDATE_HW);
TAS3001C_WriteRegister (kMixer2CtrlReg, (UInt8*)shadowRegs.sMX2, kUPDATE_HW);
TAS3001C_WriteRegister (kTrebleCtrlReg, (UInt8*)shadowRegs.sTRE, kUPDATE_HW);
TAS3001C_WriteRegister (kBassCtrlReg, (UInt8*)shadowRegs.sBAS, kUPDATE_HW);
}
}
debug4IOLog ("AppleTexasAudio ... %d = InitEQSerialMode (%8lX, %d)\n", err, mode, restoreOnNormal);
return err;
}
IOReturn AppleTexasAudio::SetAmplifierMuteState( UInt32 ampID, Boolean muteState )
{
IOReturn err;
Boolean curMuteState;
debug3IOLog( "SetAmplifierMuteState( %ld, %d )\n", ampID, muteState );
err = kIOReturnSuccess;
switch( ampID )
{
case kHEADPHONE_AMP:
curMuteState = GpioRead( hdpnMuteGpio );
if( muteState != curMuteState )
{
GpioWrite( hdpnMuteGpio, muteState );
debug2IOLog( "updated HEADPHONE mute to %d\n", muteState );
}
break;
case kSPEAKER_AMP:
curMuteState = GpioRead( ampMuteGpio );
if( muteState != curMuteState )
{
GpioWrite( ampMuteGpio, muteState );
debug2IOLog( "updated AMP mute to %d\n", muteState );
}
break;
default:
err = -50 ;
break;
}
return err;
}
IOReturn AppleTexasAudio::SetVolumeCoefficients( UInt32 left, UInt32 right )
{
UInt8 volumeData[kVOLwidth];
IOReturn err;
debug3IOLog("SetVolumeCoefficients: L=0x%lx R=0x%lx\n", left, right);
volumeData[2] = left;
volumeData[1] = left >> 8;
volumeData[0] = left >> 16;
volumeData[5] = right;
volumeData[4] = right >> 8;
volumeData[3] = right >> 16;
err = TAS3001C_WriteRegister( kVolumeCtrlReg, volumeData, kUPDATE_ALL );
return err;
}
IOReturn AppleTexasAudio::TAS3001C_Initialize(UInt32 resetFlag) {
IOReturn err;
UInt32 retryCount;
UInt32 initMode;
UInt8 oldMode;
Boolean done;
switch( resetFlag )
{
case kFORCE_RESET_SETUP_TIME: debug2IOLog( "TAS3001C_Initialize( %s )\n", "kFORCE_RESET_SETUP_TIME" ); break;
case kNO_FORCE_RESET_SETUP_TIME: debug2IOLog( "TAS3001C_Initialize( %s )\n", "kNO_FORCE_RESET_SETUP_TIME" ); break;
default: debug2IOLog( "TAS3001C_Initialize( %s )\n", "UNKNOWN" ); break;
}
err = -227; done = false;
oldMode = 0;
initMode = kUPDATE_HW;
retryCount = 0;
if (!semaphores)
{
semaphores = 1;
do{
debug2IOLog( "RESETTING, retryCount %ld\n", retryCount );
TAS3001C_Reset( resetFlag ); if( 0 == oldMode )
TAS3001C_ReadRegister( kMainCtrlReg, &oldMode );
err = InitEQSerialMode( kSetFastLoadMode, kDontRestoreOnNormal ); FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad0CtrlReg, (UInt8*)shadowRegs.sLB0, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad1CtrlReg, (UInt8*)shadowRegs.sLB1, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad2CtrlReg, (UInt8*)shadowRegs.sLB2, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad3CtrlReg, (UInt8*)shadowRegs.sLB3, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad4CtrlReg, (UInt8*)shadowRegs.sLB4, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kLeftBiquad5CtrlReg, (UInt8*)shadowRegs.sLB5, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad0CtrlReg, (UInt8*)shadowRegs.sRB0, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad1CtrlReg, (UInt8*)shadowRegs.sRB1, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad1CtrlReg, (UInt8*)shadowRegs.sRB1, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad2CtrlReg, (UInt8*)shadowRegs.sRB2, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad3CtrlReg, (UInt8*)shadowRegs.sRB3, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kRightBiquad4CtrlReg, (UInt8*)shadowRegs.sRB4, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = InitEQSerialMode( kSetNormalLoadMode, kDontRestoreOnNormal ); FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kDynamicRangeCtrlReg, (UInt8*)shadowRegs.sDRC, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kVolumeCtrlReg, (UInt8*)shadowRegs.sVOL, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kTrebleCtrlReg, (UInt8*)shadowRegs.sTRE, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kBassCtrlReg, (UInt8*)shadowRegs.sBAS, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kMixer1CtrlReg, (UInt8*)shadowRegs.sMX1, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kMixer2CtrlReg, (UInt8*)shadowRegs.sMX2, initMode );
FailIf( kIOReturnSuccess != err, AttemptToRetry );
err = TAS3001C_WriteRegister( kMainCtrlReg, &oldMode, initMode ); FailIf( kIOReturnSuccess != err, AttemptToRetry );
AttemptToRetry:
if( kIOReturnSuccess == err ) {
done = true;
}
retryCount++;
} while ( !done && ( kRESET_MAX_RETRY_COUNT != retryCount ) );
semaphores = 0;
if( kRESET_MAX_RETRY_COUNT == retryCount ) {
debug2IOLog( "\n\n\n\n TAS3001 IS DEAD: Check %s\n\n\n\n", "ChooseAudio in fcr1" );
}
}
if( kIOReturnSuccess != err )
debug3IOLog( "TAS3001C_Initialize( %ld ) err = %d\n", resetFlag, err );
return err;
}
IOReturn AppleTexasAudio::TAS3001C_ReadRegister(UInt8 regAddr, UInt8* registerData) {
UInt32 registerSize;
UInt32 regByteIndex;
UInt8 *shadowPtr;
IOReturn err;
err = kIOReturnSuccess;
registerSize = 0;
shadowPtr = NULL;
switch( regAddr )
{
case kMainCtrlReg: shadowPtr = (UInt8*)shadowRegs.sMCR; registerSize = kMCRwidth; break;
case kDynamicRangeCtrlReg: shadowPtr = (UInt8*)shadowRegs.sDRC; registerSize = kDRCwidth; break;
case kVolumeCtrlReg: shadowPtr = (UInt8*)shadowRegs.sVOL; registerSize = kVOLwidth; break;
case kTrebleCtrlReg: shadowPtr = (UInt8*)shadowRegs.sTRE; registerSize = kTREwidth; break;
case kBassCtrlReg: shadowPtr = (UInt8*)shadowRegs.sBAS; registerSize = kBASwidth; break;
case kMixer1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sMX1; registerSize = kMIXwidth; break;
case kMixer2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sMX2; registerSize = kMIXwidth; break;
case kLeftBiquad0CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB0; registerSize = kBIQwidth; break;
case kLeftBiquad1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB1; registerSize = kBIQwidth; break;
case kLeftBiquad2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB2; registerSize = kBIQwidth; break;
case kLeftBiquad3CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB3; registerSize = kBIQwidth; break;
case kLeftBiquad4CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB4; registerSize = kBIQwidth; break;
case kLeftBiquad5CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB5; registerSize = kBIQwidth; break;
case kRightBiquad0CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB0; registerSize = kBIQwidth; break;
case kRightBiquad1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB1; registerSize = kBIQwidth; break;
case kRightBiquad2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB2; registerSize = kBIQwidth; break;
case kRightBiquad3CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB3; registerSize = kBIQwidth; break;
case kRightBiquad4CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB4; registerSize = kBIQwidth; break;
case kRightBiquad5CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB5; registerSize = kBIQwidth; break;
default: err = -201; break;
}
if( kIOReturnSuccess == err )
{
for( regByteIndex = 0; regByteIndex < registerSize; regByteIndex++ )
{
registerData[regByteIndex] = shadowPtr[regByteIndex];
}
}
if( kIOReturnSuccess != err )
debug4IOLog( "%d notEnoughHardware = TAS3001C_ReadRegister( 0x%2.0X, 0x%8.0X )", err, regAddr, (unsigned int)registerData );
return err;
}
IOReturn AppleTexasAudio::TAS3001C_Reset(UInt32 resetFlag){
IOReturn err = kIOReturnSuccess;
#if DEBUGLOG
IOLog( "TAS3001C_Reset( %lu )\n", resetFlag );
#endif
switch( resetFlag )
{
case kFORCE_RESET_SETUP_TIME: debug2IOLog( "[AppleTexasAudio] TAS3001C_Reset( %s )\n", "kFORCE_RESET_SETUP_TIME" ); break;
case kNO_FORCE_RESET_SETUP_TIME: debug2IOLog( "[AppleTexasAudio] TAS3001C_Reset( %s )\n", "kNO_FORCE_RESET_SETUP_TIME" ); break;
default: debug2IOLog( "[AppleTexasAudio] TAS3001C_Reset( %s )\n", "UNKNOWN" ); break;
}
if( hwResetActiveState == GpioRead( hwResetGpio ) || !GpioGetDDR( hwResetGpio ) || resetFlag ) {
GpioWrite( hwResetGpio, 0 == hwResetActiveState ? 1 : 0 ); IOSleep (200);
}
else
{
IOSleep (3);
}
GpioWrite( hwResetGpio, hwResetActiveState ); IOSleep (3);
GpioWrite( hwResetGpio, 0 == hwResetActiveState ? 1 : 0 ); IOSleep (3);
#if DEBUGLOG
IOLog( "%d = TAS3001C_Reset( %lu )\n", err, resetFlag );
#endif
return err;
}
IOReturn AppleTexasAudio::TAS3001C_WriteRegister(UInt8 regAddr, UInt8* registerData, UInt8 mode){
UInt32 registerSize;
UInt32 regByteIndex;
UInt8 *shadowPtr;
IOReturn err;
Boolean updateRequired;
Boolean success;
err = kIOReturnSuccess;
updateRequired = false;
success = false;
registerSize = 0;
shadowPtr = NULL;
switch( regAddr )
{
case kMainCtrlReg: shadowPtr = (UInt8*)shadowRegs.sMCR; registerSize = kMCRwidth; break;
case kDynamicRangeCtrlReg: shadowPtr = (UInt8*)shadowRegs.sDRC; registerSize = kDRCwidth; break;
case kVolumeCtrlReg: shadowPtr = (UInt8*)shadowRegs.sVOL; registerSize = kVOLwidth; break;
case kTrebleCtrlReg: shadowPtr = (UInt8*)shadowRegs.sTRE; registerSize = kTREwidth; break;
case kBassCtrlReg: shadowPtr = (UInt8*)shadowRegs.sBAS; registerSize = kBASwidth; break;
case kMixer1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sMX1; registerSize = kMIXwidth; break;
case kMixer2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sMX2; registerSize = kMIXwidth; break;
case kLeftBiquad0CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB0; registerSize = kBIQwidth; break;
case kLeftBiquad1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB1; registerSize = kBIQwidth; break;
case kLeftBiquad2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB2; registerSize = kBIQwidth; break;
case kLeftBiquad3CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB3; registerSize = kBIQwidth; break;
case kLeftBiquad4CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB4; registerSize = kBIQwidth; break;
case kLeftBiquad5CtrlReg: shadowPtr = (UInt8*)shadowRegs.sLB5; registerSize = kBIQwidth; break;
case kRightBiquad0CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB0; registerSize = kBIQwidth; break;
case kRightBiquad1CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB1; registerSize = kBIQwidth; break;
case kRightBiquad2CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB2; registerSize = kBIQwidth; break;
case kRightBiquad3CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB3; registerSize = kBIQwidth; break;
case kRightBiquad4CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB4; registerSize = kBIQwidth; break;
case kRightBiquad5CtrlReg: shadowPtr = (UInt8*)shadowRegs.sRB5; registerSize = kBIQwidth; break;
default: err = -201; break;
}
if( kIOReturnSuccess == err )
{
if( kUPDATE_SHADOW == mode || kUPDATE_ALL == mode )
{
success = true;
for( regByteIndex = 0; regByteIndex < registerSize; regByteIndex++ )
{
if( shadowPtr[regByteIndex] != registerData[regByteIndex] && kUPDATE_ALL == mode )
updateRequired = true;
shadowPtr[regByteIndex] = registerData[regByteIndex];
}
}
if( kUPDATE_HW == mode || updateRequired )
{
#if DEBUGLOG
IOLog( "TAS3001C_WriteRegister addr: %2.0X subaddr: %2.0X, data = ", DEQAddress, regAddr );
for( regByteIndex = 0; regByteIndex < registerSize; regByteIndex++ ) {
IOLog( "%2.0X ", registerData[regByteIndex] );
}
IOLog("\n");
#endif
if (openI2C()) {
#if DEBUGLOG
IOLog ("interface->writeI2CBus( addr 0x%X, subaddr 0x%X, ..., ... )\n", DEQAddress, regAddr );
#endif
success = interface->writeI2CBus (DEQAddress, regAddr, registerData, registerSize);
if ( !success ) {
#if DEBUGLOG
IOLog ("%d = interface->writeI2CBus( addr 0x%X, subaddr 0x%X, ..., ... )\n",success, DEQAddress, regAddr );
#endif
}
closeI2C();
if ( !success ) {
#if DEBUGLOG
IOLog("*** Attempting recovery ***\n");
#endif
success = TAS3001C_Initialize( kNO_FORCE_RESET_SETUP_TIME );
}
} else {
debugIOLog ("couldn't open the I2C bus!\n");
}
}
}
if( kIOReturnSuccess != err || !success ) {
debug3IOLog ("err 0x%X returned, success == %d in AppleTexasAudio::TAS3001C_WriteRegister\n", err, success);
if (kIOReturnSuccess == err)
err = -1; }
return err;
}
#pragma mark +UTILITY FUNCTIONS
bool AppleTexasAudio::DallasDriverPublished (AppleTexasAudio * appleTexasAudio, void * refCon, IOService * newService) {
bool resultCode;
resultCode = FALSE;
FailIf (NULL == appleTexasAudio, Exit);
FailIf (NULL == newService, Exit);
appleTexasAudio->dallasDriver = (AppleDallasDriver *)newService;
appleTexasAudio->attach (appleTexasAudio->dallasDriver);
appleTexasAudio->dallasDriver->open (appleTexasAudio);
if (NULL != appleTexasAudio->dallasDriverNotifier)
appleTexasAudio->dallasDriverNotifier->remove ();
resultCode = TRUE;
Exit:
return resultCode;
}
void AppleTexasAudio::DeviceInterruptService (void) {
EQPrefsElementPtr eqPrefs;
IOReturn err;
UInt32 deviceID;
Boolean result;
UInt8 bEEPROM[32];
OSNumber * headphoneState;
debugIOLog ("+ DeviceInterruptService\n");
err = kIOReturnSuccess;
deviceID = GetDeviceMatch ();
if (NULL != driverDMAEngine) {
if (kInternalSpeakerActive == deviceID) {
switch (layoutID) {
case layoutTangent:
case layoutP57:
driverDMAEngine->setRightChanMixed (FALSE);
useMasterVolumeControl = TRUE;
break;
case layoutP57b:
case layoutTessera:
case layoutP79:
driverDMAEngine->setRightChanMixed (TRUE);
useMasterVolumeControl = TRUE;
break;
default:
driverDMAEngine->setRightChanMixed (FALSE);
useMasterVolumeControl = FALSE;
}
} else {
driverDMAEngine->setRightChanMixed (FALSE);
useMasterVolumeControl = FALSE;
}
}
debug4IOLog ( "dallasDriver %x, dallasSpeakersConnected %x, dallasSpeakersProbed %x\n", (unsigned int)dallasDriver, (unsigned int)dallasSpeakersConnected, (unsigned int)dallasSpeakersProbed );
if (NULL != dallasDriver && TRUE == dallasSpeakersConnected && FALSE == dallasSpeakersProbed) {
speakerID = 0;
familyID = 0;
result = FALSE; bEEPROM[0] = 0;
bEEPROM[1] = 0;
debugIOLog ("About to get the speaker ID\n");
result = dallasDriver->getSpeakerID (bEEPROM);
dallasSpeakersProbed = TRUE;
debug3IOLog ("DallasDriver result = %d speakerID = %ld\n", result, speakerID);
speakerConnectFailed = TRUE;
if (TRUE == result) {
if ( kDallasDeviceFamilySpeaker == bEEPROM[0] ) {
familyID = bEEPROM[0];
speakerID = bEEPROM[1];
speakerConnectFailed = FALSE;
}
}
setProperty (kSpeakerConnectError, speakerConnectFailed);
if (kExternalSpeakersActive == deviceID && TRUE == speakerConnectFailed && TRUE == IsSpeakerConnected()) { DisplaySpeakersNotFullyConnected (this, NULL);
}
}
if ( !dallasSpeakersConnected ) { familyID = 0;
speakerID = 0;
}
if ( !disableLoadingEQFromFile ) {
err = GetCustomEQCoefficients (layoutID, deviceID, speakerID, &eqPrefs);
} else {
err = kIOReturnSuccess;
}
debug6IOLog ("%d = GetCustomEQCoefficients (%lX, %lX, %lX, %p)\n", err, layoutID, deviceID, speakerID, eqPrefs);
if (kIOReturnSuccess == err && NULL != eqPrefs) {
DRCInfo localDRC;
localDRC.compressionRatioNumerator = eqPrefs->drcCompressionRatioNumerator;
localDRC.compressionRatioDenominator = eqPrefs->drcCompressionRatioDenominator;
localDRC.threshold = eqPrefs->drcThreshold;
localDRC.maximumVolume = eqPrefs->drcMaximumVolume;
localDRC.enable = (Boolean)((UInt32)(eqPrefs->drcEnable));
err = SndHWSetDRC ((DRCInfoPtr)&localDRC);
err = SndHWSetOutputBiquadGroup (eqPrefs->filterCount, eqPrefs->filter[0].coefficient);
} else {
SetUnityGainAllPass ();
}
minVolume = kMinimumVolume;
maxVolume = kMaximumVolume + drc.maximumVolume;
debug3IOLog ("DeviceInterruptService: minVolume = %ld, maxVolume = %ld\n", minVolume, maxVolume);
AdjustControls ();
if (NULL != headphoneConnection) {
if (TRUE == IsHeadphoneConnected ()) {
headphoneState = OSNumber::withNumber (1, 32);
} else {
headphoneState = OSNumber::withNumber ((long long unsigned int)0, 32);
}
(void)headphoneConnection->hardwareValueChanged (headphoneState);
}
debugIOLog ("- DeviceInterruptService\n");
return;
}
void AppleTexasAudio::ExcludeHPMuteRelease (UInt32 layout) {
switch (layout) {
case layoutP92:
case layoutP54:
case layoutP29: dontReleaseHPMute = true; break;
default: dontReleaseHPMute = false; break;
}
}
UInt32 AppleTexasAudio::GetDeviceMatch (void) {
UInt32 theDeviceMatch;
if (TRUE == IsHeadphoneConnected ())
theDeviceMatch = kHeadphonesActive; else if (TRUE == dallasSpeakersConnected)
theDeviceMatch = kExternalSpeakersActive; else
theDeviceMatch = kInternalSpeakerActive;
return theDeviceMatch;
}
IORegistryEntry *AppleTexasAudio::FindEntryByNameAndProperty (const IORegistryEntry * start, const char * name, const char * key, UInt32 value) {
OSIterator *iterator;
IORegistryEntry *theEntry;
IORegistryEntry *tmpReg;
OSNumber *tmpNumber;
theEntry = NULL;
iterator = NULL;
FailIf (NULL == start, Exit);
iterator = start->getChildIterator (gIOServicePlane);
FailIf (NULL == iterator, Exit);
while (NULL == theEntry && (tmpReg = OSDynamicCast (IORegistryEntry, iterator->getNextObject ())) != NULL) {
if (strcmp (tmpReg->getName (), name) == 0) {
tmpNumber = OSDynamicCast (OSNumber, tmpReg->getProperty (key));
if (NULL != tmpNumber && tmpNumber->unsigned32BitValue () == value) {
theEntry = tmpReg;
theEntry->retain();
}
}
}
Exit:
if (NULL != iterator) {
iterator->release ();
}
return theEntry;
}
IORegistryEntry *AppleTexasAudio::FindEntryByProperty (const IORegistryEntry * start, const char * key, const char * value) {
OSIterator *iterator;
IORegistryEntry *theEntry;
IORegistryEntry *tmpReg;
OSData *tmpData;
theEntry = NULL;
iterator = start->getChildIterator (gIODTPlane);
FailIf (NULL == iterator, Exit);
while (NULL == theEntry && (tmpReg = OSDynamicCast (IORegistryEntry, iterator->getNextObject ())) != NULL) {
tmpData = OSDynamicCast (OSData, tmpReg->getProperty (key));
if (NULL != tmpData && tmpData->isEqualTo (value, strlen (value))) {
theEntry = tmpReg;
}
}
Exit:
if (NULL != iterator) {
iterator->release ();
}
return theEntry;
}
IOReturn AppleTexasAudio::GetCustomEQCoefficients (UInt32 layoutID, UInt32 deviceID, UInt32 speakerID, EQPrefsElementPtr *filterSettings) {
IOReturn err;
Boolean found;
UInt32 index;
EQPrefsElementPtr eqElementPtr;
debug5IOLog ("GetCustomEQCoefficients (%lX, %lX, %lX, %p)\n", layoutID, deviceID, speakerID, filterSettings);
debug2IOLog ("gEQPrefs %p\n", gEQPrefs);
err = -50;
FailIf (0 == layoutID, Exit);
FailIf (NULL == filterSettings, Exit);
FailIf (NULL == gEQPrefs, Exit);
found = FALSE;
eqElementPtr = NULL;
*filterSettings = NULL;
for (index = 0; index < gEQPrefs->eqCount && !found; index++) {
eqElementPtr = &(gEQPrefs->eq[index]);
debug2IOLog ("eqElementPtr %p\n", eqElementPtr);
debug3IOLog ("index %ld, eqCount %ld\n", index, gEQPrefs->eqCount);
debug3IOLog ("layoutID %lX, deviceID %lX, \n", eqElementPtr->layoutID, eqElementPtr->deviceID);
debug2IOLog ("speakerID %lX\n", eqElementPtr->speakerID);
if ((eqElementPtr->layoutID == layoutID) && (eqElementPtr->deviceID == deviceID) && (eqElementPtr->speakerID == speakerID)) {
found = TRUE;
}
}
if (TRUE == found) {
*filterSettings = eqElementPtr;
err = kIOReturnSuccess;
}
Exit:
if (kIOReturnSuccess != err) {
debug2IOLog ("err %d\n", err);
} else {
debug2IOLog ("filterSettings %p\n", filterSettings);
}
return err;
}
UInt32 AppleTexasAudio::GetDeviceID (void) {
IORegistryEntry *sound;
OSData *tmpData;
UInt32 *deviceID;
UInt32 theDeviceID;
theDeviceID = 0;
sound = ourProvider->childFromPath (kSoundEntry, gIODTPlane);
FailIf (!sound, Exit);
tmpData = OSDynamicCast (OSData, sound->getProperty (kDeviceID));
FailIf (!tmpData, Exit);
deviceID = (UInt32*)tmpData->getBytesNoCopy ();
if (NULL != deviceID) {
debug2IOLog ("deviceID = %ld\n", *deviceID);
theDeviceID = *deviceID;
} else {
debugIOLog ("deviceID = NULL!\n");
}
Exit:
return theDeviceID;
}
Boolean AppleTexasAudio::HasInput (void) {
IORegistryEntry *sound;
OSData *tmpData;
UInt32 *numInputs;
Boolean hasInput;
hasInput = false;
sound = ourProvider->childFromPath (kSoundEntry, gIODTPlane);
FailIf (!sound, Exit);
tmpData = OSDynamicCast (OSData, sound->getProperty (kNumInputs));
FailIf (!tmpData, Exit);
numInputs = (UInt32*)tmpData->getBytesNoCopy ();
debug2IOLog ("numInputs = %ld\n", *numInputs);
if (*numInputs > 1) {
hasInput = true;
debugIOLog ("Has input!\n");
} else {
debugIOLog ("Doesn't have input\n");
}
Exit:
return hasInput;
}
IOReturn AppleTexasAudio::SetActiveOutput (UInt32 output, Boolean touchBiquad) {
IOReturn err;
debug3IOLog ("AppleTexasAudio::SndHWSetActiveOutput (output = %ld, %d)\n", output, touchBiquad);
err = kIOReturnSuccess;
if (touchBiquad)
SetUnityGainAllPass ();
switch (output) {
case kSndHWOutputNone:
SetAmplifierMuteState (kHEADPHONE_AMP, ASSERT_GPIO (hdpnActiveState)); SetAmplifierMuteState (kSPEAKER_AMP, ASSERT_GPIO (ampActiveState)); break;
case kSndHWOutput1:
SetAmplifierMuteState (kHEADPHONE_AMP, NEGATE_GPIO (hdpnActiveState)); SetAmplifierMuteState (kSPEAKER_AMP, ASSERT_GPIO (ampActiveState)); IOSleep (kAmpRecoveryMuteDuration); break;
case kSndHWOutput2: case kSndHWOutput3: case kSndHWOutput4:
SetAmplifierMuteState (kHEADPHONE_AMP, ASSERT_GPIO (hdpnActiveState)); SetAmplifierMuteState (kSPEAKER_AMP, NEGATE_GPIO (ampActiveState)); IOSleep (kAmpRecoveryMuteDuration); if (!dontReleaseHPMute) SetAmplifierMuteState (kHEADPHONE_AMP, NEGATE_GPIO (hdpnActiveState)); break;
}
debug2IOLog ("AppleTexasAudio::SndHWSetActiveOutput err %d\n", err);
return err;
}
void AppleTexasAudio::SetBiquadInfoToUnityAllPass (void) {
UInt32 index;
debugIOLog ("SetBiquadInfoToUnityAllPass ()\n");
for (index = 0; index < kNumberOfBiquadCoefficients; index++) {
biquadGroupInfo[index++] = 1.0; biquadGroupInfo[index++] = 0.0; biquadGroupInfo[index++] = 0.0; biquadGroupInfo[index++] = 0.0; biquadGroupInfo[index] = 0.0; }
debugIOLog ("EXIT SetBiquadInfoToUnityAllPass ()\n");
}
void AppleTexasAudio::SetUnityGainAllPass (void) {
UInt32 prevLoadMode;
int biquadRefnum;
DRCInfo localDRC;
prevLoadMode = 0 == (shadowRegs.sMCR[0] & (kFastLoad << kFL)) ? kSetNormalLoadMode : kSetFastLoadMode;
debug3IOLog ("AppleTexasAudio::SetUnityGainAllPass (), shadowRegs.sMCR[0] %2X, prevLoadMode %ld\n", shadowRegs.sMCR[0], prevLoadMode);
if (kSetFastLoadMode == prevLoadMode)
InitEQSerialMode (kSetNormalLoadMode, kRestoreOnNormal);
InitEQSerialMode (kSetFastLoadMode, kDontRestoreOnNormal);
for (biquadRefnum = 0; biquadRefnum < kNumberOfBiquadsPerChannel; biquadRefnum++) {
TAS3001C_WriteRegister (kLeftBiquad0CtrlReg + biquadRefnum, (UInt8*)kBiquad0db, kUPDATE_ALL);
TAS3001C_WriteRegister (kRightBiquad0CtrlReg + biquadRefnum, (UInt8*)kBiquad0db, kUPDATE_ALL);
}
SetBiquadInfoToUnityAllPass ();
InitEQSerialMode (kSetNormalLoadMode, kRestoreOnNormal);
localDRC.compressionRatioNumerator = kDrcRatioNumerator;
localDRC.compressionRatioDenominator = kDrcRationDenominator;
localDRC.threshold = kDrcUnityThresholdHW;
localDRC.maximumVolume = kDefaultMaximumVolume;
localDRC.enable = false;
SndHWSetDRC (&localDRC);
if (kSetFastLoadMode == prevLoadMode)
InitEQSerialMode (kSetFastLoadMode, kDontRestoreOnNormal);
debug3IOLog ("shadowRegs.sMCR[0] %8X, prevLoadMode %ld\n", shadowRegs.sMCR[0], prevLoadMode);
}
IOReturn AppleTexasAudio::SndHWSetDRC( DRCInfoPtr theDRCSettings ) {
IOReturn err;
UInt8 regData[kDRCwidth];
Boolean enableUpdated;
err = kIOReturnSuccess;
enableUpdated = false;
FailWithAction( NULL == theDRCSettings, err = -50, Exit );
debug2IOLog( "SndHWSetDRC( theDRCSettings %p )\n", theDRCSettings );
debug3IOLog( "compressionRatioNumerator %ld, compressionRatioDenominator %ld\n", theDRCSettings->compressionRatioNumerator, theDRCSettings->compressionRatioDenominator );
debug3IOLog( "threshold %ld, maximumVolume %ld\n", theDRCSettings->threshold, theDRCSettings->maximumVolume );
debug2IOLog( "enable %d\n", theDRCSettings->enable );
if( TRUE == theDRCSettings->enable ) {
debugIOLog( "enable DRC\n" );
regData[0] = ( kDrcEnable << kEN ) | ( kCompression3to1 << kCR );
regData[1] = (UInt8)( kDrcUnityThresholdHW - ((SInt32)( -theDRCSettings->threshold / kDrcThresholdStepSize ) / 1000) );
err = TAS3001C_WriteRegister( kDynamicRangeCtrlReg, regData, kUPDATE_ALL );
FailIf( kIOReturnSuccess != err, Exit );
if( drc.enable != theDRCSettings->enable ) {
enableUpdated = true;
}
drc.enable = theDRCSettings->enable;
debug2IOLog( "drc.compressionRatioNumerator %ld\n", drc.compressionRatioNumerator );
debug2IOLog( "drc.compressionRatioDenominator %ld\n", drc.compressionRatioDenominator );
debug2IOLog( "drc.threshold %ld\n", drc.threshold );
debug2IOLog( "drc.enable %d\n", drc.enable );
if( drc.maximumVolume != theDRCSettings->maximumVolume || enableUpdated ) {
drc.maximumVolume = theDRCSettings->maximumVolume;
}
} else {
debugIOLog( "disable DRC\n" );
err = TAS3001C_ReadRegister( kDynamicRangeCtrlReg, regData );
FailIf( kIOReturnSuccess != err, Exit );
regData[0] = ( kDrcDisable << kEN ) | ( kCompression3to1 << kCR ); regData[1] = kDefaultCompThld; err = TAS3001C_WriteRegister( kDynamicRangeCtrlReg, regData, kUPDATE_ALL );
FailIf( kIOReturnSuccess != err, Exit );
drc.enable = false;
}
drc.compressionRatioNumerator = theDRCSettings->compressionRatioNumerator;
drc.compressionRatioDenominator = theDRCSettings->compressionRatioDenominator;
drc.threshold = theDRCSettings->threshold;
drc.maximumVolume = theDRCSettings->maximumVolume;
Exit:
if( kIOReturnSuccess != err ) {
debug2IOLog( "SndHWSetDRC: err = %d\n", err );
}
return err;
}
IOReturn AppleTexasAudio::SndHWSetOutputBiquad( UInt32 streamID, UInt32 biquadRefNum, FourDotTwenty *biquadCoefficients )
{
IOReturn err;
UInt32 coefficientIndex;
UInt32 tumblerBiquadIndex;
UInt32 biquadGroupIndex;
UInt8 tumblerBiquad[kTumblerCoefficientsPerBiquad * kTumblerNumBiquads];
#ifdef kBIQUAD_VERBOSE
#endif
err = kIOReturnSuccess;
FailWithAction( kTumblerMaxBiquadRefNum < biquadRefNum || NULL == biquadCoefficients, err = -50, Exit );
FailWithAction( kStreamStereo != streamID && kStreamFrontLeft != streamID && kStreamFrontRight != streamID, err = -50, Exit );
tumblerBiquadIndex = 0;
biquadGroupIndex = biquadRefNum * kTumblerCoefficientsPerBiquad;
if( kStreamFrontRight == streamID )
biquadGroupIndex += kNumberOfBiquadCoefficientsPerChannel;
#ifdef kEQ_VERBOSE
debug3IOLog( "%0.4s %d : ", &streamID, biquadRefNum );
#endif
for( coefficientIndex = 0; coefficientIndex < kTumblerCoefficientsPerBiquad; coefficientIndex++ )
{
#if kEQ_VERBOSE
#endif
tumblerBiquad[tumblerBiquadIndex++] = biquadCoefficients[coefficientIndex].integerAndFraction1;
tumblerBiquad[tumblerBiquadIndex++] = biquadCoefficients[coefficientIndex].fraction2;
tumblerBiquad[tumblerBiquadIndex++] = biquadCoefficients[coefficientIndex].fraction3;
}
debugIOLog( "\n" );
err = SetOutputBiquadCoefficients( streamID, biquadRefNum, tumblerBiquad );
Exit:
if( kIOReturnSuccess != err )
debug4IOLog( "err %d = SndHWSetOutputBiquad( '%4.4s', %ld )\n", err, (char*)&streamID, biquadRefNum );
return err;
}
IOReturn AppleTexasAudio::SndHWSetOutputBiquadGroup( UInt32 biquadFilterCount, FourDotTwenty *biquadCoefficients )
{
UInt32 index;
IOReturn err;
FailWithAction( 0 == biquadFilterCount || NULL == biquadCoefficients, err = -50, Exit );
err = kIOReturnSuccess;
InitEQSerialMode( kSetFastLoadMode, kDontRestoreOnNormal );
index = 0;
do {
if( index >= ( biquadFilterCount / 2 ) ) {
err = SndHWSetOutputBiquad( kStreamFrontRight, index - ( biquadFilterCount / 2 ), biquadCoefficients );
} else {
err = SndHWSetOutputBiquad( kStreamFrontLeft, index, biquadCoefficients );
}
index++;
biquadCoefficients += kNumberOfCoefficientsPerBiquad;
} while ( ( index < biquadFilterCount ) && ( kIOReturnSuccess == err ) );
InitEQSerialMode( kSetNormalLoadMode, kRestoreOnNormal );
Exit:
debug2IOLog( "err = %d\n", err );
return err;
}
IOReturn AppleTexasAudio::SetOutputBiquadCoefficients( UInt32 streamID, UInt32 biquadRefNum, UInt8 *biquadCoefficients )
{
IOReturn err;
debug4IOLog ( "SetOutputBiquadCoefficients( '%4.4s', %ld, %p )\n", (char*)&streamID, biquadRefNum, biquadCoefficients );
err = kIOReturnSuccess;
FailWithAction ( kTumblerMaxBiquadRefNum < biquadRefNum || NULL == biquadCoefficients, err = -50, Exit );
FailWithAction ( kStreamStereo != streamID && kStreamFrontLeft != streamID && kStreamFrontRight != streamID, err = -50, Exit );
switch ( biquadRefNum )
{
case kBiquadRefNum_0:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad0CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad0CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad0CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad0CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
case kBiquadRefNum_1:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad1CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad1CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad1CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad1CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
case kBiquadRefNum_2:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad2CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad2CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad2CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad2CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
case kBiquadRefNum_3:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad3CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad3CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad3CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad3CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
case kBiquadRefNum_4:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad4CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad4CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad4CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad4CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
case kBiquadRefNum_5:
switch( streamID )
{
case kStreamFrontLeft: err = TAS3001C_WriteRegister( kLeftBiquad5CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamFrontRight: err = TAS3001C_WriteRegister( kRightBiquad5CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
case kStreamStereo: err = TAS3001C_WriteRegister( kLeftBiquad5CtrlReg, biquadCoefficients, kUPDATE_ALL );
err = TAS3001C_WriteRegister( kRightBiquad5CtrlReg, biquadCoefficients, kUPDATE_ALL ); break;
}
break;
}
Exit:
if( kIOReturnSuccess != err )
debug5IOLog( "err %d = SetOutputBiquadCoefficients( '%4.4s', %ld, %p )\n", err, (char*)&streamID, biquadRefNum, biquadCoefficients );
return err;
}
#pragma mark +I2C FUNCTIONS
UInt32 AppleTexasAudio::getI2CPort()
{
if(ourProvider) {
OSData *t;
t = OSDynamicCast(OSData, ourProvider->getProperty("AAPL,i2c-port-select")); if (t != NULL) {
UInt32 myPort = *((UInt32*)t->getBytesNoCopy());
return myPort;
}
}
return 0;
}
bool AppleTexasAudio::openI2C()
{
FailIf (NULL == interface, Exit);
FailIf (!interface->openI2CBus (getI2CPort()), Exit);
interface->setStandardSubMode ();
interface->setPollingMode (true);
return true;
Exit:
return false;
}
void AppleTexasAudio::closeI2C ()
{
interface->closeI2CBus ();
}
bool AppleTexasAudio::findAndAttachI2C(IOService *provider)
{
const OSSymbol *i2cDriverName;
IOService *i2cCandidate;
i2cDriverName = OSSymbol::withCStringNoCopy("PPCI2CInterface.i2c-mac-io");
i2cCandidate = waitForService(resourceMatching(i2cDriverName));
interface = (PPCI2CInterface*)i2cCandidate->getProperty(i2cDriverName);
if (interface == NULL) {
debugIOLog("AppleTexasAudio::findAndAttachI2C can't find the i2c in the registry\n");
return false;
}
interface->retain();
return true;
}
bool AppleTexasAudio::detachFromI2C(IOService* )
{
if (interface) {
interface->release();
interface = 0;
}
return (true);
}
#if 0 // {
inline UInt32 AppleTexasAudio::FCR1GetReg( void )
{
return OSReadLittleInt32 ( ioBaseAddress, kFCR1Offset );
}
inline void AppleTexasAudio::Fcr1SetReg(UInt32 value)
{
OSWriteLittleInt32(ioBaseAddress, kFCR1Offset, value);
}
inline UInt32 AppleTexasAudio::FCR3GetReg( void )
{
return OSReadLittleInt32 ( ioBaseAddress, kFCR3Offset );
}
inline void AppleTexasAudio::Fcr3SetReg(UInt32 value)
{
OSWriteLittleInt32(ioBaseAddress, kFCR3Offset, value);
}
#endif // }
#if 0 // {
inline void AppleTexasAudio::I2SSetSerialFormatReg(UInt32 value)
{
OSWriteLittleInt32( ioBaseAddress, kI2S0BaseOffset + kI2SSerialFormatOffset, value);
}
inline UInt32 AppleTexasAudio::I2SGetSerialFormatReg(void)
{
return OSReadLittleInt32( ioBaseAddress, kI2S0BaseOffset + kI2SSerialFormatOffset);
}
inline void AppleTexasAudio::I2SSetDataWordSizeReg(UInt32 value)
{
OSWriteLittleInt32( ioBaseAddress, kI2S0BaseOffset + kI2SFrameMatchOffset, value);
}
inline UInt32 AppleTexasAudio::I2SGetDataWordSizeReg(void)
{
return OSReadLittleInt32( ioBaseAddress, kI2S0BaseOffset + kI2SFrameMatchOffset);
}
inline void AppleTexasAudio::I2S1SetSerialFormatReg(UInt32 value)
{
OSWriteLittleInt32( ioBaseAddress, kI2S1BaseOffset + kI2SSerialFormatOffset, value);
}
inline UInt32 AppleTexasAudio::I2S1GetSerialFormatReg(void)
{
return OSReadLittleInt32( ioBaseAddress, kI2S1BaseOffset + kI2SSerialFormatOffset);
}
inline void AppleTexasAudio::I2S1SetDataWordSizeReg(UInt32 value)
{
OSWriteLittleInt32( ioBaseAddress, kI2S1BaseOffset + kI2SFrameMatchOffset, value);
}
inline UInt32 AppleTexasAudio::I2S1GetDataWordSizeReg(void)
{
return OSReadLittleInt32( ioBaseAddress, kI2S1BaseOffset + kI2SFrameMatchOffset);
}
inline void AppleTexasAudio::KLSetRegister(void *klRegister, UInt32 value)
{
UInt32 *reg = (UInt32*)klRegister;
*reg = value;
}
inline UInt32 AppleTexasAudio::KLGetRegister(void *klRegister)
{
UInt32 *reg = (UInt32*)klRegister;
return (*reg);
}
inline UInt32 AppleTexasAudio::I2SGetIntCtlReg()
{
return OSReadLittleInt32(ioBaseAddress, kI2S0BaseOffset + kI2SIntCtlOffset);
}
inline UInt32 AppleTexasAudio::I2S1GetIntCtlReg()
{
return OSReadLittleInt32(ioBaseAddress, kI2S1BaseOffset + kI2SIntCtlOffset);
}
bool AppleTexasAudio::setSampleParameters(UInt32 sampleRate, UInt32 mclkToFsRatio)
{
UInt32 mclkRatio;
UInt32 reqMClkRate;
mclkRatio = mclkToFsRatio;
if ( mclkRatio == 0 ) mclkRatio = 64;
reqMClkRate = sampleRate * mclkRatio;
if ((kClock18MHz % reqMClkRate) == 0) {
clockSource = kClock18MHz;
}
else if ((kClock45MHz % reqMClkRate) == 0) {
clockSource = kClock45MHz;
}
else if ((kClock49MHz % reqMClkRate) == 0) {
clockSource = kClock49MHz;
}
else {
debugIOLog("AppleTexasAudio::setSampleParameters Unable to find a suitable source clock (no globals changes take effect)\n");
return false;
}
debug3IOLog("AppleTexasAudio:setSampleParameters %ld / %ld =", (UInt32)clockSource, (UInt32)reqMClkRate);
mclkDivisor = clockSource / reqMClkRate;
debug2IOLog("%ld\n", mclkDivisor);
switch (serialFormat) {
case kSndIOFormatI2SSony:
case kSndIOFormatI2S64x:
sclkDivisor = mclkRatio / k64TicksPerFrame; break;
case kSndIOFormatI2S32x:
sclkDivisor = mclkRatio / k32TicksPerFrame; break;
default:
debugIOLog("AppleTexasAudio::setSampleParameters Invalid serial format\n");
return false;
break;
}
return true;
}
void AppleTexasAudio::setSerialFormatRegister(ClockSource clockSource, UInt32 mclkDivisor, UInt32 sclkDivisor, SoundFormat serialFormat)
{
UInt32 regValue = 0;
debug5IOLog("AppleTexasAudio::SetSerialFormatRegister(%d,%d,%d,%d)\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
switch ((int)clockSource)
{
case kClock18MHz:
regValue = kClockSource18MHz;
break;
case kClock45MHz:
regValue = kClockSource45MHz;
break;
case kClock49MHz:
regValue = kClockSource49MHz;
break;
default:
debug5IOLog("AppleTexasAudio::SetSerialFormatRegister(%d,%d,%d,%d): Invalid clock source\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
break;
}
switch (mclkDivisor)
{
case 1:
regValue |= kMClkDivisor1;
break;
case 3:
regValue |= kMClkDivisor3;
break;
case 5:
regValue |= kMClkDivisor5;
break;
default:
regValue |= (((mclkDivisor / 2) - 1) << kMClkDivisorShift) & kMClkDivisorMask;
break;
}
switch ((int)sclkDivisor)
{
case 1:
regValue |= kSClkDivisor1;
break;
case 3:
regValue |= kSClkDivisor3;
break;
default:
regValue |= (((sclkDivisor / 2) - 1) << kSClkDivisorShift) & kSClkDivisorMask;
break;
}
regValue |= kSClkMaster;
switch (serialFormat)
{
case kSndIOFormatI2SSony:
regValue |= kSerialFormatSony;
break;
case kSndIOFormatI2S64x:
regValue |= kSerialFormat64x;
break;
case kSndIOFormatI2S32x:
regValue |= kSerialFormat32x;
break;
default:
debug5IOLog("AppleTexasAudio::SetSerialFormatRegister(%d,%d,%d,%d): Invalid serial format\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
break;
}
I2SSetDataWordSizeReg (0x02000200);
I2SSetSerialFormatReg(i2sSerialFormat);
}
#endif // }
#define kCommonFrameRate 44100
UInt32 AppleTexasAudio::frameRate(UInt32 index)
{
if(ourProvider) {
OSData *t;
t = OSDynamicCast(OSData, ourProvider->getProperty("sample-rates"));
if (t != NULL) {
UInt32 *fArray = (UInt32*)(t->getBytesNoCopy());
if ((fArray != NULL) && (index < fArray[0])){
UInt32 fR = fArray[index + 1] / (UInt32)65536;
debug2IOLog( "AppleTexasAudio::frameRate (%ld)\n", fR);
return fR;
}
}
}
return (UInt32)kCommonFrameRate;
}