/* Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/ All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * ======== audioStreamOutIo.c ======== */ #include // for memset #include #include #include #include "mcasp_cfg.h" #include "ioConfig.h" //TODO: remove this header #include "ioBuff.h" #include "ioPhy.h" #include "ioData.h" #include "pafsio_ialg.h" #include "stdasp.h" #include "asperr.h" #include "audioStreamProc_common.h" #include "audioStreamOutProc.h" #include "audioStreamOutIo.h" #define DEC_OUTNUMBUF_MAP(X) \ pP->poutNumBufMap[z]->map[(X) >= pP->poutNumBufMap[z]->length ? 0 : (X)] #define STRIDE_WORST_CASE 32 // 4-byte (32-bit) word, 2 slots, 4 serializers extern Ptr hMcaspTxChan; extern Int d10Initialized; // FL, New IO: this function is currently a stub // FL, New IO: need to McASP/EDMA configuration using SAP configuration from Output shortcut // Select Output devices Int asopSelectDevices(void *pConfig, PAF_AST_IoOut *pOut) { if((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) { return -1; } if(pOut->hMcaspChan == NULL) { Audk2g_STATUS status; mcaspLLDconfig * lldCfg; Ptr mcaspChanHandle; lldCfg = (mcaspLLDconfig *)pConfig; status = mcasplldChanCreate(lldCfg, &mcaspChanHandle); if(status != Audk2g_EOK) { return -1; } pOut->hMcaspChan = mcaspChanHandle; pOut->stride = lldCfg->mcaspChanParams->noOfSerRequested * lldCfg->mcaspChanParams->noOfChannels; } return 0; } // Check if Output device SIO selection changed Int checkOutDevSioSelUpdate( const PAF_ASOT_Params *pP, PAF_ASOT_Config *pAsotCfg, Int z, Bool *pOutDevSelUpdate ) { PAF_AST_Config *pAstCfg; pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration if ((z < OUTPUT1) || (z >= OUTPUTN)) { *pOutDevSelUpdate = FALSE; return -1; } *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0); return 0; } // Check if any Output device SIO selection changed Int checkAnyOutDevSioSelUpdate( const PAF_ASOT_Params *pP, PAF_ASOT_Config *pAsotCfg, Bool *pOutDevSelUpdate ) { PAF_AST_Config *pAstCfg; Int outDevSelUpdate; Int z; pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration outDevSelUpdate = FALSE; for (z=OUTPUT1; z < OUTPUTN; z++) { if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0) { outDevSelUpdate = TRUE; break; } } *pOutDevSelUpdate = outDevSelUpdate; return 0; } // ----------------------------------------------------------------------------- // ASOT Decoding Function Helper - SIO Driver Change // // Name: PAF_ASOT_setCheckRateX // Purpose: Decoding Function for reinitiating output. // From: AST Parameter Function -> decodeInfo1 // AST Parameter Function -> decodeInfo2 // Uses: See code. // States: x // Return: Error number in standard form (0 on success). // Trace: None. // /* 0: set, 1: check, unused for now. --Kurt */ Int asopSetCheckRateX( const PAF_ASOT_Params *pP, const PAF_ASOT_Patchs *pQ, PAF_ASOT_Config *pAsotCfg, Int check ) { PAF_AST_Config *pAstCfg; PAF_AST_IoOut *pOut; float rateX; PAF_SampleRateHz rateO /* std */, rateI /* inv */; Int z; /* output counter */ Int zx; /* output re-counter */ Int getVal; int inputRate, inputCount, outputRate, outputCount; Int zMD; Int zMI; Int zMS; Int zE, zX; pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration zMD = pAstCfg->masterDec; zMS = pAstCfg->masterStr; zMI = pP->zone.master; inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus; inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength; rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, inputRate, PAF_SAMPLERATEHZ_INV); for (z=OUTPUT1; z < OUTPUTN; z++) { if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) { // determine associated encoder zE = z; for (zX = ENCODE1; zX < ENCODEN; zX++) { if (pP->outputsFromEncodes[zX] == z) { zE = zX; break; } } outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate; outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength; rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, outputRate, PAF_SAMPLERATEHZ_STD); if ((rateI > 0) && (rateO > 0)) { rateX = rateO /* std */ * rateI /* inv */; } else if (inputCount != 0) { rateX = (float)outputCount / inputCount; } else { return ASPERR_INFO_RATERATIO; } #if 0 // FL, New IO: add similar thing to be figured out getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX); if (getVal == DOBERR_RATECHANGE) { for (zx=OUTPUT1; zx < OUTPUTN; zx++) { if (pAstCfg->xOut[zx].hTxSio) { SIO_idle(pAstCfg->xOut[zx].hTxSio); } } // this forces an exit from the calling state machine which will // eventually call startOutput which calls setCheckRateX for all outputs // and so it is ok, in the presence of a rate change on any output, to // exit this loop /function early. return ASPERR_INFO_RATECHANGE; } else if (getVal != SYS_OK) { return ((getVal & 0xff) | ASPERR_RATE_CHECK); } #endif // FL, New IO } } return 0; } //asopSetCheckRateX // ----------------------------------------------------------------------------- // ASOT Decoding Function Helper - SIO Driver Start // // Name: PAF_ASOT_startOutput // Purpose: Decoding Function for initiating output. // From: AST Parameter Function -> decodeInfo1 // Uses: See code. // States: x // Return: Error number in standard or SIO form (0 on success). // Trace: Message Log "trace" in Debug Project Configuration reports: // * State information as per parent. // * SIO control errors. // Int asopStartOutput( const PAF_ASOT_Params *pP, const PAF_ASOT_Patchs *pQ, PAF_ASOT_Config *pAsotCfg ) { PAF_AST_Config *pAstCfg; PAF_AST_IoOut *pOut; Int as; /* Audio Stream Number (1, 2, etc.) */ Int z; /* output counter */ Int nbufs; Int zE, zS, zX; Int zMD; PAF_SIO_IALG_Obj *pObj; PAF_SIO_IALG_Config *pAlgConfig; ioPhyCtl_t ioPhyCtl; pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration as = pAstCfg->as; zMD = pAstCfg->masterDec; for (z=OUTPUT1; z < OUTPUTN; z++) { if (pOut[z].hIoPhy) { // determine associated encoder and stream zE = z; zS = z; for (zX = ENCODE1; zX < ENCODEN; zX++) { if (pP->outputsFromEncodes[zX] == z) { zE = zX; zS = pP->streamsFromEncodes[zE]; break; } } // FL, New IO: add similar thing to be figured out // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns . #if 0 // if device selected and valid then enable stat tracking if // required and start clocking if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio)) { TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks"); errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0); if (errno) { TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno); SIO_idle(pAstCfg->xOut[z].hTxSio); if (!errno) { errno = ASPERR_DEVOUT + errme; } } } #endif // Set sample count so that DOB knows how much data to send pAstCfg->xOut[z].outBufConfig.lengthofFrame = pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount; #if 1 // FL, New IO: add similar thing to be figured out // Update framework Phy transfer size pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM; // Update IO Phy transfer size ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE; ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize; ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl); // Update IO Buff delay to match Phy transfer size ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1)); #endif if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED) { pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg; pAlgConfig = &pObj->config; memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA, pAlgConfig->pMemRec[0].size); } // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master // decoder. How should we handle the sourceProgram for multiple decoders? // Override as needed nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram); if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0) { nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram]; } //JXTODO: add similar thing to be figured out //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs); //JXTODO: data transfer start to be moved to output task state machine /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio, &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0)) { SIO_idle(pAstCfg->xOut[z].hTxSio); TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno); return errno; } */ //JXTODO: add similar thing to be figured out #if 0 if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) && (errno = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0))) { errno = (errno & 0xff) | ASPERR_MUTE; /* convert to sensical errno */ TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno); return errno; } else { pAstCfg->xOut[z].outBufStatus.audio = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND; } #endif TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS); } } return 0; } /* asopStartOutput */ // ----------------------------------------------------------------------------- // ASOT Decoding Function Helper - SIO Driver Stop // // Name: PAF_ASOT_stopOutput // Purpose: Decoding Function for terminating output. // From: AST Parameter Function -> decodeProcessing // AST Parameter Function -> decodeComplete // Uses: See code. // States: x // Return: Error number in standard or SIO form (0 on success). // Trace: Message Log "trace" in Debug Project Configuration reports: // * SIO control errors. // Int asopStopOutput( const PAF_ASOT_Params *pP, const PAF_ASOT_Patchs *pQ, PAF_ASOT_Config *pAsotCfg ) { PAF_AST_Config *pAstCfg; PAF_AST_IoOut *pOut; Int as; /* Audio Stream Number (1, 2, etc.) */ Int z; /* output counter */ Int errno = 0, getVal; Int zS, zX; PAF_SIO_IALG_Obj *pObj; PAF_SIO_IALG_Config *pAlgConfig; pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration as = pAstCfg->as; (void)as; // clear compiler warning in case not used with tracing disabled for (z=OUTPUT1; z < OUTPUTN; z++) { if (pOut[z].hIoPhy) { // determine associated encoder and stream zS = z; (void)zS; for (zX = ENCODE1; zX < ENCODEN; zX++) { if (pP->outputsFromEncodes[zX] == z) { zS = pP->streamsFromEncodes[zX]; break; } } #if 0 // FL, New IO: add similar thing to be figured out // Mute output before audio data termination in the usual case, // where such termination is due to decode error or user command. // Identification of this as the usual case is provided by the // "decode processing" state machine. if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) && ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) && (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) { if (!errno) { errno = (getVal & 0xff) | ASPERR_MUTE; /* convert to sensical errno */ } TRACE_VERBOSE1("asopStopOutput: AS%d: SIO control failed (mute)", as+zS); } TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time())); // Terminate audio data output, truncating (ignore) or flushing // (play out) final samples as per (1) control register set by // the user and (2) the type of audio data termination: #if 0 // This form is not used because driver support for truncating // data is not supported for internal clocks, although it is // for external clocks. getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE, pC->xOut[z].outBufStatus.flush & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH ? 1 : 0); /* UNTESTED */ #else // This form should be used when driver support for truncating // data is supported for both internal and external clocks. getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE, pAstCfg->xOut[z].outBufStatus.flush ? 1 : (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH ? 1 : 0); /* TESTED */ #endif TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time())); if (!errno) { errno = getVal; } // Mute output after audio data termination in a special case, // where such termination is due to processing of a final frame // or user command. Identification of this as a special case is // provided by the "decode processing" state machine. if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) && ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) && (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) { if (!errno) { errno = (getVal & 0xff) | ASPERR_MUTE; /* convert to sensical errno */ } TRACE_VERBOSE1("as1-f2: asopStopOutput: AS%d: SIO control failed (mute)", as+zS); } pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f; #endif // FL, New IO // zero output buffers pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg; pAlgConfig = &pObj->config; memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size); } //pAstCfg->xOut[z].hTxSio }//OUTPUT return errno; } //asopStopOutput /*=========================================================================== * Initialize I/O components for output processing ============================================================================*/ Int asopIoCompsInit( PAF_AST_OutBuf *pOutBuf, PAF_AST_IoOut *pOutIo ) { // Initialize I/O BUFF and I/O PHY components for output task ioBuffParams_t ioBuffParams; ioPhyParams_t ioPhyParams; ioBuffParams.base = pOutBuf->outBufConfig.base.pVoid; ioBuffParams.size = pOutBuf->outBufConfig.allocation/STRIDE_WORST_CASE*STRIDE_WORST_CASE; ioBuffParams.sync = IOBUff_READ_SYNC; ioBuffParams.nominalDelay = NUM_CYCLE_PER_FRAME_DEF * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1); if(ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) { return -1; // to remove magic number } ioPhyParams.ioBuffHandle = pOutIo->hIoBuff; ioPhyParams.xferFrameSize = NUM_CYCLE_PER_FRAME_DEF * pOutIo->stride * WORD_SIZE_PCM; ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan; ioPhyParams.ioBuffOp = IOPHY_IOBUFFOP_READ; if(ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) { return -1; // to remove magic number } pOutIo->phyXferSize = ioPhyParams.xferFrameSize; pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap) pOutIo->errIoBuffOvrCnt = 0; // initialize IO buff overflow count pOutIo->errIoBuffUndCnt = 0; // initialize IO buff underflow count return 0; } /* asopIoCompsInit */ /*====================================================================================== * This function checks whether the I/O physical layer has been initialized *====================================================================================*/ Bool asopIoPhyCheckInit(Void) { if (!d10Initialized) return FALSE; else return TRUE; } /*====================================================================================== * I/O physical layer prime operation required by McASP LLD *====================================================================================*/ Void asopIoPhyPrime( PAF_AST_IoOut *pOut ) { Int32 count; pOut->numPrimeXfers = NUM_PRIME_XFERS; for (count = 0; count < pOut->numPrimeXfers; count++) { ioPhyXferSubmit(pOut->hIoPhy); } } /* asipIoPhyPrime */ // Initialize Output buffer configuration Int asopInitOutBufConfig( PAF_AST_OutBuf *pOutBuf, PAF_AST_IoOut *pOutIo ) { PAF_OutBufConfig *pOutBufCfg; ioBuffHandle_t hIoBuff; ioBuffInfo_t outBuffInfo; pOutBufCfg = &pOutBuf->outBufConfig; hIoBuff = pOutIo->hIoBuff; pOutBufCfg->stride = pOutIo->stride; pOutBufCfg->sizeofElement = WORD_SIZE_PCM; pOutBufCfg->precision = 24; ioBuffGetInfo(hIoBuff, &outBuffInfo); pOutBufCfg->base.pLgInt = outBuffInfo.base; pOutBufCfg->sizeofBuffer = outBuffInfo.size; pOutBuf->pOutBuf = &(pOutBuf->outBufConfig); return 0; } Int asopGetOutBufPtrs( PAF_AST_IoOut *pOutIo, size_t writeSize ) { void *buff1, *buff2; size_t size1, size2; Int status; status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize, &buff1, &size1, &buff2, &size2); if (status == IOBUFF_ERR_OVERFLOW) { pOutIo->errIoBuffOvrCnt++; //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug // skip processing since output buffer overflows return -1; } else if (status == IOBUFF_ERR_UNDERFLOW) { pOutIo->errIoBuffUndCnt++; //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug // already underflows and remain in underflow } // save buffer pointers & sizes for later write complete pOutIo->buff1 = buff1; pOutIo->size1 = size1; pOutIo->buff2 = buff2; pOutIo->size2 = size2; return 0; } #if 0 // Update Output buffer configuration. // This is needed for proper operation of PCM encoder. Int asopUpdateOutBufConfig( PAF_AST_OutBuf *pOutBuf, PAF_AST_IoOut *pOutIo ) { PAF_OutBufConfig *pOutBufCfg; ioBuffHandle_t hIoBuff; ioBuffInfo_t outBuffInfo; void *buff1, *buff2; size_t size1, size2, total_write_size; Int status; pOutBufCfg = &pOutBuf->outBufConfig; hIoBuff = pOutIo->hIoBuff; // FL, New IO: original code can change these values in every DOB issue // Need to determine if this is required or not. pOutBufCfg->stride = pOutIo->stride; pOutBufCfg->sizeofElement = WORD_SIZE_PCM; pOutBufCfg->precision = 24; //JXTODO: to replace hard coded write size // Get write pointers of output memory pool total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement; status = ioBuffGetWritePtrs(hIoBuff, total_write_size, &buff1, &size1, &buff2, &size2); if (status == IOBUFF_ERR_OVERFLOW) { pOutIo->errIoBuffOvrCnt++; //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug // skip processing since output buffer overflows return -1; } else if (status == IOBUFF_ERR_UNDERFLOW) { pOutIo->errIoBuffUndCnt++; //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug // already underflows and remain in underflow } #if 0 // Update Output buffer pointer for Encoder pOutBufCfg->pntr.pLgInt = buff1; if ((buff2 != NULL) || (size2 != 0)) { // buff2 should always be NULL for Output & size2 should always be 0 for Output. // Track this here. pOutIo->ioBuffBuf2AllocCnt++; // debug } #endif // save buffer pointers & sizes for later write complete pOutIo->buff1 = buff1; pOutIo->size1 = size1; pOutIo->buff2 = buff2; pOutIo->size2 = size2; return 0; } #endif // Mark Output buffers write complete Int asopMarkOutBuffsWriteComplete( PAF_AST_OutBuf *pOutBuf, PAF_AST_IoOut *pOutIo ) { ioBuffHandle_t hIoBuff; void *buff1, *buff2; size_t size1, size2; // get buffer pointers & sizes from previous IO Buff write allocation buff1 = pOutIo->buff1; size1 = pOutIo->size1; buff2 = pOutIo->buff2; // this should always be NULL for Output size2 = pOutIo->size2; // this should always be 0 for Output hIoBuff = pOutIo->hIoBuff; ioBuffWriteComplete(hIoBuff, buff1, size1); if (buff2 != NULL) { ioBuffWriteComplete(hIoBuff, buff2, size2); } return 0; } /*====================================================================================== * This function starts an I/O PHY transfer for output *====================================================================================*/ Void asopPhyTransferStart( PAF_AST_IoOut *pOut ) { if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) { //mcaspTxReset(); //mcaspTxCreate(); //pOut->hMcaspChan = hMcaspTxChan; System_abort("\nMcASP for output underruns! %d!\n"); } else { if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) { // Output buffer underflows! System_abort("\nOutput buffer underflows!\n"); } else { // Output buffer operates normally ; } } } /* nothing past this point */