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