PASDK-577:Add McASP LLD ch reset before McASP LLD ch delete
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / framework / audioStreamOutIo.c
2 /*
3 Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
4 All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35 /*
36  *  ======== audioStreamOutIo.c ========
37  */
39 #include <string.h> // for memset
40 #include <xdc/runtime/Log.h>
41 #include <xdc/runtime/System.h>
42 #include <xdc/std.h>
44 #include "mcasp_cfg.h"
45 #include "ioConfig.h"    //TODO: remove this header
46 #include "ioBuff.h"
47 #include "ioPhy.h"
48 #include "ioData.h"
50 #include "pafsio_ialg.h"
51 #include "stdasp.h"
52 #include "asperr.h"
54 #include "audioStreamProc_common.h"
55 #include "audioStreamOutProc.h"
56 #include "audioStreamOutIo.h"
58 #define DEC_OUTNUMBUF_MAP(X) \
59       pP->poutNumBufMap[z]->map[(X) >= pP->poutNumBufMap[z]->length ? 0 : (X)]
61 //#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
63 extern Ptr hMcaspTxChan;
64 extern Int d10Initialized;
67 // Select Output devices
68 Int asopSelectDevices(
69     const PAF_SIO_Params *pOutCfg, 
70     PAF_AST_IoOut *pOut
71 )
72 {
73     mcaspLLDconfig *pReqLldCfg;
74     Ptr mcaspChanHandle;
75     Aud_STATUS status;
77     if ((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) 
78     {
79         return ASOP_IO_ERR_IO_UNINIT;
80     }
82     // Deactivate currently active Output device
83     if (pOut->hMcaspChan != NULL)
84     {
85         
86         // check McASP LLD control API
87         mcaspControlChan(pOut->hMcaspChan, MCASP_CHAN_RESET, NULL);
88         // Delete McASP LLD channel
89         status = mcaspDeleteChan(pOut->hMcaspChan);
90         if (status != Aud_EOK)
91         {
92             Log_info0("asopSelectDevices(): McASP channel deletion failed!\n");
93             return ASOP_IO_ERR_MCASP_CFG;
94         }
95         
96         pOut->hMcaspChan = NULL;            // reset active McASP LLD handle
97         pOut->pLldCfg->hMcaspChan = NULL;   // reset McASP LLD handle for active McASP LLD configuration
98         pOut->pLldCfg = NULL;               // reset pointer to active McASP LLD configuration
99     }
101     // Activate requested device
102     if (pOutCfg != NULL)
103     {
104         //
105         // Device other than OutNone selected
106         //
107         
108         pReqLldCfg = (mcaspLLDconfig *)pOutCfg->sio.pConfig;
109         if (pReqLldCfg->hMcaspChan == NULL) 
110         {
111             // Create McASP LLD channel
112             mcaspChanHandle = NULL;
113             status = mcasplldChanCreate(pReqLldCfg, &mcaspChanHandle);
114             if (status != Aud_EOK) {
115                 Log_info0("asopSelectDevices(): McASP channel creation failed!\n");
116                 return ASOP_IO_ERR_MCASP_CFG;
117             }
119             pReqLldCfg->hMcaspChan = mcaspChanHandle;   // set McASP LLD handle for requested McASP LLD configuration
120             pOut->pLldCfg = pReqLldCfg;                 // set pointer to active McASP LLD configuration
121             pOut->hMcaspChan = pReqLldCfg->hMcaspChan;  // set active McASP LLD handle
122             
123             // configure stride according to selected McASP LLD configuration
124             pOut->stride = pReqLldCfg->mcaspChanParams->noOfSerRequested * 
125                 pReqLldCfg->mcaspChanParams->noOfChannels;
126         }
127     }
128     else
129     {
130         //
131         // OutNone device selected
132         //
133         
134         pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
135         pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
136     }
138     return ASOP_IO_SOK;
141 // Check if Output device SIO selection changed
142 Int checkOutDevSioSelUpdate(
143     const PAF_ASOT_Params *pP, 
144     PAF_ASOT_Config *pAsotCfg,
145     Int z, 
146     Bool *pOutDevSelUpdate
149     PAF_AST_Config *pAstCfg;
150     
151     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
153     if ((z < OUTPUT1) || (z >= OUTPUTN))
154     {
155         *pOutDevSelUpdate = FALSE;
156         return ASOP_IO_ERR_INV_PARAMS;
157     }
158     
159     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
161     return ASOP_IO_SOK;
164 // Check if any Output device SIO selection changed
165 Int checkAnyOutDevSioSelUpdate(
166     const PAF_ASOT_Params *pP, 
167     PAF_ASOT_Config *pAsotCfg,
168     Bool *pOutDevSelUpdate
171     PAF_AST_Config *pAstCfg;
172     Int outDevSelUpdate;
173     Int z;
174     
175     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
177     outDevSelUpdate = FALSE;
178     for (z=OUTPUT1; z < OUTPUTN; z++) 
179     {
180         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
181         {
182             outDevSelUpdate = TRUE;
183             break;
184         }
185     }
186     
187     *pOutDevSelUpdate = outDevSelUpdate;
189     return ASOP_IO_SOK;
192 // -----------------------------------------------------------------------------
193 // ASOT Decoding Function Helper - SIO Driver Change
194 //
195 //   Name:      PAF_ASOT_setCheckRateX
196 //   Purpose:   Decoding Function for reinitiating output.
197 //   From:      AST Parameter Function -> decodeInfo1
198 //              AST Parameter Function -> decodeInfo2
199 //   Uses:      See code.
200 //   States:    x
201 //   Return:    Error number in standard form (0 on success).
202 //   Trace:     None.
203 //
205 /* 0: set, 1: check, unused for now. --Kurt */
206 Int asopSetCheckRateX(
207     const PAF_ASOT_Params *pP, 
208     const PAF_ASOT_Patchs *pQ, 
209     PAF_ASOT_Config *pAsotCfg, 
210     Int check
213     PAF_AST_Config *pAstCfg;
214     PAF_AST_IoOut  *pOut;
215     float rateX;
216     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
217     Int z;                              /* output counter */
218     Int zx;                             /* output re-counter */
219     Int getVal;
220     int inputRate, inputCount, outputRate, outputCount;
221     Int zMD;
222     Int zMI;
223     Int zMS;
224     Int zE, zX;
226     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
227     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
228     
229     zMD = pAstCfg->masterDec;
230     zMS = pAstCfg->masterStr;
231     zMI = pP->zone.master;
233     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
234     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
235     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
236         inputRate, PAF_SAMPLERATEHZ_INV);
238     for (z=OUTPUT1; z < OUTPUTN; z++) 
239     {
240         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
241         {
242             // determine associated encoder
243             zE = z;
244             for (zX = ENCODE1; zX < ENCODEN; zX++) 
245             {
246                 if (pP->outputsFromEncodes[zX] == z) 
247                 {
248                     zE = zX;
249                     break;
250                 }
251             }
253             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
254             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
255             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
256                 outputRate, PAF_SAMPLERATEHZ_STD);
257             if ((rateI > 0) && (rateO > 0))
258             {
259                 rateX = rateO /* std */ * rateI /* inv */;
260             }
261             else if (inputCount != 0)
262             {
263                 rateX = (float)outputCount / inputCount;
264             }
265             else
266             {
267                 return ASPERR_INFO_RATERATIO;
268             }
270 #if 0 // FL, New IO: add similar thing to be figured out     
271             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
272             if (getVal == DOBERR_RATECHANGE) 
273             {
274                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
275                 {
276                     if (pAstCfg->xOut[zx].hTxSio)
277                     {
278                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
279                     }
280                 }
282                 // this forces an exit from the calling state machine which will
283                 // eventually call startOutput which calls setCheckRateX for all outputs
284                 // and so it is ok, in the presence of a rate change on any output, to
285                 // exit this loop /function early.
286                 return ASPERR_INFO_RATECHANGE;
287             }
288             else if (getVal != SYS_OK)
289             {
290                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
291             }
292 #endif // FL, New IO
293             // FL: ugly little experiment
294             //*(volatile UInt32 *)0x23400B0 |= 7;
295         }
296     }
298     return ASOP_IO_SOK;
299 } //asopSetCheckRateX
301 // -----------------------------------------------------------------------------
302 // ASOT Decoding Function Helper - SIO Driver Start
303 //
304 //   Name:      PAF_ASOT_startOutput
305 //   Purpose:   Decoding Function for initiating output.
306 //   From:      AST Parameter Function -> decodeInfo1
307 //   Uses:      See code.
308 //   States:    x
309 //   Return:    Error number in standard or SIO form (0 on success).
310 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
311 //              * State information as per parent.
312 //              * SIO control errors.
313 //
314 Int asopStartOutput(
315     const PAF_ASOT_Params *pP,
316     const PAF_ASOT_Patchs *pQ,
317     PAF_ASOT_Config *pAsotCfg
320     PAF_AST_Config *pAstCfg;
321     PAF_AST_IoOut  *pOut;
322     Int as;                     /* Audio Stream Number (1, 2, etc.) */
323     Int z;                      /* output counter */
324     Int nbufs;
325     Int zE, zS, zX;
326     Int zMD;
327     PAF_SIO_IALG_Obj    *pObj;
328     PAF_SIO_IALG_Config *pAlgConfig;
329     ioPhyCtl_t ioPhyCtl;
332     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
333     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
334     as = pAstCfg->as;
335     zMD = pAstCfg->masterDec;
337     for (z=OUTPUT1; z < OUTPUTN; z++)
338     {
339         if (pOut[z].hIoPhy)
340         {
341             // determine associated encoder and stream
342             zE = z;
343             zS = z;
344             for (zX = ENCODE1; zX < ENCODEN; zX++)
345             {
346                 if (pP->outputsFromEncodes[zX] == z)
347                 {
348                     zE = zX;
349                     zS = pP->streamsFromEncodes[zE];
350                     break;
351                 }
352             }
354             // FL, New IO: add similar thing to be figured out
355 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
356 #if 0
357             // if device selected and valid then enable stat tracking if
358             // required and start clocking
359             if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
360             {
361                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
362                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
363                 if (errno)
364                 {
365                     TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
366                     SIO_idle(pAstCfg->xOut[z].hTxSio);
367                     if (!errno)
368                     {
369                         errno = ASPERR_DEVOUT + errme;
370                     }
371                 }
372             }
373 #endif            
375             // Set sample count so that DOB knows how much data to send
376             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
377                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
379 #if 1 // FL, New IO: add similar thing to be figured out
380             // Update framework Phy transfer size
381             pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
382             // Update IO Phy transfer size
383             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
384             ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
385             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
386             // Update IO Buff delay to match Phy transfer size
387             ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
388 #endif
390             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
391             {
392                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
393                 pAlgConfig = &pObj->config;
394                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
395                     pAlgConfig->pMemRec[0].size);
396             }
398             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
399             // decoder. How should we handle the sourceProgram for multiple decoders?
400             // Override as needed
401             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
402             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
403             {
404                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
405             }
406             //JXTODO: add similar thing to be figured out
407             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
409             //JXTODO: data transfer start to be moved to output task state machine
410             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
411                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
412             {
413                 SIO_idle(pAstCfg->xOut[z].hTxSio);
414                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
415                 return errno;
416             } */
418             //JXTODO: add similar thing to be figured out
419 #if 0
420             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
421                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
422             {
423                 errno = (errno & 0xff) | ASPERR_MUTE;
424                 /* convert to sensical errno */
425                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
426                 return errno;
427             }
428             else
429             {
430                 pAstCfg->xOut[z].outBufStatus.audio
431                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
432             }
433 #endif
434             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
435         }
436     }
438     return ASOP_IO_SOK;
439 } /* asopStartOutput */
441 // -----------------------------------------------------------------------------
442 // ASOT Decoding Function Helper - SIO Driver Stop
443 //
444 //   Name:      PAF_ASOT_stopOutput
445 //   Purpose:   Decoding Function for terminating output.
446 //   From:      AST Parameter Function -> decodeProcessing
447 //              AST Parameter Function -> decodeComplete
448 //   Uses:      See code.
449 //   States:    x
450 //   Return:    Error number in standard or SIO form (0 on success).
451 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
452 //              * SIO control errors.
453 //
454 Int asopStopOutput(
455     const PAF_ASOT_Params *pP, 
456     const PAF_ASOT_Patchs *pQ, 
457     PAF_ASOT_Config *pAsotCfg
460     PAF_AST_Config *pAstCfg;
461     PAF_AST_IoOut  *pOut;
462     Int as;                     /* Audio Stream Number (1, 2, etc.) */
463     Int z;                      /* output counter */
464     Int errno, getVal;
465     Int zS, zX;
466     PAF_SIO_IALG_Obj    *pObj;
467     PAF_SIO_IALG_Config *pAlgConfig;
469     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
470     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
471     as = pAstCfg->as;
472     (void)as;  // clear compiler warning in case not used with tracing disabled
474     errno = ASOP_IO_SOK;
475     for (z=OUTPUT1; z < OUTPUTN; z++) 
476     {
477         if (pOut[z].hIoPhy) 
478         {
479             // determine associated encoder and stream
480             zS = z;
481             (void)zS;
482             for (zX = ENCODE1; zX < ENCODEN; zX++) 
483             {
484                 if (pP->outputsFromEncodes[zX] == z) 
485                 {
486                     zS = pP->streamsFromEncodes[zX];
487                     break;
488                 }
489             }
491 #if 0 // FL, New IO: add similar thing to be figured out            
492             // Mute output before audio data termination in the usual case,
493             // where such termination is due to decode error or user command.
494             // Identification of this as the usual case is provided by the
495             // "decode processing" state machine.
496             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
497                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
498                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
499             {
500                 if (!errno) 
501                 {
502                     errno = (getVal & 0xff) | ASPERR_MUTE;
503                     /* convert to sensical errno */
504                 }
505                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
506             }
508             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
509             
510             // Terminate audio data output, truncating (ignore) or flushing
511             // (play out) final samples as per (1) control register set by
512             // the user and (2) the type of audio data termination:
514 #if 0
515             // This form is not used because driver support for truncating
516             // data is not supported for internal clocks, although it is
517             // for external clocks.
518             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
519                 pC->xOut[z].outBufStatus.flush
520                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
521                 ? 1 : 0);
522             /* UNTESTED */
523 #else
524             // This form should be used when driver support for truncating
525             // data is supported for both internal and external clocks.
526             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
527                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
528                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
529                 ? 1 : 0);
530             /* TESTED */
531 #endif
533             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
535             if (!errno)
536             {
537                 errno = getVal;
538             }
540             // Mute output after audio data termination in a special case,
541             // where such termination is due to processing of a final frame
542             // or user command. Identification of this as a special case is
543             // provided by the "decode processing" state machine.
544             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
545                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
546                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
547             {
548                 if (!errno) 
549                 {
550                     errno = (getVal & 0xff) | ASPERR_MUTE;
551                     /* convert to sensical errno */
552                 }
553                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
554             }
556             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
557 #endif // FL, New IO
559             // zero output buffers
560             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
561             pAlgConfig = &pObj->config;
562             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
563         } //pAstCfg->xOut[z].hTxSio
564     }//OUTPUT
566     return errno;
567 } //asopStopOutput
569 /*===========================================================================
570  * Initialize I/O components for output processing
571 ============================================================================*/
572 Int asopIoCompsInit(
573     Int16 strAfSampleCount,     // stream audio frame sample count
574     PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
575     PAF_AST_IoOut *pOutIo       // pointer to Output IO
578     ioBuffParams_t ioBuffParams;
579     ioPhyParams_t  ioPhyParams;
581     if (pOutIo->hMcaspChan != NULL)
582     {
583         // Initialize I/O BUFF and I/O PHY components for output task
584         ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
585         // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
586         // This ensures no split buffers will be allocated on Output buffer wrap.
587         ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
588             (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
589         ioBuffParams.sync         = IOBUff_READ_SYNC;
590         ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
591         if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
592         {
593             return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
594         }
596         ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
597         ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
598         ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
599         ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
600         if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
601         {
602             return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
603         }
605         pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
606         
607         pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
608         pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
609         pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
610     }
611     
612     return ASOP_IO_SOK;
613 } /* asopIoCompsInit */
615 /*======================================================================================
616  *  This function checks whether the I/O physical layer has been initialized
617  *====================================================================================*/
618 Bool asopIoPhyCheckInit(Void)
620     if (!d10Initialized)
621         return FALSE;
622     else 
623         return TRUE;
626 /*======================================================================================
627  *  I/O physical layer prime operation required by McASP LLD
628  *====================================================================================*/
629 Void asopIoPhyPrime(
630     PAF_AST_IoOut *pOut
633     Int32        count;
635     pOut->numPrimeXfers = NUM_PRIME_XFERS;
637     for (count = 0; count < pOut->numPrimeXfers; count++)
638     {
639         ioPhyXferSubmit(pOut->hIoPhy);
640     }
641 } /* asipIoPhyPrime */
643 // Initialize Output buffer configuration
644 Int asopInitOutBufConfig(
645     PAF_AST_OutBuf *pOutBuf, 
646     PAF_AST_IoOut *pOutIo
649     PAF_OutBufConfig *pOutBufCfg;
650     ioBuffHandle_t hIoBuff;
651     ioBuffInfo_t outBuffInfo;
652     
653     pOutBufCfg = &pOutBuf->outBufConfig;
654     hIoBuff = pOutIo->hIoBuff;
655     
656     pOutBufCfg->stride = pOutIo->stride;
657     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
658     pOutBufCfg->precision = 24;
659     
660     ioBuffGetInfo(hIoBuff, &outBuffInfo);
661     pOutBufCfg->base.pLgInt = outBuffInfo.base;
662     pOutBufCfg->sizeofBuffer = outBuffInfo.size;
663     
664     pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
665     
666     return ASOP_IO_SOK;
669 Int asopGetOutBufPtrs(
670     PAF_AST_IoOut *pOutIo,
671     size_t writeSize
674     void *buff1, *buff2;
675     size_t size1, size2;
676     Int status;
678     status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
679                                 &buff1, &size1, &buff2, &size2);
680     if (status == IOBUFF_ERR_OVERFLOW)
681     {
682         pOutIo->errIoBuffOvrCnt++;
683         //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
685         // skip processing since output buffer overflows
686         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
687     }
688     else if (status == IOBUFF_ERR_UNDERFLOW)
689     {
690         pOutIo->errIoBuffUndCnt++;
691         //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
693         // already underflows and remain in underflow
694     }
695     
696     if ((buff2 != NULL) || (size2 != 0))
697     {
698         // Two buffers allocated indicates split buffer allocation on buffer wrap.
699         pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
700     }
702     // save buffer pointers & sizes for later write complete
703     pOutIo->buff1 = buff1;
704     pOutIo->size1 = size1;
705     pOutIo->buff2 = buff2;
706     pOutIo->size2 = size2;
708     return ASOP_IO_SOK;
711 #if 0
712 // Update Output buffer configuration.
713 // This is needed for proper operation of PCM encoder.
714 Int asopUpdateOutBufConfig(
715     PAF_AST_OutBuf *pOutBuf, 
716     PAF_AST_IoOut *pOutIo
719     PAF_OutBufConfig *pOutBufCfg;
720     ioBuffHandle_t hIoBuff;
721     ioBuffInfo_t outBuffInfo;
722     void *buff1, *buff2;
723     size_t size1, size2, total_write_size;
724     Int status;
726     pOutBufCfg = &pOutBuf->outBufConfig;
727     hIoBuff = pOutIo->hIoBuff;
729     // FL, New IO: original code can change these values in every DOB issue
730     //  Need to determine if this is required or not.
731     pOutBufCfg->stride = pOutIo->stride;
732     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
733     pOutBufCfg->precision = 24;
734     
735     //JXTODO: to replace hard coded write size
736     // Get write pointers of output memory pool
737     total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
738     status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
739         &buff1, &size1, &buff2, &size2);
740     if (status == IOBUFF_ERR_OVERFLOW) 
741     {
742         pOutIo->errIoBuffOvrCnt++;
743         //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
745         // skip processing since output buffer overflows        
746         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
747     }
748     else if (status == IOBUFF_ERR_UNDERFLOW) 
749     {
750         pOutIo->errIoBuffUndCnt++;
751         //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
752         
753         // already underflows and remain in underflow
754     }
755 #if 0
756     // Update Output buffer pointer for Encoder
757     pOutBufCfg->pntr.pLgInt = buff1;
758     if ((buff2 != NULL) || (size2 != 0))
759     {
760         // buff2 should always be NULL for Output & size2 should always be 0 for Output.
761         // Track this here.
762         pOutIo->ioBuffBuf2AllocCnt++; // debug
763     }
764 #endif
765     // save buffer pointers & sizes for later write complete
766     pOutIo->buff1 = buff1;
767     pOutIo->size1 = size1;
768     pOutIo->buff2 = buff2;
769     pOutIo->size2 = size2;
770     
771     return ASOP_IO_SOK;
773 #endif
775 // Mark Output buffers write complete
776 Int asopMarkOutBuffsWriteComplete(
777     PAF_AST_OutBuf *pOutBuf, 
778     PAF_AST_IoOut *pOutIo
781     ioBuffHandle_t hIoBuff;
782     void *buff1, *buff2;
783     size_t size1, size2;
784     
785     // get buffer pointers & sizes from previous IO Buff write allocation
786     buff1 = pOutIo->buff1;
787     size1 = pOutIo->size1;
788     buff2 = pOutIo->buff2; // this should always be NULL for Output
789     size2 = pOutIo->size2; // this should always be 0 for Output
790     
791     hIoBuff = pOutIo->hIoBuff;
792     
793     ioBuffWriteComplete(hIoBuff, buff1, size1);
795     if (buff2 != NULL) 
796     {
797         ioBuffWriteComplete(hIoBuff, buff2, size2);
798     }
799     
800     return ASOP_IO_SOK;
803 /*======================================================================================
804  *  This function starts an I/O PHY transfer for output
805  *====================================================================================*/
806 Void asopPhyTransferStart(
807     PAF_AST_IoOut *pOut
810     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
811     {
812         //mcaspTxReset();
813         //mcaspTxCreate();
814         //pOut->hMcaspChan = hMcaspTxChan;
815         System_abort("\nMcASP for output underruns! %d!\n");
816     }
817     else 
818     {
819         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
820         {
821             // Output buffer underflows!
822             System_abort("\nOutput buffer underflows!\n");
823         }
824         else {
825             // Output buffer operates normally
826             ;
827         }
828     }
831 /* nothing past this point */