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