]> 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-516:Several ASOT updates
[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 // -----------------------------------------------------------------------------
68 // ASOT Decoding Function Helper - SIO Driver Change
69 //
70 //   Name:      PAF_ASOT_setCheckRateX
71 //   Purpose:   Decoding Function for reinitiating output.
72 //   From:      AST Parameter Function -> decodeInfo1
73 //              AST Parameter Function -> decodeInfo2
74 //   Uses:      See code.
75 //   States:    x
76 //   Return:    Error number in standard form (0 on success).
77 //   Trace:     None.
78 //
80 /* 0: set, 1: check, unused for now. --Kurt */
81 Int asopSetCheckRateX(
82     const PAF_ASOT_Params *pP, 
83     const PAF_ASOT_Patchs *pQ, 
84     PAF_ASOT_Config *pAsotCfg, 
85     Int check
86 )
87 {
88     PAF_AST_Config *pAstCfg;
89     PAF_AST_IoOut  *pOut;
90     float rateX;
91     PAF_SampleRateHz rateO /* std */, rateI /* inv */;
92     Int z;                              /* output counter */
93     Int zx;                             /* output re-counter */
94     Int getVal;
95     int inputRate, inputCount, outputRate, outputCount;
96     Int zMD;
97     Int zMI;
98     Int zMS;
99     Int zE, zX;
101     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
102     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
103     
104     zMD = pAstCfg->masterDec;
105     zMS = pAstCfg->masterStr;
106     zMI = pP->zone.master;
108     inputRate = pAstCfg->xInp[zMI].inpBufStatus.sampleRateStatus;
109     inputCount = pAstCfg->xDec[zMD].decodeStatus.frameLength;
110     rateI = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
111         inputRate, PAF_SAMPLERATEHZ_INV);
113     for (z=OUTPUT1; z < OUTPUTN; z++) 
114     {
115         if (pOut[z].hIoPhy && (pAstCfg->xOut[z].outBufStatus.clock & 0x01)) 
116         {
117             // determine associated encoder
118             zE = z;
119             for (zX = ENCODE1; zX < ENCODEN; zX++) 
120             {
121                 if (pP->outputsFromEncodes[zX] == z) 
122                 {
123                     zE = zX;
124                     break;
125                 }
126             }
128             outputRate = pAstCfg->xEnc[zE].encodeStatus.sampleRate;
129             outputCount = pAstCfg->xEnc[zE].encodeStatus.frameLength;
130             rateO = pAstCfg->xStr[zMS].pAudioFrame->fxns->sampleRateHz(pAstCfg->xStr[zMS].pAudioFrame, 
131                 outputRate, PAF_SAMPLERATEHZ_STD);
132             if ((rateI > 0) && (rateO > 0))
133             {
134                 rateX = rateO /* std */ * rateI /* inv */;
135             }
136             else if (inputCount != 0)
137             {
138                 rateX = (float)outputCount / inputCount;
139             }
140             else
141             {
142                 return ASPERR_INFO_RATERATIO;
143             }
145 #if 0 // FL, New IO: add similar thing to be figured out     
146             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_RATEX, (Arg)&rateX);
147             if (getVal == DOBERR_RATECHANGE) 
148             {
149                 for (zx=OUTPUT1; zx < OUTPUTN; zx++)
150                 {
151                     if (pAstCfg->xOut[zx].hTxSio)
152                     {
153                         SIO_idle(pAstCfg->xOut[zx].hTxSio);
154                     }
155                 }
157                 // this forces an exit from the calling state machine which will
158                 // eventually call startOutput which calls setCheckRateX for all outputs
159                 // and so it is ok, in the presence of a rate change on any output, to
160                 // exit this loop /function early.
161                 return ASPERR_INFO_RATECHANGE;
162             }
163             else if (getVal != SYS_OK)
164             {
165                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
166             }
167 #endif // FL, New IO
168         }
169     }
171     return 0;
172 } //asopSetCheckRateX
174 // -----------------------------------------------------------------------------
175 // ASOT Decoding Function Helper - SIO Driver Start
176 //
177 //   Name:      PAF_ASOT_startOutput
178 //   Purpose:   Decoding Function for initiating output.
179 //   From:      AST Parameter Function -> decodeInfo1
180 //   Uses:      See code.
181 //   States:    x
182 //   Return:    Error number in standard or SIO form (0 on success).
183 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
184 //              * State information as per parent.
185 //              * SIO control errors.
186 //
187 Int asopStartOutput(
188     const PAF_ASOT_Params *pP,
189     const PAF_ASOT_Patchs *pQ,
190     PAF_ASOT_Config *pAsotCfg
193     PAF_AST_Config *pAstCfg;
194     PAF_AST_IoOut  *pOut;
195     Int as;                     /* Audio Stream Number (1, 2, etc.) */
196     Int z;                      /* output counter */
197     Int nbufs;
198     Int zE, zS, zX;
199     Int zMD;
200     PAF_SIO_IALG_Obj    *pObj;
201     PAF_SIO_IALG_Config *pAlgConfig;
202     ioPhyCtl_t ioPhyCtl;
205     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
206     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
207     as = pAstCfg->as;
208     zMD = pAstCfg->masterDec;
210     for (z=OUTPUT1; z < OUTPUTN; z++)
211     {
212         if (pOut[z].hIoPhy)
213         {
214             // determine associated encoder and stream
215             zE = z;
216             zS = z;
217             for (zX = ENCODE1; zX < ENCODEN; zX++)
218             {
219                 if (pP->outputsFromEncodes[zX] == z)
220                 {
221                     zE = zX;
222                     zS = pP->streamsFromEncodes[zE];
223                     break;
224                 }
225             }
227             // FL, New IO: add similar thing to be figured out
228 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
229 #if 0
230             // if device selected and valid then enable stat tracking if
231                         // required and start clocking
232                         if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
233                         {
234                                 TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
235                                 errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
236                                 if (errno)
237                                 {
238                                         TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
239                                         SIO_idle(pAstCfg->xOut[z].hTxSio);
240                                         if (!errno)
241                                         {
242                                                 errno = ASPERR_DEVOUT + errme;
243                                         }
244                                 }
245                         }
246 #endif            
248             // Set sample count so that DOB knows how much data to send
249             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
250                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
252 #if 1 // FL New IO: add similar thing to be figured out
253             ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
254             ioPhyCtl.params.xferFrameSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame
255                                                 * OUTPUT_STRIDE * WORD_SIZE_PCM;
256             ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
257             // Update framework transfer size to IO Phy transfer size
258             pOut[z].phyXferSize = ioPhyCtl.params.xferFrameSize;
259             // Update IO Buff delay to match IO Phy transfer size
260             ioBuffAdjustDelay(pOut[z].hIoBuff, ioPhyCtl.params.xferFrameSize * (NUM_PRIME_XFERS+1));
261 #endif            
262                 
263             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
264             {
265                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
266                 pAlgConfig = &pObj->config;
267                 memset(pAstCfg->xOut[z].outBufConfig.base.pVoid, 0xAA,
268                     pAlgConfig->pMemRec[0].size);
269             }
271             // The index to DEC_OUTNUMBUF_MAP will always come from the primary/master
272             // decoder. How should we handle the sourceProgram for multiple decoders?
273             // Override as needed
274             nbufs = DEC_OUTNUMBUF_MAP(pAstCfg->xDec[zMD].decodeStatus.sourceProgram);
275             if (pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram] > 0)
276             {
277                 nbufs = pAstCfg->xOut[z].outBufStatus.numBufOverride[pAstCfg->xDec[zMD].decodeStatus.sourceProgram];
278             }
279             //JXTODO: add similar thing to be figured out
280             //SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_SET_NUMBUF, nbufs);
282             //JXTODO: data transfer start to be moved to output task state machine
283             /*if (errno = SIO_issue(pAstCfg->xOut[z].hTxSio,
284                 &pAstCfg->xOut[z].outBufConfig, sizeof(pAstCfg->xOut[z].outBufConfig), 0))
285             {
286                 SIO_idle(pAstCfg->xOut[z].hTxSio);
287                 TRACE_TERSE2("PAF_ASOT_startOutput: AS%d: SIO_issue failed (0x%x)", as+zS, errno);
288                 return errno;
289             } */
291             //JXTODO: add similar thing to be figured out
292 #if 0
293             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
294                 (errno =  SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_UNMUTE, 0)))
295             {
296                 errno = (errno & 0xff) | ASPERR_MUTE;
297                 /* convert to sensical errno */
298                 TRACE_TERSE2("as1-f2: PAF_ASOT_startOutput: AS%d: SIO control failed (unmute) 0x%x", as+zS, errno);
299                 return errno;
300             }
301             else
302             {
303                 pAstCfg->xOut[z].outBufStatus.audio
304                     = (pAstCfg->xOut[z].outBufStatus.audio & 0xf0) | PAF_OB_AUDIO_SOUND;
305             }
306 #endif
307             TRACE_VERBOSE1("PAF_ASOT_startOutput: AS%d: output started", as+zS);
308         }
309     }
311     return 0;
312 } /* asopStartOutput */
314 // -----------------------------------------------------------------------------
315 // ASOT Decoding Function Helper - SIO Driver Stop
316 //
317 //   Name:      PAF_ASOT_stopOutput
318 //   Purpose:   Decoding Function for terminating output.
319 //   From:      AST Parameter Function -> decodeProcessing
320 //              AST Parameter Function -> decodeComplete
321 //   Uses:      See code.
322 //   States:    x
323 //   Return:    Error number in standard or SIO form (0 on success).
324 //   Trace:     Message Log "trace" in Debug Project Configuration reports:
325 //              * SIO control errors.
326 //
327 Int asopStopOutput(
328     const PAF_ASOT_Params *pP, 
329     const PAF_ASOT_Patchs *pQ, 
330     PAF_ASOT_Config *pAsotCfg
333     PAF_AST_Config *pAstCfg;
334     PAF_AST_IoOut  *pOut;
335     Int as;                     /* Audio Stream Number (1, 2, etc.) */
336     Int z;                      /* output counter */
337     Int errno = 0, getVal;
338     Int zS, zX;
339     PAF_SIO_IALG_Obj    *pObj;
340     PAF_SIO_IALG_Config *pAlgConfig;
342     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
343     pOut = pAsotCfg->pIoOut; // get pointer to ASOT IO configuration
344     as = pAstCfg->as;
345     (void)as;  // clear compiler warning in case not used with tracing disabled
347     for (z=OUTPUT1; z < OUTPUTN; z++) 
348     {
349         if (pOut[z].hIoPhy) 
350         {
351             // determine associated encoder and stream
352             zS = z;
353             (void)zS;
354             for (zX = ENCODE1; zX < ENCODEN; zX++) 
355             {
356                 if (pP->outputsFromEncodes[zX] == z) 
357                 {
358                     zS = pP->streamsFromEncodes[zX];
359                     break;
360                 }
361             }
363 #if 0 // FL, New IO: add similar thing to be figured out            
364             // Mute output before audio data termination in the usual case,
365             // where such termination is due to decode error or user command.
366             // Identification of this as the usual case is provided by the
367             // "decode processing" state machine.
368             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
369                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_SOUND) &&
370                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0))) 
371             {
372                 if (!errno) 
373                 {
374                     errno = (getVal & 0xff) | ASPERR_MUTE;
375                     /* convert to sensical errno */
376                 }
377                 TRACE_VERBOSE1("asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
378             }
380             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- begin PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
381             
382             // Terminate audio data output, truncating (ignore) or flushing
383             // (play out) final samples as per (1) control register set by
384             // the user and (2) the type of audio data termination:
386 #if 0
387             // This form is not used because driver support for truncating
388             // data is not supported for internal clocks, although it is
389             // for external clocks.
390             getVal = SIO_ctrl(pC->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
391                 pC->xOut[z].outBufStatus.flush
392                 & (pC->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
393                 ? 1 : 0);
394             /* UNTESTED */
395 #else
396             // This form should be used when driver support for truncating
397             // data is supported for both internal and external clocks.
398             getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_IDLE,
399                 pAstCfg->xOut[z].outBufStatus.flush ? 1 :
400                 (pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH
401                 ? 1 : 0);
402             /* TESTED */
403 #endif
405             TRACE_TIME((&TIME_MOD, "... + %d = %d (stopOutput -- after PAF_SIO_CONTROL_IDLE)", dtime(), TSK_time()));
407             if (!errno)
408             {
409                 errno = getVal;
410             }
412             // Mute output after audio data termination in a special case,
413             // where such termination is due to processing of a final frame
414             // or user command. Identification of this as a special case is
415             // provided by the "decode processing" state machine.
416             if (!(pAstCfg->xOut[z].outBufStatus.audio & 0xf0) &&
417                 ((pAstCfg->xOut[z].outBufStatus.audio & 0x0f) == PAF_OB_AUDIO_FLUSH) &&
418                 (getVal = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_MUTE, 0)))
419             {
420                 if (!errno) 
421                 {
422                     errno = (getVal & 0xff) | ASPERR_MUTE;
423                     /* convert to sensical errno */
424                 }
425                 TRACE_VERBOSE1("as1-f2: asopStopOutput:  AS%d: SIO control failed (mute)", as+zS);
426             }
428             pAstCfg->xOut[z].outBufStatus.audio &= ~0x0f;
429 #endif // FL, New IO
431             // zero output buffers
432             pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
433             pAlgConfig = &pObj->config;
434             memset (pAstCfg->xOut[z].outBufConfig.base.pVoid, 0, pAlgConfig->pMemRec[0].size);
435         } //pAstCfg->xOut[z].hTxSio
436     }//OUTPUT
438     return errno;
439 } //asopStopOutput
441 // FL, New IO: this function is currently a stub
442 // FL, New IO: need to McASP/EDMA configuration using SAP configuration from Output shortcut
443 // Select Output devices
444 Int asopSelectDevices(PAF_AST_IoOut *pOut)
446     if((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) {
447         return -1;
448     }
450     pOut->hMcaspChan = hMcaspTxChan;
452     return 0;
455 /*===========================================================================
456  * Initialize I/O components for output processing
457 ============================================================================*/
458 Int asopIoCompsInit(
459     PAF_AST_OutBuf *pOutBuf, 
460     PAF_AST_IoOut *pOutIo
463     // Initialize I/O BUFF and I/O PHY components for output task
464     ioBuffParams_t ioBuffParams;
465     ioPhyParams_t  ioPhyParams;
467     ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
468     ioBuffParams.size         = pOutBuf->outBufConfig.allocation/STRIDE_WORST_CASE*STRIDE_WORST_CASE;
469     ioBuffParams.sync         = IOBUff_READ_SYNC;
470     ioBuffParams.nominalDelay = OUTPUT_FRAME_SIZE * (NUM_PRIME_XFERS+1);
471     if(ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
472     {
473         return -1;   // to remove magic number
474     }
476     ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
477     ioPhyParams.xferFrameSize   = OUTPUT_FRAME_SIZE;
478     ioPhyParams.mcaspChanHandle = hMcaspTxChan;
479     ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
480     if(ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
481     {
482         return -1;   // to remove magic number
483     }
485     pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
487     return 0;
488 } /* asopIoCompsInit */
491 /*======================================================================================
492  *  I/O physical layer prime operation required by McASP LLD
493  *====================================================================================*/
494 Void asopIoPhyPrime(
495     PAF_AST_IoOut *pOut
498     Int32        count;
500     pOut->numPrimeXfers = NUM_PRIME_XFERS;
502     for (count = 0; count < pOut->numPrimeXfers; count++)
503     {
504         ioPhyXferSubmit(pOut->hIoPhy);
505     }
506 } /* asipIoPhyPrime */
509 /*======================================================================================
510  *  This function checks whether the I/O physical layer has been initialized
511  *====================================================================================*/
512 Bool asopIoPhyCheckInit(Void)
514     if (!d10Initialized)
515         return FALSE;
516     else 
517         return TRUE;
520 /*======================================================================================
521  *  This function starts an I/O PHY transfer for output
522  *====================================================================================*/
523 Void asopPhyTransferStart(
524     PAF_AST_IoOut *pOut
527     if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
528     {
529         mcaspTxReset();
530         mcaspTxCreate();
531         pOut->hMcaspChan = hMcaspTxChan;
532     }
533     else 
534     {
535         if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
536         {
537             // Output buffer underflows!
538             System_abort("\nOutput buffer underflows!\n");
539         }
540         else {
541             // Output buffer operates normally
542             ;
543         }
544     }
547 // Write output buffers with encoded data
548 Int asopWriteOpBuffers(
549     PAF_OutBufConfig *pOpBufCfg, 
550     PAF_AST_IoOut *pOut
553     PAF_UnionPointer pntr;
554     void *buff1, *buff2;
555     size_t size1, size2;
556     int status;
558     pntr = pOpBufCfg->pntr; // get output buffer pointer
559     
560     status = ioBuffGetWritePtrs(pOut->hIoBuff, pOut->phyXferSize,
561         &buff1, &size1, &buff2, &size2);
562     if (status == IOBUFF_ERR_OVERFLOW) 
563     {
564         /* skip processing since output buffer overflows */
565         return IOBUFF_ERR_OVERFLOW;   // to use a different error code
566     }
568     // Copy data to output buffer to be transmitted by McASP
569     memcpy(buff1, &pntr.pSmInt[0], size1);
570     Cache_wbInv(buff1, size1, Cache_Type_ALL,TRUE);
572     ioBuffWriteComplete(pOut->hIoBuff, buff1, size1);
574     if (buff2 != NULL) 
575     {
576       memcpy(buff2, &pntr.pSmInt[size1], size2);
577       Cache_wbInv(buff2, size2, Cache_Type_ALL,TRUE);
579       ioBuffWriteComplete(pOut->hIoBuff, buff2, size2);
580     }
582     return 0;
585 // Check if Output device SIO selection changed
586 Int checkOutDevSioSelUpdate(
587     const PAF_ASOT_Params *pP, 
588     PAF_ASOT_Config *pAsotCfg,
589     Int z, 
590     Bool *pOutDevSelUpdate
593     PAF_AST_Config *pAstCfg;
594     
595     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
597     if ((z < OUTPUT1) || (z >= OUTPUTN))
598     {
599         *pOutDevSelUpdate = FALSE;
600         return -1;
601     }
602     
603     *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
605     return 0;
608 // Check if any Output device SIO selection changed
609 Int checkAnyOutDevSioSelUpdate(
610     const PAF_ASOT_Params *pP, 
611     PAF_ASOT_Config *pAsotCfg,
612     Bool *pOutDevSelUpdate
615     PAF_AST_Config *pAstCfg;
616     Int outDevSelUpdate;
617     Int z;
618     
619     pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
621     outDevSelUpdate = FALSE;
622     for (z=OUTPUT1; z < OUTPUTN; z++) 
623     {
624         if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
625         {
626             outDevSelUpdate = TRUE;
627             break;
628         }
629     }
630     
631     *pOutDevSelUpdate = outDevSelUpdate;
633     return 0;
636 /* nothing past this point */