Merge pull request #37 in PASDK/pasdk_sr from pasdk_663_shalini to pasdk1_3_master
[processor-sdk/performance-audio-sr.git] / pasrc / 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     Int32 status;
76     Aud_STATUS audStatus;
77     UInt postedEvents;    
79     if ((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) 
80     {
81         return ASOP_IO_ERR_IO_UNINIT;
82     }
84     // Deactivate currently active Output device
85     if (pOut->hMcaspChan != NULL)
86     {
87         // Reset channel
88         status = mcaspControlChan(pOut->hMcaspChan, MCASP_CHAN_RESET, NULL);
89         if (status != MCASP_COMPLETED)
90         {
91             Log_info0("asopSelectDevices(): McASP channel reset failed!\n");
92             return ASOP_IO_ERR_MCASP_CFG;            
93         }
94         
95         // Delete McASP LLD channel
96         status = mcaspDeleteChan(pOut->hMcaspChan);
97         if (status != MCASP_COMPLETED)
98         {
99             Log_info0("asopSelectDevices(): McASP channel deletion failed!\n");
100             return ASOP_IO_ERR_MCASP_CFG;
101         }
102         
103         // Clear (drop) already posted Output data events
104         postedEvents = Event_getPostedEvents(gAsotEvtHandle);
105         while ((postedEvents & Evt_Id_AsotTxMcaspEdma) != 0)
106         {
107             Event_pend(gAsotEvtHandle, Event_Id_NONE, Evt_Id_AsotTxMcaspEdma, 0);
108             postedEvents = Event_getPostedEvents(gAsotEvtHandle);
109         }        
110         
111         pOut->hMcaspChan = NULL;            // reset active McASP LLD handle
112         pOut->pLldCfg->hMcaspChan = NULL;   // reset McASP LLD handle for active McASP LLD configuration
113         pOut->pLldCfg = NULL;               // reset pointer to active McASP LLD configuration
114     }
116     // Activate requested device
117     if (pOutCfg != NULL)
118     {
119         //
120         // Device other than OutNone selected
121         //
122         
123         pReqLldCfg = (mcaspLLDconfig *)pOutCfg->sio.pConfig;
124         if (pReqLldCfg->hMcaspChan == NULL) 
125         {
126             // Create McASP LLD channel
127             mcaspChanHandle = NULL;
128             audStatus = mcasplldChanCreate(pReqLldCfg, &mcaspChanHandle);
129             if (audStatus != Aud_EOK) 
130             {
131                 Log_info0("asopSelectDevices(): McASP channel creation failed!\n");
132                 return ASOP_IO_ERR_MCASP_CFG;
133             }
135             pReqLldCfg->hMcaspChan = mcaspChanHandle;   // set McASP LLD handle for requested McASP LLD configuration
136             pOut->pLldCfg = pReqLldCfg;                 // set pointer to active McASP LLD configuration
137             pOut->hMcaspChan = pReqLldCfg->hMcaspChan;  // set active McASP LLD handle
138             
139             // configure stride according to selected McASP LLD configuration
140             pOut->stride = pReqLldCfg->mcaspChanParams->noOfSerRequested * 
141                 pReqLldCfg->mcaspChanParams->noOfChannels;
142                 
143             // initialize rateX
144             pOut->rateX = 1.; // rateX==1.0 for CLKXDIV==1
145         }
146         else
147         {
148             return ASOP_IO_ERR_INV_STATE;
149         }
150     }
151     else
152     {
153         //
154         // OutNone device selected
155         //
156         
157         pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
158         pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
159     }
161     return ASOP_IO_SOK;
164 // Check if Output device SIO selection changed
165 Int checkOutDevSioSelUpdate(
166     const PAF_ASOT_Params *pP, 
167     PAF_ASOT_Config *pAsotCfg,
168     Int z, 
169     Bool *pOutDevSelUpdate
172     PAF_AST_Config *pAstCfg;
173     
174     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
176     if ((z < OUTPUT1) || (z >= OUTPUTN))
177     {
178         *pOutDevSelUpdate = FALSE;
179         return ASOP_IO_ERR_INV_PARAMS;
180     }
181     
182     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
184     return ASOP_IO_SOK;
187 // Check if any Output device SIO selection changed
188 Int checkAnyOutDevSioSelUpdate(
189     const PAF_ASOT_Params *pP, 
190     PAF_ASOT_Config *pAsotCfg,
191     Bool *pOutDevSelUpdate
194     PAF_AST_Config *pAstCfg;
195     Int outDevSelUpdate;
196     Int z;
197     
198     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
200     outDevSelUpdate = FALSE;
201     for (z=OUTPUT1; z < OUTPUTN; z++) 
202     {
203         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
204         {
205             outDevSelUpdate = TRUE;
206             break;
207         }
208     }
209     
210     *pOutDevSelUpdate = outDevSelUpdate;
212     return ASOP_IO_SOK;
215 // -----------------------------------------------------------------------------
216 // ASOT Decoding Function Helper - SIO Driver Change
217 //
218 //   Name:      PAF_ASOT_setCheckRateX
219 //   Purpose:   Decoding Function for reinitiating output.
220 //   From:      AST Parameter Function -> decodeInfo1
221 //              AST Parameter Function -> decodeInfo2
222 //   Uses:      See code.
223 //   States:    x
224 //   Return:    Error number in standard form (0 on success).
225 //   Trace:     None.
226 //
228 /* 0: set, 1: check, unused for now. --Kurt */
229 Int asopSetCheckRateX(
230     const PAF_ASOT_Params *pP, 
231     const PAF_ASOT_Patchs *pQ, 
232     PAF_ASOT_Config *pAsotCfg, 
233     Int check
236     PAF_AST_Config *pAstCfg;
237     PAF_AST_IoOut  *pOut;
238     float rateX;
239     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
240     Int z;                              /* output counter */
241     Int zx;                             /* output re-counter */
242     Int getVal;
243     int inputRate, inputCount, outputRate, outputCount;
244     Int zMD;
245     Int zMI;
246     Int zMS;
247     Int zE, zX;
248     // "proof of concept" for McASP LLD API
249     Uint32 divider, clkXDiv;
250     Mcasp_HwSetupData mcaspSetup;
251     Int32 status;
253     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
254     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
255     
256     zMD = pAstCfg->masterDec;
257     zMS = pAstCfg->masterStr;
258     zMI = pP->zone.master;
260     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
261     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
262     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
263         inputRate, PAF_SAMPLERATEHZ_INV);
265     for (z=OUTPUT1; z < OUTPUTN; z++) 
266     {
267         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
268         {
269             // determine associated encoder
270             zE = z;
271             for (zX = ENCODE1; zX < ENCODEN; zX++) 
272             {
273                 if (pP->outputsFromEncodes[zX] == z) 
274                 {
275                     zE = zX;
276                     break;
277                 }
278             }
280             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
281             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
282             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
283                 outputRate, PAF_SAMPLERATEHZ_STD);
284             if ((rateI > 0) && (rateO > 0))
285             {
286                 rateX = rateO /* std */ * rateI /* inv */;
287             }
288             else if (inputCount != 0)
289             {
290                 rateX = (float)outputCount / inputCount;
291             }
292             else
293             {
294                 return ASPERR_INFO_RATERATIO;
295             }
297 #if 0 // FL, New IO: add similar thing to be figured out     
298             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
299             if (getVal == DOBERR_RATECHANGE) 
300             {
301                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
302                 {
303                     if (pAstCfg->xOut[zx].hTxSio)
304                     {
305                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
306                     }
307                 }
309                 // this forces an exit from the calling state machine which will
310                 // eventually call startOutput which calls setCheckRateX for all outputs
311                 // and so it is ok, in the presence of a rate change on any output, to
312                 // exit this loop /function early.
313                 return ASPERR_INFO_RATECHANGE;
314             }
315             else if (getVal != SYS_OK)
316             {
317                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
318             }
319 #endif // FL, New IO
321             //
322             // "Proof on concept" code for McASP LLD API to change bit clock divider.
323             //
324             if (pOut->rateX != rateX)
325             {
326                 // Initialize divider value.
327                 // This works for AHCLKX input from HDMI & sample rate = 44.1,48,88.2,96,192 kHz.
328                 divider = 2;
329                 
330                 // Update divider based on calculated rateX
331                 divider /= rateX;
332                 
333 #if 0 // debug
334                 {
335                     UInt32 regVal;
337                     // Experimental code: directly write CLKXDIV -- produces correct output                
338                     regVal = *(volatile UInt32 *)0x23400B0; // read MCASP_ACLKXCTL
339                     regVal &= ~0x1F; // mask off CLKXDIV bits
340                     //regVal |= 7; // set CLKXDIV for 48 kHz
341                     //regVal |= 3; // set CLKXDIV for 96 kHz
342                     //regVal |= 1; // set CLKXDIV for 192 kHz
343                     regVal |= (divider-1); // set CLKXDIV
344                     *(volatile UInt32 *)0x23400B0 = regVal; // write MCASP_ACLKXCTL                    
345                 }
346 #endif                  
348                 // Calculate CLKXDIV bit field value
349                 clkXDiv = (divider-1) & CSL_MCASP_ACLKXCTL_CLKXDIV_MASK;
351 #if 0 // use existing McASP LLD API functions -- results in Tx serializer channel swap
352                 // get existing McASP HW setup
353                 status = mcaspControlChan(pOut->hMcaspChan, Mcasp_IOCTL_CNTRL_GET_FORMAT_CHAN, &mcaspSetup);
354                 if (status != MCASP_COMPLETED)
355                 {
356                     Log_info0("asopSetCheckRateX(): McASP get channel format failed!\n");
357                     return ASOP_IO_ERR_MCASP_CFG;
358                 }
359                 
360                 // update CLKXDIV based on rateX
361                 mcaspSetup.clk.clkSetupClk &= ~CSL_MCASP_ACLKXCTL_CLKXDIV_MASK;
362                 mcaspSetup.clk.clkSetupClk |= clkXDiv;
363                 
364                 // update McASP HW setup
365                 status = mcaspControlChan(pOut->hMcaspChan, Mcasp_IOCTL_CNTRL_SET_FORMAT_CHAN, &mcaspSetup);
366                 if (status != MCASP_COMPLETED)
367                 {
368                     Log_info0("asopSetCheckRateX(): McASP set channel format failed!\n");
369                     return ASOP_IO_ERR_MCASP_CFG;
370                 }
371 #endif
373 #if 1 // use new McASP LLD API function -- produces correct output
374                 // update CLKXDIV setup
375                 status = mcaspControlChan(pOut->hMcaspChan, Mcasp_IOCTL_CNTRL_SET_FORMAT_CHAN_CLKXDIV, &clkXDiv);
376                 if (status != MCASP_COMPLETED)
377                 {
378                     Log_info0("asopSetCheckRateX(): McASP set channel format CLKXDIV failed!\n");
379                     return ASOP_IO_ERR_MCASP_CFG;
380                 }
381 #endif
382                 
383                 pOut->rateX = rateX; // update saved rateX
384                 
385                 return ASOP_IO_ERR_RATE_CHANGE;
386             }
387         }
388     }
390     return ASOP_IO_SOK;
391 } //asopSetCheckRateX
393 // -----------------------------------------------------------------------------
394 // ASOT Decoding Function Helper - SIO Driver Start
395 //
396 //   Name:      PAF_ASOT_startOutput
397 //   Purpose:   Decoding Function for initiating output.
398 //   From:      AST Parameter Function -> decodeInfo1
399 //   Uses:      See code.
400 //   States:    x
401 //   Return:    Error number in standard or SIO form (0 on success).
402 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
403 //              * State information as per parent.
404 //              * SIO control errors.
405 //
406 Int asopStartOutput(
407     const PAF_ASOT_Params *pP,
408     const PAF_ASOT_Patchs *pQ,
409     PAF_ASOT_Config *pAsotCfg
412     PAF_AST_Config *pAstCfg;
413     PAF_AST_IoOut  *pOut;
414     Int as;                     /* Audio Stream Number (1, 2, etc.) */
415     Int z;                      /* output counter */
416     Int nbufs;
417     Int zE, zS, zX;
418     Int zMD;
419     PAF_SIO_IALG_Obj    *pObj;
420     PAF_SIO_IALG_Config *pAlgConfig;
421     ioPhyCtl_t ioPhyCtl;
424     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
425     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
426     as = pAstCfg->as;
427     zMD = pAstCfg->masterDec;
429     for (z=OUTPUT1; z < OUTPUTN; z++)
430     {
431         if (pOut[z].hIoPhy)
432         {
433             // determine associated encoder and stream
434             zE = z;
435             zS = z;
436             for (zX = ENCODE1; zX < ENCODEN; zX++)
437             {
438                 if (pP->outputsFromEncodes[zX] == z)
439                 {
440                     zE = zX;
441                     zS = pP->streamsFromEncodes[zE];
442                     break;
443                 }
444             }
446             // FL, New IO: add similar thing to be figured out
447 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
448 #if 0
449             // if device selected and valid then enable stat tracking if
450             // required and start clocking
451             if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
452             {
453                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
454                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
455                 if (errno)
456                 {
457                     TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
458                     SIO_idle(pAstCfg->xOut[z].hTxSio);
459                     if (!errno)
460                     {
461                         errno = ASPERR_DEVOUT + errme;
462                     }
463                 }
464             }
465 #endif            
467             // Set sample count so that DOB knows how much data to send
468             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
469                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
471 #if 1 // FL, New IO: add similar thing to be figured out
472             // Update framework Phy transfer size
473             pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
474             // Update IO Phy transfer size
475             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
476             ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
477             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
478             // Update IO Buff delay to match Phy transfer size
479             ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
480 #endif
482             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
483             {
484                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
485                 pAlgConfig = &pObj->config;
486                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
487                     pAlgConfig->pMemRec[0].size);
488             }
490             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
491             // decoder. How should we handle the sourceProgram for multiple decoders?
492             // Override as needed
493             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
494             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
495             {
496                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
497             }
498             //JXTODO: add similar thing to be figured out
499             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
501             //JXTODO: data transfer start to be moved to output task state machine
502             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
503                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
504             {
505                 SIO_idle(pAstCfg->xOut[z].hTxSio);
506                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
507                 return errno;
508             } */
510             //JXTODO: add similar thing to be figured out
511 #if 0
512             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
513                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
514             {
515                 errno = (errno & 0xff) | ASPERR_MUTE;
516                 /* convert to sensical errno */
517                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
518                 return errno;
519             }
520             else
521             {
522                 pAstCfg->xOut[z].outBufStatus.audio
523                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
524             }
525 #endif
526             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
527         }
528     }
530     return ASOP_IO_SOK;
531 } /* asopStartOutput */
533 // -----------------------------------------------------------------------------
534 // ASOT Decoding Function Helper - SIO Driver Stop
535 //
536 //   Name:      PAF_ASOT_stopOutput
537 //   Purpose:   Decoding Function for terminating output.
538 //   From:      AST Parameter Function -> decodeProcessing
539 //              AST Parameter Function -> decodeComplete
540 //   Uses:      See code.
541 //   States:    x
542 //   Return:    Error number in standard or SIO form (0 on success).
543 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
544 //              * SIO control errors.
545 //
546 Int asopStopOutput(
547     const PAF_ASOT_Params *pP, 
548     const PAF_ASOT_Patchs *pQ, 
549     PAF_ASOT_Config *pAsotCfg
552     PAF_AST_Config *pAstCfg;
553     PAF_AST_IoOut  *pOut;
554     Int as;                     /* Audio Stream Number (1, 2, etc.) */
555     Int z;                      /* output counter */
556     Int errno, getVal;
557     Int zS, zX;
558     PAF_SIO_IALG_Obj    *pObj;
559     PAF_SIO_IALG_Config *pAlgConfig;
561     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
562     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
563     as = pAstCfg->as;
564     (void)as;  // clear compiler warning in case not used with tracing disabled
566     errno = ASOP_IO_SOK;
567     for (z=OUTPUT1; z < OUTPUTN; z++) 
568     {
569         if (pOut[z].hIoPhy) 
570         {
571             // determine associated encoder and stream
572             zS = z;
573             (void)zS;
574             for (zX = ENCODE1; zX < ENCODEN; zX++) 
575             {
576                 if (pP->outputsFromEncodes[zX] == z) 
577                 {
578                     zS = pP->streamsFromEncodes[zX];
579                     break;
580                 }
581             }
583 #if 0 // FL, New IO: add similar thing to be figured out            
584             // Mute output before audio data termination in the usual case,
585             // where such termination is due to decode error or user command.
586             // Identification of this as the usual case is provided by the
587             // "decode processing" state machine.
588             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
589                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
590                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
591             {
592                 if (!errno) 
593                 {
594                     errno = (getVal & 0xff) | ASPERR_MUTE;
595                     /* convert to sensical errno */
596                 }
597                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
598             }
600             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
601             
602             // Terminate audio data output, truncating (ignore) or flushing
603             // (play out) final samples as per (1) control register set by
604             // the user and (2) the type of audio data termination:
606 #if 0
607             // This form is not used because driver support for truncating
608             // data is not supported for internal clocks, although it is
609             // for external clocks.
610             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
611                 pC->xOut[z].outBufStatus.flush
612                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
613                 ? 1 : 0);
614             /* UNTESTED */
615 #else
616             // This form should be used when driver support for truncating
617             // data is supported for both internal and external clocks.
618             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
619                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
620                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
621                 ? 1 : 0);
622             /* TESTED */
623 #endif
625             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
627             if (!errno)
628             {
629                 errno = getVal;
630             }
632             // Mute output after audio data termination in a special case,
633             // where such termination is due to processing of a final frame
634             // or user command. Identification of this as a special case is
635             // provided by the "decode processing" state machine.
636             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
637                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
638                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
639             {
640                 if (!errno) 
641                 {
642                     errno = (getVal & 0xff) | ASPERR_MUTE;
643                     /* convert to sensical errno */
644                 }
645                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
646             }
648             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
649 #endif // FL, New IO
651             // zero output buffers
652             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
653             pAlgConfig = &pObj->config;
654             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
655         } //pAstCfg->xOut[z].hTxSio
656     }//OUTPUT
658     return errno;
659 } //asopStopOutput
661 /*===========================================================================
662  * Initialize I/O components for output processing
663 ============================================================================*/
664 Int asopIoCompsInit(
665     Int16 strAfSampleCount,     // stream audio frame sample count
666     PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
667     PAF_AST_IoOut *pOutIo       // pointer to Output IO
670     ioBuffParams_t ioBuffParams;
671     ioPhyParams_t  ioPhyParams;
673     if (pOutIo->hMcaspChan != NULL)
674     {
675         // Initialize I/O BUFF and I/O PHY components for output task
676         ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
677         // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
678         // This ensures no split buffers will be allocated on Output buffer wrap.
679         ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
680             (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
681         ioBuffParams.sync         = IOBUff_READ_SYNC;
682         ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
683         if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
684         {
685             return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
686         }
688         ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
689         ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
690         ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
691         ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
692         if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
693         {
694             return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
695         }
697         pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
698         
699         pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
700         pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
701         pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
702     }
703     
704     return ASOP_IO_SOK;
705 } /* asopIoCompsInit */
707 /*======================================================================================
708  *  This function checks whether the I/O physical layer has been initialized
709  *====================================================================================*/
710 Bool asopIoPhyCheckInit(Void)
712     if (!d10Initialized)
713         return FALSE;
714     else 
715         return TRUE;
718 /*======================================================================================
719  *  I/O physical layer prime operation required by McASP LLD
720  *====================================================================================*/
721 Void asopIoPhyPrime(
722     PAF_AST_IoOut *pOut
725     Int32        count;
727     pOut->numPrimeXfers = 2;//NUM_PRIME_XFERS;
729     for (count = 0; count < pOut->numPrimeXfers; count++)
730     {
731         ioPhyXferSubmit(pOut->hIoPhy);
732     }
733 } /* asipIoPhyPrime */
735 // Initialize Output buffer configuration
736 Int asopInitOutBufConfig(
737     PAF_AST_OutBuf *pOutBuf, 
738     PAF_AST_IoOut *pOutIo
741     PAF_OutBufConfig *pOutBufCfg;
742     ioBuffHandle_t hIoBuff;
743     ioBuffInfo_t outBuffInfo;
744         GateMP_Handle gateHandle;
745         IArg key;
746     
747     pOutBufCfg = &pOutBuf->outBufConfig;
748     hIoBuff = pOutIo->hIoBuff;
749     
750     pOutBufCfg->stride = pOutIo->stride;
751     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
752     pOutBufCfg->precision = 24;
753     
754     // Get gate handle
755     gateHandle = pOutIo->gateHandle;
756     // Enter gate
757     key = GateMP_enter(gateHandle);
758     ioBuffGetInfo(hIoBuff, &outBuffInfo);
759     // Leave the gate
760     GateMP_leave(gateHandle, key);
761     pOutBufCfg->base.pLgInt = outBuffInfo.base;
762     pOutBufCfg->sizeofBuffer = outBuffInfo.size;
763     
764     pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
765     
766     return ASOP_IO_SOK;
769 Int asopGetOutBufPtrs(
770     PAF_AST_IoOut *pOutIo,
771     size_t writeSize
774     void *buff1, *buff2;
775     size_t size1, size2;
776     Int status;
777     GateMP_Handle gateHandle;
778     IArg key;
780     // Get gate handle
781     gateHandle = pOutIo->gateHandle;
782     // Enter gate
783     key = GateMP_enter(gateHandle);
784     status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
785                                 &buff1, &size1, &buff2, &size2);
786     // Leave the gate
787     GateMP_leave(gateHandle, key);
788     if (status == IOBUFF_ERR_OVERFLOW)
789     {
790         pOutIo->errIoBuffOvrCnt++;
791         //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
793         // skip processing since output buffer overflows
794         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
795     }
796     else if (status == IOBUFF_ERR_UNDERFLOW)
797     {
798         pOutIo->errIoBuffUndCnt++;
799         //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
801         // already underflows and remain in underflow
802     }
803     
804     if ((buff2 != NULL) || (size2 != 0))
805     {
806         // Two buffers allocated indicates split buffer allocation on buffer wrap.
807         pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
808     }
810     // save buffer pointers & sizes for later write complete
811     pOutIo->buff1 = buff1;
812     pOutIo->size1 = size1;
813     pOutIo->buff2 = buff2;
814     pOutIo->size2 = size2;
816     return ASOP_IO_SOK;
819 #if 0
820 // Update Output buffer configuration.
821 // This is needed for proper operation of PCM encoder.
822 Int asopUpdateOutBufConfig(
823     PAF_AST_OutBuf *pOutBuf, 
824     PAF_AST_IoOut *pOutIo
827     PAF_OutBufConfig *pOutBufCfg;
828     ioBuffHandle_t hIoBuff;
829     ioBuffInfo_t outBuffInfo;
830     void *buff1, *buff2;
831     size_t size1, size2, total_write_size;
832     Int status;
834     pOutBufCfg = &pOutBuf->outBufConfig;
835     hIoBuff = pOutIo->hIoBuff;
837     // FL, New IO: original code can change these values in every DOB issue
838     //  Need to determine if this is required or not.
839     pOutBufCfg->stride = pOutIo->stride;
840     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
841     pOutBufCfg->precision = 24;
842     
843     //JXTODO: to replace hard coded write size
844     // Get write pointers of output memory pool
845     total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
846     status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
847         &buff1, &size1, &buff2, &size2);
848     if (status == IOBUFF_ERR_OVERFLOW) 
849     {
850         pOutIo->errIoBuffOvrCnt++;
851         //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
853         // skip processing since output buffer overflows        
854         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
855     }
856     else if (status == IOBUFF_ERR_UNDERFLOW) 
857     {
858         pOutIo->errIoBuffUndCnt++;
859         //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
860         
861         // already underflows and remain in underflow
862     }
863 #if 0
864     // Update Output buffer pointer for Encoder
865     pOutBufCfg->pntr.pLgInt = buff1;
866     if ((buff2 != NULL) || (size2 != 0))
867     {
868         // buff2 should always be NULL for Output & size2 should always be 0 for Output.
869         // Track this here.
870         pOutIo->ioBuffBuf2AllocCnt++; // debug
871     }
872 #endif
873     // save buffer pointers & sizes for later write complete
874     pOutIo->buff1 = buff1;
875     pOutIo->size1 = size1;
876     pOutIo->buff2 = buff2;
877     pOutIo->size2 = size2;
878     
879     return ASOP_IO_SOK;
881 #endif
883 // Mark Output buffers write complete
884 Int asopMarkOutBuffsWriteComplete(
885     PAF_AST_OutBuf *pOutBuf, 
886     PAF_AST_IoOut *pOutIo
889     ioBuffHandle_t hIoBuff;
890     void *buff1, *buff2;
891     size_t size1, size2;
892         GateMP_Handle gateHandle;
893         IArg key;
894     
895     // get buffer pointers & sizes from previous IO Buff write allocation
896     buff1 = pOutIo->buff1;
897     size1 = pOutIo->size1;
898     buff2 = pOutIo->buff2; // this should always be NULL for Output
899     size2 = pOutIo->size2; // this should always be 0 for Output
900     
901     hIoBuff = pOutIo->hIoBuff;
903          // Get gate handle
904     gateHandle = pOutIo->gateHandle;
905     // Enter gate
906     key = GateMP_enter(gateHandle);
907     ioBuffWriteComplete(hIoBuff, buff1, size1);
908     // Leave the gate
909     GateMP_leave(gateHandle, key);
910     if (buff2 != NULL) 
911     {
912         ioBuffWriteComplete(hIoBuff, buff2, size2);
913     }
914     
915     return ASOP_IO_SOK;
918 /*======================================================================================
919  *  This function starts an I/O PHY transfer for output
920  *====================================================================================*/
921 Void asopPhyTransferStart(
922     PAF_AST_IoOut *pOut
925     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
926     {
927         //mcaspTxReset();
928         //mcaspTxCreate();
929         //pOut->hMcaspChan = hMcaspTxChan;
930         System_abort("\nMcASP for output underruns! %d!\n");
931     }
932     else 
933     {
934         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
935         {
936             // Output buffer underflows!
937             //System_abort("\nOutput buffer underflows!\n");
938         }
939         else {
940             // Output buffer operates normally
941             ;
942         }
943     }
946 /* nothing past this point */