Annotation of XNU/iokit/Drivers/audio/drvPPCDACA/PPCDACA.cpp, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved. 
        !            24:  *
        !            25:  * Interface implementation for the DAC 3550A audio Controller
        !            26:  *
        !            27:  * HISTORY
        !            28:  *
        !            29:  *
        !            30:  */
        !            31: 
        !            32: #include <IOKit/assert.h>
        !            33: #include <IOKit/system.h>
        !            34: 
        !            35: #include <IOKit/IOLib.h>
        !            36: #include <IOKit/IODeviceTreeSupport.h>
        !            37: #include <IOKit/IOPlatformExpert.h>
        !            38: #include <IOKit/ppc/IODBDMA.h>
        !            39: 
        !            40: // Driver headers
        !            41: #include "daca_hw.h"
        !            42: #include "PPCDACA_inlined.h"
        !            43: #include "PPCDACA.h"
        !            44: 
        !            45: #define super IOAudioBus
        !            46: OSDefineMetaClassAndStructors( PPCDACA, IOAudioBus )
        !            47: 
        !            48: /* ==============
        !            49:  * Public Methods
        !            50:  * ============== */
        !            51: bool
        !            52: PPCDACA::init(OSDictionary * properties)
        !            53: {
        !            54:     if (!super::init(properties))
        !            55:             return false;
        !            56:  
        !            57:     // Nulls the pointers for the arrays we allocate:
        !            58:     fOutputComponents = NULL;
        !            59:     numOutputComponents = NULL;
        !            60: 
        !            61:     // Initialize  the defualt registers to non zero values (so they will be revitten)
        !            62:     sampleRateReg = 0xFF;
        !            63:     analogVolumeReg = kPowerOnDefaultAVOL;
        !            64:     configurationReg = 0xFF;
        !            65: 
        !            66:     // Mirror the analogVolumeReg for the speaker and for the headphones.
        !            67:     internalSpeakerVolume = analogVolumeReg;
        !            68:     internalHeadphonesVolume = analogVolumeReg;
        !            69: 
        !            70:     // Last value of the status is 0
        !            71:     lastStatus = 0;
        !            72:  
        !            73:     // Clears the interface
        !            74:     interface = NULL;
        !            75:     
        !            76:     // Forget the provider:
        !            77:     sound = NULL;
        !            78: 
        !            79:     // Initialize the sound format:
        !            80:     dacaSerialFormat = kSndIOFormatUnknown;
        !            81: 
        !            82:     return true;
        !            83: }
        !            84: 
        !            85: void
        !            86: PPCDACA::free()
        !            87: {
        !            88:     // Releases the sound:
        !            89:     if(sound != NULL)
        !            90:         sound->release();
        !            91:     sound = NULL;
        !            92: 
        !            93:     super::free();
        !            94: }
        !            95: 
        !            96: IOService*
        !            97: PPCDACA::probe(IOService* provider, SInt32* score)
        !            98: {
        !            99:     // Finds the possible candidate for sound, to be used in
        !           100:     // reading the caracteristics of this hardware:
        !           101:     IORegistryEntry *soundCandidate = provider->childFromPath("sound", gIODTPlane);
        !           102: 
        !           103:     if (super::probe(provider, score) && implementsDACA(soundCandidate)) {
        !           104: #ifdef DEBUGMODE
        !           105:         IOLog("PPCDACA::probe we are on a PPCDACA device !!\n");
        !           106: #endif // DEBUGMODE
        !           107: 
        !           108:         // we did not fail:
        !           109:         *score = kIODefaultProbeScore;
        !           110:         sound = soundCandidate;
        !           111:         return this;
        !           112:     }
        !           113: 
        !           114:     return (NULL);
        !           115: }
        !           116: 
        !           117: #define kNumDMAStreams 1
        !           118: bool
        !           119: PPCDACA::start(IOService* provider)
        !           120: {
        !           121:     // Gets the base for the DAC-3550 registers:
        !           122:     IOMemoryMap *map;
        !           123:     int i;
        !           124: 
        !           125: #ifdef DEBUGMODE
        !           126:     // Delay for 30 seconds so we have the time to attach the debugger and look at
        !           127:     // what is going on here (only if DEBUGMODE of course).
        !           128:     IOLog("Starting DAC-3550 with provider %s ...", provider->getName());
        !           129:     IOSleep(30 * 1000);
        !           130:     IOLog("...\n");
        !           131: #endif // DEBUGMODE
        !           132: 
        !           133:     if(!super::start(provider)) {
        !           134: #ifdef DEBUGMODE
        !           135:         IOLog("PPCDACA::start if(!super::start(provider)) fails !!\n");
        !           136: #endif // DEBUGMODE
        !           137:         return (false);
        !           138:     }
        !           139: 
        !           140:     if (!findAndAttachI2C(provider))  {
        !           141: #ifdef DEBUGMODE
        !           142:         IOLog("PPCDACA::start if (!findAndAttachI2C(IOService *provider)) fails !!\n");
        !           143: #endif // DEBUGMODE
        !           144:         return (false);
        !           145:     }
        !           146: 
        !           147:     map = provider->mapDeviceMemoryWithIndex(kAudioDMAdeviceInt);
        !           148:     if(!map)  {
        !           149: #ifdef DEBUGMODE
        !           150:         IOLog("PPCDACA::start if(!map) %d fails !!\n",kAudioDMAdeviceInt);
        !           151: #endif // DEBUGMODE
        !           152:         return (false);
        !           153:     }
        !           154:     soundConfigSpace = (UInt8 *)map->getPhysicalAddress();
        !           155: 
        !           156:     if (!AllocateStreams(kNumDMAStreams)) {
        !           157: #ifdef DEBUGMODE
        !           158:         IOLog("PPCDACA::start if (!AllocateStreams(kNumDMAStreams)) fails !!\n");
        !           159: #endif // DEBUGMODE
        !           160:         return (false);
        !           161:     }
        !           162: 
        !           163:     map = provider->mapDeviceMemoryWithIndex(kAudioDMAtxInt);
        !           164:     if(!map)  {
        !           165: #ifdef DEBUGMODE
        !           166:         IOLog("PPCDACA::start if(!map) %d fails !!\n",kAudioDMAtxInt);
        !           167: #endif // DEBUGMODE
        !           168:         return (false);
        !           169:     }
        !           170:     DefineStream(kAudioDMAOutputStream, kOutput, frameRate(0), (IODBDMAChannelRegisters*)map->getVirtualAddress());
        !           171: 
        !           172:     // Creates the array of output components
        !           173:     numOutputComponents = numberOfInputComponents();
        !           174: 
        !           175:     fOutputComponents = (IOAudioComponentImplPtr*)IOMalloc(sizeof(IOAudioComponentImplPtr) * numOutputComponents);
        !           176:     if (fOutputComponents == NULL) {
        !           177: #ifdef DEBUGMODE
        !           178:         IOLog("PPCDACA::start if (fOutputComponents == NULL) fails !!\n");
        !           179: #endif // DEBUGMODE
        !           180: 
        !           181:         // Free the DMA and exit:
        !           182:         FreeStreams();
        !           183:         return false;
        !           184:     }
        !           185: 
        !           186:     // Initalizes all the components:
        !           187:     for (i = 0; i < numOutputComponents; i++)
        !           188:         fOutputComponents[i] = NULL;
        !           189: 
        !           190:     // sets the clock base address figuring out which I2S cell we're on
        !           191:     if ((((UInt32)soundConfigSpace ^ kI2S0BaseOffset) & 0x0001FFFF) == 0) {
        !           192:         ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S0BaseOffset);
        !           193:         i2SInterfaceNumber = 0;
        !           194:     }
        !           195:     else if ((((UInt32)soundConfigSpace ^ kI2S1BaseOffset) & 0x0001FFFF) == 0) {
        !           196:         ioBaseAddress = (void *)((UInt32)soundConfigSpace - kI2S1BaseOffset);
        !           197:         i2SInterfaceNumber = 1;
        !           198:     }
        !           199:     else {
        !           200:         IOLog("PPCDACA::start failed to setup ioBaseAddress and ioClockBaseAddress\n");
        !           201:     }
        !           202: 
        !           203:     // This is the keylargo FC1 (Feature configuration 1)
        !           204:     ioClockBaseAddress = (void *)((UInt32)ioBaseAddress + kI2SClockOffset);
        !           205: 
        !           206:     // Finds the position of the status register:
        !           207:     ioStatusRegister_GPIO12 = (void *)((UInt32)ioBaseAddress + kGPio12);
        !           208: 
        !           209:     // Enables the I2S Interface:
        !           210:     KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) | kI2S0InterfaceEnable);
        !           211:  
        !           212:     // Starts the workloop and exit since there is nothing we can be interested about anymore
        !           213:     startWorkLoop();
        !           214: 
        !           215:     return true;
        !           216: }
        !           217: 
        !           218: void
        !           219: PPCDACA::stop(IOService *provider)
        !           220: {
        !           221:     // Releases all DMA streams:
        !           222:     FreeStreams();
        !           223: 
        !           224:     // Releases the output components
        !           225:     if (fOutputComponents != NULL) {
        !           226:         IOFree(fOutputComponents, sizeof(IOAudioComponentImplPtr) * numOutputComponents);
        !           227:         fOutputComponents = NULL;
        !           228:         numOutputComponents = 0;
        !           229:     }
        !           230: 
        !           231:     // Call the parent stop:
        !           232:     super::stop(provider);
        !           233: }
        !           234: 
        !           235: void
        !           236: PPCDACA::CreateAudioTopology(IOCommandQueue *queue)
        !           237: {
        !           238:     IOAudioComponentImpl *mixerOut;
        !           239:     IOAudioComponentImpl *modem;
        !           240:     IOAudioComponentImpl *headphones;
        !           241:     IOAudioComponentImpl *cd;
        !           242:     IOAudioComponentImpl *speaker;
        !           243:     IOAudioComponentImpl *passthru;
        !           244: 
        !           245:     AudioStreamIndex outputStream;
        !           246:     
        !           247:     if (!fStreams)
        !           248:         return;
        !           249: 
        !           250:     outputStream = firstStreamAfter(kOutput, 0);
        !           251: 
        !           252:     if (outputStream == kInvalidStreamIndex) {
        !           253:         IOLog("PPCDACA::CreateAudioTopology called without available DMA streams\n");
        !           254:         return;
        !           255:     }
        !           256:     else
        !           257:         IOLog("PPCDACA::CreateAudioTopology output stream is %d\n", outputStream);
        !           258: 
        !           259:     mixerOut = buildComponentAndAttach(GetStream(outputStream), NULL, componentDictionaryMixerOut(), queue);
        !           260:     headphones = buildComponentAndAttach(mixerOut, NULL, componentDictionaryHeadphones(), queue);
        !           261:     speaker = buildComponentAndAttach(mixerOut, NULL, componentDictionarySpeaker(), queue);
        !           262: 
        !           263:     cd = buildComponentAndAttach(NULL, NULL,  componentDictionaryCD(), queue);
        !           264:     modem = buildComponentAndAttach(NULL, NULL, componentDictionaryModem(), queue);
        !           265: 
        !           266:     passthru = buildComponentAndAttach(NULL, mixerOut, componentDictionaryPassThru(), queue);
        !           267: 
        !           268:     // FIXME: the component connection could be done better than so
        !           269:     if (fOutputComponents != NULL) {
        !           270:         fOutputComponents[kSpeaker] = speaker;
        !           271: 
        !           272:         if (numOutputComponents > 1)
        !           273:             fOutputComponents[kHeadphones] = headphones;
        !           274:     }
        !           275: 
        !           276:     // Sets ups the DAC-3550 as required by this machine wiring
        !           277:     // configuration:
        !           278:     if (!dependentSetup())
        !           279:         IOLog("PPCDACA::CreateAudioTopology DAC-3550 setup failed\n");
        !           280: }
        !           281: 
        !           282: void
        !           283: PPCDACA::DoClockTick(IOTimerEventSource *t)
        !           284: {
        !           285:     checkStatusRegister();
        !           286:     super::DoClockTick(t);
        !           287: }
        !           288: 
        !           289: void
        !           290: PPCDACA::calculateTickInterval(AbsoluteTime *tickInterval)
        !           291: {
        !           292:     AbsoluteTime maxInterval;
        !           293: 
        !           294:     // We want to check the status at least one a second
        !           295:     nanoseconds_to_absolutetime(NSEC_PER_SEC, &maxInterval);
        !           296:     if(CMP_ABSOLUTETIME(&maxInterval, tickInterval) < 0) {
        !           297:         *tickInterval = maxInterval;
        !           298:     }
        !           299:     super::calculateTickInterval(tickInterval);
        !           300: }
        !           301: 
        !           302: IOReturn
        !           303: PPCDACA::SetControl(UInt16 id, int val)
        !           304: {
        !           305:     IOReturn res = kIOReturnSuccess;
        !           306:     
        !           307:     switch(id) {
        !           308:         case kSpeakerMute:
        !           309:             muteInternalSpeaker(val != 0);
        !           310:             muteHeadphones(val == 0);
        !           311:             break;
        !           312: 
        !           313:         case kHeadphonesMute:
        !           314:             muteHeadphones(val != 0);
        !           315:             muteInternalSpeaker(val == 0);
        !           316:             break;
        !           317: 
        !           318:         case kModemMute:
        !           319:             setModemInput(val == 0);
        !           320:             break;
        !           321: 
        !           322:         case kSpeakerVolLeft:
        !           323:             volumeInternalSpeakerLeft(val);
        !           324:             break;
        !           325: 
        !           326:         case kSpeakerVolRight:
        !           327:             volumeInternalSpeakerRight(val);
        !           328:             break;
        !           329: 
        !           330:         case kHeadphonesVolLeft:
        !           331:             volumeHeadphonesLeft(val);
        !           332:             break;
        !           333: 
        !           334:         case kHeadphonesVolRight:
        !           335:             volumeHeadphonesRight(val);
        !           336:             break;
        !           337: 
        !           338:         case kCDMute:
        !           339:             muteCDLine(val != 0);
        !           340:             break;
        !           341: 
        !           342:         case kPassThruVolLeft:
        !           343:             break;
        !           344: 
        !           345:         case kPassThruVolRight:
        !           346:             break;
        !           347: 
        !           348:         case kPassThruMute:
        !           349:             break;
        !           350: 
        !           351:         default:
        !           352:             res = kIOReturnUnsupported;
        !           353:     }
        !           354:     return res;
        !           355: }
        !           356: 
        !           357: /* ===============
        !           358:  * Private Methods
        !           359:  * =============== */
        !           360: 
        !           361: // --------------------------------------------------------------------------
        !           362: // Method: findAndAttachI2C
        !           363: //
        !           364: // Purpose:
        !           365: //   Attaches to the i2c interface:
        !           366: bool
        !           367: PPCDACA::findAndAttachI2C(IOService *provider)
        !           368: {
        !           369:     OSData *t;
        !           370:     UInt32 baseAddress;
        !           371:     UInt32 addressSteps;
        !           372:     UInt32 rate;
        !           373:     IORegistryEntry *i2cCandidate;
        !           374: 
        !           375:     // Searches the i2c:
        !           376:     for (i2cCandidate = NULL;
        !           377:          (provider != NULL) && (i2cCandidate == NULL);
        !           378:          provider = provider->getProvider()) {
        !           379:         i2cCandidate = provider->childFromPath("i2c", gIODTPlane);
        !           380: #ifdef DEBUGMODE
        !           381:         IOLog("Looking for i2c in %s -> 0x%08lx\n", provider->getName(), (UInt32)i2cCandidate);
        !           382: #endif // DEBUGMODE
        !           383:     }
        !           384: 
        !           385:     if (i2cCandidate == NULL) {
        !           386: #ifdef DEBUGMODE
        !           387:         IOLog("PPCDACA::findAndAttachI2C can't find the i2c in the registry\n");
        !           388: #endif // DEBUGMODE
        !           389:         return false;
        !           390:     }
        !           391: 
        !           392:     // creates the interface for real:
        !           393:     interface = new PPCI2CInterface;
        !           394:     if (interface == NULL) {
        !           395: #ifdef DEBUGMODE
        !           396:         IOLog("PPCDACA::findAndAttachI2C can't allocate memory for the PPCI2CInterface\n");
        !           397: #endif // DEBUGMODE
        !           398:         return false;
        !           399:     }
        !           400: 
        !           401:     // sets up the interface:
        !           402:     t = OSDynamicCast(OSData, i2cCandidate->getProperty("AAPL,address"));
        !           403:     if (t != NULL)
        !           404:         baseAddress = *((UInt32*)t->getBytesNoCopy());
        !           405:     else {
        !           406: #ifdef DEBUGMODE
        !           407:         IOLog( "PPCDACA::findAndAttachI2C missing property AAPL,address in i2c registry\n");
        !           408: #endif
        !           409:         return false;
        !           410:     }
        !           411: 
        !           412:     t = OSDynamicCast(OSData, i2cCandidate->getProperty("AAPL,address-step"));
        !           413:     if (t != NULL)
        !           414:         addressSteps = *((UInt32*)t->getBytesNoCopy());
        !           415:     else {
        !           416: #ifdef DEBUGMODE
        !           417:         IOLog( "PPCDACA::findAndAttachI2C missing property AAPL,address-step in i2c registry\n");
        !           418: #endif
        !           419:         return false;
        !           420:     }
        !           421: 
        !           422:     t = OSDynamicCast(OSData, i2cCandidate->getProperty("AAPL,i2c-rate"));
        !           423:     if (t != NULL)
        !           424:         rate = *((UInt32*)t->getBytesNoCopy());
        !           425:     else {
        !           426: #ifdef DEBUGMODE
        !           427:         IOLog( "PPCDACA::findAndAttachI2C missing property AAPL,i2c-rate in i2c registry\n");
        !           428: #endif
        !           429:         return false;
        !           430:     }
        !           431: 
        !           432:     if (!interface->initI2CBus((UInt8*)baseAddress, (UInt8)addressSteps))
        !           433:         return false;
        !           434: 
        !           435:     if (!interface->setKhzSpeed((UInt)rate))
        !           436:         return false;
        !           437: 
        !           438:     // Also sets the default mode
        !           439:     interface->setStandardSubMode();
        !           440:   
        !           441:     // Finds the port to use:
        !           442:     return(interface->openI2CBus(getI2CPort()));
        !           443: }
        !           444: 
        !           445: // --------------------------------------------------------------------------
        !           446: // Method: detachFromI2C
        !           447: //
        !           448: // Purpose:
        !           449: //   detaches from the I2C
        !           450: bool
        !           451: PPCDACA::detachFromI2C(IOService* /*provider*/)
        !           452: {
        !           453:     if (interface)
        !           454:         delete interface;
        !           455: 
        !           456:     return (true);
        !           457: }
        !           458: 
        !           459: // --------------------------------------------------------------------------
        !           460: // Method: implementsDACA
        !           461: //
        !           462: // Purpose:
        !           463: //   Attempts to discover if the device implements DAC-3550:
        !           464: bool
        !           465: PPCDACA::implementsDACA(IORegistryEntry *device)
        !           466: {
        !           467:     if (device != NULL) {
        !           468:         OSData *s = NULL;
        !           469: 
        !           470: #ifdef DEBUGMODE
        !           471:         IOLog("Matching DAC-3550 compatibility with %s\n", device->getName());
        !           472: #endif // DEBUGMODE
        !           473:         s = OSDynamicCast(OSData, device->getProperty("compatible"));
        !           474: 
        !           475:         if (s != NULL) {
        !           476:             if(s->isEqualTo("daca", sizeof("daca")-1)) {
        !           477:                 return true;
        !           478:             }
        !           479:             else {
        !           480: #ifdef DEBUGMODE
        !           481:                 IOLog("PPCDAC-3550::probe sound is compatible with %s.\n", (char*)s->getBytesNoCopy(0, sizeof("daca")-1));
        !           482: #endif // DEBUGMODE
        !           483:             }
        !           484:         }
        !           485:         else {
        !           486: #ifdef DEBUGMODE
        !           487:             IOLog("PPCDAC-3550::probe sound does not have a compatible property.\n");
        !           488: #endif // DEBUGMODE
        !           489:         }
        !           490:     }
        !           491:     else{
        !           492: #ifdef DEBUGMODE
        !           493:         IOLog("PPCDAC-3550::probe this hardware does not have a sound chip\n");
        !           494: #endif // DEBUGMODE
        !           495:     }
        !           496:     return false;
        !           497: }
        !           498: 
        !           499: // --------------------------------------------------------------------------
        !           500: // Method: numberOfInputComponents
        !           501: //
        !           502: // Purpose:
        !           503: //        returns the number of components for the input lines
        !           504: //        the name registry describes the CHIP (which has 3 inputs
        !           505: //       however, the iBook has no inputs, so I have to force 0
        !           506: //        as output).
        !           507: #define kCommonNumberOfInputComponents 0
        !           508: 
        !           509: int
        !           510: PPCDACA::numberOfInputComponents()
        !           511: {
        !           512:     return kCommonNumberOfInputComponents;
        !           513: }
        !           514: 
        !           515: // --------------------------------------------------------------------------
        !           516: // Method: numberOfOutputComponents
        !           517: //
        !           518: // Purpose:
        !           519: //        returns the number of components for the output lines
        !           520: //        usually are 2 one is the internal speacker and the other
        !           521: //        is the headphone line.
        !           522: #define kCommonNumberOfOutputComponents 2
        !           523: 
        !           524: int
        !           525: PPCDACA::numberOfOutputComponents()
        !           526: {
        !           527:     if(sound) {
        !           528:         OSData *t;
        !           529:         
        !           530:         t = OSDynamicCast(OSData, sound->getProperty("#-outputs"));
        !           531:         if (t != NULL) {
        !           532:             return *(UInt32*)(t->getBytesNoCopy());
        !           533:         }
        !           534:     }
        !           535:     return kCommonNumberOfOutputComponents;
        !           536: }
        !           537: 
        !           538: 
        !           539: // --------------------------------------------------------------------------
        !           540: // Method: frameRate
        !           541: //
        !           542: // Purpose:
        !           543: //        returns the frame rate as in the registry, if it is
        !           544: //        not found in the registry, it returns the default value.
        !           545: #define kCommonFrameRate 44100
        !           546: 
        !           547: UInt32
        !           548: PPCDACA::frameRate(UInt32 index)
        !           549: {
        !           550:     if(sound) {
        !           551:         OSData *t;
        !           552: 
        !           553:         t = OSDynamicCast(OSData, sound->getProperty("sample-rates"));
        !           554:         if (t != NULL) {
        !           555:             UInt32 *fArray = (UInt32*)(t->getBytesNoCopy());
        !           556: 
        !           557:             if ((fArray != NULL) && (index < fArray[0])){
        !           558:                 // I could do >> 16, but in this way the code is portable and
        !           559:                 // however any decent compiler will recognize this as a shift
        !           560:                 // and do the right thing.
        !           561:                 UInt32 fR = fArray[index + 1] / (UInt32)65536;
        !           562: 
        !           563: #ifdef DEBUGMODE
        !           564:                 IOLog( "PPCDACA::frameRate (%ld)\n",  fR);
        !           565: #endif
        !           566:                 return fR;
        !           567:             }
        !           568:         }
        !           569:     }
        !           570: 
        !           571:     return (UInt32)kCommonFrameRate;
        !           572: }
        !           573: 
        !           574: // --------------------------------------------------------------------------
        !           575: // Method: getI2CPort
        !           576: //
        !           577: // Purpose:
        !           578: //        returns the i2c port to use for the audio chip.
        !           579: UInt32
        !           580: PPCDACA::getI2CPort()
        !           581: {
        !           582:     if(sound) {
        !           583:         OSData *t;
        !           584: 
        !           585:         t = OSDynamicCast(OSData, sound->getProperty("AAPL,i2c-port-select"));
        !           586:         if (t != NULL) {
        !           587:             UInt32 myPort = *((UInt32*)t->getBytesNoCopy());
        !           588:             return myPort;
        !           589:         }
        !           590: #ifdef DEBUGMODE
        !           591:         else
        !           592:             IOLog( "PPCDACA::getI2CPort missing property port\n");
        !           593: #endif
        !           594:     }
        !           595:     
        !           596:     return 0;
        !           597: }
        !           598: 
        !           599: // --------------------------------------------------------------------------
        !           600: // Method(s): componentDictionaryXXXXXX
        !           601: //
        !           602: // Purpose:
        !           603: //        the next N methods return the strings for the component dictionaries
        !           604: //        for each kind of component. As stated in the AWACS driver, these should
        !           605: //        end in the driver resources.
        !           606: 
        !           607: // NOTE: (This is important !!!) the soundControls enum in the header file is
        !           608: //       bounded to the following stings in this way:
        !           609: //       for each component the control Id in the string must have the same value
        !           610: //       of the corrispondent soundControls enum item. For example the sound control
        !           611: //       enum item kHeadphonesVolLeft has value 4, so in sHeadphones the ID of the
        !           612: //       volume left control must be 4.
        !           613: 
        !           614: char*
        !           615: PPCDACA::componentDictionarySpeaker()
        !           616: {
        !           617:     static const char *sSpeaker =
        !           618:     "{
        !           619:     'Type' = 'Speaker';
        !           620:     'Channels' = 2:8;
        !           621:     'Master' = 1:8;
        !           622:     'Controls' = {
        !           623:         'MuteAll' = {
        !           624:             'Type' = 'Mute';
        !           625:             'Id' = 0:16;
        !           626:             'Val' = 0:8;
        !           627:             'Min' = 0:8;
        !           628:             'Max' = 1:8;
        !           629:             'Chan' = 0:8;
        !           630:         };
        !           631:         'VolumeLeft' = {
        !           632:             'Type' = 'Volume';
        !           633:             'Id' = 1:16;
        !           634:             'Val' = 65535:16;
        !           635:             'Min' = 0:16;
        !           636:             'Max' = 65535:16;
        !           637:             'Chan' = 1:8;
        !           638:         };
        !           639:         'VolumeRight' = {
        !           640:             'Type' = 'Volume';
        !           641:             'Id' = 2:16;
        !           642:             'Val' = 65535:16;
        !           643:             'Min' = 0:16;
        !           644:             'Max' = 65535:16;
        !           645:             'Chan' = 2:8;
        !           646:         };
        !           647:     };
        !           648:     }";
        !           649:     return (char*)sSpeaker;
        !           650: }
        !           651: 
        !           652: char*
        !           653: PPCDACA::componentDictionaryHeadphones()
        !           654: {
        !           655:     static const char *sHeadphones =
        !           656:     "{
        !           657:     'Type' = 'Headphones';
        !           658:     'Channels' = 2:8;
        !           659:     'Master' = 1:8;
        !           660:     'Controls' = {
        !           661:         'MuteAll' = {
        !           662:             'Type' = 'Mute';
        !           663:             'Id' = 3:16;
        !           664:             'Val' = 0:8;
        !           665:             'Min' = 0:8;
        !           666:             'Max' = 1:8;
        !           667:             'Chan' = 0:8;
        !           668:         };
        !           669:         'VolumeLeft' = {
        !           670:             'Type' = 'Volume';
        !           671:             'Id' = 4:16;
        !           672:             'Val' = 65535:16;
        !           673:             'Min' = 0:16;
        !           674:             'Max' = 65535:16;
        !           675:             'Chan' = 1:8;
        !           676:         };
        !           677:         'VolumeRight' = {
        !           678:             'Type' = 'Volume';
        !           679:             'Id' = 5:16;
        !           680:             'Val' = 65535:16;
        !           681:             'Min' = 0:16;
        !           682:             'Max' = 65535:16;
        !           683:             'Chan' = 2:8;
        !           684:         };
        !           685:     };
        !           686:     'Inputs' = {
        !           687:         'Jack' = {
        !           688:             'Val' = 0:8;
        !           689:             'Min' = 0:8;
        !           690:             'Max' = 1:8;
        !           691:         };
        !           692:     };
        !           693:     }";
        !           694:     return (char*)sHeadphones;
        !           695: }
        !           696: 
        !           697: char*
        !           698: PPCDACA::componentDictionaryModem()
        !           699: {
        !           700:     static const char *sModem =
        !           701:     "{
        !           702:     'Type' = 'Modem';
        !           703:     'Channels' = 2:8;
        !           704:     'Controls' = {
        !           705:         'MuteAll' = {
        !           706:             'Type' = 'Mute';
        !           707:             'Id' = 6:16;
        !           708:             'Val' = 0:8;
        !           709:             'Min' = 0:8;
        !           710:             'Max' = 1:8;
        !           711:             'Chan' = 0:8;
        !           712:         };
        !           713:     };
        !           714:     'Inputs' = {
        !           715:         'Jack' = {
        !           716:             'Val' = 0:8;
        !           717:             'Min' = 0:8;
        !           718:             'Max' = 1:8;
        !           719:         };
        !           720:     };
        !           721:     }";
        !           722:     return (char*)sModem;
        !           723: }
        !           724: 
        !           725: char*
        !           726: PPCDACA::componentDictionaryCD()
        !           727: {
        !           728:     static const char *sCD =
        !           729:     "{
        !           730:     'Type' = 'CD';
        !           731:     'Channels' = 2:8;
        !           732:     'Controls' = {
        !           733:         'MuteAll' = {
        !           734:             'Type' = 'Mute';
        !           735:             'Id' = 7:16;
        !           736:             'Val' = 0:8;
        !           737:             'Min' = 0:8;
        !           738:             'Max' = 1:8;
        !           739:             'Chan' = 0:8;
        !           740:         };
        !           741:     };
        !           742:     }";
        !           743:     return (char*)sCD;
        !           744: }
        !           745: 
        !           746: char*
        !           747: PPCDACA::componentDictionaryMixerOut()
        !           748: {
        !           749:     static const char *sMixerOut =
        !           750:     "{
        !           751:     'Type' = 'Mixer';
        !           752:     'Channels' = 2:8;
        !           753:     }";
        !           754:     return (char*)sMixerOut;
        !           755: }
        !           756: 
        !           757: char*
        !           758: PPCDACA::componentDictionaryPassThru()
        !           759: {
        !           760:     static const char *sPassThru =
        !           761:     "{
        !           762:     'Type' = 'Feature';
        !           763:     'Channels' = 2:8;
        !           764:     'Controls' = {
        !           765:         'MuteAll' = {
        !           766:             'Type' = 'Mute';
        !           767:             'Id' = 12:16;
        !           768:             'Val' = 1:8;
        !           769:             'Min' = 0:8;
        !           770:             'Max' = 1:8;
        !           771:             'Chan' = 0:8;
        !           772:         };
        !           773:         'VolumeLeft' = {
        !           774:             'Type' = 'Volume';
        !           775:             'Id' = 10:16;
        !           776:             'Val' = 65535:16;
        !           777:             'Min' = 0:16;
        !           778:             'Max' = 65535:16;
        !           779:             'Chan' = 1:8;
        !           780:         };
        !           781:         'VolumeRight' = {
        !           782:             'Type' = 'Volume';
        !           783:             'Id' = 11:16;
        !           784:             'Val' = 65535:16;
        !           785:             'Min' = 0:16;
        !           786:             'Max' = 65535:16;
        !           787:             'Chan' = 2:8;
        !           788:         };
        !           789:     };
        !           790:     }";
        !           791:     return (char*)sPassThru;
        !           792: }
        !           793: 
        !           794: // --------------------------------------------------------------------------
        !           795: // Method: dependentSetup
        !           796: //
        !           797: // Purpose:
        !           798: //        this handles the setup of the DAC-3550 chip for each kind of
        !           799: //        hosting hardware.
        !           800: bool
        !           801: PPCDACA::dependentSetup()
        !           802: {
        !           803:     // Sets the frame rate:
        !           804:     UInt32 myFrameRate = frameRate(0);
        !           805: 
        !           806:     dacaSerialFormat = kSndIOFormatI2SSony;                    // start out in Sony format
        !           807: 
        !           808:     // Reads the initial status of the DAC3550A registers:
        !           809:     // The following functions return "false" on the first generation of iBooks. However I wish to
        !           810:     // keep them, since:
        !           811:     // 1] it is bad to make assumptions on what the hardware can do and can not do here (eventually these
        !           812:     //    assumptions should be made in the i2c driver).
        !           813:     // 2] the next generation of iBook may supprot reading the DACA registers, and we will have more precise
        !           814:     //    values in the "mirror" registers.
        !           815:     if (interface != NULL) {
        !           816:         interface->readI2CBus((UInt8)i2cBusAddrDAC3550A, i2cBusSubAddrSR_REG, & sampleRateReg, sizeof(sampleRateReg));
        !           817:         interface->readI2CBus((UInt8)i2cBusAddrDAC3550A, i2cBusSubAddrAVOL, (UInt8*)& analogVolumeReg, sizeof(analogVolumeReg));
        !           818:         interface->readI2CBus((UInt8)i2cBusAddrDAC3550A, i2cBusSubaddrGCFG, & configurationReg, sizeof(configurationReg));
        !           819:     }
        !           820: 
        !           821:     // If nobody set a format before choose one:
        !           822:     if (dacaSerialFormat ==  kSndIOFormatUnknown)
        !           823:         dacaSerialFormat = kSndIOFormatI2SSony;
        !           824: 
        !           825:     // This call will set the next of the drame parametes
        !           826:     // (dacaClockSource, dacaMclkDivisor,  dacaSclkDivisor)
        !           827:     if (!setSampleParameters(myFrameRate, 0)) {
        !           828:         IOLog("PPCDACA::dependentSetup can not set i2s sample rate\n");
        !           829:         return false;
        !           830:     }
        !           831:     else if (!setDACASampleRate(myFrameRate)) {
        !           832:         IOLog("PPCDACA::dependentSetup can not set DACA sample rate\n");
        !           833:         return false;
        !           834:     }
        !           835:     else 
        !           836:         setSerialFormatRegister(dacaClockSource, dacaMclkDivisor, dacaSclkDivisor, dacaSerialFormat);
        !           837: 
        !           838:     // Sets the molumes to max as in the audio registry:
        !           839:     volumeInternalSpeakerLeft(65535);
        !           840:     volumeInternalSpeakerRight(65535);
        !           841:     volumeHeadphonesLeft(65535);
        !           842:     volumeHeadphonesRight(65535);
        !           843:     volumeCDLineLeft(65535);
        !           844:     volumeCDLineRight(65535);
        !           845: 
        !           846:     return true;
        !           847: }
        !           848: 
        !           849: // --------------------------------------------------------------------------
        !           850: // Method: checkStatusRegister
        !           851: //
        !           852: // Purpose:
        !           853: //        if the argument is true mutes the internal speaker, otherwise
        !           854: //        it "unmutes" it.
        !           855: void
        !           856: PPCDACA::checkStatusRegister()
        !           857: {
        !           858:     if (statusChanged())  {
        !           859:         int i;
        !           860: 
        !           861:         OSNumber * num = OSNumber::withNumber(lastStatus, 8);
        !           862:         setProperty("Status", num);
        !           863:         num->release();
        !           864: 
        !           865: #ifdef DEBUGMODE
        !           866:         IOLog("New Status = 0x%02x\n", lastStatus);
        !           867: #endif
        !           868: 
        !           869:         for (i = 0; i < numOutputComponents; i++)
        !           870:             if (fOutputComponents[i] != NULL)
        !           871:                 fOutputComponents[i]->Set(gInputsSym, gJackSym, outputComponentStatus(i));
        !           872:     }
        !           873: }
        !           874: 
        !           875: // --------------------------------------------------------------------------
        !           876: // Method: outputComponentStatus
        !           877: //
        !           878: // Purpose:
        !           879: //        checks the status of the jack line of the ith output component:
        !           880: bool
        !           881: PPCDACA::outputComponentStatus(int index)
        !           882: {
        !           883:     switch(index)
        !           884:     {
        !           885:         case kSpeaker:
        !           886:             return false;      // the internal speaker does not have a jack
        !           887: 
        !           888:         case kHeadphones:      // check the headphones:
        !           889:             return headphonesInserted();
        !           890:     }
        !           891: 
        !           892:     return false;      // by deafult there is no jack
        !           893: }
        !           894: 
        !           895: // --------------------------------------------------------------------------
        !           896: // Method: muteInternalSpeaker
        !           897: //
        !           898: // Purpose:
        !           899: //        if the argument is true mutes the internal speaker, otherwise
        !           900: //        it "unmutes" it.
        !           901: void
        !           902: PPCDACA::muteInternalSpeaker(bool mute)
        !           903: {
        !           904:     if (mute){
        !           905:         if (!headphonesInserted())
        !           906:             writeRegisterBits(i2cBusSubAddrAVOL, 0, kRightAVOLMask | kLeftAVOLMask);
        !           907:         internalSpeakerMuted = mute;
        !           908:     }
        !           909:     else {
        !           910:         internalSpeakerMuted = mute;
        !           911: 
        !           912:         if (!headphonesInserted())
        !           913:             writeRegisterBits(i2cBusSubAddrAVOL, internalSpeakerVolume, kRightAVOLMask | kLeftAVOLMask);
        !           914:     }
        !           915: }
        !           916: 
        !           917: // --------------------------------------------------------------------------
        !           918: // Method: muteHeadphones
        !           919: //
        !           920: // Purpose:
        !           921: //        if the argument is true mutes the rear panel mini jack, otherwise
        !           922: //        it "unmutes" it.
        !           923: void
        !           924: PPCDACA::muteHeadphones(bool mute)
        !           925: {
        !           926:     if (mute){
        !           927:         if (headphonesInserted())
        !           928:             writeRegisterBits(i2cBusSubAddrAVOL, 0, kRightAVOLMask | kLeftAVOLMask);
        !           929:         internalHeadphonesMuted = mute;       
        !           930:     }
        !           931:     else {
        !           932:         internalHeadphonesMuted = mute;        
        !           933: 
        !           934:         if (headphonesInserted())
        !           935:             writeRegisterBits(i2cBusSubAddrAVOL, internalHeadphonesVolume, kRightAVOLMask | kLeftAVOLMask);
        !           936:     }
        !           937: }
        !           938: 
        !           939: // --------------------------------------------------------------------------
        !           940: // Method: muteCDLine
        !           941: //
        !           942: // Purpose:
        !           943: //        if the argument is true mutes the line of the cd player
        !           944: void
        !           945: PPCDACA::muteCDLine(bool mute)
        !           946: {
        !           947:     // FIXME: Figure out how this is wired up:
        !           948: }
        !           949: 
        !           950: // --------------------------------------------------------------------------
        !           951: // Method: setModemInput
        !           952: //
        !           953: // Purpose:
        !           954: //        selects the modem as input source (if bool = true)
        !           955: void
        !           956: PPCDACA::setModemInput(bool mod)
        !           957: {
        !           958: #ifdef DEBUGMODE
        !           959:     IOLog( "PPCDACA::setModemInput: %s\n", (mod ? "True" : "False"));
        !           960: #endif
        !           961: }
        !           962: 
        !           963: 
        !           964: // --------------------------------------------------------------------------
        !           965: // Method: statusChanged()
        !           966: //
        !           967: // Purpose:
        !           968: //        returns true if something changed in the status register:.
        !           969: bool
        !           970: PPCDACA::statusChanged()
        !           971: {
        !           972:     UInt8 currentStatusRegister = *(UInt8*)ioStatusRegister_GPIO12;
        !           973: 
        !           974:     if (lastStatus == currentStatusRegister)
        !           975:         return (false);
        !           976: 
        !           977:     // Otherwise refresh the value of the last status register read and
        !           978:     // returns that the value changed:
        !           979:     lastStatus = currentStatusRegister;
        !           980:     return (true);
        !           981: }
        !           982: 
        !           983: // --------------------------------------------------------------------------
        !           984: // Method: headphonesInserted
        !           985: //
        !           986: // Purpose:
        !           987: //        returns true if the headphones are inserted.
        !           988: bool
        !           989: PPCDACA::headphonesInserted()
        !           990: {
        !           991:     return((lastStatus & kHeadphoneBit) == 0);
        !           992: }
        !           993: 
        !           994: // --------------------------------------------------------------------------
        !           995: // Method: volumeHeadphonesLeft & volumeHeadphonesRight
        !           996: //
        !           997: // Purpose:
        !           998: //        sets the volume for the left and right channel of the internal
        !           999: //        headphones.
        !          1000: void
        !          1001: PPCDACA::volumeHeadphonesLeft(int vol)
        !          1002: {
        !          1003:     analogVolumeReg = internalHeadphonesVolume;
        !          1004:     setDACAVolume(vol, true);
        !          1005:     internalHeadphonesVolume = analogVolumeReg;
        !          1006: }
        !          1007: 
        !          1008: void
        !          1009: PPCDACA::volumeHeadphonesRight(int vol)
        !          1010: {
        !          1011:     analogVolumeReg = internalHeadphonesVolume;
        !          1012:     setDACAVolume(vol, false);
        !          1013:     internalHeadphonesVolume = analogVolumeReg;
        !          1014: }
        !          1015: 
        !          1016: // --------------------------------------------------------------------------
        !          1017: // Method: volumeInternalSpeakerLeft & volumeInternalSpeakerRight
        !          1018: //
        !          1019: // Purpose:
        !          1020: //        sets the volume for the left and right channel of the internal
        !          1021: //        speaker.
        !          1022: void
        !          1023: PPCDACA::volumeInternalSpeakerLeft(int vol)
        !          1024: {
        !          1025:     analogVolumeReg = internalSpeakerVolume;
        !          1026:     setDACAVolume(vol, true);
        !          1027:     internalSpeakerVolume = analogVolumeReg;
        !          1028: }
        !          1029: 
        !          1030: void
        !          1031: PPCDACA::volumeInternalSpeakerRight(int vol)
        !          1032: {
        !          1033:     analogVolumeReg = internalSpeakerVolume;
        !          1034:     setDACAVolume(vol, false);
        !          1035:     internalSpeakerVolume = analogVolumeReg;
        !          1036: }
        !          1037: 
        !          1038: // --------------------------------------------------------------------------
        !          1039: // Method: volumeCDLineLeft & volumeCDLineRight
        !          1040: //
        !          1041: // Purpose:
        !          1042: //        sets the volume for the left and right channel of the CD
        !          1043: //        line.
        !          1044: void
        !          1045: PPCDACA::volumeCDLineLeft(int vol)
        !          1046: {
        !          1047: }
        !          1048: 
        !          1049: void
        !          1050: PPCDACA::volumeCDLineRight(int vol)
        !          1051: {
        !          1052: }
        !          1053: 
        !          1054: /* =============================================================
        !          1055:  * VERY Private Methods used to access to the DAC-3550 registers
        !          1056:  * ============================================================= */
        !          1057: 
        !          1058: // --------------------------------------------------------------------------
        !          1059: // Method: enableInterrupts
        !          1060: //
        !          1061: // Purpose:
        !          1062: //         enable the interrupts for the I2S interface:
        !          1063: bool
        !          1064: PPCDACA::enableInterrupts()
        !          1065: {
        !          1066:     I2SSetIntCtlReg(kFrameCountEnable | kClocksStoppedEnable);
        !          1067:     return true;
        !          1068: }
        !          1069: 
        !          1070: // Method: disableInterrupts
        !          1071: //
        !          1072: // Purpose:
        !          1073: //         disable the interrupts for the I2S interface:
        !          1074: bool
        !          1075: PPCDACA::disableInterrupts()
        !          1076: {
        !          1077:     I2SSetIntCtlReg(I2SGetIntCtlReg() & (~(kFrameCountEnable | kClocksStoppedEnable)));
        !          1078:     return true;
        !          1079: }
        !          1080: 
        !          1081: // --------------------------------------------------------------------------
        !          1082: // Method: clockRun
        !          1083: //
        !          1084: // Purpose:
        !          1085: //         starts and stops the clock count:
        !          1086: bool
        !          1087: PPCDACA::clockRun(bool start)
        !          1088: {
        !          1089:     bool success = true;
        !          1090:     UInt32 *baseInterrupt = (UInt32*)soundConfigSpace + kI2SIntCtlOffset;
        !          1091: 
        !          1092: #ifdef DEBUGMODE
        !          1093:     IOLog("PPCDACA::clockRun(%s) 1] 0x%08lx -> 0x%08lx\n", (start ? "true" : "false"), (UInt32)baseInterrupt, *baseInterrupt);
        !          1094: #endif
        !          1095: 
        !          1096:     if (start) {
        !          1097:         KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) | kI2S0ClockEnable);
        !          1098:     }
        !          1099:     else {
        !          1100:         UInt16 loop = 50;
        !          1101:         KLSetRegister(ioClockBaseAddress, KLGetRegister(ioClockBaseAddress) & (~kI2S0ClockEnable));
        !          1102:         
        !          1103:         while (((I2SGetIntCtlReg() & kClocksStoppedPending) == 0) && (loop--)) {
        !          1104:             // it does not do anything, jut waites for the clock
        !          1105:             // to stop
        !          1106:             IOSleep(10);
        !          1107: #ifdef DEBUGMODE
        !          1108:             IOLog("PPCDACA::clockRun(%s) 2] 0x%08lx -> 0x%08lx\n", (start ? "true" : "false"), (UInt32)baseInterrupt, *baseInterrupt);
        !          1109: #endif
        !          1110:         }
        !          1111: 
        !          1112:         // we are successful if the clock actually stopped.
        !          1113:         success =  ((I2SGetIntCtlReg() & kClocksStoppedPending) != 0);
        !          1114:     }
        !          1115: 
        !          1116: #ifdef DEBUGMODE
        !          1117:     if (!success)
        !          1118:         IOLog("PPCDACA::clockRun(%s) failed\n", (start ? "true" : "false"));
        !          1119: #endif
        !          1120: 
        !          1121:     return success;
        !          1122: }
        !          1123: 
        !          1124: // --------------------------------------------------------------------------
        !          1125: // Method: setSampleRate
        !          1126: //
        !          1127: // Purpose:
        !          1128: //        Sets the sample rate on the I2S bus
        !          1129: bool
        !          1130: PPCDACA::setSampleParameters(UInt32 sampleRate, UInt32 mclkToFsRatio)
        !          1131: {
        !          1132:     UInt32     mclkRatio;
        !          1133:     UInt32     reqMClkRate;
        !          1134: 
        !          1135:     mclkRatio = mclkToFsRatio;                 // remember the MClk ratio required
        !          1136: 
        !          1137:     if ( mclkRatio == 0 )                                                                                                                                                             // or make one up if MClk not required
        !          1138:         mclkRatio = 64;                                // use 64 x ratio since that will give us the best characteristics
        !          1139:     
        !          1140:     reqMClkRate = sampleRate * mclkRatio;      // this is the required MClk rate
        !          1141: 
        !          1142:     // look for a source clock that divides down evenly into the MClk
        !          1143:     if ((kClock18MHz % reqMClkRate) == 0) {
        !          1144:         // preferential source is 18 MHz
        !          1145:         dacaClockSource = kClock18MHz;
        !          1146:     }
        !          1147:     else if ((kClock45MHz % reqMClkRate) == 0) {
        !          1148:         // next check 45 MHz clock
        !          1149:         dacaClockSource = kClock45MHz;
        !          1150:     }
        !          1151:     else if ((kClock49MHz % reqMClkRate) == 0) {
        !          1152:         // last, try 49 Mhz clock
        !          1153:         dacaClockSource = kClock49MHz;
        !          1154:     }
        !          1155:     else {
        !          1156:         IOLog("PPCDACA::setSampleParameters Unable to find a suitable source clock (no globals changes take effect)\n");
        !          1157:         return false;
        !          1158:     }
        !          1159: 
        !          1160:     // get the MClk divisor
        !          1161:     IOLog("PPCDACA:setSampleParameters %ld / %ld =", (UInt32)dacaClockSource, (UInt32)reqMClkRate); 
        !          1162:     dacaMclkDivisor = dacaClockSource / reqMClkRate;
        !          1163:     IOLog("%ld\n", dacaMclkDivisor);
        !          1164:     switch (dacaSerialFormat)                                  // SClk depends on format
        !          1165:     {
        !          1166:         case kSndIOFormatI2SSony:
        !          1167:         case kSndIOFormatI2S64x:
        !          1168:             dacaSclkDivisor = mclkRatio / k64TicksPerFrame;    // SClk divisor is MClk ratio/64
        !          1169:             break;
        !          1170:         case kSndIOFormatI2S32x:
        !          1171:             dacaSclkDivisor = mclkRatio / k32TicksPerFrame;    // SClk divisor is MClk ratio/32
        !          1172:             break;
        !          1173:         default:
        !          1174:             IOLog("PPCDACA::setSampleParameters Invalid serial format\n");
        !          1175:             return false;
        !          1176:             break;
        !          1177:     }
        !          1178: 
        !          1179:     return true;
        !          1180:  }
        !          1181: 
        !          1182: 
        !          1183: // --------------------------------------------------------------------------
        !          1184: // Method: setSerialFormatRegister
        !          1185: //
        !          1186: // Purpose:
        !          1187: //        Set global values to the serial format register
        !          1188: void
        !          1189: PPCDACA::setSerialFormatRegister(ClockSource clockSource, UInt32 mclkDivisor, UInt32 sclkDivisor, SoundFormat serialFormat)
        !          1190: {
        !          1191:     UInt32     regValue = 0;
        !          1192: 
        !          1193: #ifdef DEBUGMODE
        !          1194:     IOLog("PPCDACA::SetSerialFormatRegister(%d,%d,%d,%d)\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
        !          1195: #endif // DEBUGMODE
        !          1196: 
        !          1197:     switch ((int)clockSource)
        !          1198:     {
        !          1199:         case kClock18MHz:
        !          1200:             regValue = kClockSource18MHz;
        !          1201:             break;
        !          1202:         case kClock45MHz:
        !          1203:             regValue = kClockSource45MHz;
        !          1204:             break;
        !          1205:         case kClock49MHz:
        !          1206:             regValue = kClockSource49MHz;
        !          1207:             break;
        !          1208:         default:
        !          1209:             IOLog("PPCDACA::SetSerialFormatRegister(%d,%d,%d,%d): Invalid clock source\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
        !          1210:             break;
        !          1211:     }
        !          1212: 
        !          1213:     switch (mclkDivisor)
        !          1214:     {
        !          1215:         case 1:
        !          1216:             regValue |= kMClkDivisor1;
        !          1217:             break;
        !          1218:         case 3:
        !          1219:             regValue |= kMClkDivisor3;
        !          1220:             break;
        !          1221:         case 5:
        !          1222:             regValue |= kMClkDivisor5;
        !          1223:             break;
        !          1224:         default:
        !          1225:             regValue |= (((mclkDivisor / 2) - 1) << kMClkDivisorShift) & kMClkDivisorMask;
        !          1226:             break;
        !          1227:     }
        !          1228: 
        !          1229:     switch ((int)sclkDivisor)
        !          1230:     {
        !          1231:         case 1:
        !          1232:             regValue |= kSClkDivisor1;
        !          1233:             break;
        !          1234:         case 3:
        !          1235:             regValue |= kSClkDivisor3;
        !          1236:             break;
        !          1237:         default:
        !          1238:             regValue |= (((sclkDivisor / 2) - 1) << kSClkDivisorShift) & kSClkDivisorMask;
        !          1239:             break;
        !          1240:     }
        !          1241:     regValue |= kSClkMaster;                                                                           // force master mode
        !          1242: 
        !          1243:     switch (serialFormat)
        !          1244:     {
        !          1245:         case kSndIOFormatI2SSony:
        !          1246:             regValue |= kSerialFormatSony;
        !          1247:             break;
        !          1248:         case kSndIOFormatI2S64x:
        !          1249:             regValue |= kSerialFormat64x;
        !          1250:             break;
        !          1251:         case kSndIOFormatI2S32x:
        !          1252:             regValue |= kSerialFormat32x;
        !          1253:             break;
        !          1254:         default:
        !          1255:             IOLog("PPCDACA::SetSerialFormatRegister(%d,%d,%d,%d): Invalid serial format\n",(int)clockSource, (int)mclkDivisor, (int)sclkDivisor, (int)serialFormat);
        !          1256:             break;
        !          1257:     }
        !          1258: 
        !          1259:     // This is a 3 step process:
        !          1260: 
        !          1261:     // 1] Stop the clock:
        !          1262:     clockRun(false);
        !          1263: 
        !          1264:     // 2] Setup the serial format register
        !          1265:     I2SSetSerialFormatReg(regValue);
        !          1266: 
        !          1267:     // 3 restarts the clock:
        !          1268:     clockRun(true);    
        !          1269: }
        !          1270: 
        !          1271: // --------------------------------------------------------------------------
        !          1272: // Method: setDACASampleRate
        !          1273: //
        !          1274: // Purpose:
        !          1275: //        Gets the sample rate and makes it in a format that is compatible
        !          1276: //        with the adac register. The funtion returs false if it fails.
        !          1277: bool
        !          1278: PPCDACA::setDACASampleRate(UInt rate)
        !          1279: {
        !          1280:     UInt32 dacRate = 0;
        !          1281: 
        !          1282: #ifdef DEBUGMODE
        !          1283:     IOLog("PPCDACA::setDACASampleRate(%d)\n", rate);
        !          1284: #endif // DEBUGMODE
        !          1285: 
        !          1286:         switch (rate)
        !          1287:         {
        !          1288:                 case 44100:                            // 32 kHz - 48 kHz
        !          1289:                         dacRate = kSRC_48SR_REG;
        !          1290:                         break;
        !          1291: 
        !          1292:                 default:
        !          1293:                 IOLog("PPCDACA::setDACASampleRate, supports only 44100 Hz (for now)\n");
        !          1294:                         break;
        !          1295:         }
        !          1296: 
        !          1297:         return(writeRegisterBits(i2cBusSubAddrSR_REG, dacRate, kSampleRateControlMask));
        !          1298: }
        !          1299: 
        !          1300: 
        !          1301: // --------------------------------------------------------------------------
        !          1302: // Method: setDACAVolume
        !          1303: //
        !          1304: // Purpose:
        !          1305: //        sets the volume for the left or right channel. The first argument is
        !          1306: //        the wnated volume (as a range from 0 to 255), while the second argument
        !          1307: //        is a boolean (true for the right channel, false for the left channel).
        !          1308: bool
        !          1309: PPCDACA::setDACAVolume(UInt16 volume, bool isLeft)
        !          1310: {
        !          1311:     UInt8 newVolume = ((UInt32)((UInt32)volume * (UInt32)kVolumeRangeLevel_VOL) / (UInt32)65535 + (UInt32)kMinVolumeLevel_VOL);
        !          1312:     bool success = true;
        !          1313: 
        !          1314:     if (isLeft) // Sets the volume on the right channel
        !          1315:         success = writeRegisterBits(i2cBusSubAddrAVOL, (newVolume << kLeftAVOLShift), kLeftAVOLMask);
        !          1316:     else       // Sets the volume on the left channel
        !          1317:         success = writeRegisterBits(i2cBusSubAddrAVOL, (newVolume << kRightAVOLShift), kRightAVOLMask);
        !          1318: 
        !          1319:     return success;
        !          1320: }
        !          1321: 
        !          1322: // ---------------------------------------------------------------------------------------
        !          1323: // Method: writeRegisterBits
        !          1324: //
        !          1325: // Purpose:
        !          1326: //      This function sets or clears bits in the Daca registers.  The first argument is the
        !          1327: //      register sub-address, the second argument is a mask for turning bits on, while the third
        !          1328: //      argument is a mask for turning bits off.
        !          1329: bool
        !          1330: PPCDACA::writeRegisterBits(UInt8 subAddress, UInt32 bitMaskOn, UInt32 bitMaskOff)
        !          1331: {
        !          1332:     UInt8 bitsOn = 0, bitsOff = 0, value;
        !          1333:     UInt16 shortBitsOn = 0, shortBitsOff = 0, value16;
        !          1334:     bool success = false;
        !          1335: 
        !          1336: #ifdef DEBUGMODE
        !          1337:     IOLog("PPCDACA::writeRegisterBits(0x%x, 0x%08lx, 0x%08lx)\n", (UInt16)subAddress, bitMaskOn, bitMaskOff);
        !          1338: #endif // DEBUGMODE
        !          1339: 
        !          1340:     // mask off irrelevant bytes
        !          1341:     if (subAddress == i2cBusSubAddrAVOL) {
        !          1342:         // 16-bit register
        !          1343:         shortBitsOn = bitMaskOn & 0x0000FFFF;
        !          1344:         shortBitsOff = bitMaskOff & 0x0000FFFF;
        !          1345:     }
        !          1346:     else {
        !          1347:         // 8-bit registers
        !          1348:         bitsOn = bitMaskOn & 0x000000FF;
        !          1349:         bitsOff = bitMaskOff & 0x000000FF;
        !          1350:     }
        !          1351: 
        !          1352:     switch (subAddress)
        !          1353:     {
        !          1354:         case i2cBusSubAddrSR_REG:
        !          1355:             value = sampleRateReg | bitsOn;
        !          1356:             value &= ~bitsOff;
        !          1357:             // continue only if on bits are not already on and off bits are not already off
        !          1358:             if (value != sampleRateReg) {
        !          1359:                 success = interface->writeI2CBus((UInt8)i2cBusAddrDAC3550A, subAddress, &value, sizeof(value));
        !          1360: 
        !          1361:                 if (success)
        !          1362:                     sampleRateReg = value;
        !          1363:             }
        !          1364:                 else {
        !          1365:                     // If the sample rate is already set at the wanted value
        !          1366:                     // we do not do anything, but we return success since from the
        !          1367:                     // caller point of view it is as the sample rate was correctly
        !          1368:                     // set.
        !          1369:                     success = true;
        !          1370:                 }
        !          1371:                 break;
        !          1372: 
        !          1373:         case i2cBusSubAddrAVOL:
        !          1374:             value16 = analogVolumeReg;
        !          1375:             value16 &= ~shortBitsOff;
        !          1376:             value16 |= shortBitsOn;
        !          1377:             // continue only if on bits are not already on and off bits are not already off
        !          1378:             if (value16 !=analogVolumeReg)
        !          1379:             {
        !          1380:                 // It changes the volume for real only if the current output is not muted.
        !          1381:                 if (((!headphonesInserted()) && (!internalSpeakerMuted)) ||
        !          1382:                     (headphonesInserted() && (!internalHeadphonesMuted)))
        !          1383:                     success = interface->writeI2CBus((UInt8)i2cBusAddrDAC3550A, subAddress, (UInt8*)&value16, sizeof(value16));
        !          1384:                 else
        !          1385:                     success = true;
        !          1386: 
        !          1387:                 if (success)
        !          1388:                     analogVolumeReg = value16;
        !          1389:             }
        !          1390:                 else {
        !          1391:                     // If the volume is already set at the wanted value
        !          1392:                     // we do not do anything, but we return success since from the
        !          1393:                     // caller point of view it is as the volume was correctly
        !          1394:                     // set.
        !          1395:                     success = true;
        !          1396:                 }
        !          1397:                 break;
        !          1398: 
        !          1399:         case i2cBusSubaddrGCFG:
        !          1400:             value = configurationReg | bitsOn;
        !          1401:             value &= ~bitsOff;
        !          1402:             // continue only if on bits are not already on and off bits are not already off
        !          1403:             if (value != configurationReg)
        !          1404:             {
        !          1405:                 success = interface->writeI2CBus((UInt8)i2cBusAddrDAC3550A, subAddress, &value, sizeof(value));
        !          1406:                 if (success)
        !          1407:                     configurationReg = value;
        !          1408:             }
        !          1409:                 else {
        !          1410:                     // If the config register is already set at the wanted value
        !          1411:                     // we do not do anything, but we return success since from the
        !          1412:                     // caller point of view it is as the configuration was correctly
        !          1413:                     // set.
        !          1414:                     success = true;
        !          1415:                 }
        !          1416:                 break;
        !          1417: 
        !          1418:         default:
        !          1419:             IOLog("PPCDACA::writeRegisterBits 0x%x unknown subaddress\n", (UInt16)subAddress);
        !          1420:             break;
        !          1421:     }
        !          1422:     return success;
        !          1423: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.