|
|
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.