Annotation of driverkit/libDriver/Kernel/IOAudio.m, revision 1.1.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.