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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*
        !            25:  * AudioChannel.m
        !            26:  *
        !            27:  * Copyright (c) 1991, NeXT Computer, Inc.  All rights reserved.
        !            28:  *
        !            29:  *      Audio driver channel object.
        !            30:  *
        !            31:  * HISTORY
        !            32:  *     06/22/94/wmg    HP modifications.
        !            33:  *      11/17/93/rkd    Added XPRs.
        !            34:  *      07/14/92/mtm    Original coding.
        !            35:  */
        !            36:  
        !            37: #import "AudioChannel.h"
        !            38: #import "AudioStream.h"
        !            39: #import "InputStream.h"
        !            40: #import "OutputStream.h"
        !            41: #import <driverkit/IOAudio.h>
        !            42: #import <driverkit/IOAudioPrivate.h>
        !            43: #import "AudioCommand.h"
        !            44: #import "audio_peak.h"
        !            45: #import "audio_msgs.h"
        !            46: #import "audioLog.h"
        !            47: #import "AudioCommand.h"
        !            48: #import "audio_kern_server.h"
        !            49: #import <mach/vm_param.h>              // PAGE_SIZE
        !            50: #import <driverkit/generalFuncs.h>
        !            51: #import <driverkit/kernelDriver.h>     // IOPhysicalFromVirtual / IOVmTaskSelf
        !            52: #import <bsd/string.h>                 // bzero
        !            53: 
        !            54: #if    i386
        !            55: /*
        !            56:  * Temporary function prototype for alloc_cnvmem
        !            57:  * copied from <machdep/i386/i386_init.c)
        !            58:  */
        !            59: vm_offset_t alloc_cnvmem(vm_size_t size, vm_offset_t align);
        !            60: #endif i386
        !            61: #if    hppa
        !            62: #import <machdep/hppa/pmap.h>
        !            63: extern hpaudiobuffer;
        !            64: extern hpaudiosilent;
        !            65: #endif hppa
        !            66: #if    sparc
        !            67: //
        !            68: // set in device init routine
        !            69: //
        !            70: u_int AudioIn_dmaSize = 0;
        !            71: u_int AudioIn_dmaCount = 0;
        !            72: caddr_t AudioIn_dmaBuf = 0;
        !            73: u_int AudioOut_dmaSize = 0;
        !            74: u_int AudioOut_dmaCount = 0;
        !            75: caddr_t AudioOut_dmaBuf = 0;
        !            76: #endif sparc
        !            77: 
        !            78: #if ppc
        !            79: extern void *kernel_map;
        !            80: #endif
        !            81: 
        !            82: @implementation AudioChannel
        !            83: 
        !            84: /* Factory variables */
        !            85: static id allStreams = nil;
        !            86: 
        !            87: /*
        !            88:  * Both input and output channels share one buffer. 
        !            89:  */
        !            90: static BOOL sharedChannelBuffer = YES;
        !            91: static vm_offset_t sharedChannelBufferPtr = 0;
        !            92: 
        !            93: /*
        !            94:  * Add a stream.
        !            95:  */
        !            96: + addStream:stream
        !            97: {
        !            98:     if (!allStreams)
        !            99:        allStreams = [[List alloc] init];
        !           100:     [allStreams addObject:stream];
        !           101:     return self;
        !           102: }
        !           103: 
        !           104: /*
        !           105:  * Remove a stream.
        !           106:  */
        !           107: + removeStream:stream
        !           108: {
        !           109:     [allStreams removeObject:stream];
        !           110:     return self;
        !           111: }
        !           112: 
        !           113: /*
        !           114:  * Search for a stream given a user port.
        !           115:  */
        !           116: + streamForUserPort:(port_t)port
        !           117: {
        !           118:     int i;
        !           119:     id stream;
        !           120: 
        !           121:     for (i = 0; i < [allStreams count]; i++) {
        !           122:        stream = [allStreams objectAt:i];
        !           123:        if ([stream userPort] == port)
        !           124:            return stream;
        !           125:     }
        !           126:     return nil;
        !           127: }
        !           128: 
        !           129: /*
        !           130:  * Search for a stream given an owner port.
        !           131:  * Returns the FIRST such stream found.
        !           132:  */
        !           133: + streamForOwnerPort:(port_t)port
        !           134: {
        !           135:     int i;
        !           136:     id stream;
        !           137: 
        !           138:     for (i = 0; i < [allStreams count]; i++) {
        !           139:        stream = [allStreams objectAt:i];
        !           140:        if ([stream ownerPort] == port)
        !           141:            return stream;
        !           142:     }
        !           143:     return nil;
        !           144: }
        !           145: 
        !           146: /*
        !           147:  * Initialize.
        !           148:  */
        !           149:  
        !           150: - initOnDevice: device read: (BOOL)isRead
        !           151: {
        !           152:     [super init];
        !           153:     audioDevice = device;
        !           154:     
        !           155:     _isRead = isRead;
        !           156:     
        !           157:     if (isRead)
        !           158:         streamClass = [InputStream class];
        !           159:     else
        !           160:         streamClass = [OutputStream class];
        !           161:     
        !           162:     exclusiveUser = PORT_NULL;
        !           163:     streamList = [[List alloc] init];
        !           164:     streamListLock = [[NXLock alloc] init];
        !           165:     queue_init(&dmaQueue);
        !           166:     queue_init(&freeQueue);
        !           167: #if    hppa
        !           168:     queue_init(&devQueue);
        !           169:     queue_init(&dfreeQueue);
        !           170: #endif hppa
        !           171:     peakHistory = 1;
        !           172:     
        !           173:     channelBufferPtr = 0;
        !           174:     /*
        !           175:      * Note:
        !           176:      * Until the DMA buffer can be reallocated, the dmaSize cannot be changed.
        !           177:      */
        !           178: #if    i386
        !           179:     if ([audioDevice isEISAPresent])   {
        !           180:        [self setDMASize: PAGE_SIZE * 16];
        !           181:        (void) [self setDescriptorSize: PAGE_SIZE];
        !           182:     } else {
        !           183:        [self setDMASize: PAGE_SIZE * 8];               // 64K limit
        !           184:        (void) [self setDescriptorSize: PAGE_SIZE];
        !           185:     }
        !           186: #elif  hppa
        !           187:        // uses 64k too
        !           188:        dmaSize = PAGE_SIZE * 8;
        !           189:        dmaCount = 16;
        !           190:        (void) [self setDescriptorSize: (dmaSize/dmaCount)];
        !           191: #elif sparc
        !           192:     // dmaSize = PAGE_SIZE * 8;
        !           193:     // dmaCount = 16;
        !           194:        // 16 - 4K buffers
        !           195:        if (isRead) {
        !           196:                dmaSize = AudioIn_dmaSize;
        !           197:                dmaCount = AudioIn_dmaCount;
        !           198:        } else {
        !           199:                dmaSize = AudioOut_dmaSize;
        !           200:                dmaCount = AudioOut_dmaCount;
        !           201:        }
        !           202:        (void) [self setDescriptorSize: (dmaSize/dmaCount)];
        !           203: #elif ppc
        !           204:         dmaCount = 32;
        !           205:         dmaSize = PAGE_SIZE * dmaCount;
        !           206:         (void) [self setDescriptorSize: (dmaSize/dmaCount)];
        !           207: #else
        !           208:     dmaSize = PAGE_SIZE * 8;
        !           209:     dmaCount = 16;
        !           210: #endif
        !           211: 
        !           212:     
        !           213:     return self;
        !           214: }
        !           215:     
        !           216: /*
        !           217:  * Currently cannot free, but if want to someday, worry about:
        !           218:  * destroyDMABuffers; and
        !           219:  * Free peak history buffers
        !           220:  */
        !           221: - free
        !           222: {
        !           223:     IOLog("AudioChannel: -free not supported\n");
        !           224:     return [super free];
        !           225: }
        !           226: 
        !           227: /*
        !           228:  *
        !           229:  */
        !           230: - (u_int) descriptorSize
        !           231: {
        !           232:     return descriptorSize;
        !           233: }
        !           234: 
        !           235: /*
        !           236:  * Returns the desciptorSize which may be different from the one requested. 
        !           237:  */
        !           238: - (u_int) setDescriptorSize:(u_int) size
        !           239: {
        !           240:     dmaCount = [self dmaSize] / size;
        !           241: 
        !           242: #ifndef ppc
        !           243:     if (dmaCount < 4 || dmaCount > 16) {
        !           244:        dmaCount = 8;
        !           245:        size = [self dmaSize] / dmaCount;
        !           246:     }
        !           247: #endif
        !           248: 
        !           249:     descriptorSize = size;
        !           250:     
        !           251:     return descriptorSize;
        !           252: }
        !           253: 
        !           254: - (u_int) dmaSize
        !           255: {
        !           256:     return dmaSize;
        !           257: }
        !           258: 
        !           259: - (void) setDMASize:(u_int) size
        !           260: {
        !           261:     dmaSize = size;
        !           262: }
        !           263: 
        !           264: - (u_int)dmaCount
        !           265: {
        !           266:     return dmaCount;
        !           267: }
        !           268: 
        !           269: - (BOOL) isRead
        !           270: {
        !           271:     return _isRead;
        !           272: }
        !           273: 
        !           274: /*
        !           275:  * Return number of outstanding (enqueued) dma descriptors on dmaQueue.
        !           276:  */
        !           277: - (u_int)enqueueCount
        !           278: {
        !           279:     return enqueueCount;
        !           280: }
        !           281: 
        !           282: /*
        !           283:  * Create channel dma buffers.
        !           284:  * There must be no active streams when this is called.
        !           285:  */
        !           286: - (BOOL) createChannelBuffer
        !           287: {
        !           288:     BOOL status;
        !           289:     int len;
        !           290: #ifdef hppa
        !           291:     extern pmap_t audio_pmap;  // defined in IOAudio.m
        !           292: #endif
        !           293:     
        !           294:     /*
        !           295:      * To Do: Until better versions of IOMallocLow and IOFreeLow are available,
        !           296:      * the channel will use alloc_cnvmem (allocate conventional memory) which
        !           297:      * can allocate more than one physically contiguous page. The memory cannot
        !           298:      * be freed; therefore, the code checks to see if the channelBuffer has
        !           299:      * been created.
        !           300:      */        
        !           301:     if (channelBufferPtr)
        !           302:        return TRUE;
        !           303:        
        !           304: #if    i386
        !           305:     if ((sharedChannelBuffer) && (sharedChannelBufferPtr))     {
        !           306:        channelBufferPtr = sharedChannelBufferPtr;
        !           307:        
        !           308:        channelBuffer = [audioDevice createDMABufferFor: &channelBufferPtr
        !           309:            length: dmaSize
        !           310:            read:(BOOL) _isRead
        !           311:            needsLowMemory: TRUE
        !           312:            limitSize: NO];
        !           313:     
        !           314:        [self initializeFreeQueue];
        !           315:        return TRUE;
        !           316:     }
        !           317: 
        !           318:     /*
        !           319:      * We treat ISA systems as special case since other systems do not have
        !           320:      * DMA memory restrictions like it. For ISA we assign memory using
        !           321:      * alloc_envmem() and for others we will use an IOBuffer object
        !           322:      * (eventually). 
        !           323:      */
        !           324:     if (![audioDevice isEISAPresent])  {
        !           325:         channelBufferPtr = alloc_cnvmem(dmaSize, 65536);       // 64K align
        !           326:        if (!channelBufferPtr)  {
        !           327:            IOLog("Audio: no memory for allocating buffers.\n");
        !           328:            return FALSE;
        !           329:        }
        !           330:     } else if ([audioDevice isEISAPresent])    {
        !           331:         channelBufferPtr = alloc_cnvmem(dmaSize, PAGE_SIZE);
        !           332:        if (!channelBufferPtr)  {
        !           333:            IOLog("Audio: no memory for allocating buffers.\n");
        !           334:            return FALSE;
        !           335:        }
        !           336:     }
        !           337: #elif  hppa
        !           338:     if (_isRead) {
        !           339:        // if read it is read buffer
        !           340:        channelBufferPtr = (vm_address_t)(&hpaudiosilent);
        !           341:     } else {
        !           342:        channelBufferPtr = (vm_address_t)(&hpaudiobuffer);
        !           343:     }
        !           344: #elif sparc
        !           345:        if (_isRead) 
        !           346:                channelBufferPtr = (vm_offset_t)AudioIn_dmaBuf;
        !           347:        else 
        !           348:                channelBufferPtr = (vm_offset_t)AudioOut_dmaBuf;
        !           349: #elif ppc
        !           350:    {
        !           351:      int       kr;
        !           352:      kr = kmem_alloc_wired( kernel_map, (vm_offset_t)&channelBufferPtr, dmaSize );
        !           353:      if ( kr != KERN_SUCCESS )
        !           354:      {
        !           355:        IOLog("Audio: no memory for allocating buffers.\n");
        !           356:        return FALSE;
        !           357:      }
        !           358:    }
        !           359: #else
        !           360: #warning       AudioChannel class only supports i386 , hppa or sparc
        !           361: #endif
        !           362: 
        !           363:     sharedChannelBufferPtr = channelBufferPtr;
        !           364:     
        !           365: #if    i386
        !           366:     channelBuffer = [audioDevice createDMABufferFor: &channelBufferPtr
        !           367:         length: dmaSize
        !           368:         read:(BOOL) _isRead
        !           369:         needsLowMemory: TRUE
        !           370:         limitSize: NO];
        !           371: #else
        !           372:     // for hppa and sparc there is no seperate setups for DMA
        !           373:     channelBuffer = (void *)channelBufferPtr;
        !           374: #endif
        !           375: 
        !           376:     [self initializeFreeQueue];
        !           377: #if    hppa
        !           378:     [self initializeDFreeQueue];
        !           379: #endif
        !           380:     return TRUE;
        !           381: }
        !           382: 
        !           383: - (void) initializeFreeQueue
        !           384: {
        !           385:     dma_desc_t *ddp;
        !           386:     int i;
        !           387:     vm_address_t ptr;
        !           388:     
        !           389:     while (!queue_empty(&freeQueue)) {
        !           390:        queue_remove_first(&freeQueue, ddp, dma_desc_t *, link);
        !           391:        IOFree((void *)ddp, sizeof(dma_desc_t));
        !           392:     }
        !           393: 
        !           394:     bzero((void *)channelBufferPtr, dmaSize);
        !           395: 
        !           396:     ptr = channelBufferPtr;
        !           397: 
        !           398:     for (i = 0; i < dmaCount; i++) {
        !           399:        ddp = (dma_desc_t *)IOMalloc(sizeof(dma_desc_t));
        !           400:        ddp->size = 0;
        !           401:        ddp->mem = ptr;
        !           402:        ptr += descriptorSize;
        !           403:        queue_enter(&freeQueue, ddp, dma_desc_t *, link);
        !           404:     }
        !           405: }
        !           406: 
        !           407: #if    hppa
        !           408: - (void) initializeDFreeQueue
        !           409: {
        !           410:     dma_desc_t *ddp;
        !           411:     int i;
        !           412:     vm_address_t ptr;
        !           413:     
        !           414:     while (!queue_empty(&dfreeQueue)) {
        !           415:        queue_remove_first(&dfreeQueue, ddp, dma_desc_t *, link);
        !           416:        IOFree((void *)ddp, sizeof(dma_desc_t));
        !           417:     }
        !           418: 
        !           419:     bzero((void *)channelBufferPtr, dmaSize);
        !           420: 
        !           421:        pmap_flush_range(kernel_pmap, (vm_offset_t)channelBufferPtr, dmaSize);
        !           422: 
        !           423: 
        !           424:     ptr = channelBufferPtr;
        !           425: 
        !           426:     for (i = 0; i < dmaCount; i++) {
        !           427:                ddp = (dma_desc_t *)IOMalloc(sizeof(dma_desc_t));
        !           428:                ddp->size = 0;
        !           429:                ddp->mem = ptr;
        !           430:                ptr += descriptorSize;
        !           431:                queue_enter(&dfreeQueue, ddp, dma_desc_t *, link);
        !           432:     }
        !           433: }
        !           434: 
        !           435: /* returns the device dma address also releases the queue
        !           436:  * 
        !           437:  */
        !           438: 
        !           439: - (vm_offset_t) getDevDmaAddress
        !           440: {
        !           441:     dma_desc_t *ddp_d; // for the dev queue
        !           442:     vm_offset_t dev_dma_addr = (vm_offset_t)NULL;
        !           443:     vm_offset_t addr;
        !           444:      extern pmap_t audio_pmap; // defined in IOAudio.m
        !           445: 
        !           446:        if (queue_empty(&devQueue)) return (vm_offset_t)NULL;
        !           447:        queue_remove_first(&devQueue, ddp_d, dma_desc_t *, link);
        !           448:        // now the buffer is a kernel buffer mapped 1 to 1
        !           449:        // dev_dma_addr = ddp_d->mem;
        !           450:        dev_dma_addr = pmap_extract(kernel_pmap,ddp_d->mem);
        !           451:        
        !           452:        queue_enter(&dfreeQueue, ddp_d, dma_desc_t *, link);
        !           453:        return dev_dma_addr;
        !           454: }
        !           455: #endif hppa
        !           456: 
        !           457: /*
        !           458:  * Destroy dma buffers.
        !           459:  * There must be no active streams when this is called.
        !           460:  */
        !           461: - (void) destroyChannelBuffer
        !           462: {
        !           463:     
        !           464:     /*
        !           465:      * The channelBuffer cannot be freed until a better version
        !           466:      *         of IOFreeLow is available.
        !           467:      */
        !           468: }
        !           469: 
        !           470: /*
        !           471:  * enqueue a dma descriptor using the current device parameters.
        !           472:  */
        !           473: - (BOOL) enqueueDescriptor: (u_int *) rate
        !           474:        dataFormat: (IOAudioDataFormat *) format
        !           475:        channelCount: (u_int *) count
        !           476: {
        !           477:     id stream;
        !           478:     int i;
        !           479:     u_int bufferSize = 0;
        !           480:     u_int streamCount;
        !           481:     u_int streamSize;
        !           482:     dma_desc_t *ddp;
        !           483: #if    hppa
        !           484:     dma_desc_t *ddp_d; // for the dev queue
        !           485: #endif hppa
        !           486: 
        !           487:     xpr_audio_channel("AC: enqueueDescriptor: rate %d dataFormat %d "
        !           488:                "channelCount %d\n", rate, format, count, 4,5);
        !           489:     [streamListLock lock];
        !           490:     streamCount = [streamList count];
        !           491:     if (streamCount == 0 || queue_empty(&freeQueue)) {
        !           492:        [streamListLock unlock];
        !           493:        return FALSE;
        !           494:     }
        !           495:     queue_remove_first(&freeQueue, ddp, dma_desc_t *, link);
        !           496:     for (i = 0; i < streamCount; i++) {
        !           497:        stream = [streamList objectAt:i];
        !           498:        streamSize = [stream mixBuffer:ddp->mem maxCount:descriptorSize
        !           499:                                  rate:rate format:format
        !           500:                          channelCount:count descriptor:ddp
        !           501:                                 virgin:(bufferSize == 0)
        !           502:                            streamCount:streamCount];
        !           503:        if (streamSize > bufferSize)
        !           504:            bufferSize = streamSize;
        !           505:     }
        !           506:     [streamListLock unlock];
        !           507:     if (bufferSize == 0) {
        !           508:        queue_enter_first(&freeQueue, ddp, dma_desc_t *, link);
        !           509:        return(FALSE);
        !           510:     }
        !           511:     
        !           512:     ddp->size = bufferSize;    
        !           513: #ifdef sparc
        !           514:        vac_flush((caddr_t)ddp->mem, ddp->size);
        !           515: #endif
        !           516: #ifdef hppa
        !           517:        pmap_flush_range(kernel_pmap,(vm_offset_t)ddp->mem,ddp->size);
        !           518: #endif
        !           519: #ifdef ppc
        !           520:         flush_cache_v((vm_offset_t)ddp->mem,ddp->size);
        !           521: #endif
        !           522:     queue_enter(&dmaQueue, ddp, dma_desc_t *, link);
        !           523: #ifdef hppa
        !           524:     if (!queue_empty(&dfreeQueue)) {
        !           525:            queue_remove_first(&dfreeQueue, ddp_d, dma_desc_t *, link);
        !           526:            ddp_d->mem = ddp->mem;
        !           527:            ddp_d->size = ddp->size;
        !           528:            queue_enter(&devQueue, ddp_d, dma_desc_t *, link);
        !           529:     }
        !           530: #endif
        !           531: 
        !           532:     enqueueCount++;
        !           533: 
        !           534:     xpr_audio_channel("AC: enqueueDescriptor done\n",1,2,3,4,5);
        !           535:     
        !           536:     return(TRUE);
        !           537: }
        !           538: 
        !           539: 
        !           540: /*
        !           541:  * dequeue a DMA descriptor
        !           542:  */
        !           543: - (void) dequeueDescriptor
        !           544: {
        !           545:     dma_desc_t *ddp;
        !           546:     int i;
        !           547:     id stream;
        !           548:     u_int peak_left = 0, peak_right = 0;
        !           549:     u_int numStreams;
        !           550: 
        !           551:     xpr_audio_channel("AC: dequeueDescriptor\n",1,2,3,4,5);
        !           552:     
        !           553:     queue_remove_first(&dmaQueue, ddp, dma_desc_t *, link);
        !           554: 
        !           555:     [streamListLock lock];
        !           556:     numStreams = [streamList count];
        !           557:     if (numStreams > 0) {
        !           558:        if (peakEnabled) {
        !           559:            switch ([audioDevice dataEncoding]) {
        !           560:              case NX_SoundStreamDataEncoding_Linear16:
        !           561:                audio_linear16_peak([audioDevice channelCount],
        !           562:                                    (short *)ddp->mem, ddp->size/2,
        !           563:                                    &peak_left, &peak_right);
        !           564:                break;
        !           565:                
        !           566:              case NX_SoundStreamDataEncoding_Linear8:
        !           567:                audio_linear8_peak([audioDevice channelCount],
        !           568:                                   (char *)ddp->mem, ddp->size,
        !           569:                                   &peak_left, &peak_right);
        !           570:                break;
        !           571:                
        !           572:              case NX_SoundStreamDataEncoding_Mulaw8:
        !           573:                audio_mulaw8_peak([audioDevice channelCount],
        !           574:                                  (unsigned char *)ddp->mem,
        !           575:                                  ddp->size, &peak_left, &peak_right);
        !           576:                break;
        !           577:                
        !           578:              default:
        !           579:                /* FIXME: A-law and AES peak not supported */
        !           580:                break;
        !           581:            }
        !           582:            audio_add_peak(peaksLeft, peak_left, &currentPeak, peakHistory);
        !           583:            audio_add_peak(peaksRight, peak_right, &currentPeak, peakHistory);
        !           584:        }
        !           585:        
        !           586:        for (i = 0; i < numStreams; i++) {
        !           587:            stream = [streamList objectAt:i];
        !           588:            /*
        !           589:             * Note: transfer count is only valid for input channel
        !           590:             * (0 sent for output channel).
        !           591:             */
        !           592:            [stream dmaCompleteDescriptor:ddp transfered:ddp->size];
        !           593:            
        !           594:            /*
        !           595:             * In the original driver, the dequeueDMA operation would return
        !           596:             * the actually transfer count. We need to offer a similar
        !           597:             * solution at some point:
        !           598:             * [stream dmaCompleteDescriptor:ddp transfered:count];
        !           599:             */
        !           600:        }
        !           601:     }
        !           602:     [streamListLock unlock];
        !           603: 
        !           604:     bzero((void *)ddp->mem, descriptorSize);
        !           605: 
        !           606: #ifdef ppc
        !           607:     flush_cache_v((vm_offset_t)ddp->mem,descriptorSize);
        !           608: #endif
        !           609: 
        !           610:     queue_enter(&freeQueue, ddp, dma_desc_t *, link);
        !           611:     
        !           612:     --enqueueCount;
        !           613:     xpr_audio_channel("AC: dequeueDescriptor done\n",1,2,3,4,5);
        !           614: }
        !           615: 
        !           616: 
        !           617: /*
        !           618:  * returns the channel buffer as a void *
        !           619:  */
        !           620: - (void *) channelBuffer
        !           621: {
        !           622:     return channelBuffer;
        !           623: }
        !           624: 
        !           625: - (vm_address_t) channelBufferAddress
        !           626: {
        !           627:     return channelBufferPtr;
        !           628: }
        !           629: 
        !           630: - (void) freeDescriptors
        !           631: {
        !           632:     /*
        !           633:      * When a DMA operation is aborted, descriptors might still remain on
        !           634:      * the DMA queue.
        !           635:      */
        !           636:     while (!queue_empty(&dmaQueue)) 
        !           637:         [self dequeueDescriptor];
        !           638: 
        !           639:    [self initializeFreeQueue];
        !           640: }
        !           641: 
        !           642: - (void) setLocalChannel:(u_int) channel
        !           643: {
        !           644:     localChannel = channel;
        !           645: }
        !           646: 
        !           647: - (u_int) localChannel
        !           648: {
        !           649:     return localChannel;
        !           650: }
        !           651: 
        !           652: /*
        !           653:  * Get and set user channel and snd ports.
        !           654:  */
        !           655: - setUserChannelPort:(port_t)port
        !           656: {
        !           657:     userChannelPort = port;
        !           658:     return self;
        !           659: }
        !           660: - (port_t)userChannelPort
        !           661: {
        !           662:     return userChannelPort;
        !           663: }
        !           664: - setUserSndPort:(port_t)port
        !           665: {
        !           666:     userSndPort = port;
        !           667:     return self;
        !           668: }
        !           669: - (port_t)userSndPort
        !           670: {
        !           671:     return userSndPort;
        !           672: }
        !           673: 
        !           674: /*
        !           675:  * Search for the FIRST stream with the given owner port
        !           676:  * (used by the snd interface, which has one stream per channel).
        !           677:  * Returns the stream's user port.
        !           678:  */
        !           679: - (port_t)streamUserForOwnerPort:(port_t)port
        !           680: {
        !           681:     int i;
        !           682:     id stream;
        !           683: 
        !           684:     for (i = 0; i < [streamList count]; i++) {
        !           685:        stream = [streamList objectAt:i];
        !           686:        if ([stream ownerPort] == port)
        !           687:            return [stream userPort];
        !           688:     }
        !           689:     return PORT_NULL;
        !           690: }
        !           691: 
        !           692: /*
        !           693:  * Remove all snd type streams.
        !           694:  */
        !           695: - removeSndStreams
        !           696: {
        !           697:     id stream;
        !           698:     List *remList = [[List alloc] init];
        !           699:     int i;
        !           700: 
        !           701:     [streamListLock lock];
        !           702:     for (i = 0; i < [streamList count]; i++) {
        !           703:        stream = [streamList objectAt:i];
        !           704:        if ([stream type] != AS_TypeUser)
        !           705:            [remList addObject:stream];
        !           706:     }
        !           707:     [streamListLock unlock];
        !           708: 
        !           709:     for (i = 0; i < [remList count]; i++)
        !           710:        [self removeStream:[remList objectAt:i]];
        !           711: 
        !           712:     [remList free];
        !           713:     return self;
        !           714: }
        !           715: 
        !           716: /*
        !           717:  * Get and set exclusive user.
        !           718:  */
        !           719: - (void)setExclusiveUser:(port_t)streamPort
        !           720: {
        !           721:     int streamCount, i;
        !           722: 
        !           723:     exclusiveUser = streamPort;
        !           724:     /*
        !           725:      * Cause other owner's streams to abort with excluded messages.
        !           726:      */
        !           727:     [streamListLock lock];
        !           728:     streamCount = [streamList count];
        !           729:     if (streamCount == 0) {
        !           730:        [streamListLock unlock];
        !           731:        return;
        !           732:     }
        !           733:     for (i = 0; i < streamCount; i++)
        !           734:        [[streamList objectAt:i] control:AC_ControlExclude];
        !           735:     [streamListLock unlock];
        !           736: }
        !           737: - (port_t)exclusiveUser
        !           738: {
        !           739:     return exclusiveUser;
        !           740: }
        !           741: 
        !           742: /*
        !           743:  * Check prospective owner port against current exclusive user port.
        !           744:  */
        !           745: - (BOOL)checkOwner:(port_t)owner
        !           746: {
        !           747:     if (exclusiveUser != PORT_NULL && owner != exclusiveUser)
        !           748:        return NO;
        !           749:     else
        !           750:        return YES;
        !           751: }
        !           752: 
        !           753: /*
        !           754:  * 
        !           755:  */
        !           756: - streamClass
        !           757: {
        !           758:     return streamClass;
        !           759: }
        !           760: 
        !           761: /*
        !           762:  * Return number of streams
        !           763:  */
        !           764: - (u_int)streamCount
        !           765: {
        !           766:     u_int count;
        !           767: 
        !           768:     [streamListLock lock];
        !           769:     count = [streamList count];
        !           770:     [streamListLock unlock];
        !           771:     return count;
        !           772: }
        !           773: 
        !           774: /*
        !           775:  * When a stream is added, its user port must be registered with the
        !           776:  * audio loadable kernel server.
        !           777:  */
        !           778: - (BOOL)addStreamTag:(int)tag user:(port_t *)userPort
        !           779:       owner:(port_t)owner type:(u_int)type
        !           780: {
        !           781:     id aStream;
        !           782: 
        !           783:     xpr_audio_channel("AC: addStreamTag tag=%d user=%x owner=%x"
        !           784:                 " type=%d\n", tag, userPort, owner, type, 5);
        !           785:     
        !           786:     if (![audioDevice _channelWillAddStream])  {
        !           787:         xpr_audio_channel("AC: audioDevice can not add stream.\n",1,2,3,4,5);
        !           788:        return NO;
        !           789:     }
        !           790: 
        !           791:     aStream = [[[self streamClass] alloc] initChannel:self tag:tag
        !           792:                                                 user:userPort
        !           793:                                                owner:owner type:type];
        !           794:     if (!aStream)      {
        !           795:         xpr_audio_channel("AC: addStreamTag: can not add stream.\n",1,2,3,4,5);
        !           796:        return NO;
        !           797:     }
        !           798: 
        !           799:     [streamListLock lock];
        !           800: 
        !           801:     if ([streamList count] == 0) {
        !           802:        if (![self createChannelBuffer]) {
        !           803:            [streamListLock unlock];
        !           804:            xpr_audio_channel("AC: addStreamTag: can not create"
        !           805:                " channel buffer.\n",1,2,3,4,5);
        !           806:            return NO;
        !           807:        }
        !           808:     }
        !           809: 
        !           810:     [streamList addObject:aStream];
        !           811:     [streamListLock unlock];
        !           812:     [AudioChannel addStream:aStream];
        !           813:     
        !           814:     return audio_enroll_stream_port(*userPort, TRUE);
        !           815: }
        !           816: 
        !           817: /*
        !           818:  * Remove a stream.
        !           819:  */
        !           820: - (void)removeStream:stream
        !           821: {
        !           822:     unsigned int count;
        !           823:     
        !           824:     audio_enroll_stream_port([stream userPort], FALSE);
        !           825:     [streamListLock lock];
        !           826:     count = [streamList count];
        !           827:     
        !           828:     /*
        !           829:      * When only one stream remains, DMA is aborted when the stream is removed.
        !           830:      */
        !           831:     if (count == 1) {
        !           832:     
        !           833:         /*
        !           834:         * The streamListLock needs to be unlocked to prevent deadlock. When
        !           835:         * the abort command is sent to the IO thread, the dequeueDescriptor
        !           836:         * method will be executed. This method needs to acquire the lock. 
        !           837:         */
        !           838:        [streamListLock unlock];
        !           839: 
        !           840:         if ([self isRead])
        !           841:            [[audioDevice _audioCommand] send: abortInputChannel];
        !           842:        else
        !           843:            [[audioDevice _audioCommand] send: abortOutputChannel];
        !           844:            
        !           845:        [streamListLock lock];
        !           846:        
        !           847:        if (peaksLeft)
        !           848:            audio_clear_peaks(peaksLeft, MAX_PEAK_HISTORY);
        !           849:        if (peaksRight)
        !           850:            audio_clear_peaks(peaksRight, MAX_PEAK_HISTORY);
        !           851:        clipCount = 0;
        !           852: 
        !           853:     }
        !           854: 
        !           855:     [streamList removeObject:stream];
        !           856:     [AudioChannel removeStream:stream];
        !           857:     [stream free];
        !           858:     [streamListLock unlock];
        !           859: 
        !           860: }
        !           861: 
        !           862: 
        !           863: /*
        !           864:  * Send stream control to all streams.
        !           865:  */
        !           866: - (void)controlStreams:(ACStreamControl)action
        !           867: {
        !           868:     int streamCount, i;
        !           869: 
        !           870:     [streamListLock lock];
        !           871:     streamCount = [streamList count];
        !           872:     if (streamCount == 0) {
        !           873:        [streamListLock unlock];
        !           874:        return;
        !           875:     }
        !           876:     for (i = 0; i < streamCount; i++)
        !           877:        [[streamList objectAt:i] control:action];
        !           878:     [streamListLock unlock];
        !           879: }
        !           880: 
        !           881: - (BOOL)isDetectingPeaks
        !           882: {
        !           883:     return peakEnabled;
        !           884: }
        !           885: 
        !           886: - (void)setDetectPeaks:(BOOL)flag;
        !           887: {
        !           888:     /*
        !           889:      * FIXME: unsupport history.
        !           890:      */
        !           891:     peakEnabled = flag;
        !           892:     if (peakEnabled && !peaksLeft) {
        !           893:        peaksLeft = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int));
        !           894:        peaksRight = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int));
        !           895:        audio_clear_peaks(peaksLeft, MAX_PEAK_HISTORY);
        !           896:        audio_clear_peaks(peaksRight, MAX_PEAK_HISTORY);
        !           897:     }
        !           898: }
        !           899: 
        !           900: /*
        !           901:  * Get peaks and clip count.
        !           902:  */
        !           903: - (void)getPeakLeft:(u_int *)leftPeak right:(u_int *)rightPeak
        !           904: {
        !           905:     if (peakEnabled) {
        !           906:        *leftPeak = audio_max_peak(peaksLeft, peakHistory);
        !           907:        *rightPeak = audio_max_peak(peaksRight, peakHistory);
        !           908:     } else
        !           909:        *leftPeak = *rightPeak = 0;
        !           910: }
        !           911: - (u_int)clipCount
        !           912: {
        !           913:     return clipCount;
        !           914: }
        !           915: - incrementClipCount:(u_int)count
        !           916: {
        !           917:     clipCount += count;
        !           918:     return self;
        !           919: }
        !           920: 
        !           921: /*
        !           922:  * Return device.
        !           923:  */
        !           924: - audioDevice
        !           925: {
        !           926:     return audioDevice;
        !           927: }
        !           928: 
        !           929: @end

unix.superglobalmegacorp.com

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