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