]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - pasdk/test_dsp/framework/audioStreamOutIo.c
PASDK-577:Clear already posted Output events on Output re-select
[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;
76     UInt postedEvents;    
78     if ((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) 
79     {
80         return ASOP_IO_ERR_IO_UNINIT;
81     }
83     // Deactivate currently active Output device
84     if (pOut->hMcaspChan != NULL)
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         // Clear (drop) already posted Output data events
97         postedEvents = Event_getPostedEvents(gAsotEvtHandle);
98         while ((postedEvents & Evt_Id_AsotTxMcaspEdma) != 0)
99         {
100             Event_pend(gAsotEvtHandle, Event_Id_NONE, Evt_Id_AsotTxMcaspEdma, 0);
101             postedEvents = Event_getPostedEvents(gAsotEvtHandle);
102         }        
103         
104         pOut->hMcaspChan = NULL;            // reset active McASP LLD handle
105         pOut->pLldCfg->hMcaspChan = NULL;   // reset McASP LLD handle for active McASP LLD configuration
106         pOut->pLldCfg = NULL;               // reset pointer to active McASP LLD configuration
107     }
109     // Activate requested device
110     if (pOutCfg != NULL)
111     {
112         //
113         // Device other than OutNone selected
114         //
115         
116         pReqLldCfg = (mcaspLLDconfig *)pOutCfg->sio.pConfig;
117         if (pReqLldCfg->hMcaspChan == NULL) 
118         {
119             // Create McASP LLD channel
120             mcaspChanHandle = NULL;
121             status = mcasplldChanCreate(pReqLldCfg, &mcaspChanHandle);
122             if (status != Aud_EOK) {
123                 Log_info0("asopSelectDevices(): McASP channel creation failed!\n");
124                 return ASOP_IO_ERR_MCASP_CFG;
125             }
127             pReqLldCfg->hMcaspChan = mcaspChanHandle;   // set McASP LLD handle for requested McASP LLD configuration
128             pOut->pLldCfg = pReqLldCfg;                 // set pointer to active McASP LLD configuration
129             pOut->hMcaspChan = pReqLldCfg->hMcaspChan;  // set active McASP LLD handle
130             
131             // configure stride according to selected McASP LLD configuration
132             pOut->stride = pReqLldCfg->mcaspChanParams->noOfSerRequested * 
133                 pReqLldCfg->mcaspChanParams->noOfChannels;
134         }
135     }
136     else
137     {
138         //
139         // OutNone device selected
140         //
141         
142         pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
143         pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
144     }
146     return ASOP_IO_SOK;
149 // Check if Output device SIO selection changed
150 Int checkOutDevSioSelUpdate(
151     const PAF_ASOT_Params *pP, 
152     PAF_ASOT_Config *pAsotCfg,
153     Int z, 
154     Bool *pOutDevSelUpdate
157     PAF_AST_Config *pAstCfg;
158     
159     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
161     if ((z < OUTPUT1) || (z >= OUTPUTN))
162     {
163         *pOutDevSelUpdate = FALSE;
164         return ASOP_IO_ERR_INV_PARAMS;
165     }
166     
167     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
169     return ASOP_IO_SOK;
172 // Check if any Output device SIO selection changed
173 Int checkAnyOutDevSioSelUpdate(
174     const PAF_ASOT_Params *pP, 
175     PAF_ASOT_Config *pAsotCfg,
176     Bool *pOutDevSelUpdate
179     PAF_AST_Config *pAstCfg;
180     Int outDevSelUpdate;
181     Int z;
182     
183     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
185     outDevSelUpdate = FALSE;
186     for (z=OUTPUT1; z < OUTPUTN; z++) 
187     {
188         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
189         {
190             outDevSelUpdate = TRUE;
191             break;
192         }
193     }
194     
195     *pOutDevSelUpdate = outDevSelUpdate;
197     return ASOP_IO_SOK;
200 // -----------------------------------------------------------------------------
201 // ASOT Decoding Function Helper - SIO Driver Change
202 //
203 //   Name:      PAF_ASOT_setCheckRateX
204 //   Purpose:   Decoding Function for reinitiating output.
205 //   From:      AST Parameter Function -> decodeInfo1
206 //              AST Parameter Function -> decodeInfo2
207 //   Uses:      See code.
208 //   States:    x
209 //   Return:    Error number in standard form (0 on success).
210 //   Trace:     None.
211 //
213 /* 0: set, 1: check, unused for now. --Kurt */
214 Int asopSetCheckRateX(
215     const PAF_ASOT_Params *pP, 
216     const PAF_ASOT_Patchs *pQ, 
217     PAF_ASOT_Config *pAsotCfg, 
218     Int check
221     PAF_AST_Config *pAstCfg;
222     PAF_AST_IoOut  *pOut;
223     float rateX;
224     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
225     Int z;                              /* output counter */
226     Int zx;                             /* output re-counter */
227     Int getVal;
228     int inputRate, inputCount, outputRate, outputCount;
229     Int zMD;
230     Int zMI;
231     Int zMS;
232     Int zE, zX;
234     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
235     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
236     
237     zMD = pAstCfg->masterDec;
238     zMS = pAstCfg->masterStr;
239     zMI = pP->zone.master;
241     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
242     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
243     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
244         inputRate, PAF_SAMPLERATEHZ_INV);
246     for (z=OUTPUT1; z < OUTPUTN; z++) 
247     {
248         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
249         {
250             // determine associated encoder
251             zE = z;
252             for (zX = ENCODE1; zX < ENCODEN; zX++) 
253             {
254                 if (pP->outputsFromEncodes[zX] == z) 
255                 {
256                     zE = zX;
257                     break;
258                 }
259             }
261             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
262             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
263             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
264                 outputRate, PAF_SAMPLERATEHZ_STD);
265             if ((rateI > 0) && (rateO > 0))
266             {
267                 rateX = rateO /* std */ * rateI /* inv */;
268             }
269             else if (inputCount != 0)
270             {
271                 rateX = (float)outputCount / inputCount;
272             }
273             else
274             {
275                 return ASPERR_INFO_RATERATIO;
276             }
278 #if 0 // FL, New IO: add similar thing to be figured out     
279             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
280             if (getVal == DOBERR_RATECHANGE) 
281             {
282                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
283                 {
284                     if (pAstCfg->xOut[zx].hTxSio)
285                     {
286                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
287                     }
288                 }
290                 // this forces an exit from the calling state machine which will
291                 // eventually call startOutput which calls setCheckRateX for all outputs
292                 // and so it is ok, in the presence of a rate change on any output, to
293                 // exit this loop /function early.
294                 return ASPERR_INFO_RATECHANGE;
295             }
296             else if (getVal != SYS_OK)
297             {
298                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
299             }
300 #endif // FL, New IO
301             // FL: ugly little experiment
302             //*(volatile UInt32 *)0x23400B0 |= 7;
303         }
304     }
306     return ASOP_IO_SOK;
307 } //asopSetCheckRateX
309 // -----------------------------------------------------------------------------
310 // ASOT Decoding Function Helper - SIO Driver Start
311 //
312 //   Name:      PAF_ASOT_startOutput
313 //   Purpose:   Decoding Function for initiating output.
314 //   From:      AST Parameter Function -> decodeInfo1
315 //   Uses:      See code.
316 //   States:    x
317 //   Return:    Error number in standard or SIO form (0 on success).
318 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
319 //              * State information as per parent.
320 //              * SIO control errors.
321 //
322 Int asopStartOutput(
323     const PAF_ASOT_Params *pP,
324     const PAF_ASOT_Patchs *pQ,
325     PAF_ASOT_Config *pAsotCfg
328     PAF_AST_Config *pAstCfg;
329     PAF_AST_IoOut  *pOut;
330     Int as;                     /* Audio Stream Number (1, 2, etc.) */
331     Int z;                      /* output counter */
332     Int nbufs;
333     Int zE, zS, zX;
334     Int zMD;
335     PAF_SIO_IALG_Obj    *pObj;
336     PAF_SIO_IALG_Config *pAlgConfig;
337     ioPhyCtl_t ioPhyCtl;
340     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
341     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
342     as = pAstCfg->as;
343     zMD = pAstCfg->masterDec;
345     for (z=OUTPUT1; z < OUTPUTN; z++)
346     {
347         if (pOut[z].hIoPhy)
348         {
349             // determine associated encoder and stream
350             zE = z;
351             zS = z;
352             for (zX = ENCODE1; zX < ENCODEN; zX++)
353             {
354                 if (pP->outputsFromEncodes[zX] == z)
355                 {
356                     zE = zX;
357                     zS = pP->streamsFromEncodes[zE];
358                     break;
359                 }
360             }
362             // FL, New IO: add similar thing to be figured out
363 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
364 #if 0
365             // if device selected and valid then enable stat tracking if
366             // required and start clocking
367             if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
368             {
369                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
370                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
371                 if (errno)
372                 {
373                     TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
374                     SIO_idle(pAstCfg->xOut[z].hTxSio);
375                     if (!errno)
376                     {
377                         errno = ASPERR_DEVOUT + errme;
378                     }
379                 }
380             }
381 #endif            
383             // Set sample count so that DOB knows how much data to send
384             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
385                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
387 #if 1 // FL, New IO: add similar thing to be figured out
388             // Update framework Phy transfer size
389             pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
390             // Update IO Phy transfer size
391             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
392             ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
393             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
394             // Update IO Buff delay to match Phy transfer size
395             ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
396 #endif
398             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
399             {
400                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
401                 pAlgConfig = &pObj->config;
402                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
403                     pAlgConfig->pMemRec[0].size);
404             }
406             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
407             // decoder. How should we handle the sourceProgram for multiple decoders?
408             // Override as needed
409             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
410             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
411             {
412                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
413             }
414             //JXTODO: add similar thing to be figured out
415             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
417             //JXTODO: data transfer start to be moved to output task state machine
418             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
419                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
420             {
421                 SIO_idle(pAstCfg->xOut[z].hTxSio);
422                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
423                 return errno;
424             } */
426             //JXTODO: add similar thing to be figured out
427 #if 0
428             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
429                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
430             {
431                 errno = (errno & 0xff) | ASPERR_MUTE;
432                 /* convert to sensical errno */
433                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
434                 return errno;
435             }
436             else
437             {
438                 pAstCfg->xOut[z].outBufStatus.audio
439                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
440             }
441 #endif
442             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
443         }
444     }
446     return ASOP_IO_SOK;
447 } /* asopStartOutput */
449 // -----------------------------------------------------------------------------
450 // ASOT Decoding Function Helper - SIO Driver Stop
451 //
452 //   Name:      PAF_ASOT_stopOutput
453 //   Purpose:   Decoding Function for terminating output.
454 //   From:      AST Parameter Function -> decodeProcessing
455 //              AST Parameter Function -> decodeComplete
456 //   Uses:      See code.
457 //   States:    x
458 //   Return:    Error number in standard or SIO form (0 on success).
459 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
460 //              * SIO control errors.
461 //
462 Int asopStopOutput(
463     const PAF_ASOT_Params *pP, 
464     const PAF_ASOT_Patchs *pQ, 
465     PAF_ASOT_Config *pAsotCfg
468     PAF_AST_Config *pAstCfg;
469     PAF_AST_IoOut  *pOut;
470     Int as;                     /* Audio Stream Number (1, 2, etc.) */
471     Int z;                      /* output counter */
472     Int errno, getVal;
473     Int zS, zX;
474     PAF_SIO_IALG_Obj    *pObj;
475     PAF_SIO_IALG_Config *pAlgConfig;
477     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
478     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
479     as = pAstCfg->as;
480     (void)as;  // clear compiler warning in case not used with tracing disabled
482     errno = ASOP_IO_SOK;
483     for (z=OUTPUT1; z < OUTPUTN; z++) 
484     {
485         if (pOut[z].hIoPhy) 
486         {
487             // determine associated encoder and stream
488             zS = z;
489             (void)zS;
490             for (zX = ENCODE1; zX < ENCODEN; zX++) 
491             {
492                 if (pP->outputsFromEncodes[zX] == z) 
493                 {
494                     zS = pP->streamsFromEncodes[zX];
495                     break;
496                 }
497             }
499 #if 0 // FL, New IO: add similar thing to be figured out            
500             // Mute output before audio data termination in the usual case,
501             // where such termination is due to decode error or user command.
502             // Identification of this as the usual case is provided by the
503             // "decode processing" state machine.
504             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
505                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
506                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
507             {
508                 if (!errno) 
509                 {
510                     errno = (getVal & 0xff) | ASPERR_MUTE;
511                     /* convert to sensical errno */
512                 }
513                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
514             }
516             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
517             
518             // Terminate audio data output, truncating (ignore) or flushing
519             // (play out) final samples as per (1) control register set by
520             // the user and (2) the type of audio data termination:
522 #if 0
523             // This form is not used because driver support for truncating
524             // data is not supported for internal clocks, although it is
525             // for external clocks.
526             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
527                 pC->xOut[z].outBufStatus.flush
528                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
529                 ? 1 : 0);
530             /* UNTESTED */
531 #else
532             // This form should be used when driver support for truncating
533             // data is supported for both internal and external clocks.
534             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
535                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
536                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
537                 ? 1 : 0);
538             /* TESTED */
539 #endif
541             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
543             if (!errno)
544             {
545                 errno = getVal;
546             }
548             // Mute output after audio data termination in a special case,
549             // where such termination is due to processing of a final frame
550             // or user command. Identification of this as a special case is
551             // provided by the "decode processing" state machine.
552             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
553                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
554                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
555             {
556                 if (!errno) 
557                 {
558                     errno = (getVal & 0xff) | ASPERR_MUTE;
559                     /* convert to sensical errno */
560                 }
561                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
562             }
564             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
565 #endif // FL, New IO
567             // zero output buffers
568             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
569             pAlgConfig = &pObj->config;
570             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
571         } //pAstCfg->xOut[z].hTxSio
572     }//OUTPUT
574     return errno;
575 } //asopStopOutput
577 /*===========================================================================
578  * Initialize I/O components for output processing
579 ============================================================================*/
580 Int asopIoCompsInit(
581     Int16 strAfSampleCount,     // stream audio frame sample count
582     PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
583     PAF_AST_IoOut *pOutIo       // pointer to Output IO
586     ioBuffParams_t ioBuffParams;
587     ioPhyParams_t  ioPhyParams;
589     if (pOutIo->hMcaspChan != NULL)
590     {
591         // Initialize I/O BUFF and I/O PHY components for output task
592         ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
593         // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
594         // This ensures no split buffers will be allocated on Output buffer wrap.
595         ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
596             (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
597         ioBuffParams.sync         = IOBUff_READ_SYNC;
598         ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
599         if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
600         {
601             return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
602         }
604         ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
605         ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
606         ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
607         ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
608         if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
609         {
610             return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
611         }
613         pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
614         
615         pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
616         pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
617         pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
618     }
619     
620     return ASOP_IO_SOK;
621 } /* asopIoCompsInit */
623 /*======================================================================================
624  *  This function checks whether the I/O physical layer has been initialized
625  *====================================================================================*/
626 Bool asopIoPhyCheckInit(Void)
628     if (!d10Initialized)
629         return FALSE;
630     else 
631         return TRUE;
634 /*======================================================================================
635  *  I/O physical layer prime operation required by McASP LLD
636  *====================================================================================*/
637 Void asopIoPhyPrime(
638     PAF_AST_IoOut *pOut
641     Int32        count;
643     pOut->numPrimeXfers = NUM_PRIME_XFERS;
645     for (count = 0; count < pOut->numPrimeXfers; count++)
646     {
647         ioPhyXferSubmit(pOut->hIoPhy);
648     }
649 } /* asipIoPhyPrime */
651 // Initialize Output buffer configuration
652 Int asopInitOutBufConfig(
653     PAF_AST_OutBuf *pOutBuf, 
654     PAF_AST_IoOut *pOutIo
657     PAF_OutBufConfig *pOutBufCfg;
658     ioBuffHandle_t hIoBuff;
659     ioBuffInfo_t outBuffInfo;
660     
661     pOutBufCfg = &pOutBuf->outBufConfig;
662     hIoBuff = pOutIo->hIoBuff;
663     
664     pOutBufCfg->stride = pOutIo->stride;
665     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
666     pOutBufCfg->precision = 24;
667     
668     ioBuffGetInfo(hIoBuff, &outBuffInfo);
669     pOutBufCfg->base.pLgInt = outBuffInfo.base;
670     pOutBufCfg->sizeofBuffer = outBuffInfo.size;
671     
672     pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
673     
674     return ASOP_IO_SOK;
677 Int asopGetOutBufPtrs(
678     PAF_AST_IoOut *pOutIo,
679     size_t writeSize
682     void *buff1, *buff2;
683     size_t size1, size2;
684     Int status;
686     status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
687                                 &buff1, &size1, &buff2, &size2);
688     if (status == IOBUFF_ERR_OVERFLOW)
689     {
690         pOutIo->errIoBuffOvrCnt++;
691         //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
693         // skip processing since output buffer overflows
694         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
695     }
696     else if (status == IOBUFF_ERR_UNDERFLOW)
697     {
698         pOutIo->errIoBuffUndCnt++;
699         //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
701         // already underflows and remain in underflow
702     }
703     
704     if ((buff2 != NULL) || (size2 != 0))
705     {
706         // Two buffers allocated indicates split buffer allocation on buffer wrap.
707         pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
708     }
710     // save buffer pointers & sizes for later write complete
711     pOutIo->buff1 = buff1;
712     pOutIo->size1 = size1;
713     pOutIo->buff2 = buff2;
714     pOutIo->size2 = size2;
716     return ASOP_IO_SOK;
719 #if 0
720 // Update Output buffer configuration.
721 // This is needed for proper operation of PCM encoder.
722 Int asopUpdateOutBufConfig(
723     PAF_AST_OutBuf *pOutBuf, 
724     PAF_AST_IoOut *pOutIo
727     PAF_OutBufConfig *pOutBufCfg;
728     ioBuffHandle_t hIoBuff;
729     ioBuffInfo_t outBuffInfo;
730     void *buff1, *buff2;
731     size_t size1, size2, total_write_size;
732     Int status;
734     pOutBufCfg = &pOutBuf->outBufConfig;
735     hIoBuff = pOutIo->hIoBuff;
737     // FL, New IO: original code can change these values in every DOB issue
738     //  Need to determine if this is required or not.
739     pOutBufCfg->stride = pOutIo->stride;
740     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
741     pOutBufCfg->precision = 24;
742     
743     //JXTODO: to replace hard coded write size
744     // Get write pointers of output memory pool
745     total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
746     status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
747         &buff1, &size1, &buff2, &size2);
748     if (status == IOBUFF_ERR_OVERFLOW) 
749     {
750         pOutIo->errIoBuffOvrCnt++;
751         //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
753         // skip processing since output buffer overflows        
754         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
755     }
756     else if (status == IOBUFF_ERR_UNDERFLOW) 
757     {
758         pOutIo->errIoBuffUndCnt++;
759         //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
760         
761         // already underflows and remain in underflow
762     }
763 #if 0
764     // Update Output buffer pointer for Encoder
765     pOutBufCfg->pntr.pLgInt = buff1;
766     if ((buff2 != NULL) || (size2 != 0))
767     {
768         // buff2 should always be NULL for Output & size2 should always be 0 for Output.
769         // Track this here.
770         pOutIo->ioBuffBuf2AllocCnt++; // debug
771     }
772 #endif
773     // save buffer pointers & sizes for later write complete
774     pOutIo->buff1 = buff1;
775     pOutIo->size1 = size1;
776     pOutIo->buff2 = buff2;
777     pOutIo->size2 = size2;
778     
779     return ASOP_IO_SOK;
781 #endif
783 // Mark Output buffers write complete
784 Int asopMarkOutBuffsWriteComplete(
785     PAF_AST_OutBuf *pOutBuf, 
786     PAF_AST_IoOut *pOutIo
789     ioBuffHandle_t hIoBuff;
790     void *buff1, *buff2;
791     size_t size1, size2;
792     
793     // get buffer pointers & sizes from previous IO Buff write allocation
794     buff1 = pOutIo->buff1;
795     size1 = pOutIo->size1;
796     buff2 = pOutIo->buff2; // this should always be NULL for Output
797     size2 = pOutIo->size2; // this should always be 0 for Output
798     
799     hIoBuff = pOutIo->hIoBuff;
800     
801     ioBuffWriteComplete(hIoBuff, buff1, size1);
803     if (buff2 != NULL) 
804     {
805         ioBuffWriteComplete(hIoBuff, buff2, size2);
806     }
807     
808     return ASOP_IO_SOK;
811 /*======================================================================================
812  *  This function starts an I/O PHY transfer for output
813  *====================================================================================*/
814 Void asopPhyTransferStart(
815     PAF_AST_IoOut *pOut
818     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
819     {
820         //mcaspTxReset();
821         //mcaspTxCreate();
822         //pOut->hMcaspChan = hMcaspTxChan;
823         System_abort("\nMcASP for output underruns! %d!\n");
824     }
825     else 
826     {
827         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
828         {
829             // Output buffer underflows!
830             System_abort("\nOutput buffer underflows!\n");
831         }
832         else {
833             // Output buffer operates normally
834             ;
835         }
836     }
839 /* nothing past this point */