|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /*
25: * IOAudio.m
26: *
27: * Copyright (c) 1991, NeXT Computer, Inc. All rights reserved.
28: *
29: */
30:
31: #import <mach/mach_user_internal.h>
32: #import <driverkit/interruptMsg.h>
33: #import <driverkit/kernelDriver.h>
34: #import <driverkit/IODeviceDescription.h>
35: #if defined (ppc)
36: #import "kernserv/ppc/spl.h"
37: #elif defined (i386)
38: #import "kernserv/i386/spl.h"
39: #else
40: #error architecture not supported
41: #endif
42:
43:
44: #if defined(hppa)
45: #import <machdep/machine/pmap.h>
46: #endif
47:
48: #import <driverkit/IOAudio.h>
49: #import <driverkit/IOAudioPrivate.h>
50: #import <kernserv/prototypes.h> // for msg_send_from_kernel
51: #import "AudioChannel.h"
52:
53: #import "InputStream.h"
54: #import "OutputStream.h"
55:
56: #import "AudioCommand.h"
57:
58: #import "portFuncs.h"
59: #import "audio_types.h"
60: #import "audio_kern_server.h"
61: #import "audio_mulaw.h"
62: #import "audioLog.h" // For XPRs
63:
64: #ifdef hppa
65: #warning interrupt hack for hppa on
66: id my_audioid = 0;
67: // The below map is used in files AudioChannel.m, HPAdvancedAudio.m apart from here
68: pmap_t audio_pmap;
69: extern aspitab();
70: #endif
71:
72: static void ioThread(IOAudio *audioDevice);
73: static void keyThread(IOAudio *audioDevice);
74:
75: /*
76: * FIXME: These tags should be incorporated in NXSoundParameterTags.
77: */
78: typedef enum {
79: NX_SoundDeviceLineOut = NX_SoundDeviceParameterKeyBase + 25,
80: NX_SoundDeviceSpeakerOut,
81: NX_SoundDeviceCDOut,
82: NX_SoundDeviceAux1Out,
83: NX_SoundDeviceAux2Out,
84:
85: NX_SoundDeviceMicIn,
86: NX_SoundDeviceLineIn,
87: NX_SoundDeviceCDIn,
88: NX_SoundDeviceAux1In,
89: NX_SoundDeviceAux2In,
90: } NXSoundParameterTagExtra;
91:
92: /*
93: * NeXTTime relies on +_instance, so
94: * these can be factory variables.
95: */
96: static BOOL runningExclusive = NO;
97: static unsigned long exclusiveProgress = 0;
98: static unsigned int exclusiveIncrement = 0;
99: static IOAudioInterruptClearFunc exclusiveInterruptClearFunc = 0;
100:
101: /*
102: * Driver makefiles generate source with this interface
103: * that goes into each reloc.
104: */
105: @interface Object (AudioDriverPrivate)
106: + (kern_server_t *)kernelServerInstance;
107: @end
108:
109: /*
110: * Since EventDriver.h cannot be imported, the objc_lookUpClass interface is
111: * used to locate the EventDriver class. This definition eliminates warning
112: * messages from the compiler.
113: */
114: @interface Object (EventDriver)
115: + instance;
116:
117: - (IOReturn) setSpecialKeyPort: (port_t)dev_port
118: keyFlavor: (int)special_key
119: keyPort: (port_t)key_port;
120:
121: - (port_t)ev_port;
122: @end
123:
124: /*
125: * imports for EventDriver
126: */
127: #import <bsd/dev/ev_keymap.h>
128: #import <bsd/dev/evio.h>
129: #import <objc/objc-runtime.h> // objc_lookUpClass
130:
131: /*
132: * Currently we store the timestamp for only the last interrupt. In future we
133: * might store them for last n interrupts. This will allow us to know if any
134: * interrupts have been dropped.
135: */
136:
137: static ns_time_t _lastInterruptTime;
138:
139: #if defined(hppa) || defined(sparc)
140: interruptHandler(void *identity, void *state)
141: #else hppa
142: static void
143: interruptHandler(void *identity, void *state, unsigned int arg)
144: #endif hppa
145: {
146: if (runningExclusive) {
147: exclusiveProgress += exclusiveIncrement;
148: if (exclusiveInterruptClearFunc) {
149: (*exclusiveInterruptClearFunc)();
150: return;
151: }
152: }
153:
154: IOGetTimestamp(&_lastInterruptTime);
155:
156: xpr_audio_device("AD: interruptHandler\n", 1,2,3,4,5);
157:
158: /* Forward this to the I/O thread for further handling. */
159: IOSendInterrupt(identity, state, IO_DEVICE_INTERRUPT_MSG);
160: }
161:
162: @implementation IOAudio (Private)
163:
164: /* Factory variables */
165: static id _channelList = nil;
166: static id _deviceInstance = nil;
167:
168:
169: /*
170: * Add a channel.
171: * Note: channels are added at driver init time (main.m)
172: * and never removed. Therefore channel list locking is not necessary.
173: */
174: + _addChannel:channel
175: {
176: if (!_channelList)
177: _channelList = [[List alloc] init];
178: [_channelList addObject:channel];
179: return self;
180: }
181:
182: /*
183: * Search for a channel given a user port.
184: */
185: + _channelForUserPort:(port_t)port
186: {
187: int i;
188: id channel;
189:
190: for (i = 0; i < [_channelList count]; i++) {
191: channel = [_channelList objectAt:i];
192: if ([channel userChannelPort] == port)
193: return channel;
194: }
195: return nil;
196: }
197:
198: /*
199: * Search for a channel given an exclusive owner port.
200: */
201: + _channelForExclusivePort:(port_t)port
202: {
203: int i;
204: id channel;
205:
206: for (i = 0; i < [_channelList count]; i++) {
207: channel = [_channelList objectAt:i];
208: if ([channel exclusiveUser] == port)
209: return channel;
210: }
211: return nil;
212: }
213:
214: /*
215: * Search for a input channel given an snd user port.
216: */
217: + _inputChannelForSndPort:(port_t)port
218: {
219: int i;
220: id channel;
221:
222: for (i = 0; i < [_channelList count]; i++) {
223: channel = [_channelList objectAt:i];
224: if (channel == [[channel audioDevice] _inputChannel] && [channel userSndPort] == port)
225: return channel;
226: }
227: return nil;
228: }
229:
230: /*
231: * Search for a output channel given an snd user port.
232: */
233: + _outputChannelForSndPort:(port_t)port
234: {
235: int i;
236: id channel;
237:
238: for (i = 0; i < [_channelList count]; i++) {
239: channel = [_channelList objectAt:i];
240: if (channel == [[channel audioDevice] _outputChannel] && [channel userSndPort] == port)
241: return channel;
242: }
243: return nil;
244: }
245:
246: + (void) _setInstance:anObject
247: {
248: _deviceInstance = anObject;
249: }
250:
251: + _instance
252: {
253: return _deviceInstance;
254: }
255:
256: - _inputChannel
257: {
258: return _inputChannel;
259: }
260: - _outputChannel
261: {
262: return _outputChannel;
263: }
264:
265: /*
266: * Subclass can override to detect when a stream is added to a channel.
267: * Returning NO prevents the stream from being added.
268: */
269: - (BOOL) _channelWillAddStream
270: {
271: return YES;
272: }
273:
274: /*
275: * The audioCommand allows channels to send synchronous commands to the
276: * device.
277: */
278: - _audioCommand
279: {
280: return _audioCommand;
281: }
282:
283: /*
284: *
285: */
286: - (void) _setSampleRate: (unsigned int) rate
287: {
288: _sampleRate = rate;
289: }
290:
291: - (void) _setDataEncoding:(unsigned int)encoding
292: {
293: _dataEncoding = encoding;
294: }
295:
296: /*
297: *
298: */
299: - (void) _setChannelCount:(unsigned int)count
300: {
301: _channelCount = count;
302: }
303:
304: - (void) _dataPendingForChannel: (id)channel
305: {
306: kern_return_t krtn;
307:
308: xpr_audio_device("AD: _dataPendingForChannel\n",1,2,3,4,5);
309:
310: if (!_dataPendingMessage) {
311: _dataPendingMessage = (msg_header_t *)IOMalloc(sizeof(msg_header_t));
312: _dataPendingMessage->msg_simple = TRUE;
313: _dataPendingMessage->msg_size = sizeof(msg_header_t);
314: _dataPendingMessage->msg_type = MSG_TYPE_NORMAL;
315: _dataPendingMessage->msg_local_port = PORT_NULL;
316: _dataPendingMessage->msg_remote_port = _commandPort;
317: }
318:
319: if ([channel isRead])
320: _dataPendingMessage->msg_id = AD_CMD_MSG_INPUT_PENDING;
321: else
322: _dataPendingMessage->msg_id = AD_CMD_MSG_OUTPUT_PENDING;
323:
324: krtn = msg_send_from_kernel(_dataPendingMessage, SEND_TIMEOUT, 1000);
325: if (krtn != KERN_SUCCESS && krtn != SEND_TIMED_OUT)
326: IOLog("Audio: data pending msg_send error: %d\n", krtn);
327: }
328:
329:
330: /*
331: * The ioThread executes this method when a pending message arrives on the
332: * command port. The IOAudio subclass will ask each channel to see if
333: * stream requests are pending. When requests are pending, the device asks
334: * the channel to make a dma buffer. If this operation is successful, the
335: * device initiates DMA for the channel. The implementation of this method
336: * is dependent on the number of DMA channels supported by the device. For
337: * example, when one channel is supported, DMA occurs in one direction until
338: * it is complete, then DMA is started in the other direction.
339: *
340: * See <newClasses/IOAudio.m> for a version which will support simultaneous
341: * transfer when 2 independent DMA channels are available.
342: */
343:
344: - (void) _dataPendingOccurred: (id) channel
345: {
346: if ([self isInputActive] || [self isOutputActive])
347: return;
348:
349: (void) [self _attemptToStartDMAForChannel: channel channelStatus: FALSE];
350: }
351:
352: /*
353: * The ioThread executes this method when an interrupt message arrives on
354: * the interrupt port.
355: */
356: - (void) _interruptOccurred
357: {
358: BOOL serviceInputChannel = FALSE;
359: BOOL serviceOutputChannel = FALSE;
360:
361: if (!runningExclusive ||
362: (runningExclusive && !exclusiveInterruptClearFunc))
363: [self interruptOccurredForInput: &serviceInputChannel
364: forOutput: &serviceOutputChannel];
365:
366: /*
367: * Private, exclusive dma mode.
368: */
369: if (runningExclusive)
370: return;
371:
372: xpr_audio_device("AD: _interruptOccurred\n",1,2,3,4,5);
373:
374: /*
375: * spurious interrupt
376: */
377: if (!serviceInputChannel && !serviceOutputChannel)
378: return;
379:
380: [self _setLastInterruptTimeStamp:_lastInterruptTime];
381:
382: if (serviceInputChannel)
383: (void)[self _attemptToStopDMAForChannel: [self _inputChannel]];
384:
385: if (serviceOutputChannel)
386: (void)[self _attemptToStopDMAForChannel: [self _outputChannel]];
387:
388: xpr_audio_device("AD: interrupt serviced\n",1,2,3,4,5);
389: }
390:
391: /*
392: * The ioThread executes this method when a command message arrives on the
393: * command port.
394: */
395: - (void) _commandOccurred
396: {
397: int command = [[self _audioCommand] command];
398: int result = 1;
399:
400: switch (command) {
401:
402: case setDeviceInputGainLeft:
403: [self updateInputGainLeft];
404: [[self _audioCommand] done: result];
405: break;
406:
407: case setDeviceInputGainRight:
408: [self updateInputGainRight];
409: [[self _audioCommand] done: result];
410: break;
411:
412: case setDeviceOutputMute:
413: [self updateOutputMute];
414: [[self _audioCommand] done: result];
415: break;
416:
417: case setDeviceOutputAttenuationLeft:
418: [self updateOutputAttenuationLeft];
419: [[self _audioCommand] done: result];
420: break;
421:
422: case setDeviceOutputAttenuationRight:
423: [self updateOutputAttenuationRight];
424: [[self _audioCommand] done: result];
425: break;
426:
427: case setDeviceLoudness:
428: [self updateLoudnessEnhanced];
429: [[self _audioCommand] done: result];
430: break;
431:
432: case abortInputChannel:
433: if ([self isInputActive])
434: [self _stopDMAForChannel: [self _inputChannel]];
435: [[self _audioCommand] done: result];
436: break;
437:
438: case abortOutputChannel:
439: if ([self isOutputActive])
440: [self _stopDMAForChannel: [self _outputChannel]];
441: [[self _audioCommand] done: result];
442: break;
443:
444: case setDeviceInputMicEnable:
445: [self setInput:NX_SoundDeviceMicIn enable: YES];
446: [[self _audioCommand] done: result];
447: break;
448:
449: case setDeviceInputMicDisable:
450: [self setInput:NX_SoundDeviceMicIn enable: NO];
451: [[self _audioCommand] done: result];
452: break;
453:
454: case setDeviceInputLineEnable:
455: [self setInput:NX_SoundDeviceLineIn enable: YES];
456: [[self _audioCommand] done: result];
457: break;
458:
459: case setDeviceInputLineDisable:
460: [self setInput:NX_SoundDeviceLineIn enable: NO];
461: [[self _audioCommand] done: result];
462: break;
463:
464: case setDeviceInputCDEnable:
465: [self setInput:NX_SoundDeviceCDIn enable: YES];
466: [[self _audioCommand] done: result];
467: break;
468:
469: case setDeviceInputCDDisable:
470: [self setInput:NX_SoundDeviceCDIn enable: NO];
471: [[self _audioCommand] done: result];
472: break;
473:
474: case setDeviceInputAux1Enable:
475: [self setInput:NX_SoundDeviceAux1In enable: YES];
476: [[self _audioCommand] done: result];
477: break;
478:
479: case setDeviceInputAux1Disable:
480: [self setInput:NX_SoundDeviceAux1In enable: NO];
481: [[self _audioCommand] done: result];
482: break;
483:
484: case setDeviceInputAux2Enable:
485: [self setInput:NX_SoundDeviceAux2In enable: YES];
486: [[self _audioCommand] done: result];
487: break;
488:
489: case setDeviceInputAux2Disable:
490: [self setInput:NX_SoundDeviceAux2In enable: NO];
491: [[self _audioCommand] done: result];
492: break;
493:
494: case setDeviceOutputLineEnable:
495: [self setOutput:NX_SoundDeviceLineOut enable: YES];
496: [[self _audioCommand] done: result];
497: break;
498:
499: case setDeviceOutputLineDisable:
500: [self setOutput:NX_SoundDeviceLineOut enable: NO];
501: [[self _audioCommand] done: result];
502: break;
503:
504: case setDeviceOutputSpeakerEnable:
505: [self setOutput:NX_SoundDeviceSpeakerOut enable: YES];
506: [[self _audioCommand] done: result];
507: break;
508:
509: case setDeviceOutputSpeakerDisable:
510: [self setOutput:NX_SoundDeviceSpeakerOut enable: NO];
511: [[self _audioCommand] done: result];
512: break;
513:
514: case setDeviceOutputCDEnable:
515: [self setOutput:NX_SoundDeviceCDOut enable: YES];
516: [[self _audioCommand] done: result];
517: break;
518:
519: case setDeviceOutputCDDisable:
520: [self setOutput:NX_SoundDeviceCDOut enable: NO];
521: [[self _audioCommand] done: result];
522: break;
523:
524: case setDeviceOutputAux1Enable:
525: [self setOutput:NX_SoundDeviceAux1Out enable: YES];
526: [[self _audioCommand] done: result];
527: break;
528:
529: case setDeviceOutputAux1Disable:
530: [self setOutput:NX_SoundDeviceAux1Out enable: NO];
531: [[self _audioCommand] done: result];
532: break;
533:
534: case setDeviceOutputAux2Enable:
535: [self setOutput:NX_SoundDeviceAux2Out enable: YES];
536: [[self _audioCommand] done: result];
537: break;
538:
539: case setDeviceOutputAux2Disable:
540: [self setOutput:NX_SoundDeviceAux2Out enable: NO];
541: [[self _audioCommand] done: result];
542: break;
543:
544: default:
545: // error message?
546: [[self _audioCommand] done: result];
547: break;
548: }
549: }
550:
551: /*
552: *
553: */
554: - (void) _setTimeout: (unsigned int)milliseconds
555: {
556: _timeout = milliseconds;
557: }
558:
559: /*
560: *
561: */
562: - (unsigned int) _timeout
563: {
564: return _timeout;
565: }
566:
567: - (port_set_name_t) _devicePortSet
568: {
569: return _devicePortSet;
570: }
571:
572: - (void) _setLastInterruptTimeStamp: (ns_time_t)startTime
573: {
574: ((_audioPrivateData *) _audioPrivate)->_timestampBuffer =
575: _lastInterruptTime;
576: }
577:
578: - (ns_time_t) _lastInterruptTimeStamp
579: {
580: return ((_audioPrivateData *)_audioPrivate)->_timestampBuffer;
581: }
582:
583: - (void) _setOutputStartTime: (ns_time_t)startTime
584: {
585: ((_audioPrivateData *)_audioPrivate)->_outputStartTime = startTime;
586: }
587:
588: - (ns_time_t) _outputStartTime
589: {
590: return ((_audioPrivateData *)_audioPrivate)->_outputStartTime;
591: }
592:
593: #if hppa
594: static int audio_first =0;
595: #endif hppa
596:
597: - (BOOL) _attemptToStartDMAForChannel: (id)channel channelStatus:(BOOL) isChannelActive
598: {
599: int i;
600: /*
601: * When isChannelActive is NO, the streams are allowed to change the
602: * sample rate, data format, and channel count
603: */
604: int rate = 0;
605: IOAudioDataFormat format = IOAudioDataFormatUnset;
606: unsigned int count = 0;
607: BOOL didStart = NO;
608: ns_time_t startTime;
609: #if defined(hppa) || defined(sparc)
610: vm_offset_t addr;
611: #endif
612:
613: if ( [self _is22KRateSupported] == NO )
614: {
615: rate = 44100;
616: }
617:
618: if (isChannelActive) {
619: rate = [self sampleRate];
620: //format = [self dataFormat];
621: format = _dataEncoding; // encoding FIXME
622: count = [self channelCount];
623: }
624:
625: /*
626: * Enqueue only half of the needed descriptors.
627: */
628: for (i = 0; i < [channel dmaCount] / 2; i++) {
629: if (![channel enqueueDescriptor:&rate dataFormat:&format
630: channelCount:&count])
631: break;
632: }
633:
634: #if hppa
635: audio_first = 1;
636: #endif hppa
637:
638: if ([channel enqueueCount]) {
639: [self _setSampleRate: rate];
640: [self _setDataEncoding: format];
641: [self _setChannelCount: count];
642:
643: #if defined(hppa) || defined(sparc)
644: addr = (vm_offset_t)[channel channelBuffer];
645: #if hppa
646: pmap_flush_range(kernel_pmap,addr, [channel enqueueCount] * 4096 );
647: #endif
648: didStart = [self startDMAForChannel: [channel localChannel]
649: read: [channel isRead]
650: buffer: (void *)addr // beacuse kernel is 1-1 mapped
651: bufferSizeForInterrupts: [channel descriptorSize]];
652: #else hppa
653: didStart = [self startDMAForChannel: [channel localChannel]
654: read: [channel isRead]
655: buffer: [channel channelBuffer]
656: bufferSizeForInterrupts: [channel descriptorSize]];
657: #endif hppa
658:
659: if (didStart) {
660: IOGetTimestamp(&startTime);
661: [self _setOutputStartTime: startTime];
662:
663: if ([channel isRead])
664: [self _setInputActive: YES];
665: else
666: [self _setOutputActive: YES];
667:
668: if ([self _timeout] == IOAUDIO_MAXIMUM_TIMEOUT)
669: // Assume worst case for interrupt timeouts (1K mono data)
670: [self _setTimeout:[channel descriptorSize]];
671: } else {
672: while ([channel enqueueCount])
673: [channel dequeueDescriptor];
674:
675: // FIXME: The channel never ran.
676: [self stopDMAForChannel:[channel localChannel]
677: read:[channel isRead]];
678: [channel freeDescriptors];
679: [self _setTimeout: IOAUDIO_MAXIMUM_TIMEOUT];
680: }
681: }
682:
683: return didStart;
684: }
685:
686: - (BOOL) _attemptToStopDMAForChannel: (id)channel
687: {
688: unsigned int rate = [self sampleRate];
689: IOAudioDataFormat format = _dataEncoding; // FIXME : [self dataEncoding]
690: unsigned int count = [self channelCount];
691:
692: xpr_audio_device("AD: _attemptToStopDMAForChannel\n",1,2,3,4,5);
693:
694: #if hppa
695: if (audio_first) {
696: audio_first= 0;
697: return;
698: }
699: #endif hppa
700:
701: /*
702: * We should not try to dequeue if nothing is enqueued.
703: */
704: if ([channel enqueueCount]) {
705: [channel dequeueDescriptor];
706: } else {
707: xpr_audio_device("AD: interrupt received but no descriptors enqueued!\n",1,2,3,4,5);
708: }
709:
710: xpr_audio_device("AD: descriptors dequeued\n",1,2,3,4,5);
711:
712: /*
713: * Checks to see if more data is available from the channel.
714: */
715: if (! [channel enqueueDescriptor: &rate dataFormat: &format channelCount: &count]) {
716: if (! [channel enqueueCount]) {
717: [self _stopDMAForChannel: (id)channel];
718: [self _setOutputStartTime: 0];
719: [self _setLastInterruptTimeStamp:0];
720:
721: xpr_audio_device("AD: no more descriptors\n",1,2,3,4,5);
722: return TRUE;
723: }
724: }
725: xpr_audio_device("AD: new descriptors enqueued\n",1,2,3,4,5);
726:
727: return FALSE;
728:
729: }
730:
731:
732: - (void) _stopDMAForChannel: (id)channel
733: {
734: [self stopDMAForChannel: [channel localChannel] read: [channel isRead]];
735:
736: [channel freeDescriptors];
737:
738: if ([channel isRead])
739: [self _setInputActive: NO];
740: else
741: [self _setOutputActive: NO];
742:
743: if (! [self isInputActive] && ! [self isOutputActive])
744: [self _setTimeout: IOAUDIO_MAXIMUM_TIMEOUT];
745: }
746:
747:
748: - (BOOL) _is22KRateSupported
749: {
750: int lowRate, highRate;
751:
752: if ( [self acceptsContinuousSamplingRates] == NO )
753: {
754: [self getSamplingRatesLow: &lowRate high: &highRate];
755: return ((lowRate > 22050) ? NO : YES);
756: }
757: return YES;
758: }
759:
760: /*
761: * Respond to sound key events.
762: */
763: - (void) _keyOccurred:(int)key event:(int)direction flags:(int)flags
764: {
765: BOOL up = NO, down = NO;
766: BOOL mute = NO;
767: int left, right;
768:
769: if (direction != NX_KEYDOWN)
770: return;
771:
772: if (key == NX_KEYTYPE_SOUND_UP) {
773: if (!(flags & NX_COMMANDMASK))
774: up = YES;
775: } else if (key == NX_KEYTYPE_SOUND_DOWN) {
776: if (flags & NX_COMMANDMASK)
777: mute = YES;
778: else
779: down = YES;
780: }
781:
782: if (!(flags & NX_SHIFTMASK)) {
783:
784: if (mute) {
785: [self _setOutputMute: ! [self isOutputMuted]];
786: return;
787: }
788:
789: left = [self outputAttenuationLeft];
790: right = [self outputAttenuationRight];
791: if (up) {
792: left += 1;
793: if (left > 0)
794: left = 0;
795: right += 1;
796: if (right > 0)
797: right = 0;
798: } else if (down) {
799: left -= 1;
800: if (left < -84)
801: left = -84;
802: right -= 1;
803: if (right < -84)
804: right = -84;
805: }
806: [self _setOutputAttenuationLeft: left];
807: [self _setOutputAttenuationRight: right];
808: } else {
809: left = [self inputGainLeft];
810: right = [self inputGainRight];
811: if (up) {
812: left += 1638; // same as 32768/20
813: if (left >= 32768)
814: left = 32768;
815: right += 1638;
816: if (right >= 32768)
817: right = 32768;
818: } else if (down) {
819: left -= 1638;
820: if (left <= 0)
821: left = 0;
822: right -= 1638;
823: if (right <= 0)
824: right = 0;
825: }
826: [self _setInputGainLeft: left];
827: [self _setInputGainRight: right];
828: }
829: }
830:
831: - (void) _setInputGainLeft:(unsigned int)gain
832: {
833: _inputGainLeft = gain;
834: [[self _audioCommand] send: setDeviceInputGainLeft];
835: }
836:
837: - (void) _setInputGainRight:(unsigned int)gain
838: {
839: _inputGainRight = gain;
840: [[self _audioCommand] send: setDeviceInputGainRight];
841: }
842:
843: - (void) _setOutputMute:(BOOL)flag
844: {
845: _isOutputMuted = flag;
846: [[self _audioCommand] send: setDeviceOutputMute];
847: }
848:
849: - (void) _setLoudnessEnhanced:(BOOL)flag
850: {
851: _isLoudnessEnhanced = flag;
852: [[self _audioCommand] send: setDeviceLoudness];
853: }
854:
855: - (void) _setOutputAttenuationLeft:(int)attenuation
856: {
857: _outputAttenuationLeft = attenuation;
858: [[self _audioCommand] send: setDeviceOutputAttenuationLeft];
859: }
860:
861: - (void) _setOutputAttenuationRight:(int)attenuation
862: {
863: _outputAttenuationRight = attenuation;
864: [[self _audioCommand] send: setDeviceOutputAttenuationRight];
865: }
866:
867: - (void) _setInputActive: (BOOL) isActive
868: {
869: _isInputActive = isActive;
870: }
871:
872: - (void) _setOutputActive: (BOOL) isActive
873: {
874: _isOutputActive = isActive;
875: }
876:
877: - (void) _setInputFor:(NXSoundParameterTag)ptag to:(BOOL)enable
878: {
879: switch (ptag) {
880: case NX_SoundDeviceMicIn:
881: ((_audioPrivateData *) _audioPrivate)->_enableMicIn = enable;
882: [[self _audioCommand] send: (enable) ?
883: setDeviceInputMicEnable : setDeviceInputMicDisable];
884: break;
885: case NX_SoundDeviceLineIn:
886: ((_audioPrivateData *) _audioPrivate)->_enableLineIn = enable;
887: [[self _audioCommand] send: (enable) ?
888: setDeviceInputLineEnable : setDeviceInputLineDisable];
889: break;
890: case NX_SoundDeviceCDIn:
891: ((_audioPrivateData *) _audioPrivate)->_enableCDIn = enable;
892: [[self _audioCommand] send: (enable) ?
893: setDeviceInputCDEnable : setDeviceInputCDDisable];
894: break;
895: case NX_SoundDeviceAux1In:
896: ((_audioPrivateData *) _audioPrivate)->_enableAux1In = enable;
897: [[self _audioCommand] send: (enable) ?
898: setDeviceInputAux1Enable : setDeviceInputAux1Disable];
899: break;
900: case NX_SoundDeviceAux2In:
901: ((_audioPrivateData *) _audioPrivate)->_enableAux2In = enable;
902: [[self _audioCommand] send: (enable) ?
903: setDeviceInputAux2Enable : setDeviceInputAux2Disable];
904: break;
905: default:
906: IOLog("Audio: unknown input source: %d\n", (int)ptag);
907: break;
908: }
909: }
910:
911: - (void) _setOutputFor:(NXSoundParameterTag)ptag to:(BOOL)enable
912: {
913: switch (ptag) {
914: case NX_SoundDeviceSpeakerOut:
915: ((_audioPrivateData *) _audioPrivate)->_enableSpeakerOut = enable;
916: [[self _audioCommand] send: (enable) ?
917: setDeviceOutputSpeakerEnable : setDeviceOutputSpeakerDisable];
918: break;
919: case NX_SoundDeviceLineOut:
920: ((_audioPrivateData *) _audioPrivate)->_enableLineOut = enable;
921: [[self _audioCommand] send: (enable) ?
922: setDeviceOutputLineEnable : setDeviceOutputLineDisable];
923: break;
924: case NX_SoundDeviceCDOut:
925: ((_audioPrivateData *) _audioPrivate)->_enableCDOut = enable;
926: [[self _audioCommand] send: (enable) ?
927: setDeviceOutputCDEnable : setDeviceOutputCDDisable];
928: break;
929: case NX_SoundDeviceAux1Out:
930: ((_audioPrivateData *) _audioPrivate)->_enableAux1Out = enable;
931: [[self _audioCommand] send: (enable) ?
932: setDeviceOutputAux1Enable : setDeviceOutputAux1Disable];
933: break;
934: case NX_SoundDeviceAux2Out:
935: ((_audioPrivateData *) _audioPrivate)->_enableAux2Out = enable;
936: [[self _audioCommand] send: (enable) ?
937: setDeviceOutputAux2Enable : setDeviceOutputAux2Disable];
938: break;
939: default:
940: IOLog("Audio: unknown output source: %d\n", (int)ptag);
941: break;
942: }
943: }
944:
945:
946: - (NXSoundParameterTag)_analogInputSource
947: {
948: if (((_audioPrivateData *) _audioPrivate)->_enableMicIn)
949: return NX_SoundDeviceMicIn;
950: else if (((_audioPrivateData *) _audioPrivate)->_enableLineIn)
951: return NX_SoundDeviceAux1In;
952: else if (((_audioPrivateData *) _audioPrivate)->_enableCDIn)
953: return NX_SoundDeviceAux1In;
954: else if (((_audioPrivateData *) _audioPrivate)->_enableAux1In)
955: return NX_SoundDeviceAux1In;
956: else if (((_audioPrivateData *) _audioPrivate)->_enableAux2In)
957: return NX_SoundDeviceAux2In;
958: else
959: return 0;
960: }
961:
962: - (void)_setAnalogInputSource:(NXSoundParameterTag)ptag
963: {
964: [self _setInputFor:NX_SoundDeviceMicIn to:NO];
965: [self _setInputFor:NX_SoundDeviceLineIn to:NO];
966: [self _setInputFor:NX_SoundDeviceCDIn to:NO];
967: [self _setInputFor:NX_SoundDeviceAux1In to:NO];
968: [self _setInputFor:NX_SoundDeviceAux2In to:NO];
969: [self _setInputFor:ptag to:YES];
970: }
971:
972:
973: /*
974: * FIXME: really device-dependent
975: */
976: - (int)_intValueForParameter: (NXSoundParameterTag)ptag
977: forObject: anObject
978: {
979: int val = 0;
980:
981: if ([anObject isEqual: [self _inputChannel]]) {
982: switch (ptag) {
983: case NX_SoundDeviceBufferSize:
984: val = [anObject descriptorSize];
985: break;
986: case NX_SoundDeviceBufferCount:
987: val = [anObject dmaCount];
988: break;
989: case NX_SoundDeviceDetectPeaks:
990: val = (int)[anObject isDetectingPeaks];
991: break;
992: case NX_SoundDeviceAnalogInputSource:
993: val = (int)[self _analogInputSource];
994: break;
995: case NX_SoundDeviceInputGainStereo:
996: val = (int)(([self inputGainLeft] + [self inputGainRight]) / 2);
997: break;
998: case NX_SoundDeviceInputGainLeft:
999: val = (int)[self inputGainLeft];
1000: break;
1001: case NX_SoundDeviceInputGainRight:
1002: val = (int)[self inputGainRight];
1003: break;
1004: case NX_SoundDeviceMicIn:
1005: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableMicIn;
1006: break;
1007: case NX_SoundDeviceLineIn:
1008: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableLineIn;
1009: break;
1010: case NX_SoundDeviceCDIn:
1011: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableCDIn;
1012: break;
1013: case NX_SoundDeviceAux1In:
1014: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableAux1In;
1015: break;
1016: case NX_SoundDeviceAux2In:
1017: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableAux2In;
1018: break;
1019: default:
1020: break;
1021: }
1022: } else if ([anObject isEqual: [self _outputChannel]]) {
1023: switch (ptag) {
1024: case NX_SoundDeviceBufferSize:
1025: val = [anObject descriptorSize];
1026: break;
1027: case NX_SoundDeviceBufferCount:
1028: val = [anObject dmaCount];
1029: break;
1030: case NX_SoundDeviceDetectPeaks:
1031: val = (int)[anObject isDetectingPeaks];
1032: break;
1033: case NX_SoundDeviceRampUp:
1034: val = NO; // FIXME (not implemented)
1035: break;
1036: case NX_SoundDeviceRampDown:
1037: val = NO; // FIXME (not implemented)
1038: break;
1039: case NX_SoundDeviceInsertZeros:
1040: val = NO; // FIXME (not implemented)
1041: break;
1042: case NX_SoundDeviceDeemphasize:
1043: val = NO; // FIXME (not implemented)
1044: break;
1045: case NX_SoundDeviceMuteSpeaker:
1046: case NX_SoundDeviceMuteHeadphone:
1047: case NX_SoundDeviceMuteLineOut:
1048: val = (int)[self isOutputMuted];
1049: break;
1050: case NX_SoundDeviceOutputLoudness:
1051: val = (int)[self isLoudnessEnhanced];
1052: break;
1053: case NX_SoundDeviceOutputAttenuationStereo:
1054: val = ([self outputAttenuationLeft] +
1055: [self outputAttenuationRight]) / 2;
1056: break;
1057: case NX_SoundDeviceOutputAttenuationLeft:
1058: val = [self outputAttenuationLeft];
1059: break;
1060: case NX_SoundDeviceOutputAttenuationRight:
1061: val = [self outputAttenuationRight];
1062: break;
1063: case NX_SoundDeviceSpeakerOut:
1064: val= (int)((_audioPrivateData *) _audioPrivate)->_enableSpeakerOut;
1065: break;
1066: case NX_SoundDeviceLineOut:
1067: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableLineOut;
1068: break;
1069: case NX_SoundDeviceCDOut:
1070: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableCDOut;
1071: break;
1072: case NX_SoundDeviceAux1Out:
1073: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableAux1Out;
1074: break;
1075: case NX_SoundDeviceAux2Out:
1076: val = (int) ((_audioPrivateData *) _audioPrivate)->_enableAux2Out;
1077: break;
1078: default:
1079: break;
1080: }
1081: } else if ([anObject isKindOf:[InputStream class]]) {
1082: switch (ptag) {
1083: case NX_SoundStreamDataEncoding:
1084: val = (int)[anObject dataEncoding];
1085: break;
1086: case NX_SoundStreamSamplingRate:
1087: val = [anObject samplingRate];
1088: break;
1089: case NX_SoundStreamChannelCount:
1090: val = [anObject channelCount];
1091: break;
1092: case NX_SoundStreamHighWaterMark:
1093: val = [anObject highWaterMark];
1094: break;
1095: case NX_SoundStreamLowWaterMark:
1096: val = [anObject lowWaterMark];
1097: break;
1098: case NX_SoundStreamSource:
1099: val = NX_SoundStreamSource_Analog;
1100: break;
1101: default:
1102: break;
1103: }
1104: } else if ([anObject isKindOf:[OutputStream class]]) {
1105: switch (ptag) {
1106: case NX_SoundStreamDataEncoding:
1107: val = (int)[anObject dataEncoding];
1108: break;
1109: case NX_SoundStreamSamplingRate:
1110: val = [anObject samplingRate];
1111: break;
1112: case NX_SoundStreamChannelCount:
1113: val = [anObject channelCount];
1114: break;
1115: case NX_SoundStreamHighWaterMark:
1116: val = [anObject highWaterMark];
1117: break;
1118: case NX_SoundStreamLowWaterMark:
1119: val = [anObject lowWaterMark];
1120: break;
1121: case NX_SoundStreamSink:
1122: val = NX_SoundStreamSink_Analog;
1123: break;
1124: case NX_SoundStreamDetectPeaks:
1125: val = (int)[anObject isDetectingPeaks];
1126: break;
1127: case NX_SoundStreamGainStereo:
1128: val = ([anObject gainLeft] + [anObject gainRight]) / 2;
1129: break;
1130: case NX_SoundStreamGainLeft:
1131: val = [anObject gainLeft];
1132: break;
1133: case NX_SoundStreamGainRight:
1134: val = [anObject gainRight];
1135: break;
1136: default:
1137: break;
1138: }
1139: } else {
1140: IOLog("Audio: unknown parameter object\n");
1141: return 0;
1142: }
1143: return val;
1144: }
1145:
1146: - (BOOL) _setParameter: (NXSoundParameterTag)ptag
1147: toInt: (int)value
1148: forObject: anObject
1149: {
1150: BOOL ret = YES;
1151:
1152: if ([anObject isEqual: [self _inputChannel]]) {
1153: switch (ptag) {
1154: case NX_SoundDeviceBufferSize:
1155: /*
1156: * FIXME: currently not settable
1157: * [anObject setDescriptorSize:value];
1158: */
1159: break;
1160: case NX_SoundDeviceBufferCount:
1161: /*
1162: * FIXME: currently not settable
1163: * [anObject setDmaCount:value];
1164: */
1165: break;
1166: case NX_SoundDeviceDetectPeaks:
1167: [anObject setDetectPeaks:(BOOL)value];
1168: break;
1169: case NX_SoundDeviceInputGainStereo:
1170: [self _setInputGainLeft:(unsigned int)value];
1171: [self _setInputGainRight:(unsigned int)value];
1172: break;
1173: case NX_SoundDeviceInputGainLeft:
1174: [self _setInputGainLeft:(unsigned int)value];
1175: break;
1176: case NX_SoundDeviceAnalogInputSource:
1177: [self _setAnalogInputSource:(NXSoundParameterTag)value];
1178: break;
1179: // Enable and disable individual input sources
1180: case NX_SoundDeviceMicIn:
1181: case NX_SoundDeviceLineIn:
1182: case NX_SoundDeviceCDIn:
1183: case NX_SoundDeviceAux1In:
1184: case NX_SoundDeviceAux2In:
1185: [self _setInputFor:ptag to:(BOOL)value];
1186: break;
1187: default:
1188: ret = NO;
1189: break;
1190: }
1191: } else if ([anObject isEqual: [self _outputChannel]]) {
1192: switch (ptag) {
1193: case NX_SoundDeviceBufferSize:
1194: /*
1195: * FIXME: currently not settable
1196: * [anObject setDescriptorSize:value];
1197: */
1198: break;
1199: case NX_SoundDeviceBufferCount:
1200: /*
1201: * FIXME: currently not settable
1202: * [anObject setDmaCount:value];
1203: */
1204: break;
1205: case NX_SoundDeviceDetectPeaks:
1206: [anObject setDetectPeaks:(BOOL)value];
1207: break;
1208: case NX_SoundDeviceRampUp:
1209: //[self setRampsUp:(BOOL)value]; // FIXME
1210: break;
1211: case NX_SoundDeviceRampDown:
1212: //[self setRampsDown:(BOOL)value]; // FIXME
1213: break;
1214: case NX_SoundDeviceInsertZeros:
1215: //[self _setInsertsZeros:(BOOL)value]; // FIXME
1216: break;
1217: case NX_SoundDeviceDeemphasize:
1218: //[self _setDeemphasis:(BOOL)value]; // FIXME
1219: break;
1220: case NX_SoundDeviceMuteSpeaker:
1221: case NX_SoundDeviceMuteHeadphone:
1222: case NX_SoundDeviceMuteLineOut:
1223: [self _setOutputMute:(BOOL)value];
1224: break;
1225: case NX_SoundDeviceOutputLoudness:
1226: [self _setLoudnessEnhanced:(BOOL)value];
1227: break;
1228: case NX_SoundDeviceOutputAttenuationStereo:
1229: [self _setOutputAttenuationLeft:value];
1230: [self _setOutputAttenuationRight:value];
1231: break;
1232: case NX_SoundDeviceOutputAttenuationLeft:
1233: [self _setOutputAttenuationLeft:value];
1234: break;
1235: case NX_SoundDeviceOutputAttenuationRight:
1236: [self _setOutputAttenuationRight:value];
1237: break;
1238: // Enable and disable individual output sources
1239: case NX_SoundDeviceSpeakerOut:
1240: case NX_SoundDeviceLineOut:
1241: case NX_SoundDeviceCDOut:
1242: case NX_SoundDeviceAux1Out:
1243: case NX_SoundDeviceAux2Out:
1244: [self _setOutputFor:ptag to:(BOOL)value];
1245: break;
1246: default:
1247: ret = NO;
1248: break;
1249: }
1250: } else if ([anObject isKindOf:[InputStream class]]) {
1251: switch (ptag) {
1252: case NX_SoundStreamDataEncoding:
1253: [anObject setDataEncoding:(NXSoundParameterTag)value];
1254: break;
1255: case NX_SoundStreamSamplingRate:
1256: [anObject setSamplingRate:value];
1257: break;
1258: case NX_SoundStreamChannelCount:
1259: [anObject setChannelCount:value];
1260: break;
1261: case NX_SoundStreamHighWaterMark:
1262: [anObject setHighWaterMark:value];
1263: break;
1264: case NX_SoundStreamLowWaterMark:
1265: [anObject setLowWaterMark:value];
1266: break;
1267: case NX_SoundStreamSource:
1268: if (value != NX_SoundStreamSource_Analog)
1269: ret = NO;
1270: break;
1271: default:
1272: ret = NO;
1273: break;
1274: }
1275: } else if ([anObject isKindOf:[OutputStream class]]) {
1276: switch (ptag) {
1277: case NX_SoundStreamDataEncoding:
1278: [anObject setDataEncoding:(NXSoundParameterTag)value];
1279: break;
1280: case NX_SoundStreamSamplingRate:
1281: [anObject setSamplingRate:value];
1282: break;
1283: case NX_SoundStreamChannelCount:
1284: [anObject setChannelCount:value];
1285: break;
1286: case NX_SoundStreamHighWaterMark:
1287: [anObject setHighWaterMark:value];
1288: break;
1289: case NX_SoundStreamLowWaterMark:
1290: [anObject setLowWaterMark:value];
1291: break;
1292: case NX_SoundStreamSink:
1293: if (value != NX_SoundStreamSink_Analog)
1294: ret = NO;
1295: break;
1296: case NX_SoundStreamDetectPeaks:
1297: [anObject setDetectPeaks:(BOOL)value];
1298: break;
1299: case NX_SoundStreamGainStereo:
1300: [anObject setGainLeft:value];
1301: [anObject setGainRight:value];
1302: break;
1303: case NX_SoundStreamGainLeft:
1304: [anObject setGainLeft:value];
1305: break;
1306: case NX_SoundStreamGainRight:
1307: [anObject setGainRight:value];
1308: break;
1309: default:
1310: ret = NO;
1311: break;
1312: }
1313: } else {
1314: IOLog("Audio: unknown parameter object\n");
1315: ret = NO;
1316: }
1317:
1318: return ret;
1319: }
1320:
1321:
1322: - (BOOL) _setParameters: (const NXSoundParameterTag *)plist
1323: toValues: (const unsigned int *)vlist
1324: count: (unsigned int)numParameters
1325: forObject: anObject
1326: {
1327: int i;
1328: BOOL ret = YES;
1329:
1330: for (i = 0; i < numParameters; i++)
1331: if (![self _setParameter:plist[i] toInt:vlist[i] forObject:anObject])
1332: ret = NO;
1333: return ret;
1334: }
1335:
1336: - (void) _getParameters: (const NXSoundParameterTag *)plist
1337: values: (unsigned int *)vlist
1338: count: (unsigned int)numParameters
1339: forObject: anObject
1340: {
1341: int i;
1342:
1343: for (i = 0; i < numParameters; i++)
1344: vlist[i] = [self _intValueForParameter:plist[i] forObject:anObject];
1345: }
1346:
1347: - (void) _getSupportedParameters: (NXSoundParameterTag *)list
1348: count: (unsigned int *)numParameters
1349: forObject: anObject
1350: {
1351: static const NXSoundParameterTag chan_out_params[] = {
1352: NX_SoundDeviceBufferSize,
1353: NX_SoundDeviceBufferCount,
1354: NX_SoundDeviceDetectPeaks,
1355: NX_SoundDeviceRampUp,
1356: NX_SoundDeviceRampDown,
1357: NX_SoundDeviceInsertZeros,
1358: NX_SoundDeviceDeemphasize,
1359: NX_SoundDeviceMuteSpeaker,
1360: NX_SoundDeviceMuteHeadphone,
1361: NX_SoundDeviceMuteLineOut,
1362: NX_SoundDeviceOutputLoudness,
1363: NX_SoundDeviceOutputAttenuationStereo,
1364: NX_SoundDeviceOutputAttenuationLeft,
1365: NX_SoundDeviceOutputAttenuationRight
1366: };
1367: static const NXSoundParameterTag chan_in_params[] = {
1368: NX_SoundDeviceBufferSize,
1369: NX_SoundDeviceBufferCount,
1370: NX_SoundDeviceDetectPeaks,
1371: NX_SoundDeviceAnalogInputSource,
1372: NX_SoundDeviceInputGainStereo,
1373: NX_SoundDeviceInputGainLeft,
1374: NX_SoundDeviceInputGainRight
1375: };
1376: static const NXSoundParameterTag stream_out_params[] = {
1377: NX_SoundStreamDataEncoding,
1378: NX_SoundStreamSamplingRate,
1379: NX_SoundStreamChannelCount,
1380: NX_SoundStreamHighWaterMark,
1381: NX_SoundStreamLowWaterMark,
1382: NX_SoundStreamSink,
1383: NX_SoundStreamDetectPeaks,
1384: NX_SoundStreamGainStereo,
1385: NX_SoundStreamGainLeft,
1386: NX_SoundStreamGainRight
1387: };
1388: static const NXSoundParameterTag stream_in_params[] = {
1389: NX_SoundStreamDataEncoding,
1390: NX_SoundStreamSamplingRate,
1391: NX_SoundStreamChannelCount,
1392: NX_SoundStreamHighWaterMark,
1393: NX_SoundStreamLowWaterMark,
1394: NX_SoundStreamSource
1395: };
1396: int i;
1397: const NXSoundParameterTag *plist = 0;
1398:
1399: *numParameters = 0;
1400: if ([anObject isEqual: [self _inputChannel]]) {
1401: plist = chan_in_params;
1402: *numParameters = sizeof(chan_in_params) / sizeof(NXSoundParameterTag);
1403: } else if ([anObject isEqual: [self _outputChannel]]) {
1404: plist = chan_out_params;
1405: *numParameters = sizeof(chan_out_params) / sizeof(NXSoundParameterTag);
1406: } else if ([anObject isKindOf:[InputStream class]]) {
1407: plist = stream_in_params;
1408: *numParameters = sizeof(stream_in_params) /
1409: sizeof(NXSoundParameterTag);
1410: } else if ([anObject isKindOf:[OutputStream class]]) {
1411: plist = stream_out_params;
1412: *numParameters = sizeof(stream_out_params) /
1413: sizeof(NXSoundParameterTag);
1414: } else {
1415: IOLog("Audio: unknown parameter object\n");
1416: }
1417:
1418: for (i = 0; i < *numParameters; i++)
1419: list[i] = plist[i];
1420: }
1421:
1422: - (BOOL) _getValues: (NXSoundParameterTag *)list
1423: count: (unsigned int *)numValues
1424: forParameter: (NXSoundParameterTag)ptag
1425: forObject: anObject
1426: {
1427: BOOL ret = YES;
1428:
1429: *numValues = 0;
1430:
1431: if ([anObject isEqual: [self _inputChannel]]) {
1432: switch (ptag) {
1433: case NX_SoundDeviceAnalogInputSource:
1434: *numValues = 2;
1435: list[0] = NX_SoundDeviceAnalogInputSource_Microphone;
1436: list[1] = NX_SoundDeviceAnalogInputSource_LineIn;
1437: break;
1438: default:
1439: ret = _NXAUDIO_ERR_PARAMETER;
1440: break;
1441: }
1442: } else if ([anObject isEqual: [self _outputChannel]]) {
1443: ret = NO;
1444: } else if ([anObject isKindOf:[InputStream class]]) {
1445: switch (ptag) {
1446: case NX_SoundStreamDataEncoding:
1447: /*
1448: * FIXME: should match device-dependent
1449: * getStreamDataEncodings.
1450: */
1451: *numValues = 4;
1452: list[0] = NX_SoundStreamDataEncoding_Linear16;
1453: list[1] = NX_SoundStreamDataEncoding_Linear8;
1454: list[2] = NX_SoundStreamDataEncoding_Mulaw8;
1455: list[3] = NX_SoundStreamDataEncoding_Alaw8;
1456: break;
1457: case NX_SoundStreamSource:
1458: *numValues = 1;
1459: list[0] = NX_SoundStreamSource_Analog;
1460: break;
1461: default:
1462: ret = NO;
1463: break;
1464: }
1465: } else if ([anObject isKindOf:[OutputStream class]]) {
1466: switch (ptag) {
1467: case NX_SoundStreamDataEncoding:
1468: /*
1469: * FIXME: should match device-dependent
1470: * getStreamDataEncodings.
1471: */
1472: *numValues = 4;
1473: list[0] = NX_SoundStreamDataEncoding_Linear16;
1474: list[1] = NX_SoundStreamDataEncoding_Linear8;
1475: list[2] = NX_SoundStreamDataEncoding_Mulaw8;
1476: list[3] = NX_SoundStreamDataEncoding_Alaw8;
1477: break;
1478: case NX_SoundStreamSink:
1479: *numValues = 1;
1480: list[0] = NX_SoundStreamSink_Analog;
1481: break;
1482: default:
1483: ret = NO;
1484: break;
1485: }
1486: } else {
1487: IOLog("Audio: unknown parameter object\n");
1488: ret = NO;
1489: }
1490:
1491: return ret;
1492: }
1493:
1494: /*
1495: * Initialize audio hardware with default values for gain, attenuation etc.
1496: */
1497: - (void) _initAudioHardwareSettings
1498: {
1499: [self _setInputGainRight:32768/2];
1500: [self _setInputGainRight:32768/2];
1501:
1502: [self _setOutputAttenuationLeft:-42];
1503: [self _setOutputAttenuationLeft:-42];
1504:
1505: // add more generic ones here
1506: }
1507:
1508:
1509: // Private hooks for NeXTTime.
1510:
1511: // The DMA buffer does not exist until the first stream is activated, and
1512: // it goes away when the last stream is deactivated. The app should do a
1513: // setExclusiveUse:YES, then activate a stream and not use it.
1514:
1515: - (void) _getOutputChannelBuffer:(vm_address_t *)addr
1516: size:(unsigned int *)byteCount
1517: {
1518: *addr = [_outputChannel channelBufferAddress];
1519: *byteCount = [_outputChannel descriptorSize] * [_outputChannel dmaCount];
1520: }
1521:
1522: // YES starts output DMA, NO stops it.
1523:
1524: - (void) _getInputChannelBuffer:(vm_address_t *)addr
1525: size:(unsigned int *)byteCount
1526: {
1527: *addr = [_inputChannel channelBufferAddress];
1528: *byteCount = [_inputChannel descriptorSize] * [_inputChannel dmaCount];
1529: }
1530:
1531: // YES starts output DMA, NO stops it.
1532:
1533: - (void) _runExclusiveOutputDMA:(BOOL)flag
1534: {
1535: #if defined(hppa) || defined(sparc)
1536: vm_offset_t addr;
1537: #endif
1538: if (flag == runningExclusive)
1539: return;
1540:
1541: if (flag) {
1542: exclusiveProgress = 0;
1543: exclusiveIncrement = [_outputChannel descriptorSize];
1544: exclusiveInterruptClearFunc = [self interruptClearFunc];
1545: #if defined(hppa) || defined(sparc)
1546: addr = (vm_offset_t)[_outputChannel channelBuffer];
1547: [self startDMAForChannel: [_outputChannel localChannel]
1548: read: NO
1549: buffer: (void *)addr
1550: bufferSizeForInterrupts: exclusiveIncrement];
1551: #else hppa
1552: [self startDMAForChannel: [_outputChannel localChannel]
1553: read: NO
1554: buffer: [_outputChannel channelBuffer]
1555: bufferSizeForInterrupts: exclusiveIncrement];
1556: #endif hppa
1557: } else
1558: [self stopDMAForChannel: [_outputChannel localChannel] read: NO];
1559:
1560: runningExclusive = flag;
1561: }
1562:
1563: // XXXX The following duplicates the above. Condense into 1 call,
1564: // with compat hook for NEXTIME if need be - pcd 6/95
1565: - (void) _runExclusiveInputDMA:(BOOL)flag
1566: {
1567: #if defined(hppa) || defined(sparc)
1568: vm_offset_t addr;
1569: #endif
1570: if (flag == runningExclusive)
1571: return;
1572:
1573: if (flag) {
1574: exclusiveProgress = 0;
1575: exclusiveIncrement = [_inputChannel descriptorSize];
1576: exclusiveInterruptClearFunc = [self interruptClearFunc];
1577: #if defined(hppa) || defined(sparc)
1578: addr = (vm_offset_t)[_inputChannel channelBuffer];
1579: [self startDMAForChannel: [_inputChannel localChannel]
1580: read: YES
1581: buffer: (void *)addr
1582: bufferSizeForInterrupts: exclusiveIncrement];
1583: #else hppa
1584: [self startDMAForChannel: [_inputChannel localChannel]
1585: read: YES
1586: buffer: [_inputChannel channelBuffer]
1587: bufferSizeForInterrupts: exclusiveIncrement];
1588: #endif hppa
1589: } else
1590: [self stopDMAForChannel: [_inputChannel localChannel] read: YES];
1591:
1592: runningExclusive = flag;
1593: }
1594: // XXX End duplicated code
1595:
1596:
1597: // Progress is in bytes. It gets reset to 0 when _runExclusiveDMA:YES
1598: // is called.
1599:
1600: - (unsigned long) _exclusiveProgress
1601: {
1602: return exclusiveProgress;
1603: }
1604:
1605: @end
1606:
1607:
1608: @implementation IOAudio
1609:
1610: - (IOAudioInterruptClearFunc) interruptClearFunc
1611: {
1612: return 0;
1613: }
1614:
1615: - initFromDeviceDescription:_description
1616: {
1617: int *channelList;
1618: IOConfigTable *configTable;
1619: const char *serverName;
1620: #define MAX_CLASS_NAME_LEN 256 /* FIXME */
1621: char instClassName[MAX_CLASS_NAME_LEN+1];
1622: const char *serverPostfix = "KernelServerInstance";
1623: id instClass;
1624: kern_server_t *kernServInst;
1625: IOThread thread;
1626: #if i386
1627: IOEISADeviceDescription *description = _description; // FIXME
1628: #elif hppa
1629: IOHPPADeviceDescription *description = _description; // FIXME
1630: #else
1631: id description = _description;
1632: #endif
1633:
1634: #ifdef hppa
1635: audio_pmap = (kernel_pmap);
1636: #endif
1637:
1638: if ([super initFromDeviceDescription:description] == nil)
1639: return nil;
1640:
1641: if ([self attachInterruptPort] != IO_R_SUCCESS) {
1642: return nil;
1643: }
1644:
1645: port_set_backlog(task_self(), [self interruptPort], PORT_BACKLOG_MAX);
1646:
1647: if ([self reset] == NO)
1648: return nil;
1649:
1650: [self _initAudioHardwareSettings];
1651:
1652: /*
1653: * Get the kernel server instance for the just-loaded reloc.
1654: */
1655: configTable = [description configTable];
1656: if (configTable == nil) {
1657: IOLog("Audio: no configTable\n");
1658: return nil;
1659: }
1660: serverName = [configTable valueForStringKey:"Server Name"];
1661: strncpy(instClassName, serverName,
1662: MAX_CLASS_NAME_LEN-strlen(serverPostfix));
1663: strcat(instClassName, serverPostfix);
1664: instClass = objc_lookUpClass(instClassName);
1665: if (instClass == nil) {
1666: IOLog("Audio: no kernel server instance class '%s'\n", instClassName);
1667: return nil;
1668: }
1669: kernServInst = [instClass kernelServerInstance];
1670: if (!kernServInst) {
1671: IOLog("Audio: no kernel server instance\n");
1672: return nil;
1673: }
1674: audioKernServInit(kernServInst);
1675: audio_makeIMuLawTab();
1676:
1677: _audioPrivate = (_audioPrivateData *) IOMalloc(sizeof(_audioPrivateData));
1678:
1679: #ifdef DDM_DEBUG
1680: IOInitDDM(AUDIO_NUM_XPR_BUFS);
1681: #endif DDM_DEBUG
1682:
1683: if ([IOAudio _instance] != nil)
1684: IOLog("Audio: replacing previously registered driver\n");
1685: [IOAudio _setInstance: self];
1686:
1687: /*
1688: * Initialize channel instances.
1689: */
1690: _inputChannel = [[AudioChannel alloc] initOnDevice: self read: TRUE];
1691: [IOAudio _addChannel: _inputChannel];
1692:
1693: _outputChannel = [[AudioChannel alloc] initOnDevice: self read: FALSE];
1694: [IOAudio _addChannel: _outputChannel];
1695:
1696: [_inputChannel setLocalChannel: 0];
1697:
1698: #ifdef i386
1699: if ([description numChannels] == 1) {
1700: IOLog("%s at dma channel %d irq %d\n",
1701: [self name],
1702: [description channel],
1703: [description interrupt]);
1704:
1705: [_outputChannel setLocalChannel:0];
1706: } else if ([description numChannels] == 2) {
1707: channelList = [description channelList];
1708: IOLog("%s at dma channels %d and %d irq %d\n",
1709: [self name],
1710: channelList[0], channelList[1],
1711: [description interrupt]);
1712:
1713: [_outputChannel setLocalChannel:1];
1714: }
1715: #else
1716: [_outputChannel setLocalChannel:0];
1717: #endif i386
1718:
1719: /*
1720: * The ioThread uses this port set to receive interrupt, soundkey, and
1721: * command messages.
1722: */
1723: _devicePortSet = allocatePortSet();
1724: addPort(_devicePortSet, [self interruptPort]);
1725:
1726: /*
1727: * A separate port is used to receive pending messages and synchronous
1728: * command messages from the channel instances. By ensuring that only
1729: * interrupt messages arrive at the interrupt port, the ioThread could
1730: * use port_status to see if additional interrupts are pending.
1731: */
1732: _commandPort = allocatePort();
1733: addPort(_devicePortSet, _commandPort);
1734: _commandPort = IOConvertPort(_commandPort, IO_KernelIOTask, IO_Kernel);
1735:
1736: /*
1737: * To Do: define reasonable default values for instance variables
1738: */
1739: _audioCommand = [[AudioCommand alloc] initPort: _commandPort];
1740:
1741: [self _setTimeout: IOAUDIO_MAXIMUM_TIMEOUT];
1742: thread = IOForkThread((IOThreadFunc)ioThread, (void *)self);
1743: (void) IOSetThreadPolicy(thread, POLICY_FIXEDPRI);
1744: (void) IOSetThreadPriority(thread, 30); /* XXX */
1745: (void)IOForkThread((IOThreadFunc)keyThread, (void *)self);
1746:
1747:
1748: /*
1749: * This should be after the ioThread fork to guarantee that
1750: * we are ready to receive device messages.
1751: */
1752: #ifdef hppa
1753: my_audioid = self;
1754: #endif
1755: [self registerDevice];
1756:
1757: return self;
1758: }
1759:
1760: /*
1761: * An IOAudio subclass will need to override this method to reset hardware
1762: * based on configuration information in the device description.
1763: */
1764: - (BOOL)reset
1765: {
1766: [self subclassResponsibility:_cmd];
1767: return NO;
1768: }
1769:
1770: /*
1771: * FIXME: free channels and kill threads
1772: */
1773: - free
1774: {
1775: [IOAudio _setInstance: nil];
1776: // FIXME: audio_freeIMuLawTab();
1777: IOFree(_audioPrivate, sizeof(_audioPrivateData));
1778: return [super free];
1779: }
1780:
1781: /*
1782: * returns the current sample rate
1783: */
1784: - (unsigned int) sampleRate
1785: {
1786: return _sampleRate;
1787: }
1788:
1789: /*
1790: * FIXME
1791: *
1792: * Why do we "remap" formats/encodings? Wouldn't it be simpler to use one set
1793: * of enums rather than performing translations? (bkr)
1794: *
1795: * It's just historical (see below). We can change everything over to
1796: * NXSoundParameterTags now if we want. (mminnick)
1797: *
1798: * 1. The orignial 68k sound/DSP driver used defines in the form SND_something.
1799: *
1800: * 2. The audio driver split from the DSP driver and started using _NXAUDIO.
1801: * The soundkit also used _NXAUDIO (non-public, of course). Since the DSP
1802: * driver had to communicate with the audio driver, it started converting SND
1803: * to _NXAUDIO.
1804: *
1805: * 3. The kit needed a public parameter interface, and thus was born
1806: * NXSoundParameterTags. The kit now uses an unfortunate combination of ptags
1807: * and _NXAUDIO.
1808: *
1809: * I think we should should flush IOAudio defines (at least where they overlap
1810: * with NXSoundParameterTags) from the exported interface and documentation.
1811: * We can change all of our internal code as well, although that is less
1812: * important.
1813: */
1814: - (NXSoundParameterTag) dataEncoding
1815: {
1816: switch (_dataEncoding) {
1817: case IOAudioDataFormatLinear16:
1818: return NX_SoundStreamDataEncoding_Linear16;
1819: case IOAudioDataFormatLinear8:
1820: return NX_SoundStreamDataEncoding_Linear8;
1821: case IOAudioDataFormatMulaw8:
1822: return NX_SoundStreamDataEncoding_Mulaw8;
1823: case IOAudioDataFormatAlaw8:
1824: return NX_SoundStreamDataEncoding_Alaw8;
1825: }
1826: }
1827:
1828: /*
1829: * returns the current channel count
1830: */
1831: - (unsigned int) channelCount
1832: {
1833: return _channelCount;
1834: }
1835:
1836: - (BOOL) isInputActive
1837: {
1838: return _isInputActive;
1839: }
1840:
1841: - (BOOL) isOutputActive
1842: {
1843: return _isOutputActive;
1844: }
1845:
1846: - (void) interruptOccurredForInput: (BOOL *) serviceInput
1847: forOutput: (BOOL *) serviceOutput
1848: {
1849: [self subclassResponsibility:_cmd];
1850: }
1851:
1852: /*
1853: * The ioThread executes this method when its msg_receive operation times out.
1854: * The IOAudio subclass might reset the hardware if a DMA operation is in
1855: * progress, but no interrupts are being received in the ioThread.
1856: */
1857: - (void) timeoutOccurred
1858: {
1859: xpr_audio_device("AD: time out occurred\n", 1,2,3,4,5);
1860: }
1861:
1862: - (BOOL) startDMAForChannel: (unsigned int) localChannel
1863: read: (BOOL) isRead
1864: buffer: (void *) buffer
1865: bufferSizeForInterrupts: (unsigned int) bufferSize
1866: {
1867: [self subclassResponsibility:_cmd];
1868: return NO;
1869: }
1870:
1871:
1872: - (void) stopDMAForChannel: (unsigned int) localChannel read: (BOOL) isRead
1873: {
1874: [self subclassResponsibility:_cmd];
1875: }
1876:
1877: - (void)getInputChannelBuffer: (void *)addr
1878: size: (unsigned int *)byteCount
1879: {
1880: * (vm_address_t *) addr = [_inputChannel channelBufferAddress];
1881: *byteCount = [_inputChannel descriptorSize] * [_inputChannel dmaCount];
1882: }
1883:
1884: - (void)getOutputChannelBuffer: (void *) addr
1885: size: (unsigned int *)byteCount
1886: {
1887: * (vm_address_t *) addr = [_outputChannel channelBufferAddress];
1888: *byteCount = [_outputChannel descriptorSize] * [_outputChannel dmaCount];
1889: }
1890:
1891: - (unsigned int)inputGainLeft
1892: {
1893: return _inputGainLeft;
1894: }
1895:
1896: - (unsigned int)inputGainRight
1897: {
1898: return _inputGainRight;
1899: }
1900:
1901: - (int)outputAttenuationLeft
1902: {
1903: return _outputAttenuationLeft;
1904: }
1905:
1906: - (int)outputAttenuationRight
1907: {
1908: return _outputAttenuationRight;
1909: }
1910:
1911: - (BOOL)isOutputMuted
1912: {
1913: return _isOutputMuted;
1914: }
1915:
1916: - (BOOL)isLoudnessEnhanced
1917: {
1918: return _isLoudnessEnhanced;
1919: }
1920:
1921: - (void) updateLoudnessEnhanced
1922: {
1923:
1924: }
1925:
1926: - (void) updateInputGainLeft
1927: {
1928:
1929: }
1930:
1931: - (void) updateInputGainRight
1932: {
1933:
1934: }
1935:
1936: - (void) updateOutputMute
1937: {
1938:
1939: }
1940:
1941: - (void) updateOutputAttenuationLeft
1942: {
1943:
1944: }
1945:
1946: - (void) updateOutputAttenuationRight
1947: {
1948:
1949: }
1950:
1951: - (void) setInput:(NXSoundParameterTag)ptag enable:(BOOL)enable
1952: {
1953: }
1954:
1955: - (void) setOutput:(NXSoundParameterTag)ptag enable:(BOOL)enable
1956: {
1957: }
1958:
1959:
1960: /*
1961: * Parameter access.
1962: */
1963:
1964: - (BOOL) acceptsContinuousSamplingRates
1965: {
1966: return NO;
1967: }
1968:
1969: - (void) getSamplingRatesLow: (int *)lowRate
1970: high: (int *)highRate
1971: {
1972: *lowRate = *highRate = 0;
1973: }
1974:
1975: - (void)getSamplingRates: (int *)rates
1976: count: (unsigned int *)numRates
1977: {
1978: *numRates = 0;
1979: }
1980: - (void)getDataEncodings: (NXSoundParameterTag *)encodings
1981: count: (unsigned int *)numEncodings
1982: {
1983: *numEncodings = 0;
1984: }
1985:
1986: - (unsigned int) channelCountLimit
1987: {
1988: return 0;
1989: }
1990:
1991: #if hppa
1992: - (BOOL) getHandler: (IOHPPAInterruptHandler *)handler
1993: level: (unsigned int *) ipl
1994: argument: (unsigned int *) arg
1995: forInterrupt: (unsigned int) localInterrupt
1996: {
1997: return NO;
1998: }
1999: #elif sparc
2000: - (BOOL) getHandler: (IOSPARCInterruptHandler *)handler
2001: level: (unsigned int *) ipl
2002: argument: (unsigned int *) arg
2003: forInterrupt: (unsigned int) localInterrupt
2004: {
2005: *handler = interruptHandler;
2006: *ipl = IPLDEVICE;
2007: *arg = (unsigned int)self;
2008: return YES;
2009: }
2010: #elif i386
2011: - (BOOL) getHandler: (IOEISAInterruptHandler *)handler
2012: level: (unsigned int *) ipl
2013: argument: (unsigned int *) arg
2014: forInterrupt: (unsigned int) localInterrupt
2015: {
2016: *handler = interruptHandler;
2017: *ipl = IPLDEVICE;
2018: *arg = (unsigned int)self;
2019: return YES;
2020: }
2021: #endif
2022: @end
2023:
2024:
2025: static void ioThread(IOAudio *audioDevice)
2026: {
2027: msg_return_t result;
2028: msg_header_t Msg, *msg = &Msg;
2029:
2030: while (TRUE) {
2031:
2032: msg->msg_size = sizeof(Msg);
2033: msg->msg_local_port = [audioDevice _devicePortSet];
2034:
2035: result = msg_receive(msg, RCV_TIMEOUT, [audioDevice _timeout]);
2036:
2037: switch (result) {
2038:
2039: case RCV_SUCCESS:
2040:
2041: xpr_audio_device("AD: message received in ioThread\n",
2042: 1, 2, 3, 4, 5);
2043: if (msg->msg_id == IO_DEVICE_INTERRUPT_MSG)
2044: [audioDevice _interruptOccurred];
2045: else if (msg->msg_id == AD_CMD_MSG_INPUT_PENDING)
2046: [audioDevice _dataPendingOccurred:
2047: [audioDevice _inputChannel]];
2048: else if (msg->msg_id == AD_CMD_MSG_OUTPUT_PENDING)
2049: [audioDevice _dataPendingOccurred:
2050: [audioDevice _outputChannel]];
2051: else if (msg->msg_id == AD_CMD_MSG_SYNCHRONOUS)
2052: [audioDevice _commandOccurred];
2053: else
2054: IOLog("Audio: unknown message id %d\n", msg->msg_id);
2055:
2056: break;
2057:
2058: case RCV_TIMED_OUT:
2059:
2060: if ([audioDevice isInputActive] || [audioDevice isOutputActive])
2061: [audioDevice timeoutOccurred];
2062: break;
2063:
2064: default:
2065:
2066: IOLog("%s: %s thread: msg_receive returns %d\n",
2067: [audioDevice name], [audioDevice deviceKind], result);
2068: IOExitThread();
2069: }
2070: }
2071: }
2072:
2073: static void keyThread(IOAudio *audioDevice)
2074: {
2075: id eventClass;
2076: id eventInstance;
2077: port_t keyPort;
2078: port_t eventPort;
2079: IOReturn ioReturn;
2080: struct evioSpecialKeyMsg msg;
2081: msg_return_t msgReturn;
2082:
2083: keyPort = allocatePort();
2084:
2085: /*
2086: * Locate EventDriver class
2087: */
2088: eventClass = objc_lookUpClass("EventDriver");
2089: if (eventClass == nil) {
2090: IOLog("Audio: objc_lookUpClass failure\n");
2091: IOExitThread();
2092: }
2093:
2094: /*
2095: * Locate EventDriver instance
2096: */
2097: eventInstance = [eventClass instance];
2098:
2099: eventPort = (port_t)[eventInstance ev_port];
2100: ioReturn = [eventInstance setSpecialKeyPort: eventPort
2101: keyFlavor: NX_KEYTYPE_SOUND_UP
2102: keyPort: keyPort];
2103:
2104: if (ioReturn != IO_R_SUCCESS) {
2105: IOLog("Audio: SetSpecialKeyPort error %d\n", ioReturn);
2106: IOExitThread();
2107: }
2108:
2109: ioReturn = [eventInstance setSpecialKeyPort: eventPort
2110: keyFlavor: NX_KEYTYPE_SOUND_DOWN
2111: keyPort: keyPort];
2112:
2113: if (ioReturn != IO_R_SUCCESS) {
2114: IOLog("Audio: SetSpecialKeyPort error %d\n", ioReturn);
2115: IOExitThread();
2116: }
2117:
2118: while (TRUE) {
2119: msg.Head.msg_local_port = keyPort;
2120: msg.Head.msg_size = sizeof(msg);
2121: msgReturn = msg_receive(&msg.Head, MSG_OPTION_NONE, 0);
2122:
2123: if (msgReturn != RCV_SUCCESS) {
2124: IOLog("Audio: keyThread msg_receive error: %d\n", msgReturn);
2125: IOExitThread();
2126: }
2127:
2128: if (msg.Head.msg_id != EV_SPECIAL_KEY_MSG_ID) {
2129: IOLog("Audio: unknown msg id %d in keyThread\n", msg.Head.msg_id);
2130: IOExitThread();
2131: }
2132:
2133: [audioDevice _keyOccurred:msg.key event: msg.direction flags: msg.flags];
2134: }
2135:
2136: IOExitThread();
2137: }
2138:
2139:
2140: /*
2141: * HISTORY
2142: *
2143: * 4/1/94/rkd: Added input gain, buffer address/size methods.
2144: *
2145: * 11/8/95/rkd: Added support for input/output source selection.
2146: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.