/* * AudioScreamerAudio.cpp (definition) * Project : AppleOnboardAudio * * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AN APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ * * Hardware independent (relatively) code for the Awacs Controller * NEW-WORLD MACHINE ONLY!!! * * As of the release of OS X version 1, the AppleScreamerAudio driver has gone * under major changes. These changes adress only NewWorld machines (the translucent * ones). * * This work was undertaken in order to use the information present in the Open Firmware * "sound" node, and that represent the hardware wiring. We can then avoid the multiple * cases for different machines, and have a driver that autoconfigures itself. Another * goal is to isolate the Codec related function, from the rest of the driver. A superclass * for all Apple Hardware driver can then be extracted and reused when new hardware * is coming. * * For commodity, all functions have been defined inside the driver class. This can * obviously done in a better way, by grouping the functionnality and creating * appropriate objects. * * The list of hardware access functions is not restrictive. It is only sufficient * enough to answer to the behavior asked by the UI guidelines of OS X version 1. * As long as the hardware support it, it is our intention to different * UI policies, and have a wider flexibility. * * PCMCIA card support is not supported for now */ #include "AudioHardwareCommon.h" #include "AudioHardwareConstants.h" #include "AudioHardwareUtilities.h" #include "AudioHardwareDetect.h" #include "AudioHardwareOutput.h" #include "AudioHardwareInput.h" #include "AudioHardwareMux.h" #include "AudioHardwarePower.h" #include "AppleScreamerAudio.h" #include "awacs_hw.h" #include "AppleDBDMAAudioDMAEngine.h" static void Screamer_writeCodecControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value ); static void Screamer_writeSoundControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value ); static UInt32 Screamer_ReadStatusRegisters( volatile awacs_regmap_t *ioBaseAwacs ); static int Screamer_readCodecControlReg(volatile awacs_regmap_t *ioBaseAwacs, int regNum); // Not used at the moment, turned off just to kill warning static int Screamer_readCodecControlReg(volatile awacs_regmap_t *ioBaseAwacs, int regNum) { UInt32 reg, result; reg = (((regNum << kReadBackRegisterShift) & kReadBackRegisterMask) | kReadBackEnable) & kCodecCtlDataMask; reg |= kCodecCtlAddress7; reg |= kCodecCtlEMSelect0; OSWriteLittleInt32(&ioBaseAwacs->CodecControlRegister, 0, reg); eieio(); do { result = OSReadLittleInt32(&ioBaseAwacs->CodecControlRegister, 0); eieio(); } while (result & kCodecCtlBusy); // We're going to do this twice to make sure the results are back before reading the status register // What a pain - there must be a better way OSWriteLittleInt32(&ioBaseAwacs->CodecControlRegister, 0, reg); eieio(); do { result = OSReadLittleInt32(&ioBaseAwacs->CodecControlRegister, 0); eieio(); } while (result & kCodecCtlBusy); result = (OSReadLittleInt32(&ioBaseAwacs->CodecStatusRegister, 0) >> 4) & kCodecCtlDataMask; return result; } static void Screamer_writeCodecControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value ) { int CodecControlReg; //DEBUG_IOLOG( "PPCSound(awacs): CodecControlReg @ %08x = %08x\n", (int)&ioBaseAwacs->CodecControlRegister, value); OSWriteLittleInt32(&ioBaseAwacs->CodecControlRegister, 0, value ); eieio(); do { CodecControlReg = OSReadLittleInt32( &ioBaseAwacs->CodecControlRegister, 0 ); eieio(); } while ( CodecControlReg & kCodecCtlBusy ); } static void Screamer_writeSoundControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value ) { //DEBUG_IOLOG( "PPCSound(awacs): SoundControlReg = %08x\n", value); OSWriteLittleInt32( &ioBaseAwacs->SoundControlRegister, 0, value ); eieio(); } static UInt32 Screamer_ReadStatusRegisters( volatile awacs_regmap_t *ioBaseAwacs ) { //we need to have something that check if the Screamer is busy or in readback mode return OSReadLittleInt32( &ioBaseAwacs->CodecStatusRegister, 0 ); } #define super AppleOnboardAudio OSDefineMetaClassAndStructors(AppleScreamerAudio, AppleOnboardAudio) //Unix like prototypes bool AppleScreamerAudio::init(OSDictionary *properties) { DEBUG_IOLOG("+ AppleScreamerAudio::init\n"); if (!super::init(properties)) return false; chipInformation.awacsVersion = kAWACsAwacsRevision; mVolLeft = 0; mVolRight = 0; mIsMute = false; mVolMuteActive = false; DEBUG_IOLOG("- AppleScreamerAudio::init\n"); return true; } void AppleScreamerAudio::free() { DEBUG_IOLOG("+ AppleScreamerAudio::free\n"); super::free(); DEBUG_IOLOG("- AppleScreamerAudio::free\n"); } IOService* AppleScreamerAudio::probe(IOService* provider, SInt32* score) { // Finds the possible candidate for sound, to be used in // reading the caracteristics of this hardware: IORegistryEntry *sound = 0; DEBUG_IOLOG("+ AppleScreamerAudio::probe\n"); super::probe(provider, score); *score = kIODefaultProbeScore; sound = provider->childFromPath("sound", gIODTPlane); //we are on a new world : the registry is assumed to be fixed if(sound) { OSData *tmpData; tmpData = OSDynamicCast(OSData, sound->getProperty(kModelPropName)); if(tmpData) { if(tmpData->isEqualTo(kAWACsModelName, sizeof(kAWACsModelName) -1) || tmpData->isEqualTo(kScreamerModelName, sizeof(kScreamerModelName) -1) ) { *score = *score+1; DEBUG_IOLOG("- AppleScreamerAudio::probe\n"); return(this); } } } DEBUG_IOLOG("- AppleScreamerAudio::probe\n"); return (0); } bool AppleScreamerAudio::initHardware(IOService *provider) { AbsoluteTime timerInterval; bool myreturn = true; DEBUG_IOLOG("+ AppleScreamerAudio::initHardware\n"); super::initHardware(provider); //Common information codecStatus &= ~kAllSense; gCanPollSatus = true; checkStatus(true); //create and flush ports, controls // Use the current hardware settings as our defaults /* if (chipInformation.outputAActive) { int regValue; regValue = Screamer_readCodecControlReg(ioBase, kAWACsOutputAAttenReg); mVolLeft = (15 - ((regValue & kAWACsOutputLeftAtten) << kAWACsOutputLeftShift)) * 4096; mVolRight = (15 - (regValue & kAWACsOutputRightAtten)) * 4096; regValue = Screamer_readCodecControlReg(ioBase, kAWACsMuteReg); deviceMuted = (regValue & kAWACsMuteOutputA) == kAWACsMuteOutputA; } else if (chipInformation.outputCActive) { int regValue; regValue = Screamer_readCodecControlReg(ioBase, kAWACsOutputCAttenReg); mVolLeft = (15 - ((regValue & kAWACsOutputLeftAtten) << kAWACsOutputLeftShift)) * 4096; mVolRight = (15 - (regValue & kAWACsOutputRightAtten)) * 4096; regValue = Screamer_readCodecControlReg(ioBase, kAWACsMuteReg); deviceMuted = (regValue & kAWACsMuteOutputC) == kAWACsMuteOutputC; } else { deviceMuted = true; } if (outVolLeft) { outVolLeft->setValue(mVolLeft); } if (outVolRight) { outVolRight->setValue(mVolRight); } if (outMute) { outMute->setValue(deviceMuted ? 1 : 0); } */ // flushAudioControls(); //Prepare the timer loop --> should go on the workloop nanoseconds_to_absolutetime(NSEC_PER_SEC, &timerInterval); addTimerEvent(this, &AppleScreamerAudio::timerCallback, timerInterval); duringInitialization = false; DEBUG_IOLOG("- AppleScreamerAudio::initHardware\n"); return myreturn; } void AppleScreamerAudio::setDeviceDetectionActive(){ gCanPollSatus = true; } void AppleScreamerAudio::setDeviceDetectionInActive(){ gCanPollSatus = false; } //IOAudio subclasses void AppleScreamerAudio::sndHWInitialize(IOService *provider) { IOMemoryMap *map; DEBUG_IOLOG("+ AppleScreamerAudio::sndHWInitialize\n"); map = provider->mapDeviceMemoryWithIndex(AppleDBDMAAudioDMAEngine::kDBDMADeviceIndex); ioBase = (awacs_regmap_t *)map->getVirtualAddress(); codecStatus = Screamer_ReadStatusRegisters( ioBase ); //fill the chip info chipInformation.partType = sndHWGetType(); chipInformation.awacsVersion = (codecStatus & kAWACsRevisionNumberMask) >> kAWACsRevisionShift; chipInformation.preRecalDelay = kPreRecalDelayCrystal; // assume Crystal for recalibrate (safest) chipInformation.rampDelay = kRampDelayNational; // assume National for ramping (safest) soundControlRegister = ( kInSubFrame0 |kOutSubFrame0 | kHWRate44100); Screamer_writeSoundControlReg( ioBase, soundControlRegister); codecControlRegister[0] = kCodecCtlAddress0 | kCodecCtlEMSelect0; codecControlRegister[1] = kCodecCtlAddress1 | kCodecCtlEMSelect0; codecControlRegister[2] = kCodecCtlAddress2 | kCodecCtlEMSelect0; codecControlRegister[4] = kCodecCtlAddress4 | kCodecCtlEMSelect0; Screamer_writeCodecControlReg( ioBase, codecControlRegister[0] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[1] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[2] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[4] ); if ( chipInformation.awacsVersion > kAWACsAwacsRevision ) { codecControlRegister[5] = kCodecCtlAddress5 | kCodecCtlEMSelect0; Screamer_writeCodecControlReg( ioBase, codecControlRegister[5] ); codecControlRegister[6] = kCodecCtlAddress6 | kCodecCtlEMSelect0; Screamer_writeCodecControlReg( ioBase, codecControlRegister[6] ); } switch (sndHWGetManufacturer()){ case kSndHWManfCrystal : chipInformation.preRecalDelay = kPreRecalDelayCrystal; chipInformation.rampDelay = kRampDelayCrystal; break; case kSndHWManfNational : chipInformation.preRecalDelay = kPreRecalDelayNational; chipInformation.rampDelay = kRampDelayNational; break; default : break; } //do the IO init //These line should go into the IO part //this means we assume an mic input. We should assume through the //input objects codecControlRegister[0] |= (kUnusedInput | kDefaultMicGain); //we should add the Screamer info DEBUG_IOLOG("- AppleScreamerAudio::sndHWInitialize\n"); } /****************************** Workloop functions ***************************/ /* There is work to do there !!!! */ /* In fact we should put that on the work loop, and have a family method */ /* to add whatever we want on it (polling, interrupt based stuff...) */ /* There is also to improve into the communication with any input */ /* and output. Instead of calling the arrays, we should send notification */ /* trough the IOAudioJackControl inheritance of the AudioHardwareDetect, */ /* and have all ports, listen to these notification (maybe it would have */ /* easier in Objective-C... or the IOKit does it for us) */ /*****************************************************************************/ void AppleScreamerAudio::checkStatus(bool force) { UInt32 newCodecStatus, inSense, extdevices; AudioHardwareDetect *theDetect; OSArray *AudioDetects; // DEBUG_IOLOG("+ AppleScreamerAudio::checkStatus\n"); if(false == gCanPollSatus) return; newCodecStatus = Screamer_ReadStatusRegisters(ioBase); if (((codecStatus & kAWACsStatusInSenseMask) != (newCodecStatus &kAWACsStatusInSenseMask)) || force) { UInt32 i; inSense = 0; codecStatus = newCodecStatus; extdevices = 0; inSense = sndHWGetInSenseBits(); AudioDetects = super::getDetectArray(); if(AudioDetects) { for(i = 0; i < AudioDetects->getCount(); i++) { theDetect = OSDynamicCast(AudioHardwareDetect, AudioDetects->getObject(i)); if (theDetect) extdevices |= theDetect->refreshDevices(inSense); } super::setCurrentDevices(extdevices); } else { DEBUG_IOLOG("I didn;t get the array\n"); } } // DEBUG_IOLOG("- AppleScreamerAudio::checkStatus\n"); } void AppleScreamerAudio::timerCallback(OSObject *target, IOAudioDevice *device) { AppleScreamerAudio *screamer; // DEBUG_IOLOG("+ AppleScreamerAudio::timerCallback\n"); screamer = OSDynamicCast(AppleScreamerAudio, target); if (screamer) screamer->checkStatus(false); // DEBUG_IOLOG("- AppleScreamerAudio::timerCallback\n"); } /*************************** sndHWXXXX functions******************************/ /* These functions should be common to all Apple hardware drivers and be */ /* declared as virtual in the superclass. This is the only place where we */ /* should manipulate the hardware. Order is given by the UI policy system */ /* The set of function should be enought to implement the policy */ /*****************************************************************************/ /************************** Hardware Register Manipulation ********************/ UInt32 AppleScreamerAudio::sndHWGetInSenseBits(){ UInt32 newCodecStatus, status, inSense; inSense = 0; newCodecStatus = Screamer_ReadStatusRegisters(ioBase); newCodecStatus &= kAWACsStatusMask; status = newCodecStatus & kAWACsInSenseMask; //something is screwed up in the order of bytes if(status & kAWACsInSense0) inSense |= kAWACsInSense3; if(status & kAWACsInSense1) inSense |= kAWACsInSense2; if(status & kAWACsInSense2) inSense |= kAWACsInSense1; if(status & kAWACsInSense3) inSense |= kAWACsInSense0; return(inSense); } UInt32 AppleScreamerAudio::sndHWGetRegister(UInt32 regNum){ return(codecControlRegister[regNum]); } IOReturn AppleScreamerAudio::sndHWSetRegister(UInt32 regNum, UInt32 value){ IOReturn myReturn = kIOReturnSuccess; codecControlRegister[regNum] = value; Screamer_writeCodecControlReg(ioBase, codecControlRegister[regNum]); return(myReturn); } UInt32 AppleScreamerAudio::sndHWGetConnectedDevices(void) { return(currentDevices); } /************************** Manipulation of input and outputs ***********************/ /********(These functions are enough to implement the simple UI policy)**************/ UInt32 AppleScreamerAudio::sndHWGetActiveOutputExclusive(void){ UInt32 result; if(!(chipInformation.outputAActive) && !(chipInformation.outputCActive)) result = kSndHWOutputNone; else if(chipInformation.outputAActive) result = kSndHWOutput1; else result = kSndHWOutput2; return(result); } IOReturn AppleScreamerAudio::sndHWSetActiveOutputExclusive(UInt32 outputPort ){ IOReturn myReturn = kIOReturnSuccess; switch (outputPort){ case kSndHWOutputNone: chipInformation.outputAActive = false; chipInformation.outputCActive = false; break; case kSndHWOutput1: DEBUG_IOLOG("+ output A is active \n"); chipInformation.outputAActive = true; chipInformation.outputCActive = false; break; case kSndHWOutput2: DEBUG_IOLOG("+ output C is active \n"); chipInformation.outputAActive = false; chipInformation.outputCActive = true; break; default: myReturn = false; break; } sndHWSetSystemMute(mIsMute); return (myReturn); } UInt32 AppleScreamerAudio::sndHWGetActiveInputExclusive(void){ UInt32 input; UInt32 inputReg; UInt32 pcmciaReg; input = kSndHWInputNone; inputReg = sndHWGetRegister(kAWACsInputReg) & kAWACsInputField; pcmciaReg = sndHWGetRegister(kAWACsPCMCIAAttenReg) & kAWACsPCMCIAAttenField; switch (inputReg){ case kAWACsInputA: input = kSndHWInput1; break; case kAWACsInputB: input = kSndHWInput2; break; case kAWACsInputC: input = kSndHWInput3; break; default: if (pcmciaReg == kAWACsPCMCIAOn) input = kSndHWInput4; else if (inputReg != 0) DEBUG_IOLOG("Invalid input setting\n"); break; } return (input); } IOReturn AppleScreamerAudio::sndHWSetActiveInputExclusive(UInt32 input ){ IOReturn result = kIOReturnSuccess; UInt32 inputReg; UInt32 pcmciaReg; Boolean needsRecalibrate; needsRecalibrate = (input != sndHWGetActiveInputExclusive()); // start with all inputs off inputReg = sndHWGetRegister(kAWACsInputReg) & ~kAWACsInputField; pcmciaReg = sndHWGetRegister(kAWACsPCMCIAAttenReg) & ~kAWACsPCMCIAAttenField; switch (input){ case kSndHWInputNone: break; case kSndHWInput1: inputReg |= kAWACsInputA; break; case kSndHWInput2: inputReg |= kAWACsInputB; break; case kSndHWInput3: inputReg |= kAWACsInputC; break; case kSndHWInput4: pcmciaReg |= kAWACsPCMCIAOn; needsRecalibrate = false; break; default: result = kIOReturnError; goto EXIT; break; } //this should disappear. We put the gain input to the max value // gainReg = sndHWGetRegister(kAWACsGainReg) & ~kAWACsGainField; // get and clear current gain setting // gainReg |= ((kAWACsMaxHardwareGain << kAWACsGainLeftShift) & kAWACsGainLeft); // gainReg |= (kAWACsMaxHardwareGain & kAWACsGainRight); // sndHWSetRegister(kAWACsGainReg, gainReg); sndHWSetRegister(kAWACsInputReg, inputReg); if (needsRecalibrate) GC_Recalibrate(); EXIT: return(result); } UInt32 AppleScreamerAudio::sndHWGetProgOutput(void ){ return (sndHWGetRegister(kAWACsProgOutputReg) & kAWACsProgOutputField) >> kAWACsProgOutputShift; } IOReturn AppleScreamerAudio::sndHWSetProgOutput(UInt32 outputBits){ UInt32 progOutputReg; IOReturn result; result = kIOReturnError; FAIL_IF((outputBits & (kSndHWProgOutput0 | kSndHWProgOutput1)) != outputBits, EXIT); result = kIOReturnSuccess; progOutputReg = sndHWGetRegister(kAWACsProgOutputReg) & ~kAWACsProgOutputField; progOutputReg |= ((outputBits << kAWACsProgOutputShift) & kAWACsProgOutputField); sndHWSetRegister(kAWACsProgOutputReg, progOutputReg); EXIT: return result; } /************************** Global (i.e all outputs) manipulation of mute and volume ***************/ bool AppleScreamerAudio::sndHWGetSystemMute(void){ return (mIsMute); } IOReturn AppleScreamerAudio::sndHWSetSystemMute(bool mutestate){ UInt32 muteReg; muteReg = sndHWGetRegister(kAWACsMuteReg) & ~kAWACsMuteField; if (mutestate || ((mVolRight == mVolLeft) && (0 == mVolRight))) { muteReg |= (kAWACsMuteOutputA | kAWACsMuteOutputC); mIsMute = true; } else { if (chipInformation.outputAActive) { muteReg &= ~kAWACsMuteOutputA; } else { muteReg |= kAWACsMuteOutputA; } if (chipInformation.outputCActive) { muteReg &= ~kAWACsMuteOutputC; } else { muteReg |= kAWACsMuteOutputC; } mIsMute = false; } sndHWSetRegister(kAWACsMuteReg, muteReg); return(kIOReturnSuccess); } IOReturn AppleScreamerAudio::sndHWSetSystemVolume(UInt32 value){ sndHWSetSystemVolume( value, value); return kIOReturnSuccess; } bool AppleScreamerAudio::sndHWSetSystemVolume(UInt32 leftvalue, UInt32 rightvalue) { //This function is not very flexible. It sets the volume for //each output port to the same level. This is obvioulsy not //very flexible, but we keep that for the UI Policy implementation bool hasChanged = false; UInt32 leftAttn, rightAttn; if((leftvalue != mVolLeft) || duringInitialization) { mVolLeft = leftvalue; if(0 == leftvalue) leftvalue = 1; leftvalue -=1; leftAttn = 15-leftvalue; //we change the left value for each register codecControlRegister[kAWACsOutputAAttenReg] = (codecControlRegister[kAWACsOutputAAttenReg] & ~kAWACsOutputLeftAtten) | (leftAttn << kAWACsOutputLeftShift); codecControlRegister[kAWACsOutputCAttenReg] = (codecControlRegister[kAWACsOutputCAttenReg] & ~kAWACsOutputLeftAtten) | (leftAttn << kAWACsOutputLeftShift); hasChanged = true; } if((rightvalue != mVolRight) || duringInitialization){ mVolRight = rightvalue; if(0 == rightvalue) rightvalue = 1; rightvalue -=1; rightAttn = 15-rightvalue; //we change the right value for each register codecControlRegister[kAWACsOutputAAttenReg] = (codecControlRegister[kAWACsOutputAAttenReg] & ~kAWACsOutputRightAtten) | (rightAttn); codecControlRegister[kAWACsOutputCAttenReg] = (codecControlRegister[kAWACsOutputCAttenReg] & ~kAWACsOutputRightAtten) | (rightAttn); hasChanged = true; } if(hasChanged) { Screamer_writeCodecControlReg( ioBase, codecControlRegister[kAWACsOutputAAttenReg] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[kAWACsOutputCAttenReg] ); } if((rightvalue == leftvalue) && (0 == rightvalue)) { mVolMuteActive = true; sndHWSetSystemMute(true); //We set the mute volume } else { if(mVolMuteActive) { mVolMuteActive = false; sndHWSetSystemMute(false); } } return(true); } IOReturn AppleScreamerAudio::sndHWSetPlayThrough( bool playthroughState ) { UInt32 playthruReg; IOReturn result = kIOReturnSuccess; playthruReg = sndHWGetRegister(kAWACsLoopThruReg) & ~kAWACsLoopThruEnable; if (playthroughState) { playthruReg |= kAWACsLoopThruEnable; } sndHWSetRegister(kAWACsLoopThruReg, playthruReg); return result; } /************************** Identification of the codec ************************/ UInt32 AppleScreamerAudio::sndHWGetType( void ) { UInt32 revision, info; UInt32 codecStatus; codecStatus = Screamer_ReadStatusRegisters( ioBase ); revision = (codecStatus & kAWACsRevisionNumberMask) >> kAWACsRevisionShift; switch (revision) { case kAWACsAwacsRevision : info = kSndHWTypeAWACs; break; case kAWACsScreamerRevision : info = kSndHWTypeScreamer; break; default : info = kSndHWTypeUnknown; break; } return info; } IOReturn AppleScreamerAudio::sndHWSetPowerState(IOAudioDevicePowerState theState){ if (chipInformation.partType == kSndHWTypeAWACs) setAWACsPowerState(theState); else setScreamerPowerState(theState); return(kIOReturnSuccess); } UInt32 AppleScreamerAudio::sndHWGetManufacturer(void) { UInt32 codecStatus, info = 0; codecStatus = Screamer_ReadStatusRegisters( ioBase ); switch (codecStatus & kAWACsManufacturerIDMask){ case kAWACsManfCrystal: DEBUG_IOLOG("Crystal Manufacturer\n"); info = kSndHWManfCrystal; break; case kAWACsManfNational: DEBUG_IOLOG("National Manufacturer\n"); info = kSndHWManfNational; break; case kAWACsManfTI: DEBUG_IOLOG("TI Manufacturer\n"); info = kSndHWManfTI; break; default: DEBUG_IOLOG("Unknown Manufacturer\n"); info = kSndHWManfUnknown; break; } return info; } IOReturn AppleScreamerAudio::sndHWSetSystemInputGain(UInt32 leftGain, UInt32 rightGain){ IOReturn myReturn = kIOReturnSuccess; UInt32 gainReg; UInt8 galeft, garight; DEBUG3_IOLOG("+ AppleScreamerAudio::sndHWSetSystemInputGain (%ld, %ld)\n", leftGain, rightGain); galeft = (UInt8) leftGain; garight = (UInt8) rightGain; gainReg = sndHWGetRegister(kAWACsGainReg) & ~kAWACsGainField; // get and clear current gain setting gainReg |= ((galeft << kAWACsGainLeftShift) & kAWACsGainLeft); gainReg |= (garight & kAWACsGainRight); sndHWSetRegister(kAWACsGainReg, gainReg); DEBUG_IOLOG("- AppleScreamerAudio::sndHWSetSystemInputGain\n"); return(myReturn); } #pragma mark ++++++++ UTILITIES /************************** Utilities for AWACS/Screamer only ************************/ void AppleScreamerAudio::GC_Recalibrate() { UInt32 awacsReg, saveReg; DEBUG_IOLOG("+ AppleScreamerAudio::GC_Recalibrate\n"); IOSleep( kPreRecalDelayCrystal); //This recalibrate delay is a hack for some //broken Crystal parts awacsReg = sndHWGetRegister(kAWACsRecalibrateReg); saveReg = awacsReg; awacsReg |= (kMuteInternalSpeaker | kMuteHeadphone); //mute the outputs awacsReg |= kAWACsRecalibrate; //set the recalibrate bits sndHWSetRegister(kAWACsRecalibrateReg, awacsReg); IOSleep(1000);//kRecalibrateDelay*2);//There seems to be some confusion on the time we have to wait //No doc indicates it clearly. This value was indicated in //the OS 9 code sndHWSetRegister(kAWACsRecalibrateReg, saveReg); DEBUG_IOLOG("- AppleScreamerAudio::GC_Recalibrate\n"); } void AppleScreamerAudio::restoreSndHWRegisters( void ) { Screamer_writeCodecControlReg( ioBase, codecControlRegister[0] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[1] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[2] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[4] ); if ( chipInformation.awacsVersion > kAWACsAwacsRevision ) { Screamer_writeCodecControlReg( ioBase, codecControlRegister[5] ); Screamer_writeCodecControlReg( ioBase, codecControlRegister[6] ); } } void AppleScreamerAudio::setAWACsPowerState( IOAudioDevicePowerState state ) { switch (state){ case kIOAudioDeviceActive : restoreSndHWRegisters(); GC_Recalibrate(); break; case kIOAudioDeviceSleep : break; default: break; } } void AppleScreamerAudio::setScreamerPowerState(IOAudioDevicePowerState state) { setAWACsPowerState(state); //we should do better !!! } void AppleScreamerAudio::InitializeShadowRegisters(void){ UInt32 regNumber; switch(chipInformation.partType) { case kSndHWTypeScreamer: codecControlRegister[kMaxSndHWRegisters] = 0; for (regNumber = 0; regNumber < kMaxSndHWRegisters-1; regNumber++) codecControlRegister[regNumber] = Screamer_readCodecControlReg(ioBase,regNumber);; break; case kSndHWTypeAWACs: for (regNumber = 0; regNumber < kMaxSndHWRegisters; regNumber++) codecControlRegister[regNumber] = 0; break; } }