Annotation of driverkit/libDriver/Kernel/IOAudio.m, revision 1.1

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:  */ 

unix.superglobalmegacorp.com

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