PASDK-577:Add "proof of concept" code for McASP LLD to setCheckRateX
[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     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             pOut->rateX = 1.; // intialize rateX
144         }
145         else
146         {
147             return ASOP_IO_ERR_INV_STATE;
148         }
149     }
150     else
151     {
152         //
153         // OutNone device selected
154         //
155         
156         pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
157         pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
158     }
160     return ASOP_IO_SOK;
163 // Check if Output device SIO selection changed
164 Int checkOutDevSioSelUpdate(
165     const PAF_ASOT_Params *pP, 
166     PAF_ASOT_Config *pAsotCfg,
167     Int z, 
168     Bool *pOutDevSelUpdate
171     PAF_AST_Config *pAstCfg;
172     
173     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
175     if ((z < OUTPUT1) || (z >= OUTPUTN))
176     {
177         *pOutDevSelUpdate = FALSE;
178         return ASOP_IO_ERR_INV_PARAMS;
179     }
180     
181     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
183     return ASOP_IO_SOK;
186 // Check if any Output device SIO selection changed
187 Int checkAnyOutDevSioSelUpdate(
188     const PAF_ASOT_Params *pP, 
189     PAF_ASOT_Config *pAsotCfg,
190     Bool *pOutDevSelUpdate
193     PAF_AST_Config *pAstCfg;
194     Int outDevSelUpdate;
195     Int z;
196     
197     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
199     outDevSelUpdate = FALSE;
200     for (z=OUTPUT1; z < OUTPUTN; z++) 
201     {
202         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
203         {
204             outDevSelUpdate = TRUE;
205             break;
206         }
207     }
208     
209     *pOutDevSelUpdate = outDevSelUpdate;
211     return ASOP_IO_SOK;
214 // -----------------------------------------------------------------------------
215 // ASOT Decoding Function Helper - SIO Driver Change
216 //
217 //   Name:      PAF_ASOT_setCheckRateX
218 //   Purpose:   Decoding Function for reinitiating output.
219 //   From:      AST Parameter Function -> decodeInfo1
220 //              AST Parameter Function -> decodeInfo2
221 //   Uses:      See code.
222 //   States:    x
223 //   Return:    Error number in standard form (0 on success).
224 //   Trace:     None.
225 //
227 /* 0: set, 1: check, unused for now. --Kurt */
228 Int asopSetCheckRateX(
229     const PAF_ASOT_Params *pP, 
230     const PAF_ASOT_Patchs *pQ, 
231     PAF_ASOT_Config *pAsotCfg, 
232     Int check
235     PAF_AST_Config *pAstCfg;
236     PAF_AST_IoOut  *pOut;
237     float rateX;
238     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
239     Int z;                              /* output counter */
240     Int zx;                             /* output re-counter */
241     Int getVal;
242     int inputRate, inputCount, outputRate, outputCount;
243     Int zMD;
244     Int zMI;
245     Int zMS;
246     Int zE, zX;
247     // "proof of concept" for McASP LLD API
248     Uint32 divider;
249     Mcasp_HwSetupData mcaspSetup;
250     Int32 status;
252     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
253     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
254     
255     zMD = pAstCfg->masterDec;
256     zMS = pAstCfg->masterStr;
257     zMI = pP->zone.master;
259     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
260     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
261     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
262         inputRate, PAF_SAMPLERATEHZ_INV);
264     for (z=OUTPUT1; z < OUTPUTN; z++) 
265     {
266         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
267         {
268             // determine associated encoder
269             zE = z;
270             for (zX = ENCODE1; zX < ENCODEN; zX++) 
271             {
272                 if (pP->outputsFromEncodes[zX] == z) 
273                 {
274                     zE = zX;
275                     break;
276                 }
277             }
279             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
280             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
281             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
282                 outputRate, PAF_SAMPLERATEHZ_STD);
283             if ((rateI > 0) && (rateO > 0))
284             {
285                 rateX = rateO /* std */ * rateI /* inv */;
286             }
287             else if (inputCount != 0)
288             {
289                 rateX = (float)outputCount / inputCount;
290             }
291             else
292             {
293                 return ASPERR_INFO_RATERATIO;
294             }
296 #if 0 // FL, New IO: add similar thing to be figured out     
297             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
298             if (getVal == DOBERR_RATECHANGE) 
299             {
300                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
301                 {
302                     if (pAstCfg->xOut[zx].hTxSio)
303                     {
304                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
305                     }
306                 }
308                 // this forces an exit from the calling state machine which will
309                 // eventually call startOutput which calls setCheckRateX for all outputs
310                 // and so it is ok, in the presence of a rate change on any output, to
311                 // exit this loop /function early.
312                 return ASPERR_INFO_RATECHANGE;
313             }
314             else if (getVal != SYS_OK)
315             {
316                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
317             }
318 #endif // FL, New IO
319             if (pOut->rateX != rateX)
320             {
321                 UInt32 regVal;
322                 
323                 //
324                 // "Proof on concept" code for McASP LLD API to change bit clock divider.
325                 //
327                 // Initialize divider value.
328                 // This works for AHCLKX input from HDMI & sample rate = 44.1,48,88.2,96,192 kHz.
329                 divider = 2;
330                 
331                 // Update divider based on calculated rateX
332                 divider /= rateX;
334 #if 0 // debug
335                 // Experimental code: directly write CLKXDIV
336                 regVal = *(volatile UInt32 *)0x23400B0; // read MCASP_ACLKXCTL
337                 regVal &= ~0x1F; // mask off CLKXDIV bits
338                 //regVal |= 7; // set CLKXDIV for 48 kHz
339                 //regVal |= 3; // set CLKXDIV for 96 kHz
340                 //regVal |= 1; // set CLKXDIV for 192 kHz
341                 regVal |= (divider-1); // set CLKXDIV
342                 *(volatile UInt32 *)0x23400B0 = regVal; // write MCASP_ACLKXCTL
343 #endif                
345 #if 1
346                 // get existing McASP HW setup
347                 status = mcaspControlChan(pOut->hMcaspChan, Mcasp_IOCTL_CNTRL_GET_FORMAT_CHAN, &mcaspSetup);
348                 if (status != MCASP_COMPLETED)
349                 {
350                     Log_info0("asopSetCheckRateX(): McASP get channel format failed!\n");
351                     return ASOP_IO_ERR_MCASP_CFG;
352                 }
353                 
354                 // update CLKXDIV based on rateX
355                 mcaspSetup.clk.clkSetupClk &= ~CSL_MCASP_ACLKXCTL_CLKXDIV_MASK;
356                 mcaspSetup.clk.clkSetupClk |= (divider-1);
357                 
358                 // update McASP HW setup
359                 status = mcaspControlChan(pOut->hMcaspChan, Mcasp_IOCTL_CNTRL_SET_FORMAT_CHAN, &mcaspSetup);
360                 if (status != MCASP_COMPLETED)
361                 {
362                     Log_info0("asopSetCheckRateX(): McASP set channel format failed!\n");
363                     return ASOP_IO_ERR_MCASP_CFG;
364                 }
365 #endif            
366                 
367                 pOut->rateX = rateX;
368             }
369         }
370     }
372     return ASOP_IO_SOK;
373 } //asopSetCheckRateX
375 // -----------------------------------------------------------------------------
376 // ASOT Decoding Function Helper - SIO Driver Start
377 //
378 //   Name:      PAF_ASOT_startOutput
379 //   Purpose:   Decoding Function for initiating output.
380 //   From:      AST Parameter Function -> decodeInfo1
381 //   Uses:      See code.
382 //   States:    x
383 //   Return:    Error number in standard or SIO form (0 on success).
384 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
385 //              * State information as per parent.
386 //              * SIO control errors.
387 //
388 Int asopStartOutput(
389     const PAF_ASOT_Params *pP,
390     const PAF_ASOT_Patchs *pQ,
391     PAF_ASOT_Config *pAsotCfg
394     PAF_AST_Config *pAstCfg;
395     PAF_AST_IoOut  *pOut;
396     Int as;                     /* Audio Stream Number (1, 2, etc.) */
397     Int z;                      /* output counter */
398     Int nbufs;
399     Int zE, zS, zX;
400     Int zMD;
401     PAF_SIO_IALG_Obj    *pObj;
402     PAF_SIO_IALG_Config *pAlgConfig;
403     ioPhyCtl_t ioPhyCtl;
406     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
407     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
408     as = pAstCfg->as;
409     zMD = pAstCfg->masterDec;
411     for (z=OUTPUT1; z < OUTPUTN; z++)
412     {
413         if (pOut[z].hIoPhy)
414         {
415             // determine associated encoder and stream
416             zE = z;
417             zS = z;
418             for (zX = ENCODE1; zX < ENCODEN; zX++)
419             {
420                 if (pP->outputsFromEncodes[zX] == z)
421                 {
422                     zE = zX;
423                     zS = pP->streamsFromEncodes[zE];
424                     break;
425                 }
426             }
428             // FL, New IO: add similar thing to be figured out
429 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
430 #if 0
431             // if device selected and valid then enable stat tracking if
432             // required and start clocking
433             if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
434             {
435                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
436                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
437                 if (errno)
438                 {
439                     TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
440                     SIO_idle(pAstCfg->xOut[z].hTxSio);
441                     if (!errno)
442                     {
443                         errno = ASPERR_DEVOUT + errme;
444                     }
445                 }
446             }
447 #endif            
449             // Set sample count so that DOB knows how much data to send
450             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
451                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
453 #if 1 // FL, New IO: add similar thing to be figured out
454             // Update framework Phy transfer size
455             pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
456             // Update IO Phy transfer size
457             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
458             ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
459             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
460             // Update IO Buff delay to match Phy transfer size
461             ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
462 #endif
464             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
465             {
466                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
467                 pAlgConfig = &pObj->config;
468                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
469                     pAlgConfig->pMemRec[0].size);
470             }
472             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
473             // decoder. How should we handle the sourceProgram for multiple decoders?
474             // Override as needed
475             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
476             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
477             {
478                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
479             }
480             //JXTODO: add similar thing to be figured out
481             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
483             //JXTODO: data transfer start to be moved to output task state machine
484             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
485                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
486             {
487                 SIO_idle(pAstCfg->xOut[z].hTxSio);
488                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
489                 return errno;
490             } */
492             //JXTODO: add similar thing to be figured out
493 #if 0
494             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
495                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
496             {
497                 errno = (errno & 0xff) | ASPERR_MUTE;
498                 /* convert to sensical errno */
499                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
500                 return errno;
501             }
502             else
503             {
504                 pAstCfg->xOut[z].outBufStatus.audio
505                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
506             }
507 #endif
508             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
509         }
510     }
512     return ASOP_IO_SOK;
513 } /* asopStartOutput */
515 // -----------------------------------------------------------------------------
516 // ASOT Decoding Function Helper - SIO Driver Stop
517 //
518 //   Name:      PAF_ASOT_stopOutput
519 //   Purpose:   Decoding Function for terminating output.
520 //   From:      AST Parameter Function -> decodeProcessing
521 //              AST Parameter Function -> decodeComplete
522 //   Uses:      See code.
523 //   States:    x
524 //   Return:    Error number in standard or SIO form (0 on success).
525 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
526 //              * SIO control errors.
527 //
528 Int asopStopOutput(
529     const PAF_ASOT_Params *pP, 
530     const PAF_ASOT_Patchs *pQ, 
531     PAF_ASOT_Config *pAsotCfg
534     PAF_AST_Config *pAstCfg;
535     PAF_AST_IoOut  *pOut;
536     Int as;                     /* Audio Stream Number (1, 2, etc.) */
537     Int z;                      /* output counter */
538     Int errno, getVal;
539     Int zS, zX;
540     PAF_SIO_IALG_Obj    *pObj;
541     PAF_SIO_IALG_Config *pAlgConfig;
543     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
544     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
545     as = pAstCfg->as;
546     (void)as;  // clear compiler warning in case not used with tracing disabled
548     errno = ASOP_IO_SOK;
549     for (z=OUTPUT1; z < OUTPUTN; z++) 
550     {
551         if (pOut[z].hIoPhy) 
552         {
553             // determine associated encoder and stream
554             zS = z;
555             (void)zS;
556             for (zX = ENCODE1; zX < ENCODEN; zX++) 
557             {
558                 if (pP->outputsFromEncodes[zX] == z) 
559                 {
560                     zS = pP->streamsFromEncodes[zX];
561                     break;
562                 }
563             }
565 #if 0 // FL, New IO: add similar thing to be figured out            
566             // Mute output before audio data termination in the usual case,
567             // where such termination is due to decode error or user command.
568             // Identification of this as the usual case is provided by the
569             // "decode processing" state machine.
570             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
571                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
572                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
573             {
574                 if (!errno) 
575                 {
576                     errno = (getVal & 0xff) | ASPERR_MUTE;
577                     /* convert to sensical errno */
578                 }
579                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
580             }
582             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
583             
584             // Terminate audio data output, truncating (ignore) or flushing
585             // (play out) final samples as per (1) control register set by
586             // the user and (2) the type of audio data termination:
588 #if 0
589             // This form is not used because driver support for truncating
590             // data is not supported for internal clocks, although it is
591             // for external clocks.
592             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
593                 pC->xOut[z].outBufStatus.flush
594                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
595                 ? 1 : 0);
596             /* UNTESTED */
597 #else
598             // This form should be used when driver support for truncating
599             // data is supported for both internal and external clocks.
600             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
601                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
602                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
603                 ? 1 : 0);
604             /* TESTED */
605 #endif
607             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
609             if (!errno)
610             {
611                 errno = getVal;
612             }
614             // Mute output after audio data termination in a special case,
615             // where such termination is due to processing of a final frame
616             // or user command. Identification of this as a special case is
617             // provided by the "decode processing" state machine.
618             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
619                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
620                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
621             {
622                 if (!errno) 
623                 {
624                     errno = (getVal & 0xff) | ASPERR_MUTE;
625                     /* convert to sensical errno */
626                 }
627                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
628             }
630             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
631 #endif // FL, New IO
633             // zero output buffers
634             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
635             pAlgConfig = &pObj->config;
636             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
637         } //pAstCfg->xOut[z].hTxSio
638     }//OUTPUT
640     return errno;
641 } //asopStopOutput
643 /*===========================================================================
644  * Initialize I/O components for output processing
645 ============================================================================*/
646 Int asopIoCompsInit(
647     Int16 strAfSampleCount,     // stream audio frame sample count
648     PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
649     PAF_AST_IoOut *pOutIo       // pointer to Output IO
652     ioBuffParams_t ioBuffParams;
653     ioPhyParams_t  ioPhyParams;
655     if (pOutIo->hMcaspChan != NULL)
656     {
657         // Initialize I/O BUFF and I/O PHY components for output task
658         ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
659         // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
660         // This ensures no split buffers will be allocated on Output buffer wrap.
661         ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
662             (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
663         ioBuffParams.sync         = IOBUff_READ_SYNC;
664         ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
665         if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
666         {
667             return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
668         }
670         ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
671         ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
672         ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
673         ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
674         if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
675         {
676             return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
677         }
679         pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
680         
681         pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
682         pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
683         pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
684     }
685     
686     return ASOP_IO_SOK;
687 } /* asopIoCompsInit */
689 /*======================================================================================
690  *  This function checks whether the I/O physical layer has been initialized
691  *====================================================================================*/
692 Bool asopIoPhyCheckInit(Void)
694     if (!d10Initialized)
695         return FALSE;
696     else 
697         return TRUE;
700 /*======================================================================================
701  *  I/O physical layer prime operation required by McASP LLD
702  *====================================================================================*/
703 Void asopIoPhyPrime(
704     PAF_AST_IoOut *pOut
707     Int32        count;
709     pOut->numPrimeXfers = NUM_PRIME_XFERS;
711     for (count = 0; count < pOut->numPrimeXfers; count++)
712     {
713         ioPhyXferSubmit(pOut->hIoPhy);
714     }
715 } /* asipIoPhyPrime */
717 // Initialize Output buffer configuration
718 Int asopInitOutBufConfig(
719     PAF_AST_OutBuf *pOutBuf, 
720     PAF_AST_IoOut *pOutIo
723     PAF_OutBufConfig *pOutBufCfg;
724     ioBuffHandle_t hIoBuff;
725     ioBuffInfo_t outBuffInfo;
726     
727     pOutBufCfg = &pOutBuf->outBufConfig;
728     hIoBuff = pOutIo->hIoBuff;
729     
730     pOutBufCfg->stride = pOutIo->stride;
731     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
732     pOutBufCfg->precision = 24;
733     
734     ioBuffGetInfo(hIoBuff, &outBuffInfo);
735     pOutBufCfg->base.pLgInt = outBuffInfo.base;
736     pOutBufCfg->sizeofBuffer = outBuffInfo.size;
737     
738     pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
739     
740     return ASOP_IO_SOK;
743 Int asopGetOutBufPtrs(
744     PAF_AST_IoOut *pOutIo,
745     size_t writeSize
748     void *buff1, *buff2;
749     size_t size1, size2;
750     Int status;
752     status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
753                                 &buff1, &size1, &buff2, &size2);
754     if (status == IOBUFF_ERR_OVERFLOW)
755     {
756         pOutIo->errIoBuffOvrCnt++;
757         //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
759         // skip processing since output buffer overflows
760         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
761     }
762     else if (status == IOBUFF_ERR_UNDERFLOW)
763     {
764         pOutIo->errIoBuffUndCnt++;
765         //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
767         // already underflows and remain in underflow
768     }
769     
770     if ((buff2 != NULL) || (size2 != 0))
771     {
772         // Two buffers allocated indicates split buffer allocation on buffer wrap.
773         pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
774     }
776     // save buffer pointers & sizes for later write complete
777     pOutIo->buff1 = buff1;
778     pOutIo->size1 = size1;
779     pOutIo->buff2 = buff2;
780     pOutIo->size2 = size2;
782     return ASOP_IO_SOK;
785 #if 0
786 // Update Output buffer configuration.
787 // This is needed for proper operation of PCM encoder.
788 Int asopUpdateOutBufConfig(
789     PAF_AST_OutBuf *pOutBuf, 
790     PAF_AST_IoOut *pOutIo
793     PAF_OutBufConfig *pOutBufCfg;
794     ioBuffHandle_t hIoBuff;
795     ioBuffInfo_t outBuffInfo;
796     void *buff1, *buff2;
797     size_t size1, size2, total_write_size;
798     Int status;
800     pOutBufCfg = &pOutBuf->outBufConfig;
801     hIoBuff = pOutIo->hIoBuff;
803     // FL, New IO: original code can change these values in every DOB issue
804     //  Need to determine if this is required or not.
805     pOutBufCfg->stride = pOutIo->stride;
806     pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
807     pOutBufCfg->precision = 24;
808     
809     //JXTODO: to replace hard coded write size
810     // Get write pointers of output memory pool
811     total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
812     status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
813         &buff1, &size1, &buff2, &size2);
814     if (status == IOBUFF_ERR_OVERFLOW) 
815     {
816         pOutIo->errIoBuffOvrCnt++;
817         //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
819         // skip processing since output buffer overflows        
820         return ASOP_IO_ERR_OUTBUF_OVERFLOW;
821     }
822     else if (status == IOBUFF_ERR_UNDERFLOW) 
823     {
824         pOutIo->errIoBuffUndCnt++;
825         //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
826         
827         // already underflows and remain in underflow
828     }
829 #if 0
830     // Update Output buffer pointer for Encoder
831     pOutBufCfg->pntr.pLgInt = buff1;
832     if ((buff2 != NULL) || (size2 != 0))
833     {
834         // buff2 should always be NULL for Output & size2 should always be 0 for Output.
835         // Track this here.
836         pOutIo->ioBuffBuf2AllocCnt++; // debug
837     }
838 #endif
839     // save buffer pointers & sizes for later write complete
840     pOutIo->buff1 = buff1;
841     pOutIo->size1 = size1;
842     pOutIo->buff2 = buff2;
843     pOutIo->size2 = size2;
844     
845     return ASOP_IO_SOK;
847 #endif
849 // Mark Output buffers write complete
850 Int asopMarkOutBuffsWriteComplete(
851     PAF_AST_OutBuf *pOutBuf, 
852     PAF_AST_IoOut *pOutIo
855     ioBuffHandle_t hIoBuff;
856     void *buff1, *buff2;
857     size_t size1, size2;
858     
859     // get buffer pointers & sizes from previous IO Buff write allocation
860     buff1 = pOutIo->buff1;
861     size1 = pOutIo->size1;
862     buff2 = pOutIo->buff2; // this should always be NULL for Output
863     size2 = pOutIo->size2; // this should always be 0 for Output
864     
865     hIoBuff = pOutIo->hIoBuff;
866     
867     ioBuffWriteComplete(hIoBuff, buff1, size1);
869     if (buff2 != NULL) 
870     {
871         ioBuffWriteComplete(hIoBuff, buff2, size2);
872     }
873     
874     return ASOP_IO_SOK;
877 /*======================================================================================
878  *  This function starts an I/O PHY transfer for output
879  *====================================================================================*/
880 Void asopPhyTransferStart(
881     PAF_AST_IoOut *pOut
884     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
885     {
886         //mcaspTxReset();
887         //mcaspTxCreate();
888         //pOut->hMcaspChan = hMcaspTxChan;
889         System_abort("\nMcASP for output underruns! %d!\n");
890     }
891     else 
892     {
893         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
894         {
895             // Output buffer underflows!
896             System_abort("\nOutput buffer underflows!\n");
897         }
898         else {
899             // Output buffer operates normally
900             ;
901         }
902     }
905 /* nothing past this point */