|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.