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