|
|
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: * Hardware independent (relatively) code for the Awacs Controller
24: *
25: * HISTORY
26: *
27: * 14-Jan-1999
28: * Created.
29: *
30: */
31: #include <IOKit/assert.h>
32: #include <IOKit/system.h>
33:
34: #include <IOKit/IOLib.h>
35: #include <IOKit/IODeviceTreeSupport.h>
36: #include <IOKit/IOPlatformExpert.h>
37: #include <IOKit/ppc/IODBDMA.h>
38: #include "PPCAwacs.h"
39: #include "awacs_hw.h"
40:
41: /*
42: * From Excelsior:Toolbox:SoundMgr:Hardware:Ports:OutPorts.cp & GossamerOut.h
43: */
44: #define kSGS7433Addr 0x8A
45: #define kSGSNumRegs 7
46: unsigned char SGSShadow[kSGSNumRegs] =
47: { 0x09, /* Adr:1, AutoIncr */
48: 0x20, /* Reg 1: Vol = 0dB */
49: 0xFF, /* Reg 2: Bass = 0dB, Treble = 0dB */
50: 0x00, /* Reg 3: Internal Spkr - Left Atten = 0dB */
51: 0x0A, /* Reg 4: Line Out - Left Atten = -10dB */
52: 0x00, /* Reg 5: Internal Spkr - Right Atten = 0dB */
53: 0x0A }; /* Reg 6: Line Out - Right Atten = -10dB */
54: #define sgsBalMuteBit 0x020 // When this bit is set in the output fader/ balance regs, the channel is muted
55: #define sgsBalVolBits 0x1F // mask for volume steps
56: #define kLFAttnReg 0x03 // Left Front (ie everything except the rear spkr jack)
57: #define kRFAttnReg 0x05 // Right Front
58: #define kLRAttnReg 0x04 // Left Rear (the rear speaker jack only)
59: #define kRRAttnReg 0x06 // Right Rear
60:
61:
62: // "deivce-id" values come from the sound block in Open Firmware on B&W G3's and later
63: const u_int32_t kG4WithAwacsDeviceID = 5;
64: const u_int32_t kiMacDVDeviceID = 8;
65:
66: /*
67: *
68: */
69:
70: static void writeCodecControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value );
71: static void writeSoundControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value );
72: static u_int32_t readCodecStatusReg( volatile awacs_regmap_t *ioBaseAwacs );
73: static int readClippingCountReg( volatile awacs_regmap_t *ioBaseAwacs );
74:
75: static void writeCodecControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value )
76: {
77: int CodecControlReg;
78:
79: #if 0
80: IOLog( "PPCSound(awacs): CodecControlReg @ %08x = %08x\n\r", (int)&ioBaseAwacs->CodecControlRegister, value);
81: #endif
82:
83: OSWriteLittleInt32(&ioBaseAwacs->CodecControlRegister, 0, value );
84: eieio();
85:
86: do
87: {
88: CodecControlReg = OSReadLittleInt32( &ioBaseAwacs->CodecControlRegister, 0 );
89: eieio();
90: }
91: while ( CodecControlReg & kCodecCtlBusy );
92: }
93:
94:
95: static void writeSoundControlReg( volatile awacs_regmap_t *ioBaseAwacs, int value )
96: {
97:
98: #if 0
99: IOLog( "PPCSound(awacs): SoundControlReg = %08x\n\r", value);
100: #endif
101:
102: OSWriteLittleInt32( &ioBaseAwacs->SoundControlRegister, 0, value );
103: eieio();
104: }
105:
106: static u_int32_t readCodecStatusReg( volatile awacs_regmap_t *ioBaseAwacs )
107: {
108: return OSReadLittleInt32( &ioBaseAwacs->CodecStatusRegister, 0 );
109: }
110:
111: static int readClippingCountReg( volatile awacs_regmap_t *ioBaseAwacs )
112: {
113: return OSReadLittleInt32( &ioBaseAwacs->ClippingCountRegister, 0 );
114: }
115:
116: static void writeSGSRegs()
117: {
118: int i;
119: for (i = 0; i < kSGSNumRegs; i++) {
120: (*PE_write_IIC)(kSGS7433Addr, i, SGSShadow[i]);
121: }
122: }
123:
124: #define super IOAudioBus
125:
126: OSDefineMetaClassAndStructors( PPCAwacs, IOAudioBus )
127:
128: /*
129: * Public Instance Methods
130: */
131: bool PPCAwacs::init(OSDictionary * properties)
132: {
133: if (!super::init(properties))
134: return false;
135: if(!properties)
136: return false; // Need to know where Awacs is!
137:
138: return true;
139: }
140:
141: void PPCAwacs::free()
142: {
143: super::free();
144: }
145:
146: bool PPCAwacs::start(IOService * provider)
147: {
148: IOMemoryMap * map;
149: u_int32_t awacsVersion;
150: IORegistryEntry * perch = NULL;
151: IORegistryEntry * sound = NULL;
152:
153: if( !super::start(provider))
154: return (false);
155:
156: map = provider->mapDeviceMemoryWithIndex(kAudioDMAdeviceInt);
157: if(!map) {
158: return false;
159: }
160: fIOBaseAwacs = (awacs_regmap_t *)map->getVirtualAddress();
161:
162: if (!AllocateStreams(kNumDMAStreams))
163: return false;
164:
165: map = provider->mapDeviceMemoryWithIndex(kAudioDMAtxInt);
166: if(!map) {
167: return false;
168: }
169: DefineStream(kAudioDMAOutputStream, kOutput, 44100L, (IODBDMAChannelRegisters*)map->getVirtualAddress());
170:
171: map = provider->mapDeviceMemoryWithIndex(kAudioDMArxInt);
172: if(!map) {
173: return false;
174: }
175: DefineStream(kAudioDMAInputStream, kInput, 44100L, (IODBDMAChannelRegisters*)map->getVirtualAddress());
176:
177: // Dig out the sound nub that's below our match
178: fDetects = 2; // Mic jack and lineout jack
179: fOutputs = 2; // internal speaker and lineout
180:
181: fIsG4WithAwacs = FALSE;
182: fIsiMacDVWithAwacs = FALSE;
183:
184: sound = provider->childFromPath("sound", gIODTPlane);
185: if(sound) {
186: OSData *t;
187: t = OSDynamicCast(OSData, sound->getProperty("#-detects"));
188: if(t) {
189: fDetects = *(UInt32*)(t->getBytesNoCopy());
190: }
191: t = OSDynamicCast(OSData, sound->getProperty("#-outputs"));
192: if(t) {
193: fOutputs = *(UInt32*)(t->getBytesNoCopy());
194: }
195:
196: #if 1
197: IOLog( "PPCAwacs::start: about to get device-id\n" );
198: #endif
199: // Check for G4WithAwacs & iMacDVWithAwacs
200: // Note: "device-id" found on New World machines and later (B&W G3 is first such box)
201: t = OSDynamicCast( OSData, sound->getProperty( "device-id" ) );
202: if( t ) {
203: u_int32_t deviceID = *(UInt32 *)( t->getBytesNoCopy() );
204: #if 1
205: IOLog( "PPCAwacs::start: got deviceID = %d\n", deviceID );
206: #endif
207: switch ( deviceID )
208: {
209: case kG4WithAwacsDeviceID:
210: fIsG4WithAwacs = TRUE;
211: break;
212: case kiMacDVDeviceID:
213: fIsiMacDVWithAwacs = TRUE;
214: break;
215: default: ;// NOP
216: }
217: }
218: }
219:
220: // Debugging aids
221: OSNumber *num = OSNumber::withNumber(fDetects, 32);
222: setProperty("Detects", num);
223: num->release();
224: num = OSNumber::withNumber(fOutputs, 32);
225: setProperty("Outputs", num);
226: num->release();
227:
228: perch = IORegistryEntry::fromPath("/perch", gIODTPlane );
229: fIICAudioDevPresent = perch != NULL;
230: if(fIICAudioDevPresent) {
231: waitForService( resourceMatching( "IOiic0" ));
232: }
233: fCodecStatus = readCodecStatusReg( fIOBaseAwacs );
234: awacsVersion = (fCodecStatus & kRevisionNumberMask) >> kRevisionNumberShft;
235:
236: /*
237: * Mask out the input bits in the cached status register so that the AudioComponents
238: * get updated to the correct values the first time we update the device status
239: * (Everything is initialized on the assumption that nothing is plugged in)
240: */
241: fCodecStatus &= ~kAllSense;
242:
243: if ( awacsVersion > kAWACSMaxVersion ) {
244: fCodecControlRegister[5] = kCodecCtlAddress5 | kCodecCtlEMSelect0;
245: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[5] );
246: fCodecControlRegister[6] = kCodecCtlAddress6 | kCodecCtlEMSelect0;
247: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[6] );
248: }
249:
250: if ( fIICAudioDevPresent ) {
251: writeSGSRegs();
252: }
253:
254: fSoundControlRegister = ( kInSubFrame0 |
255: kOutSubFrame0 |
256: kHWRate44100 );
257: writeSoundControlReg( fIOBaseAwacs, fSoundControlRegister);
258:
259: fCodecControlRegister[0] = kCodecCtlAddress0 | kCodecCtlEMSelect0;
260: fCodecControlRegister[1] = kCodecCtlAddress1 | kCodecCtlEMSelect0;
261: fCodecControlRegister[2] = kCodecCtlAddress2 | kCodecCtlEMSelect0;
262: fCodecControlRegister[4] = kCodecCtlAddress4 | kCodecCtlEMSelect0;
263:
264: fCodecControlRegister[0] |= (kMicInput | kDefaultMicGain);
265:
266: // Gossamer passes sound right through to be later controlled
267: // by the SGS audio processor--turn on these pass-thru ports.
268: if ( fIICAudioDevPresent || fIsG4WithAwacs ) {
269: fCodecControlRegister[1] |= (kParallelOutputEnable);
270: }
271:
272: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[0] );
273: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[1] );
274: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[2] );
275: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[4] );
276:
277: startWorkLoop();
278:
279: if(perch)
280: perch->release();
281: if(sound)
282: sound->release();
283: return true;
284: }
285:
286:
287: void PPCAwacs::stop(IOService *provider)
288: {
289: super::stop(provider);
290: FreeStreams();
291: }
292:
293: void PPCAwacs::CreateAudioTopology(IOCommandQueue *queue)
294: {
295: /*
296: * These should be resources in the loadable driver
297: */
298: static const char *sSpeaker =
299: "{
300: 'Type' = 'Speaker';
301: 'Channels' = 2:8;
302: 'Master' = 1:8;
303: 'Controls' = {
304: 'MuteAll' = {
305: 'Type' = 'Mute';
306: 'Id' = 0:16;
307: 'Val' = 0:8;
308: 'Min' = 0:8;
309: 'Max' = 1:8;
310: 'Chan' = 0:8;
311: };
312: 'VolumeLeft' = {
313: 'Type' = 'Volume';
314: 'Id' = 1:16;
315: 'Val' = 65535:16;
316: 'Min' = 0:16;
317: 'Max' = 65535:16;
318: 'Chan' = 1:8;
319: };
320: 'VolumeRight' = {
321: 'Type' = 'Volume';
322: 'Id' = 2:16;
323: 'Val' = 65535:16;
324: 'Min' = 0:16;
325: 'Max' = 65535:16;
326: 'Chan' = 2:8;
327: };
328: };
329: }";
330:
331: static const char *sHeadphones =
332: "{
333: 'Type' = 'Headphones';
334: 'Channels' = 2:8;
335: 'Master' = 1:8;
336: 'Controls' = {
337: 'MuteAll' = {
338: 'Type' = 'Mute';
339: 'Id' = 3:16;
340: 'Val' = 0:8;
341: 'Min' = 0:8;
342: 'Max' = 1:8;
343: 'Chan' = 0:8;
344: };
345: 'VolumeLeft' = {
346: 'Type' = 'Volume';
347: 'Id' = 4:16;
348: 'Val' = 65535:16;
349: 'Min' = 0:16;
350: 'Max' = 65535:16;
351: 'Chan' = 1:8;
352: };
353: 'VolumeRight' = {
354: 'Type' = 'Volume';
355: 'Id' = 5:16;
356: 'Val' = 65535:16;
357: 'Min' = 0:16;
358: 'Max' = 65535:16;
359: 'Chan' = 2:8;
360: };
361: };
362: 'Inputs' = {
363: 'Jack' = {
364: 'Val' = 0:8;
365: 'Min' = 0:8;
366: 'Max' = 1:8;
367: };
368: };
369: }";
370:
371: static const char *sMicrophone =
372: "{
373: 'Type' = 'Microphone';
374: 'Channels' = 2:8;
375: 'Controls' = {
376: 'MuteAll' = {
377: 'Type' = 'Mute';
378: 'Id' = 6:16;
379: 'Val' = 0:8;
380: 'Min' = 0:8;
381: 'Max' = 1:8;
382: 'Chan' = 0:8;
383: };
384: };
385: 'Inputs' = {
386: 'Jack' = {
387: 'Val' = 0:8;
388: 'Min' = 0:8;
389: 'Max' = 1:8;
390: };
391: };
392: }";
393:
394: static const char *sLineout =
395: "{
396: 'Type' = 'LineOut';
397: 'Channels' = 2:8;
398: 'Controls' = {
399: 'MuteAll' = {
400: 'Type' = 'Mute';
401: 'Id' = 13:16;
402: 'Val' = 0:8;
403: 'Min' = 0:8;
404: 'Max' = 1:8;
405: 'Chan' = 0:8;
406: };
407: };
408: 'Inputs' = {
409: 'Jack' = {
410: 'Val' = 0:8;
411: 'Min' = 0:8;
412: 'Max' = 1:8;
413: };
414: };
415: }";
416:
417: static const char *sCD =
418: "{
419: 'Type' = 'CD';
420: 'Channels' = 2:8;
421: 'Controls' = {
422: 'MuteAll' = {
423: 'Type' = 'Mute';
424: 'Id' = 7:16;
425: 'Val' = 0:8;
426: 'Min' = 0:8;
427: 'Max' = 1:8;
428: 'Chan' = 0:8;
429: };
430: };
431: }";
432:
433: static const char *sMixerIn =
434: "{
435: 'Type' = 'Mixer';
436: 'Channels' = 2:8;
437: 'Controls' = {
438: 'VolumeLeft' = {
439: 'Type' = 'Volume';
440: 'Id' = 8:16;
441: 'Val' = 65535:16;
442: 'Min' = 0:16;
443: 'Max' = 65535:16;
444: 'Chan' = 1:8;
445: };
446: 'VolumeRight' = {
447: 'Type' = 'Volume';
448: 'Id' = 9:16;
449: 'Val' = 65535:16;
450: 'Min' = 0:16;
451: 'Max' = 65535:16;
452: 'Chan' = 2:8;
453: };
454: };
455: }";
456:
457: static const char *sPassThru =
458: "{
459: 'Type' = 'Feature';
460: 'Channels' = 2:8;
461: 'Controls' = {
462: 'MuteAll' = {
463: 'Type' = 'Mute';
464: 'Id' = 12:16;
465: 'Val' = 1:8;
466: 'Min' = 0:8;
467: 'Max' = 1:8;
468: 'Chan' = 0:8;
469: };
470: 'VolumeLeft' = {
471: 'Type' = 'Volume';
472: 'Id' = 10:16;
473: 'Val' = 65535:16;
474: 'Min' = 0:16;
475: 'Max' = 65535:16;
476: 'Chan' = 1:8;
477: };
478: 'VolumeRight' = {
479: 'Type' = 'Volume';
480: 'Id' = 11:16;
481: 'Val' = 65535:16;
482: 'Min' = 0:16;
483: 'Max' = 65535:16;
484: 'Chan' = 2:8;
485: };
486: };
487: }";
488:
489: static const char *sMixerOut =
490: "{
491: 'Type' = 'Mixer';
492: 'Channels' = 2:8;
493: }";
494:
495: IOAudioComponentImpl *mixerIn;
496: IOAudioComponentImpl *mixerOut;
497: IOAudioComponentImpl *microphone;
498: IOAudioComponentImpl *lineout;
499: IOAudioComponentImpl *headphones;
500: AudioStreamIndex outputStream;
501: AudioStreamIndex inputStream;
502:
503: if (!fStreams)
504: return;
505:
506: outputStream = firstStreamAfter(kOutput, 0);
507: inputStream = firstStreamAfter(kInput, 0);
508: if ((outputStream == kInvalidStreamIndex) || (inputStream == kInvalidStreamIndex)) {
509: IOLog("PPCAwacs::CreateAudioTopology called without available DMA streams\n");
510: return;
511: }
512: else
513: IOLog("PPCAwacs::CreateAudioTopology input stream is %d output is %d\n", inputStream, outputStream);
514:
515: mixerOut = buildComponentAndAttach(GetStream(outputStream), NULL, sMixerOut, queue);
516: headphones = buildComponentAndAttach(mixerOut, NULL, sHeadphones, queue);
517: buildComponentAndAttach(mixerOut, NULL, sSpeaker, queue);
518: microphone = buildComponentAndAttach(NULL, NULL, sMicrophone, queue);
519: mixerIn = buildComponentAndAttach(microphone, GetStream(inputStream), sMixerIn, queue);
520: buildComponentAndAttach(mixerIn, mixerOut, sPassThru, queue);
521: buildComponentAndAttach(NULL, mixerIn, sCD, queue);
522:
523: /*
524: * This stuff should perhaps be table-driven, depending on how much it varies
525: * between different Mac models that use versions of Awacs wired up in different ways
526: *
527: * 9500: Speaker Out jack = kHeadphoneSense
528: * Microphone jack = kAux1Sense
529: *
530: * AllInOne: Line Out jack = kAux1Sense
531: * Microphone jack = kLineInSense
532: * Either Headphone jack = kHeadphoneSense
533: *
534: * Beige G3: Line Out jack = kAux1Sense
535: * Microphone jack = kLineInSense
536: *
537: * B&W G3: Line Out jack = kAux1Sense
538: * Microphone jack = kLineInSense
539: *
540: * A big problem is how to tell the difference between AllInOne and Beige G3,
541: * and perhaps iMac and B&W G3
542: */
543: if ( fIICAudioDevPresent ) {
544: fInputComponents[kLineInShft] = microphone;
545: if(fOutputs == 3 && fDetects == 3) {
546: // CPU has lineout and headphone jacks
547: lineout = buildComponentAndAttach(mixerOut, NULL, sLineout, queue);
548: fInputComponents[kAux1Shft] = lineout;
549: fInputComponents[kHeadphoneShft] = headphones;
550: }
551: else {
552: fInputComponents[kAux1Shft] = headphones;
553: }
554: }
555: else if ( fIsG4WithAwacs ) {
556: fInputComponents[kLineInShft] = microphone;
557: fInputComponents[kAux1Shft] = headphones;
558: }
559: else if ( fIsiMacDVWithAwacs ) {
560: #if 1
561: IOLog( "PPCAwacs::CreateAudioTopology: fIsiMacDVWithAwacs\n" );
562: #endif
563: // The DV iMac has 2 headphones outputs, 1 line out, and 1 microphone
564: // The names of the bits do not match how they are actually wired :-)
565: lineout = buildComponentAndAttach(mixerOut, NULL, sLineout, queue);
566: fInputComponents[kNotMicShift] = lineout;
567: fInputComponents[kLineInShft] = headphones;
568: fInputComponents[kAux1Shft] = headphones;
569: fInputComponents[kHeadphoneShft] = microphone;
570: }
571: else {
572: fInputComponents[kAux1Shft] = microphone;
573: fInputComponents[kHeadphoneShft] = headphones;
574: }
575: // Update state of all inputs now that all the bookkeeping objects are created.
576: checkStatus();
577: }
578:
579: void PPCAwacs::DoClockTick(IOTimerEventSource *t)
580: {
581: checkStatus();
582: super::DoClockTick(t);
583: }
584:
585: void PPCAwacs::calculateTickInterval(AbsoluteTime *tickInterval)
586: {
587: AbsoluteTime maxInterval;
588:
589: // We want to check the status at least one a second
590: nanoseconds_to_absolutetime(NSEC_PER_SEC, &maxInterval);
591: if(CMP_ABSOLUTETIME(&maxInterval, tickInterval) < 0) {
592: *tickInterval = maxInterval;
593: }
594: super::calculateTickInterval(tickInterval);
595: }
596:
597: void PPCAwacs::checkStatus()
598: {
599: u_int32_t codecStatus;
600:
601: codecStatus = readCodecStatusReg( fIOBaseAwacs );
602:
603: if(fCodecStatus != codecStatus) {
604: int i;
605: // Debugging aids
606: //kprintf("Awacs status: 0x%x\n", codecStatus);
607: #if 1
608: IOLog( "PPCAwacs::checkStatusAwacs status: 0x%x\n", codecStatus );
609: #endif
610: OSNumber * num = OSNumber::withNumber(codecStatus, 32);
611: setProperty("Status", num);
612: num->release();
613:
614: for(i=0; i<4; i++) {
615: if( (fCodecStatus & (1<<i)) != (codecStatus & (1<<i)))
616: if(fInputComponents[i]) {
617: fInputComponents[i]->Set(gInputsSym, gJackSym,
618: (codecStatus & (1<<i)) >> i);
619: }
620: }
621: }
622: fCodecStatus = codecStatus;
623: }
624:
625: IOReturn
626: PPCAwacs::SetControl(UInt16 id, int val)
627: {
628: IOReturn res = kIOReturnSuccess;
629: switch(id) {
630: case kSpeakerMute:
631: if(val)
632: fCodecControlRegister[1] |= kMuteInternalSpeaker;
633: else
634: fCodecControlRegister[1] &= ~kMuteInternalSpeaker;
635: if ( fIICAudioDevPresent ) {
636: #if 0
637: /*
638: * Mute the left and right front channels
639: */
640: SGSShadow[kLFAttnReg] &= ~sgsBalMuteBit;
641: SGSShadow[kRFAttnReg] &= ~sgsBalMuteBit;
642:
643: if ( val ) {
644: SGSShadow[kLFAttnReg] |= sgsBalMuteBit;
645: SGSShadow[kRFAttnReg] |= sgsBalMuteBit;
646: }
647: writeSGSRegs();
648:
649: #else
650: if(val)
651: fCodecControlRegister[1] &= ~kOutputOne;
652: else
653: fCodecControlRegister[1] |= kOutputOne;
654: #endif
655: }
656: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[1] );
657:
658: break;
659:
660: case kSpeakerVolLeft:
661: if ( fIICAudioDevPresent ) {
662: // Actually sets volume of speaker and front headphone
663: val = 31 - ((val * 32 / 65536) & 31);
664: SGSShadow[kLFAttnReg] = (SGSShadow[kLFAttnReg] & sgsBalMuteBit) | val;
665: writeSGSRegs();
666: }
667: else {
668: val = 15 - ((val * 16 / 65536) & 15);
669: fCodecControlRegister[4] = (fCodecControlRegister[4] & ~kLeftSpeakerAttenMask) |
670: (val << kLeftSpeakerAttenShift);
671: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[4] );
672: }
673:
674: break;
675:
676: case kSpeakerVolRight:
677: if ( fIICAudioDevPresent ) {
678: // Actually sets volume of speaker and front headphone
679: val = 31 - ((val * 32 / 65536) & 31);
680: SGSShadow[kRFAttnReg] = (SGSShadow[kRFAttnReg] & sgsBalMuteBit) | val;
681: writeSGSRegs();
682: }
683: else {
684: val = 15 - ((val * 16 / 65536) & 15);
685: fCodecControlRegister[4] = (fCodecControlRegister[4] & ~kRightSpeakerAttenMask) |
686: (val << kRightSpeakerAttenShift);
687: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[4] );
688: }
689: break;
690:
691: case kHeadphonesMute:
692: if(val)
693: fCodecControlRegister[1] |= kMuteHeadphone;
694: else
695: fCodecControlRegister[1] &= ~kMuteHeadphone;
696: if ( fIICAudioDevPresent ) {
697: if(val)
698: fCodecControlRegister[1] &= ~kOutputOne;
699: else
700: fCodecControlRegister[1] |= kOutputOne;
701: }
702: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[1] );
703:
704: break;
705:
706: case kHeadphonesVolLeft:
707: val = 15 - ((val * 16 / 65536) & 15);
708: fCodecControlRegister[2] = (fCodecControlRegister[2] & ~kLeftHeadphoneAttenMask) |
709: (val << kLeftHeadphoneAttenShift);
710: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[2] );
711: break;
712:
713: case kHeadphonesVolRight:
714: val = 15 - ((val * 16 / 65536) & 15);
715: fCodecControlRegister[2] = (fCodecControlRegister[2] & ~kRightHeadphoneAttenMask) |
716: (val << kRightHeadphoneAttenShift);
717: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[2] );
718: break;
719:
720: case kMicrophoneMute:
721: if(val)
722: fCodecControlRegister[0] &= ~kMicInput;
723: else
724: fCodecControlRegister[0] |= kMicInput;
725: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[0] );
726: break;
727:
728: case kCDMute:
729: if(val)
730: fCodecControlRegister[0] &= ~kCDInput;
731: else
732: fCodecControlRegister[0] |= kCDInput;
733: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[0] );
734: break;
735:
736: case kMixerInVolLeft:
737: val = (val * 16 / 65536) & 15;
738: fCodecControlRegister[0] = (fCodecControlRegister[0] & ~kLeftInputGainMask) |
739: (val << kLeftInputGainShift);
740: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[0] );
741: break;
742:
743: case kMixerInVolRight:
744: val = (val * 16 / 65536) & 15;
745: fCodecControlRegister[0] = (fCodecControlRegister[0] & ~kRightInputGainMask) |
746: (val << kRightInputGainShift);
747: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[0] );
748: break;
749:
750: case kPassThruVolLeft:
751: val = 15 - ((val * 16 / 65536) & 15);
752: fCodecControlRegister[5] = (fCodecControlRegister[5] & ~kLeftLoopThruAttenMask) |
753: (val << kLeftLoopThruAttenShift);
754: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[5] );
755: break;
756:
757: case kPassThruVolRight:
758: val = 15 - ((val * 16 / 65536) & 15);
759: fCodecControlRegister[5] = (fCodecControlRegister[5] & ~kRightLoopThruAttenMask) |
760: (val << kRightLoopThruAttenShift);
761: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[5] );
762: break;
763:
764: case kPassThruMute:
765: if(val)
766: fCodecControlRegister[1] &= ~kLoopThruEnable;
767: else
768: fCodecControlRegister[1] |= kLoopThruEnable;
769: writeCodecControlReg( fIOBaseAwacs, fCodecControlRegister[1] );
770: break;
771:
772:
773: default:
774: res = kIOReturnUnsupported;
775: }
776: return res;
777: }
778:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.