Annotation of XNU/iokit/Families/IOAudio/IOAudioBus.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
                     24:  *
                     25:  * Hardware independent (relatively) code for the AudioBus
                     26:  *
                     27:  * HISTORY
                     28:  *
                     29:  *
                     30:  */
                     31: 
                     32: #include <IOKit/audio/IOAudioBus.h>
                     33: #include <IOKit/IOLib.h>
                     34: #include <IOKit/IOWorkLoop.h>
                     35: #include <IOKit/IOFilterInterruptEventSource.h>
                     36: 
                     37: #undef super
                     38: #define super IOAudioController
                     39: 
                     40: //************************************************************************
                     41: // Implementation of protocol clas.
                     42: //************************************************************************
                     43: OSDefineMetaClass(  IOAudioBus, IOAudioController )
                     44: OSDefineAbstractStructors(  IOAudioBus, IOAudioController )
                     45: 
                     46: #ifdef __ppc__
                     47: 
                     48: //************************************************************************
                     49: // Begin implementation of IOAudioBus class.
                     50: //************************************************************************
                     51: 
                     52: #define kNumberOfBuffers  4
                     53: #define kNumberOfSamples  8192
                     54: #define kNumberOfChannels 2    // left and right
                     55: #define kSampleSize      2     // 16 bit channels
                     56: #define kBlockSize       256
                     57: 
                     58: const int IOAudioBus::kAudioDMAdeviceInt       = 0;
                     59: const int IOAudioBus::kAudioDMAtxInt           = 1;
                     60: const int IOAudioBus::kAudioDMArxInt           = 2;
                     61: 
                     62: const int IOAudioBus::kAudioDMAOutputStream    = 0;
                     63: const int IOAudioBus::kAudioDMAInputStream     = 1;
                     64: 
                     65: // Constructs an empty audio bus:
                     66: bool
                     67: IOAudioBus::init(OSDictionary * properties)
                     68: {
                     69:     if (!super::init(properties))
                     70:             return false;
                     71: 
                     72:     ioAudioStreamsDMA = NULL;
                     73:     numDMAStreams = NULL;
                     74: 
                     75:     // Initialize my ivars.
                     76:     fBufMax = kNumberOfBuffers * kNumberOfSamples * kNumberOfChannels * kSampleSize;
                     77:     fBlockSize = kBlockSize;
                     78: 
                     79:     return true;
                     80: }
                     81: 
                     82: // This should free everything
                     83: void
                     84: IOAudioBus::free()
                     85: {
                     86:     FreeStreams();
                     87:     super::free();
                     88: }
                     89: 
                     90: void IOAudioBus::startWorkLoop()
                     91: {
                     92:     super::startWorkLoop();
                     93:     registerInterrupts();
                     94: }
                     95: 
                     96: void IOAudioBus::registerInterrupts()
                     97: {
                     98:     fTxInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
                     99:                                                                                   IOAudioBus::AudioBusInterruptHandler,
                    100:                                                                                   IOAudioBus::AudioBusInterruptFilter,
                    101:                                                                                   fDevice,
                    102:                                                                                   kAudioDMAtxInt);
                    103:     fWorkLoop->addEventSource(fTxInterruptSource);
                    104: 
                    105:     fRxInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
                    106:                                                                                   IOAudioBus::AudioBusInterruptHandler,
                    107:                                                                                   IOAudioBus::AudioBusInterruptFilter,
                    108:                                                                                   fDevice,
                    109:                                                                                   kAudioDMArxInt);
                    110:     fWorkLoop->addEventSource(fRxInterruptSource);
                    111: 
                    112:     fTxInterruptSource->enable();
                    113:     fRxInterruptSource->enable();
                    114: }
                    115: 
                    116: bool IOAudioBus::AudioBusInterruptFilter(OSObject *owner,
                    117:                                IOFilterInterruptEventSource *source)
                    118: {
                    119:     register IOAudioBus *bus = (IOAudioBus *)owner;
                    120:     bool result = true;
                    121: 
                    122:     if (bus) {
                    123:         result = bus->filterInterrupt(source->getIntIndex());
                    124:     }
                    125: 
                    126:     return result;
                    127: }
                    128: 
                    129: bool IOAudioBus::filterInterrupt(int index)
                    130: {
                    131:     IOAudioStreamStatus *status = getSharedStatus(getStreamForInterrupt(index));
                    132: 
                    133:     if (status) {
                    134:         clock_get_uptime(&status->fLastLoopTime);
                    135:         ++status->fCurrentLoopCount;
                    136:     }
                    137: 
                    138:     return false;
                    139: }
                    140: 
                    141: void IOAudioBus::AudioBusInterruptHandler(OSObject *owner,
                    142:                                 IOInterruptEventSource * /*source*/,
                    143:                                 int /*count*/)
                    144: {
                    145:     return;
                    146: }
                    147: 
                    148: AudioStreamIndex IOAudioBus::getStreamForInterrupt(int index)
                    149: {
                    150:     AudioStreamIndex result = kNoStream;
                    151: 
                    152:     switch (index) {
                    153:         case kAudioDMAtxInt:
                    154:             result = kAudioDMAOutputStream;
                    155:             break;
                    156:         case kAudioDMArxInt:
                    157:             result = kAudioDMAInputStream;
                    158:             break;
                    159:     }
                    160:     return result;
                    161: }
                    162: 
                    163: // Creates n empty streams (also a method to free them)
                    164: bool
                    165: IOAudioBus::AllocateStreams(int n)
                    166: {
                    167:     numDMAStreams = n;
                    168: 
                    169:     if (numDMAStreams > 0) {
                    170:         // Allocates as many StreamDMAInfo as needed:
                    171:         ioAudioStreamsDMA = (StreamDMAInfo*)IOMalloc(sizeof(StreamDMAInfo) * numDMAStreams);
                    172:         if (ioAudioStreamsDMA == NULL) {
                    173:             numDMAStreams = 0;
                    174:             return false;
                    175:         }
                    176:         for (n =0 ; n < numDMAStreams; n++) {
                    177:             ioAudioStreamsDMA[n].streamProperty = NULL;
                    178:             ioAudioStreamsDMA[n].fIOBaseDMA = NULL;
                    179:             ioAudioStreamsDMA[n].fSharedStatus = NULL;
                    180:         }
                    181:   
                    182:         return (true);
                    183:     }
                    184: 
                    185:     return (false);
                    186: }
                    187: 
                    188: bool
                    189: IOAudioBus::FreeStreams()
                    190: {
                    191:     int n;
                    192: 
                    193:     if (ioAudioStreamsDMA != NULL) {
                    194:         // First stops all the streams:
                    195:         for (n =0 ; n < numDMAStreams; n++)
                    196:             if (ioAudioStreamsDMA[n].fIOBaseDMA != NULL) {
                    197:                 stopStream(n);
                    198: 
                    199:                 // If we ever created a stream property fpr the stream, delete it:
                    200:                 IOFree(ioAudioStreamsDMA[n].streamProperty, 128);
                    201:                 ioAudioStreamsDMA[n].streamProperty = NULL;
                    202:             }
                    203: 
                    204:         IOFree(ioAudioStreamsDMA, sizeof(StreamDMAInfo) * numDMAStreams);
                    205:         ioAudioStreamsDMA = NULL;
                    206: 
                    207:         return true;
                    208:     }
                    209: 
                    210:     return false;
                    211: }
                    212: 
                    213: // For each stream defines its properties:
                    214: bool
                    215: IOAudioBus::DefineStream(AudioStreamIndex i, int direction, UInt32 rate, IODBDMAChannelRegisters *base)
                    216: {
                    217:     if ((ioAudioStreamsDMA != NULL) && (i < numDMAStreams) && (base != NULL)) {
                    218:         ioAudioStreamsDMA[i].fIOBaseDMA = base;
                    219: 
                    220:         // The stream direction is "hardwired" so that ecah channel
                    221:         // can go in one direction. 
                    222:         if (direction == kInput) {
                    223:             ioAudioStreamsDMA[i].fDmaCmd = kdbdmaInputMore;
                    224:             ioAudioStreamsDMA[i].fNeedsErase = false;
                    225:             ioAudioStreamsDMA[i].fIsInput = true;
                    226:         }
                    227:         else {
                    228:             ioAudioStreamsDMA[i].fDmaCmd = kdbdmaOutputMore;
                    229:             ioAudioStreamsDMA[i].fNeedsErase = true;
                    230:             ioAudioStreamsDMA[i].fIsInput = false;
                    231:         }
                    232:         ioAudioStreamsDMA[i].fSampleRate = rate;
                    233: 
                    234: #ifdef DEBUGMODE
                    235:         IOLog("IOAudioBus::DefineStream(%d, %s, %ld, 0x%08lx)\n",i, (direction == kInput ? "kInput" : "kOutput"),rate, (UInt32)base);
                    236: #endif
                    237:     }
                    238:     
                    239:     return false;
                    240: }
                    241: 
                    242: // Returns the first stream in the given direction after the given
                    243: // index. (this is useful if we have to handle more than one stream
                    244: // for input and output). (afterIndex is inclusive)
                    245: 
                    246: AudioStreamIndex
                    247: IOAudioBus::firstStreamAfter(int inDirection, AudioStreamIndex afterIndex)
                    248: {
                    249:     if ((ioAudioStreamsDMA != NULL) && (afterIndex < numDMAStreams)) {
                    250:         for (;afterIndex < numDMAStreams; afterIndex++) {
                    251:             if ((inDirection == kInput) && (ioAudioStreamsDMA[afterIndex].fIsInput))
                    252:                 return (afterIndex);
                    253:             else if ((inDirection == kOutput) && (!ioAudioStreamsDMA[afterIndex].fIsInput))
                    254:                 return (afterIndex);
                    255:         }
                    256:     }
                    257: 
                    258:     // We did not find a stream with the wanted properties
                    259:     return (kInvalidStreamIndex);
                    260: }
                    261: 
                    262: OSDictionary*
                    263: IOAudioBus::getStreamProperties(AudioStreamIndex i)
                    264: {
                    265:     OSDictionary *dict = NULL;
                    266:     OSString *errorString = NULL;
                    267: 
                    268:     if ((ioAudioStreamsDMA != NULL) && (i < numDMAStreams))
                    269:         if (ioAudioStreamsDMA[i].fIOBaseDMA != NULL) {
                    270: 
                    271:             ioAudioStreamsDMA[i].streamProperty = (char*)IOMalloc(128);
                    272:             if (ioAudioStreamsDMA[i].streamProperty != NULL) {
                    273:                 // Depending from the direction of the stream this builds the property
                    274:                 // string:
                    275:                 if (ioAudioStreamsDMA[i].fIsInput) {
                    276:                     sprintf(ioAudioStreamsDMA[i].streamProperty, "{'In'=%d:8;'Out'=%d:8;'Channels'=%d:8;'Rate'=%ld:32;}",
                    277:                             (UInt8)1, (UInt8)0, (UInt8)2,
                    278:                             ioAudioStreamsDMA[i].fSampleRate);
                    279:                 }
                    280:                 else{
                    281:                     sprintf(ioAudioStreamsDMA[i].streamProperty, "{'In'=%d:8;'Out'=%d:8;'Channels'=%d:8;'Rate'=%ld:32;}",
                    282:                             (UInt8)0, (UInt8)1, (UInt8)2,
                    283:                             ioAudioStreamsDMA[i].fSampleRate);
                    284:                 }
                    285: 
                    286:                 dict = OSDynamicCast(OSDictionary, OSUnserialize(ioAudioStreamsDMA[i].streamProperty, &errorString));
                    287:             }
                    288:         }
                    289:             else
                    290:                 IOLog("IOAudioBus::getStreamProperties: bad index %d\n", i);
                    291: 
                    292:     if (dict == NULL) {
                    293:         if (errorString != NULL) {
                    294:             IOLog("IOAudioBus::getStreamProperties %s (\"%s\")\n", errorString->getCStringNoCopy(), ioAudioStreamsDMA[i].streamProperty);
                    295:             errorString->release();
                    296:         }
                    297:     }
                    298: 
                    299:     return dict;
                    300: }
                    301: 
                    302: /*
                    303:  * Map stream data for caller.
                    304:  */
                    305: 
                    306: IOAudioStream *
                    307: IOAudioBus::createAudioStream(AudioStreamIndex index)
                    308: {
                    309:     assert(index < numDMAStreams);
                    310:     IOAudioStream * stream = super::createAudioStream(index);
                    311:     return stream;
                    312: }
                    313: 
                    314: int IOAudioBus::probeStreams()
                    315: {
                    316:     return numDMAStreams;
                    317: }
                    318: 
                    319: IOAudioStreamStatus * IOAudioBus::startStream(AudioStreamIndex index)
                    320: {
                    321:     assert(index < numDMAStreams);
                    322: 
                    323:     int numBlocks, bufSize, i, cmdSize;
                    324:     u_int32_t cmdPhys, bufPhys, seqPhys, offset;
                    325:     IOAudioStreamStatus *status;
                    326:     char *bufs;
                    327:     bool doInterrupt = false;
                    328: 
                    329:     // Calculate size and allocate dbdma command area, sample buffer and shared status.
                    330:     numBlocks = fBufMax/fBlockSize;
                    331:     bufSize = fBlockSize * numBlocks;
                    332:     cmdSize = (numBlocks * 2 + 1) * sizeof(IODBDMADescriptor);
                    333:     IODBDMADescriptor *cmds = (IODBDMADescriptor *)IOMallocAligned(cmdSize, 4);
                    334:     bufs = (char *)IOMallocAligned(round_page(bufSize), PAGE_SIZE);
                    335: 
                    336:     // This makes sure we get an entire page for the status buffer
                    337:     // to prevent the problem of other memory being allocated
                    338:     // in the same page that we're sharing read-only with user space.
                    339:     // Since we don't need an entire page for each status struct,
                    340:     // we could keep track of how much of the page that we've used and
                    341:     // assign chunks of it for each stream...
                    342: 
                    343:     status = (IOAudioStreamStatus *)IOMallocAligned(round_page(sizeof(IOAudioStreamStatus)), PAGE_SIZE);
                    344: 
                    345:     // Everything after this check should always succeed.
                    346:     if(!cmds || !bufs || !status)
                    347:         return NULL;
                    348: 
                    349:     bzero(bufs, bufSize);
                    350: 
                    351:     // get physical addresses of everything for the DBDMA controller.
                    352:     seqPhys = pmap_extract(kernel_pmap, (vm_address_t) &(status->fCurrentBlock));
                    353:     cmdPhys = pmap_extract(kernel_pmap, (vm_address_t) cmds);
                    354:     bufPhys = pmap_extract(kernel_pmap, (vm_address_t) bufs);
                    355:     offset = 0;
                    356:     
                    357:     // The address of the stop command:
                    358:     u_int32_t cmdStopPys = pmap_extract(kernel_pmap, (vm_address_t) (&cmds[numBlocks * 2]));
                    359: 
                    360:     for(i=0; i<numBlocks; i++) {
                    361:         u_int32_t cmdDest;
                    362: 
                    363:         if(offset >= PAGE_SIZE) {
                    364:             bufPhys = pmap_extract(kernel_pmap, (vm_address_t) (bufs + i*fBlockSize));
                    365:             offset = 0;
                    366:         }
                    367: 
                    368:         // Need a DBDMA branch if the next command is on a different page or
                    369:         // if we have to loop back to the first DBDMA command.
                    370:         if(i == numBlocks-1) {
                    371:             cmdDest = cmdPhys;
                    372:             doInterrupt = true;
                    373:         } else if( ((2*(i+1)*sizeof(IODBDMADescriptor)) % PAGE_SIZE) == 0)
                    374:             cmdDest = pmap_extract(kernel_pmap, (vm_address_t) (cmds+2*(i+1)));
                    375:         else
                    376:             cmdDest = 0;
                    377: 
                    378:         IOMakeDBDMADescriptorDep( &cmds[2*i],
                    379:                                         kdbdmaStoreQuad,
                    380:                                         kdbdmaKeyStream0,
                    381:                                         kdbdmaIntNever,
                    382:                                         kdbdmaBranchNever,
                    383:                                         kdbdmaWaitNever,
                    384:                                         sizeof(u_int32_t),
                    385:                                         seqPhys,
                    386:                                         OSReadLittleInt32(&i, 0)  );
                    387:         if(cmdDest) {
                    388:             IOMakeDBDMADescriptorDep( &cmds[2*i+1],
                    389:                                       ioAudioStreamsDMA[index].fDmaCmd,
                    390:                                       kdbdmaKeyStream0,
                    391:                                       doInterrupt ? kdbdmaIntAlways : kdbdmaIntNever,
                    392:                                       kdbdmaBranchAlways,
                    393:                                       kdbdmaWaitNever,
                    394:                                       fBlockSize,
                    395:                                       bufPhys+offset,
                    396:                                       cmdDest);
                    397:         }
                    398:         else {
                    399:            IOMakeDBDMADescriptorDep(  &cmds[2*i+1],
                    400:                                     ioAudioStreamsDMA[index].fDmaCmd,
                    401:                                     kdbdmaKeyStream0,
                    402:                                     kdbdmaIntNever,
                    403:                                     kdbdmaBranchIfTrue,
                    404:                                     kdbdmaWaitNever,
                    405:                                     fBlockSize,
                    406:                                     bufPhys+offset,
                    407:                                     cmdStopPys);
                    408: 
                    409:         }
                    410:         offset += fBlockSize;
                    411:     }
                    412:     
                    413:     // Add a STOP:
                    414:     IOMakeDBDMADescriptor(  &cmds[2*i],
                    415:                         kdbdmaStop,
                    416:                         kdbdmaKeyStream0,
                    417:                         kdbdmaIntNever,
                    418:                         kdbdmaBranchNever,
                    419:                         kdbdmaWaitNever,
                    420:                         0,
                    421:                         NULL);
                    422:     
                    423:     ioAudioStreamsDMA[index].fSharedStatus = status;
                    424:     ioAudioStreamsDMA[index].fCmds = cmds;
                    425:     ioAudioStreamsDMA[index].fCmdSize = cmdSize;
                    426:     ioAudioStreamsDMA[index].fSampleBuffer = (int16_t *)bufs;
                    427:     status->fVersion = 1;
                    428:     status->fErases = ioAudioStreamsDMA[index].fNeedsErase;
                    429:     status->fRunning = 0;
                    430:     status->fConnections = 0;
                    431: 
                    432:     status->fBufSize = bufSize;
                    433:     status->fBlockSize = fBlockSize;
                    434:     status->fNumBlocks = numBlocks;
                    435:     status->fSampleSize = 2;
                    436:     status->fChannels = 2;
                    437:     status->fDataRate = ioAudioStreamsDMA[index].fSampleRate * status->fSampleSize * status->fChannels;
                    438:     status->fCurrentBlock = 0;
                    439:     status->fEraseHeadBlock = 0;
                    440:     status->fCurrentLoopCount = 0;
                    441:     status->fMixBufferInUse = false;
                    442: 
                    443: #ifdef DEBUGMODE
                    444:     IOLog("DMA commands at 0x%x, %d blocks, seq at 0x%x\n", cmds, numBlocks, seqVirt);
                    445:     IOLog("Block size %d, total size %d\n", fBlockSize, bufSize);
                    446: #endif
                    447: 
                    448:     flush_dcache((vm_offset_t) cmds, cmdSize, false );
                    449: 
                    450:     clock_get_uptime(&status->fLastLoopTime);
                    451: 
                    452:     IOSetDBDMAChannelControl( ioAudioStreamsDMA[index].fIOBaseDMA, IOClearDBDMAChannelControlBits(kdbdmaS0));
                    453:     IOSetDBDMABranchSelect( ioAudioStreamsDMA[index].fIOBaseDMA, IOSetDBDMAChannelControlBits(kdbdmaS0));
                    454:     IODBDMAStart( ioAudioStreamsDMA[index].fIOBaseDMA, cmdPhys );
                    455: 
                    456:     return status;
                    457: }
                    458: 
                    459: void IOAudioBus::stopStream(AudioStreamIndex index)
                    460: {
                    461:     IOFilterInterruptEventSource *interruptEventSource;
                    462:     UInt8 attemptsToStop = 100;
                    463: 
                    464:     assert(!ioAudioStreamsDMA[index].fSharedStatus->fRunning);
                    465: 
                    466:     if (index == kAudioDMAOutputStream) {
                    467:         interruptEventSource = fTxInterruptSource;
                    468:     } else {   // index == kAudioDMAInputStream
                    469:         interruptEventSource = fRxInterruptSource;
                    470:     }
                    471:     interruptEventSource->disable();
                    472: 
                    473:     IOSetDBDMAChannelControl( ioAudioStreamsDMA[index].fIOBaseDMA, IOSetDBDMAChannelControlBits(kdbdmaS0));
                    474:     while ((IOGetDBDMAChannelStatus(ioAudioStreamsDMA[index].fIOBaseDMA) & kdbdmaActive ) && (attemptsToStop--)) {
                    475:         eieio();
                    476:         IOSleep(10);
                    477:     }
                    478: 
                    479:     IODBDMAStop( ioAudioStreamsDMA[index].fIOBaseDMA );
                    480:     IODBDMAReset( ioAudioStreamsDMA[index].fIOBaseDMA );
                    481: 
                    482:     IOFreeAligned(ioAudioStreamsDMA[index].fCmds, ioAudioStreamsDMA[index].fCmdSize);
                    483:     IOFreeAligned(ioAudioStreamsDMA[index].fSampleBuffer, round_page(ioAudioStreamsDMA[index].fSharedStatus->fBufSize));
                    484:     IOFreeAligned(ioAudioStreamsDMA[index].fSharedStatus, round_page(sizeof(IOAudioStreamStatus)));
                    485: 
                    486:     ioAudioStreamsDMA[index].fCmds = NULL;
                    487:     ioAudioStreamsDMA[index].fSampleBuffer = NULL;
                    488:     ioAudioStreamsDMA[index].fSharedStatus = NULL;
                    489: 
                    490:     interruptEventSource->enable();
                    491: }
                    492: 
                    493: void IOAudioBus::pauseStream(AudioStreamIndex index)
                    494: {
                    495:     assert(index < numDMAStreams);
                    496:     IODBDMAPause( ioAudioStreamsDMA[index].fIOBaseDMA );
                    497: }
                    498: 
                    499: void IOAudioBus::resumeStream(AudioStreamIndex index)
                    500: {
                    501:     assert(index < numDMAStreams);
                    502: 
                    503:     IODBDMAContinue( ioAudioStreamsDMA[index].fIOBaseDMA );
                    504: }
                    505: 
                    506: IOAudioStreamStatus * IOAudioBus::getSharedStatus(AudioStreamIndex index)
                    507: {
                    508:     assert(index < numDMAStreams);
                    509:     return ioAudioStreamsDMA[index].fSharedStatus;
                    510: }
                    511: 
                    512: void * IOAudioBus::getSampleBuffer(AudioStreamIndex index)
                    513: {
                    514:     assert(index < numDMAStreams);
                    515:     return ioAudioStreamsDMA[index].fSampleBuffer;
                    516: }
                    517: 
                    518: #endif // __ppc__

unix.superglobalmegacorp.com

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