/* Copyright (c) 2017, Texas Instruments Incorporated - http://www.ti.com/ All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // // // Stacking Input Buffer Driver implementations // // // Derived from /c/ti/c6000/src/drivers/dgs.c #include #include #include #include #include #include #include #include #include #include #include "mib.h" #include "miberr.h" #include #include #include #include #include //INT_MAX #include typedef xdc_Short MdInt; typedef xdc_UShort MdUns; typedef xdc_Char SmInt; typedef xdc_UChar SmUns; extern const ti_sysbios_heaps_HeapMem_Handle heapMemDdr3; #define HEAPMALLOC (IHeap_Handle)heapMemDdr3 extern HeapMem_Handle DEV2_memSpaceToHeap (IALG_MemSpace space); #if 0 #if ((PAF_DEVICE&0xFF000000) == 0xD8000000) #ifndef dMAX_CFG #include #else #include #include #endif /* dMAX_CFG */ #include "psdkaf_hjt.h" extern Uint32 DAT_cacheop_and_copy (void *src, void *dst, Uint16 byteCnt); #undef DAT_copy #define DAT_copy DAT_cacheop_and_copy #else #include "pafhjt.h" #include "dmax_dat.h" // this has to come after pafhjt #endif #else #include "pafhjt.h" #endif #include #include //grab from samrat.c #include #include #include #include // printf in case of programming error // allows you to set a different trace module in pa.cfg #define TR_MOD trace //#define TRACE_ENABLE #ifdef TRACE_ENABLE #include "dp.h" #define TRACE(a) dp a // LOG_printf a #else #define TRACE(a) #endif extern const PAF_SampleRateHz PAF_ASP_sampleRateHzTable[PAF_SAMPLERATE_N][PAF_SAMPLERATEHZ_N]; #define SCANATSAMPLERATELIMIT ((float) 48000.) // Likely needs to be 7 when/if AC3 handling is changed to // throw away fill. #define NUM_CHILD_BUFFERS 6 Int DIB_ctrl (DEV2_Handle device, Uns code, Arg Arg); Int DIB_idle (DEV2_Handle device, Bool Flush); Int DIB_issue (DEV2_Handle device); Int DIB_open (DEV2_Handle device, String Name); Int DIB_reclaim (DEV2_Handle device); Int DIB_getSync (DEV2_Handle device, PAF_InpBufConfig *pBufConfig); Int DIB_initFrame (DEV2_Handle device, PAF_InpBufConfig *pBufConfig); Int DIB_requestFrame (DEV2_Handle device, PAF_InpBufConfig *pBufConfig); Int DIB_issueChild (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, Int size, Int forTotal); Int DIB_reclaimChild (DEV2_Handle device, PAF_InpBufConfig *pBufConfig); Int DIB_reset (DEV2_Handle device, PAF_InpBufConfig *pBufConfig); Int DIB_syncScan (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 *pTimeout); Int DIB_waitForData (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 count); Int DIB_syncScanDTS (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 *pTimeout, XDAS_UInt16 *pHeaderEnd); // Driver function table. DIB_Fxns DIB_FXNS = { NULL, // close not used in PA/F systems DIB_ctrl, DIB_idle, DIB_issue, DIB_open, NULL, // ready not used in PA/F systems DIB_reclaim, DIB_getSync, DIB_initFrame, DIB_requestFrame, DIB_issueChild, DIB_reclaimChild, DIB_reset, DIB_syncScan, DIB_waitForData, DIB_syncScanDTS }; // macros assume pDevExt is available and pDevExt->pFxns is valid #define DIB_FTABLE_getSync(_a,_b) (*pDevExt->pFxns->getSync)(_a,_b) #define DIB_FTABLE_initFrame(_a,_b) (*pDevExt->pFxns->initFrame)(_a,_b) #define DIB_FTABLE_requestFrame(_a,_b) (*pDevExt->pFxns->requestFrame)(_a,_b) #define DIB_FTABLE_issueChild(_a,_b,_c,_d) (*pDevExt->pFxns->issueChild)(_a,_b,_c,_d) #define DIB_FTABLE_reclaimChild(_a,_b) (*pDevExt->pFxns->reclaimChild)(_a,_b) #define DIB_FTABLE_reset(_a,_b) (*pDevExt->pFxns->reset)(_a,_b) #define DIB_FTABLE_syncScan(_a,_b,_c) (*pDevExt->pFxns->syncScan)(_a,_b,_c) #define DIB_FTABLE_waitForData(_a,_b,_c) (*pDevExt->pFxns->waitForData)(_a,_b,_c) #define DIB_FTABLE_syncScanDTS(_a,_b,_c,_d) (*pDevExt->pFxns->syncScanDTS)(_a,_b,_c,_d) // ............................................................................. //IBMODE enum { MODE_DEFAULT = 0, MODE_NO_ZERORUNRESTART = 1, MODE_NO_ZERORUN = 2 }; // syncState enum { SYNC_NONE, SYNC_ONE, SYNC_ONGOING, SYNC_PCM, SYNC_PCM_FORCED, SYNC_AUTO }; // scanState enum { SCANNED_NONE, SCANNED_IEC_PA, SCANNED_IEC_PB, SCANNED_IEC_PC, SCANNED_DTS14_SYNC_A, SCANNED_DTS14_SYNC_B, SCANNED_DTS14_SYNC_C, SCANNED_DTS14_SYNC_D, SCANNED_DTS16_SYNC_A, SCANNED_DTS16_SYNC_B, SCANNED_DTS16_SYNC_C }; // all sizes in number of 16bit words words #define IEC_HEADER_SIZE 4 //PA PB PC PD #define DTS14_HEADER_SIZE 6 #define DTS16_HEADER_SIZE 4 //table needed until PAF_SOURCE is reordered to match IEC numbering const SmUns iecPafSource[23] = { PAF_SOURCE_UNKNOWN, // 0: IEC NULL Type PAF_SOURCE_AC3, // 1: Comments on 1-15 match IEC 61937 part 2. PAF_SOURCE_UNKNOWN, // 2: IEC reserved PAF_SOURCE_UNKNOWN, // 3: IEC pause PAF_SOURCE_UNKNOWN, // 4: MPEG 1 layer 1 PAF_SOURCE_MP3, // 5: MPEG layer 2 or 3 PAF_SOURCE_UNKNOWN, // 6: MPEG 2 data with extension PAF_SOURCE_AAC, // 7: MPEG-2 AAC ADTS PAF_SOURCE_UNKNOWN, // 8: MPEG 2 layer 1 low sampling frequency PAF_SOURCE_UNKNOWN, // 9: MPEG 2 layer 2 or 3 low sampling frequency PAF_SOURCE_UNKNOWN, // 10: reserved PAF_SOURCE_DTS, // 11: DTS type 1 (11 bit: 512 sample repeat period) PAF_SOURCE_DTS12, // 12: DTS type 2 (12 bit: 1024 sample repeat period) PAF_SOURCE_DTS13, // 13: DTS type 3 (13 bit: 2048 sample repeat period) PAF_SOURCE_DTS14, // 14: ATRAC PAF_SOURCE_UNKNOWN, // 15: ATRAC 2/3 PAF_SOURCE_THD, // 16 PAF_SOURCE_DTSHD, // 17 PAF_SOURCE_WMA9PRO, // 18 PAF_SOURCE_UNKNOWN, // 19 PAF_SOURCE_UNKNOWN, // 20 PAF_SOURCE_DDP, // 21 PAF_SOURCE_THD, // 22 }; // IEC framelengths (in 16bit words) static const MdUns iecFrameLength[23] = { 0, 1536*2, 0, 0, 0, 1152*2, 0, 1024*2, 0, 0, 0, 512*2, 1024*2, 2048*2, 0, 0, 15*1024*2, //THD 1*1024, // DTSHD, actual framelength is adjusted by DTSsubType 4096*2, 0,0, 1536*2*4, 15*1024*2 //THD }; #define IEC_PA ((short) 0xF872) #define IEC_PB ((short) 0x4E1F) #define DTS16_SYNC_A ((short) 0x7FFE) #define DTS16_SYNC_B ((short) 0x8001) #define DTS16_SYNC_C ((short) 0xFC00) #define DTS14_SYNC_A ((short) 0x1FFF) #define DTS14_SYNC_B ((short) 0xE800) #define DTS14_SYNC_C ((short) 0x07F0) #define DTS_BURST_TYPE_I 0x008B #define DTS_BURST_TYPE_II 0x018C #define DTS_BURST_TYPE_III 0x028D #define DTS_BURST_TYPE_IV 0x0491 #define DTS_BURST_TYPE_IV_CBR 0x02 #define DTS_BURST_TYPE_IV_LBR 0x03 #define DTS_BURST_TYPE_IV_HBR 0x04 #define DEFAULT_AUTOREQUESTSIZE 128 //#define DEFAULT_AUTOREQUESTSIZE 256 // This is used at a couple of locations to ensure the transfer // size is sufficiently long to be useful. //#define NOMINAL_XFERSIZE 128 #define NOMINAL_XFERSIZE 128 //GJ Debug //#define NOMINAL_XFERSIZE 512 //GJ Debug #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) // FL: (***) debug #include "evmc66x_gpio_dbg.h" // ----------------------------------------------------------------------------- inline void IncrementPtr (PAF_InpBufConfig *pBufConfig, Ptr *pPtr, int numWords) { int addr; addr = (int) *pPtr + numWords*pBufConfig->sizeofElement; if (addr > ((int) pBufConfig->base.pVoid + pBufConfig->sizeofBuffer - 1)) addr -= pBufConfig->sizeofBuffer; *pPtr = (Ptr) addr; return; } // IncrementPtr // ----------------------------------------------------------------------------- inline int GetNumAvail (PAF_InpBufConfig *pBufConfig) { int numBytes; if ( (Uns) pBufConfig->head.pVoid >= (Uns) pBufConfig->pntr.pVoid) numBytes = ((int)pBufConfig->head.pVoid - (int)pBufConfig->pntr.pVoid); else numBytes = ((int)pBufConfig->head.pVoid - (int)pBufConfig->pntr.pVoid + pBufConfig->sizeofBuffer); // return in words return (numBytes / pBufConfig->sizeofElement); } // GetNumAvail // ----------------------------------------------------------------------------- // compute how much data we have including outstanding requests inline int GetFutureAvail (PAF_InpBufConfig *pBufConfig) { int numBytes; if ( (Uns) pBufConfig->futureHead.pVoid >= (Uns) pBufConfig->pntr.pVoid) numBytes = ((int)pBufConfig->futureHead.pVoid - (int)pBufConfig->pntr.pVoid); else numBytes = ((int)pBufConfig->futureHead.pVoid - (int)pBufConfig->pntr.pVoid + pBufConfig->sizeofBuffer); // return in words return (numBytes / pBufConfig->sizeofElement); } // GetFutureAvail // ----------------------------------------------------------------------------- Int DIB_issue (DEV2_Handle device) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Frame *srcFrame; Int status; PAF_InpBufConfig *pBufConfig; srcFrame = Queue_get (device->todevice); pBufConfig = (PAF_InpBufConfig *) srcFrame->addr; if (!pBufConfig || !pBufConfig->pBufStatus) return SIO2_EINVAL; Queue_put (device->fromdevice, (Queue_Elem *)srcFrame); //GJ: PAF_SIO_REQUEST_AUTO, Not Supported, yet. if (srcFrame->arg == PAF_SIO_REQUEST_AUTO) { #if 0 // if not yet running, prime input buffer if (pDevExt->syncState == SYNC_NONE) { status = DIB_FTABLE_reset (device, pBufConfig); if (status) return status; pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; status = DIB_FTABLE_issueChild (device, &pDevExt->bufConfig, pDevExt->autoRequestSize, 0); if (status) return status; // * also reset pDevExt->zeroCount, as in DIB_getSync()? // just for PAF_SOURCE_PCMAUTO? * pDevExt->pcmTimeout = pDevExt->sourceSelect == PAF_SOURCE_PCMAUTO ? 0 : 2 * pBufConfig->pBufStatus->unknownTimeout; pDevExt->syncState = SYNC_AUTO; // allows PCM decoder to be used to generate zero-valued audio frames while scanning pBufConfig->deliverZeros = 1; } // no action if already sync'ed else if (pDevExt->syncState != SYNC_AUTO) return 0; status = DIB_FTABLE_issueChild (device, &pDevExt->bufConfig, pDevExt->autoRequestSize, 0); if (status) return status; #endif } else if (srcFrame->arg == PAF_SIO_REQUEST_NEWFRAME) { // do nothing if not synced since syncing done in reclaim // This is executed in force modes from the first call to PAF_AST_decodeInit // which calls SIO2_issue for NEWFRAME before all other calls. if (pDevExt->syncState == SYNC_NONE) return 0; status = DIB_FTABLE_requestFrame (device, &pDevExt->bufConfig); if (status) return status; } return 0; } // DIB_issue // ----------------------------------------------------------------------------- // Although interface allows for arbitrary BufConfigs we only support 1 -- so // we can assume the one on the fromdevice is the one we want extern int gIsrInputCnt; // GJ Debug extern int gIsrOutputCnt; // GJ Debug Int DIB_reclaim (DEV2_Handle device) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *) device->object; DEV2_Frame *dstFrame; Int status = 0; PAF_InpBufConfig *pBufConfig; dstFrame = (DEV2_Frame *) Queue_head (device->fromdevice); if (dstFrame == (DEV2_Frame *) device->fromdevice) return DIBERR_UNSPECIFIED; if (!dstFrame->addr) return DIBERR_UNSPECIFIED; // if deferred error from last request frame then return now status = pDevExt->deferredError; if (status) { pDevExt->deferredError = 0; pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; return status; } pBufConfig = (Ptr) dstFrame->addr; dstFrame->size = sizeof (PAF_InpBufConfig); // ......................................................................... if (dstFrame->arg == PAF_SIO_REQUEST_AUTO) { //GJ: PAF_SIO_REQUEST_AUTO - not supported, yet. #if 0 Log_info0("DIB: At case = PAF_SIO_REQUEST_AUTO"); // GJ Debug // verify set up by prior DIB_issue() // no action if already sync'ed if (pDevExt->syncState == SYNC_NONE) return DIBERR_AUTO; else if (pDevExt->syncState != SYNC_AUTO) return 0; // get next block of data to scan status = DIB_FTABLE_waitForData (device, &pDevExt->bufConfig, pDevExt->autoRequestSize); if (status) return status; if (pDevExt->sourceSelect == PAF_SOURCE_NONE) { IncrementPtr (pBufConfig, &pDevExt->bufConfig.pntr.pVoid, pDevExt->autoRequestSize); return 0; } // this function updates the tail pointer; it WON'T reset to SYNC_NONE status = DIB_FTABLE_syncScan (device, &pDevExt->bufConfig, &pDevExt->pcmTimeout); if (status) return status; // if not yet sync'ed ... if (pDevExt->syncState == SYNC_AUTO) { // if timeout, harness tail of DIB_getSync() if (!pDevExt->pcmTimeout) { // checks pDevExt->zeroCount, runs DIB_reset(), // updates pBufConfig->deliverZeros/sizeofElement/sizeofBuffer, // sets pDevExt->sourceProgram = PAF_SOURCE_PCM/DSD? // and pDevExt->syncState = SYNC_PCM[_FORCED] status = DIB_FTABLE_getSync (device, &pDevExt->bufConfig); if (status) return status; } } // if sync'ed to bitstream, this requests add'l input; // if PCM, this "kickstarts" the input, // using settings per above call to DIB_getSync() if (pDevExt->syncState != SYNC_AUTO) { status = DIB_FTABLE_initFrame (device, &pDevExt->bufConfig); if (status) return status; // this situation may occur for various IEC types, // w/ no matching PAF_SOURCE_ type is defined // (see iecPafSource[] table for the latter mapping) // most like cases are null & pause packets if (pDevExt->sourceProgram == PAF_SOURCE_UNKNOWN) return DIBERR_SYNC; // request timing frame status = DIB_FTABLE_requestFrame (device, &pDevExt->bufConfig); if (status) return status; } #endif } //dstFrame->arg == PAF_SIO_REQUEST_AUTO // ......................................................................... if ((pDevExt->syncState == SYNC_NONE) || (dstFrame->arg == PAF_SIO_REQUEST_SYNC)) { Log_info0("DIB: At case: syncState == SYNC_NONE (or PAF_SIO_REQUEST_SYNC)"); // GJ Debug // pass in external buffer config which used to initialize the internal view status = DIB_FTABLE_reset (device, pBufConfig); if (status) return status; status = DIB_FTABLE_getSync (device, &pDevExt->bufConfig); if (status) return status; // since getSync resets sourceProgram to unknown at entry // sourceProgram will remain unknown if no sync is returned // (i.e. no need to reset it here) if (pDevExt->syncState == SYNC_NONE) { Log_info0("Returning DIBERR_SYNC after DIB_FTABLE_getSync"); // GJ Debug return DIBERR_SYNC; } // get input info (frameLength/etc) status = DIB_FTABLE_initFrame (device, &pDevExt->bufConfig); if (status) { Log_info1("Returning %d after DIB_FTABLE_initFrame", status); // GJ Debug return status; } // request timing frame status = DIB_FTABLE_requestFrame (device, &pDevExt->bufConfig); if (status) { Log_info1("Returning %d after DIB_FTABLE_requestFrame", status); // GJ Debug return status; } // update external view of bufConfig. In particular for slave force PCM // this insures that the first decode will be processed with deliverZeros = 1 // which is necessary since the first decode of slave input occurs before the // first slave input frame is actually captured. *pBufConfig = pDevExt->bufConfig; } //((pDevExt->syncState == SYNC_NONE) || (dstFrame->arg == PAF_SIO_REQUEST_SYNC)) // ......................................................................... if (dstFrame->arg == PAF_SIO_REQUEST_NEWFRAME) { Log_info0("DIB: At case = PAF_SIO_REQUEST_NEWFRAME"); // GJ Debug // wait for enough data to check for sync at expected location status = DIB_FTABLE_waitForData (device, &pDevExt->bufConfig, pDevExt->bufConfig.frameLength); if (status) { Log_info2("DIB_reclaim.%d DIB_FTABLE_waitForData returned %d", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d DIB_FTABLE_waitForData returned %d\n", __LINE__, status)); return status; } // if PCM, but not forced PCM, then scan for bitstream sync // note that we we using the local view of bufConfig here and we update the // public view afterwards. if (pDevExt->syncState == SYNC_PCM) { float sampleRate = PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD]; PAF_InpBufConfig *pBufConfig = &pDevExt->bufConfig; Int ibMode = pBufConfig->pBufStatus->mode; // read mode register once // normally no scanning done if sampleRate > 48kHz since bitstream input is highly unlikley. if ((sampleRate <= SCANATSAMPLERATELIMIT) || pBufConfig->pBufStatus->scanAtHighSampleRateMode) { if (!pBufConfig->deliverZeros) { pDevExt->pcmTimeout = pBufConfig->lengthofData; // check zeroRunTrigger if needed if (ibMode != MODE_NO_ZERORUN) { if(pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunTrigger) { // set this flag one block late to allow for // transmission of all data in frame which contained zeroRunTrigger pBufConfig->deliverZeros = 1; pDevExt->pcmTimeout = 2 * pBufConfig->pBufStatus->unknownTimeout; } // > zeroRunTrigger } // !MODE_NO_ZERORUN } // !pBufConfig->deliverZeros // scan PCM data status = DIB_FTABLE_syncScan (device, pBufConfig, &pDevExt->pcmTimeout); if (status) { pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; Log_info2("DIB_reclaim.%d DIB_FTABLE_syncScan returned %d", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d DIB_FTABLE_syncScan returned %d\n", __LINE__, status)); return status; } // if scan found something other than PCM, then exit with error if (pDevExt->syncState != SYNC_PCM) { Log_info1("DIB_reclaim.%d error: syncState != SYNC_PCM", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d error: syncState != SYNC_PCM\n", __LINE__)); return DIBERR_SYNC; } // if heeding zeroRunRestart control then return to unknown if necessary if ((ibMode == MODE_DEFAULT) && (pDevExt->zeroCount >= 2*pBufConfig->pBufStatus->zeroRunRestart)) { // if zeroRunRestart me then reset input to unknown Log_info1("DIB_reclaim.%d error: zeroRunRestart, setting PAF_SOURCE_UNKNOWN", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d error: zeroRunRestart, setting PAF_SOURCE_UNKNOWN\n", __LINE__)); pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; return DIBERR_SYNC; } // since in skeptical state we disallow returning to PCM when end of timeout contains zeros // note that we need not check the mode here since above logic prevents deliverZeros state. if (pBufConfig->deliverZeros && (pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunTrigger)) { //TRACE((&TR_MOD, "DIB_reclaim.%d set pcmTimeout = unknown timeout\n", __LINE__)); pDevExt->pcmTimeout = 2 * pBufConfig->pBufStatus->unknownTimeout; } } //scanAtHighSampleRate } //SYNC_PCM // clear this flag immediately to play new audio ASAP // this check is OK for forced PCM since pcmTimeout and zeroCount are not // updated if (pDevExt->bufConfig.deliverZeros && !pDevExt->pcmTimeout && (pDevExt->zeroCount < 2 * pDevExt->bufConfig.pBufStatus->zeroRunTrigger)) { pDevExt->bufConfig.deliverZeros = 0; } // update external view of buffer with local view we do this with current // frame info before the following update to the local view for the next // frame to be captured. Need to subtract headerSize from lengthofData // since, at least for THD, it is needed by decoders. *pBufConfig = pDevExt->bufConfig; pBufConfig->lengthofData -= pDevExt->headerSize; Log_info4("DIB_reclaim.%d lengthofData = %d; InISRCNT=%d; OutISRCNT=%d", __LINE__, pBufConfig->lengthofData, gIsrInputCnt, gIsrInputCnt); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d lengthofData = %d\n", __LINE__, pBufConfig->lengthofData)); // HACK: for DSD the frameLength needs to be the number of samples to generate. if ((pDevExt->sourceSelect >= PAF_SOURCE_DSD1) && (pDevExt->sourceSelect <= PAF_SOURCE_DSD3)) pBufConfig->frameLength /= pBufConfig->stride; Log_info2("DIB_reclaim.%d frameLength = %d", __LINE__, pBufConfig->frameLength); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d frameLength = %d\n", __LINE__, pBufConfig->frameLength)); // set external view to point at synch position of the frame guaranteed // to be captured by above waitForData. Need to condition this against PCM since // in that case pSync could point anywhere in the buffer to to syncScan. E.g. // if there was a partial sync then pSync would point at that rather than // at the beginning of the buffer. // TODO: change syncScan to only update pDevExt->pSync when there is an actual sync // so that we can use this for both PCM and bitstream if (pDevExt->syncState == SYNC_ONGOING) { pBufConfig->pntr = pDevExt->pSync; IncrementPtr (pBufConfig, &pBufConfig->pntr.pVoid, pDevExt->headerSize); } //SYNC_ONGOING // if a bitstream then need to update tail to bitstream sync location // and check for next sync at expected location // quick scan for sync. if decoding IEC but sync is missing then // defer error until the next frame so that we decode all frames // TODO: does this assume decoders have copied the entire input frame // i.e. it is ok to adjust the input buffer pointers. // if successful then this sets // pSync = address of PA (for IEC) status = DIB_FTABLE_initFrame (device, &pDevExt->bufConfig); if (status) { if (pBufConfig->pBufStatus->lastFrameMask & (1 << pDevExt->sourceProgram)) { pDevExt->deferredError = status; Log_info1("DIB_reclaim.%d last frame\n", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d last frame\n", __LINE__)); pBufConfig->pBufStatus->lastFrameFlag = 1; return 0; } else { Log_info1("DIB_reclaim.%d setting PAF_SOURCE_UNKNOWN", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d setting PAF_SOURCE_UNKNOWN\n", __LINE__)); pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; return status; } } } //(dstFrame->arg == PAF_SIO_REQUEST_NEWFRAME) // ......................................................................... Log_info4("DIB_reclaim.%d exit status = %d, InISRCNT = %d OutISRCNT = %d", __LINE__, status, gIsrInputCnt, gIsrOutputCnt); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaim.%d exit status = %d\n", __LINE__, status)); return status; } // DIB_reclaim // ----------------------------------------------------------------------------- Int DIB_ctrl (DEV2_Handle device, Uns code, Arg arg) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; Int status = 0; switch (code) { case PAF_SIO_CONTROL_GET_CHILD_DEVICE: *((Arg *)arg) = (Arg) pChild; break; //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, case PAF_SIO_CONTROL_SET_DECSTATUSADDR: pDevExt->pDecodeStatus = (PAF_DecodeStatus *) arg; break; case PAF_SIO_CONTROL_SET_PCMFRAMELENGTH: pDevExt->pcmFrameLength = (XDAS_Int32) arg; break; case PAF_SIO_CONTROL_SET_SOURCESELECT: pDevExt->sourceSelect = (XDAS_Int8) arg; break; case PAF_SIO_CONTROL_SET_AUTOREQUESTSIZE: pDevExt->autoRequestSize = (XDAS_Int16) arg; break; case PAF_SIO_CONTROL_GET_SOURCEPROGRAM: if (!arg) return DIBERR_UNSPECIFIED; *((XDAS_Int8 *) arg) = pDevExt->sourceProgram; break; case PAF_SIO_CONTROL_SET_IALGADDR: pDevExt->pSioIalg = (PAF_SIO_IALG_Obj *) arg; break; //,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, case PAF_SIO_CONTROL_OPEN: pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; pDevExt->zeroCount = 0; if (pDevExt->pInpBufStatus) pDevExt->pInpBufStatus->zeroRun = 0; status = DEV2_ctrl (pChild, code, arg); break; case PAF_SIO_CONTROL_CLOSE: if (pDevExt->pInpBufStatus) pDevExt->pInpBufStatus->zeroRun = 0; status = DEV2_ctrl (pChild, code, arg); break; // return number of DMA events vs. request size // only update if not in error state (i.e. status = 0) case PAF_SIO_CONTROL_GET_NUM_EVENTS: if (!arg) return DIBERR_UNSPECIFIED; status = DEV2_ctrl (pChild, code, arg); if (!status) *((Int *)arg) -= pDevExt->pcmFrameLength; break; // return net samples until next DIB_waitForData() should succeed w/o blocking case PAF_SIO_CONTROL_GET_NUM_REMAINING: if (!arg) return DIBERR_UNSPECIFIED; status = DEV2_ctrl (pChild, code, arg); *((Int *)arg) -= pDevExt->numSamplesExtra; break; default: status = DEV2_ctrl (pChild, code, arg); break; } return status; } // DIB_ctrl // ----------------------------------------------------------------------------- Int DIB_idle (DEV2_Handle device, Bool flush) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; Int status; while (!Queue_empty (device->todevice)) Queue_enqueue (device->fromdevice, Queue_dequeue (device->todevice)); while (!Queue_empty (device->fromdevice)) Queue_enqueue (Queue_handle(&((SIO2_Handle) device)->framelist), Queue_dequeue (device->fromdevice)); status = DIB_FTABLE_reset (device, NULL); if (status) return status; return 0; } // DIB_idle // ----------------------------------------------------------------------------- Int DIB_open (DEV2_Handle device, String name) { DIB_DeviceExtension *pDevExt; DEV2_Handle pChild; DEV2_Device *entry; DEV2_Frame *frame; Int status, i; Error_Block eb; Error_init(&eb); name = DEV2_match (name, &entry); if (entry == NULL) { Log_info1("DEV2_match failed in DIB_open:", SIO2_ENODEV); return SIO2_ENODEV; } // only one frame interface supported if (device->nbufs != 1) return SYS_EALLOC; if (!(pDevExt = Memory_alloc (device->bufSeg, sizeof(DIB_DeviceExtension), 0, &eb))) { Log_info1("DIB Memory alloc failed in DIB_open:", SYS_EALLOC); return SYS_EALLOC; } pDevExt->pcmFrameLength = 0; pDevExt->sourceSelect = PAF_SOURCE_NONE; pDevExt->autoRequestSize = DEFAULT_AUTOREQUESTSIZE; pDevExt->pInpBufStatus = NULL; pDevExt->pDecodeStatus = NULL; device->object = (Ptr)pDevExt; pChild = (DEV2_Handle)&pDevExt->child; pChild->fromdevice = Queue_create (NULL, &eb); pChild->todevice = Queue_create (NULL, &eb); if (pChild->fromdevice == NULL || pChild->todevice == NULL) { Log_info1 ("DIB Queue_create failed in DIB_open:", SYS_EALLOC); return SYS_EALLOC; } pChild->bufsize = 0; pChild->nbufs = NUM_CHILD_BUFFERS; pChild->bufSeg = device->bufSeg; pChild->mode = device->mode; pChild->timeout = device->timeout; pChild->align = device->align; pChild->devid = entry->devid; pChild->params = entry->params; pChild->fxns = *(DEV2_Fxns *)(entry->fxns); ((SIO2_Handle)pChild)->model = ((SIO2_Handle)device)->model; //Create frames and put them on the correct device queue. // We only support ISSUERECLAIM mode so size = 0 Queue_construct(&((SIO2_Handle)pChild)->framelist, NULL); //Queue_new (&((SIO2_Handle)pChild)->framelist); for (i=0; i < pChild->nbufs; i++) { frame = DEV2_mkframe (0, 0, 0); if (!frame) return SYS_EALLOC; Queue_put (Queue_handle(&((SIO2_Handle)pChild)->framelist), (Queue_Elem *) frame); } // open underlying device status = DEV2_open (pChild, name); if (status) return status; // use dev match to fetch function table pointer for DIB name = DEV2_match ("/DIB", &entry); if (entry == NULL) { Log_info1 ("DEV2_match for DIB in DIB_open:", SIO2_ENODEV); return SIO2_ENODEV; } pDevExt->pFxns = (DIB_Fxns *) entry->fxns; // set IEC frame length table pointer -- change in // subsequent control call (not defined) to add new IEC type pDevExt->pIECFrameLength = (XDAS_UInt16 *) iecFrameLength; status = DIB_FTABLE_reset (device,NULL); if (status) return status; return status; } // DIB_open // ----------------------------------------------------------------------------- // Although this is void it is still needed since BIOS calls all DEV inits on // startup. Void DIB_init (Void) { } // DIB_init // ----------------------------------------------------------------------------- // Notes: // 1. DIB_reset is called prior to this function being called.(see DIB_reclaim) // 2. (1) ==> sizeofBuffer is an integral # of 2byte samples. // 3. (2) ==> if we use a request size which is divisor of sizeofBuffer there // will be no wrap-around when requesting data for scanning. // 4. (3) ==> we meet the interface requirement for syncScan which has no // circular arithmetic. Int DIB_getSync (DEV2_Handle device, PAF_InpBufConfig *pBufConfig ) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; int status; Uns timeout, syncBufSize, syncRequestSize; Int ibMode = pBufConfig->pBufStatus->mode; // read mode register once Int deliverZeros; //.......................................................................... // implement local timeout so that we don't get 'stuck' here when input // is all zeros + lock if (pDevExt->syncState == SYNC_NONE) { Uns localTimeout; // latch value before resetting to PAF_SOURCE_UNKNOWN Int sourceProgram = pDevExt->sourceProgram; pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; // if here then guaranteed to have fresh reset if (pDevExt->sourceSelect == PAF_SOURCE_PCM || pDevExt->sourceSelect == PAF_SOURCE_DSD1 || pDevExt->sourceSelect == PAF_SOURCE_DSD2 || pDevExt->sourceSelect == PAF_SOURCE_DSD3) { timeout = 0; // no zero run counting in force modes since no scanning pBufConfig->pBufStatus->zeroRun = 0; pDevExt->zeroCount = 0; } else if ((pDevExt->sourceSelect == PAF_SOURCE_PCMAUTO) && ((sourceProgram == PAF_SOURCE_UNKNOWN) || (sourceProgram == PAF_SOURCE_PCM))) { // if sourceselect is PCMAUTO then // if current input is a bistream then scan for normal timeout period // if current input is unknown or PCM then transition immediately to PCM // this provides for *no* lossed PCM, detection of bitstreams, but some noise // is possible. timeout = 0; pDevExt->zeroCount = 0; } else timeout = 2*pBufConfig->pBufStatus->unknownTimeout; // force request size to be a divisor of sizeofBuffer syncRequestSize = NOMINAL_XFERSIZE; if (pBufConfig->stride > 2) syncRequestSize *= pBufConfig->stride; syncBufSize = pBufConfig->sizeofBuffer / ((int) (pBufConfig->sizeofBuffer/syncRequestSize)); if (timeout) { status = DIB_FTABLE_issueChild (device, pBufConfig, syncBufSize, 0); if (status) return status; } localTimeout = timeout; while ((timeout) && (pDevExt->syncState != SYNC_ONE)) { status = DIB_FTABLE_issueChild (device, pBufConfig, syncBufSize, 0); if (status) return status; #if 0 // (***) FL: shows timing of Input Rx SIO reclaim during autodet // (***) debug // B5 { static Uint8 toggleState = 0; if (toggleState == 0) GPIOSetOutput(GPIO_PORT_0, GPIO_PIN_99); else GPIOClearOutput(GPIO_PORT_0, GPIO_PIN_99); toggleState = ~(toggleState); } #endif // get next block of data to scan status = DIB_FTABLE_waitForData (device, pBufConfig, syncBufSize); if (status) return status; // this function updates the tail pointer status = DIB_FTABLE_syncScan (device, pBufConfig, &timeout); if (status) return status; // if input is zero, i.e. haven't decremented at all, // then break out and use more logic and if (localTimeout < syncBufSize) { // Should this be 2 *? MAW if (timeout == 2*pBufConfig->pBufStatus->unknownTimeout) break; } else { Log_info3("DIB: Inside DIB_getSync with syncState != SYNC_ONE. localTimeout = %d, syncBufSize = %d, timeout = %d", localTimeout,syncBufSize, timeout); // GJ Debug localTimeout -= syncBufSize; } } // if found sync then return to caller who will call // initFrame to get bitstream info and requestFrame for data if (pDevExt->syncState != SYNC_NONE) return 0; } //pDevExt->syncState == SYNC_NONE //.......................................................................... // set default to zero -- we assume decode calls will not be made // before data is available since this must be master input. Will be changed below // as needed deliverZeros = 0; if (pDevExt->syncState == SYNC_AUTO) { timeout = pDevExt->pcmTimeout; deliverZeros = 1; } // if in zero run, and heeding full zeroRun control, then return to unknown if # zeros > trigger/Restart if (ibMode == MODE_DEFAULT) { if ((pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunTrigger) || (pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunRestart)) return DIBERR_SYNC; // since we may have exited prematurely above we check timeout if (timeout) return DIBERR_SYNC; } // if heeding trigger but not restart then enter deliverZeros state of PCM else if (ibMode == MODE_NO_ZERORUNRESTART) { if (pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunTrigger) deliverZeros = 1; } // here if timeout to PCM (includes force PCM) status = DIB_FTABLE_reset (device, pBufConfig); if (status) return status; // hack -- try 32bit then 16bit if necessary pBufConfig->sizeofElement = 4; status = SIO2_ctrl (pChild,(Uns)PAF_SIO_CONTROL_SET_WORDSIZE,pBufConfig->sizeofElement); if(status) { pBufConfig->sizeofElement = 2; status = SIO2_ctrl (pChild, (Uns)PAF_SIO_CONTROL_SET_WORDSIZE,pBufConfig->sizeofElement); if(status) return status; } // Force sizeofBuffer to be integral number of frame sizes. This ensures that the // pcm buffers will not need a circular wrap-around. We prevent this because // syncScan makes this assumption in order to perform an efficient scan. { int sizeofStride = pBufConfig->sizeofElement*pBufConfig->stride*pDevExt->pcmFrameLength; pBufConfig->sizeofBuffer = (pBufConfig->allocation)/sizeofStride*sizeofStride; } if (pDevExt->sourceSelect == PAF_SOURCE_DSD1 || pDevExt->sourceSelect == PAF_SOURCE_DSD2 || pDevExt->sourceSelect == PAF_SOURCE_DSD3) pDevExt->sourceProgram = pDevExt->sourceSelect; else pDevExt->sourceProgram = PAF_SOURCE_PCM; if (pDevExt->sourceSelect == PAF_SOURCE_PCM || pDevExt->sourceSelect == PAF_SOURCE_DSD1 || pDevExt->sourceSelect == PAF_SOURCE_DSD2 || pDevExt->sourceSelect == PAF_SOURCE_DSD3) { pDevExt->syncState = SYNC_PCM_FORCED; // set to one -- ensures that PCM decode calls made before data is // available will result in zero output. // (mostly needed for PA15 since, currently, all other frameworks // require a frame of data before the first decode call. deliverZeros = 1; } else pDevExt->syncState = SYNC_PCM; // update config struct pBufConfig->deliverZeros = deliverZeros; //.......................................................................... return 0; } // DIB_getSync // ----------------------------------------------------------------------------- int gWrapCtr=0; Int DIB_issueChild (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, int size, int forTotal) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *) device->object; DEV2_Handle pChild = (DEV2_Handle) &pDevExt->child; int bufEnd = (int) pBufConfig->base.pVoid + pBufConfig->sizeofBuffer; DEV2_Frame *dstFrame; int futureHead, status; int i, sizes[2]; Ptr endAddr[2]; // if seeking for total amount then adjust for difference if (forTotal) size -= GetFutureAvail (pBufConfig); // return success if we needn't make any requests if (size <= 0) return 0; // assume if eight channel then using optimized dMAX routine which requires // requests which are a mulitple of 8 to operate correctly. If not a proper // multiple then we increase the requested size as needed. This information // is communicated to other portions of DIB indirectly through the update // of the futureHead pointer (here) and head pointer (in reclaim). To these // other portions it is a don't care as we ensure enough data requested will // be available at, the now slightly deferred, reclaim point. We assume that // the buffer is a multiple of 8 and so, by using this single statement, we // ensure all requests are a mulitple 8 even if they need to be split across // the buffer wrap point. if (pBufConfig->stride == 8) size = (size + 7) & ~0x7; // convert to bytes size *= pBufConfig->sizeofElement; //size *= 4; // if request crosses circular buffer boundary then split into two requests futureHead = (int) pBufConfig->futureHead.pVoid + size; if (futureHead <= bufEnd) { sizes[0] = size; sizes[1] = 0; // If this request happens to be the rest of the buffer, then // futureHead must be set to the beginning of the buffer. if (futureHead != bufEnd) endAddr[0] = (Ptr) futureHead; else endAddr[0] = pBufConfig->base.pVoid; } else { sizes[0] = bufEnd - (int) pBufConfig->futureHead.pVoid; sizes[1] = futureHead - bufEnd; endAddr[0] = pBufConfig->base.pVoid; endAddr[1] = (Ptr) ((int)pBufConfig->base.pVoid + sizes[1]); } for (i=0; i < 2; i++) { if (sizes[i]) { dstFrame = Queue_get (Queue_handle(&((SIO2_Handle) pChild)->framelist)); if (dstFrame == (DEV2_Frame *)&((SIO2_Handle) pChild)->framelist) return DIBERR_UNSPECIFIED; dstFrame->arg = (Arg) pBufConfig; dstFrame->addr = pBufConfig->futureHead.pVoid; dstFrame->size = sizes[i]; Queue_put (pChild->todevice, (Queue_Elem *)dstFrame); status = DEV2_issue (pChild); if (status) return DIBERR_UNSPECIFIED; pBufConfig->futureHead.pVoid = endAddr[i]; // GJ Debug if (i==1) { gWrapCtr++; Log_info4("DIB: Inside DIB_issueChild Wrap Around Point #%d, with Future Head: 0x%x, current addr: 0x%x, current size: %d", gWrapCtr, pBufConfig->futureHead.pVoid, dstFrame->addr, dstFrame->size ); // GJ Debug } } } return 0; } // DIB_issueChild // ----------------------------------------------------------------------------- Int DIB_reclaimChild (DEV2_Handle device, PAF_InpBufConfig *pBufConfig) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; DEV2_Frame *srcFrame; int status, bufEnd; //Log_info3("DIB_reclaimChild.%d: Inside DEV2_reclaim(pChild) pChild = 0x%x DEV2_reclaim = 0x%x", __LINE__, pChild, &pChild->fxns.reclaim); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d: calling DEV2_reclaim(pChild) pChild = 0x%x DEV2_reclaim = 0x%x", __LINE__, pChild, &pChild->fxns.reclaim)); status = DEV2_reclaim (pChild); if (status) { Log_info2("DIB_reclaimChild.%d DEV2_reclaim() returned (%d) DIBERR_UNSPECIFIED", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d DEV2_reclaim() returned (%d) DIBERR_UNSPECIFIED \n", __LINE__, status)); return DIBERR_UNSPECIFIED; } //Log_info1("DIB_reclaimChild.%d calling Queue_get()", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d calling Queue_get()\n", __LINE__)); srcFrame = Queue_get (pChild->fromdevice); //Log_info2("DIB_reclaimChild.%d calling Queue_put(), srcFrame = 0x%x", __LINE__, srcFrame); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d calling Queue_put(), srcFrame = 0x%x\n", __LINE__, srcFrame)); Queue_put (Queue_handle(&((SIO2_Handle) pChild)->framelist), (Queue_Elem *)srcFrame); // Only for non-fill requests do we update ptrs if (srcFrame->addr != NULL) { //Log_info2("DIB_reclaimChild.%d update pointers with srcFrame->size = %d", __LINE__, srcFrame->size); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d update pointers\n", __LINE__)); pBufConfig->head.pVoid = (Ptr) ((int)srcFrame->addr + srcFrame->size); // wrap, if necessary bufEnd = (int) pBufConfig->base.pVoid + pBufConfig->sizeofBuffer; if( (int) pBufConfig->head.pVoid >= bufEnd ) { Log_info1("DIB_reclaimChild.%d wrap pointer", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d wrap pointer\n", __LINE__)); pBufConfig->head.pVoid = (Ptr) ((int) pBufConfig->base.pVoid + (int) pBufConfig->head.pVoid - bufEnd); } } Log_info2("DIB_reclaimChild.%d exit with status = %d", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_reclaimChild.%d exit with status = %d\n", __LINE__, status)); return status; } // DIB_reclaimChild // ----------------------------------------------------------------------------- // This function uses the local definition of frameLength and lengthofData in // pDevExt to request the next frame of data. Int DIB_requestFrame (DEV2_Handle device, PAF_InpBufConfig *pBufConfig) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; int status = 0; // if in steady state then update tail pointer to indicate we are done, i.e. no // longer own, the last frame of data. if (pDevExt->running > 1) IncrementPtr (pBufConfig, &pBufConfig->pntr.pVoid, pBufConfig->lengthofData); switch (pDevExt->syncState) { case SYNC_PCM: case SYNC_PCM_FORCED: if (pDevExt->sourceSelect == PAF_SOURCE_DSD1) pDevExt->frameLength = 256; else if (pDevExt->sourceSelect == PAF_SOURCE_DSD2) pDevExt->frameLength = 128; else if (pDevExt->sourceSelect == PAF_SOURCE_DSD3) pDevExt->frameLength = 64; else pDevExt->frameLength = pDevExt->pcmFrameLength; pDevExt->lengthofData = pBufConfig->stride*pDevExt->frameLength; pDevExt->frameLength = pDevExt->lengthofData; // note that the following issueChild // doesn't *fetch* the data which will next be consumed, // but rather *replenishes* what's about to be consumed status = DIB_FTABLE_issueChild (device, pBufConfig, pDevExt->lengthofData, 0); break; case SYNC_ONE: // for the first issue we need to set the tail pointer to the bitstream sync pBufConfig->pntr = pDevExt->pSync; IncrementPtr (pBufConfig, &pBufConfig->pntr.pVoid, pDevExt->headerSize); status = DIB_FTABLE_issueChild (device, pBufConfig, pDevExt->frameLength, 1); // HD codecs need extra time due to several factors // time between first info call and starting output is non-negligible // peak decoder MIPs // reset time for decoders/ASPs if ((pDevExt->sourceProgram == PAF_SOURCE_DDP) || (pDevExt->sourceProgram == PAF_SOURCE_DTSHD) || (pDevExt->sourceProgram == PAF_SOURCE_THD) || (pDevExt->sourceProgram == PAF_SOURCE_DXP)) status = DIB_FTABLE_issueChild (device, pBufConfig, pDevExt->lengthofData, 0); pDevExt->syncState = SYNC_ONGOING; break; case SYNC_ONGOING: status = DIB_FTABLE_issueChild (device, pBufConfig, pDevExt->lengthofData, 0); break; } //switch // update bufConfig with info for use in next reclaim call // the interface to DIB is based on a single frame. So the amount // of data requested in this issue is assumed to be what is wanted in the next // reclaim. pBufConfig->frameLength = pDevExt->frameLength; pBufConfig->lengthofData = pDevExt->lengthofData; // enable to inspect input buffer. // if (pDevExt->lengthofData > 512) // asm( " SWBP 0" ); // breakpoint if (pDevExt->running < 3) pDevExt->running++; // Goal is to align timing so synchronized with forthcoming // "DIB_waitForData (... pDevExt->lengthofData);" // in DIB_reclaim(), servicing PAF_SIO_REQUEST_NEWFRAME, for PAF_SOURCE_PCM/DSD?. // ** need to revise above DSD handling so it works w/ this calc. ** { int futureAvail = GetFutureAvail (pBufConfig); // GetFutureAvail() returns 0 if full buffer requested or if no requests outstanding // -- 0 (empty) can't be right interpretation here, on account of foregoing issueChild() if( ! futureAvail) futureAvail = pBufConfig->sizeofBuffer / pBufConfig->sizeofElement; // total words in buffer pDevExt->numSamplesExtra = (XDAS_Int16) (futureAvail - pDevExt->frameLength); } return status; } // DIB_requestFrame // ----------------------------------------------------------------------------- Int DIB_reset (DEV2_Handle device, PAF_InpBufConfig *pBufConfig) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; int status, numChan; //?? Do we need a shutdown to handle queue problems? // or are there no problems since we use one frame status = DEV2_idle (pChild, 1); if(status) return status; if (pBufConfig) { int sizeofStride; pBufConfig->pntr = pBufConfig->base; pBufConfig->head = pBufConfig->base; pBufConfig->futureHead = pBufConfig->base; pBufConfig->lengthofData = 0; //devices must? support 2byte words pBufConfig->sizeofElement = 2; status = SIO2_ctrl (pChild, (Uns)PAF_SIO_CONTROL_SET_WORDSIZE,pBufConfig->sizeofElement); if(status) return status; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan); if(status) return status; pBufConfig->stride = numChan; // compute and use *effective buffer size* sizeofStride = pBufConfig->sizeofElement*pBufConfig->stride; pBufConfig->sizeofBuffer = (pBufConfig->allocation)/sizeofStride*sizeofStride; //GJ: Debug - Account for EDMA padding //hack -- save status context for use in close pDevExt->pInpBufStatus = pBufConfig->pBufStatus; pBufConfig->pBufStatus->lastFrameFlag = 0; pDevExt->bufConfig = *pBufConfig; pDevExt->pSync = pBufConfig->base; } pDevExt->syncState = SYNC_NONE; pDevExt->scanState = SCANNED_NONE; pDevExt->pcmTimeout = 0; pDevExt->deferredError = 0; pDevExt->numSamplesSinceDTS = 0; pDevExt->numSamplesExtra = 0; pDevExt->headerSize = 0; pDevExt->running = 0; return 0; } // DIB_reset // ----------------------------------------------------------------------------- // Notes: // 1. The amount of data to be scanned will not result in a buffer wrap-around // 2. (1) is currently met from the two locations that call this function // a. DIB_getSync // b. DIB_reclaim (for PCM) // 3. We require that pTimeout != NULL since we dereference to make a const Int DIB_syncScan (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 *pTimeout) { DIB_DeviceExtension * restrict pDevExt = (DIB_DeviceExtension *)device->object; MdInt * restrict pTail, * restrict pShadowTail, * restrict pSync; MdInt *pLocalTail, pc; XDAS_Int8 scanState; XDAS_UInt32 zeroCount; int stride, numLeft, i, datId; int status, foundDTS = 0; Uns scanCount, pageSize; PAF_SIO_IALG_Obj *pObj = pDevExt->pSioIalg; PAF_SIO_IALG_Config *pAlgConfig = &pObj->config; const int timeoutChanged = (*pTimeout != 2 * pBufConfig->pBufStatus->unknownTimeout); MdInt DTSHDSubType; // ......................................................................... // works for both SYNC_NONE and SYNC_PCM numLeft = min (*pTimeout, GetNumAvail(pBufConfig)); pTail = pBufConfig->pntr.pMdInt; pShadowTail = pBufConfig->pntr.pMdInt; // if scratch buffer present then assume it is needed for paging pageSize = numLeft*pBufConfig->sizeofElement; Log_info3("DIB: Entered DIB_syncScan with pTail = 0x%x & numLeft = %d, timeout = %d", pTail, numLeft, *pTimeout); // GJ Debug if ((pAlgConfig->numRec > 1) && pAlgConfig->pMemRec[1].base && (pAlgConfig->pMemRec[1].size >= pageSize)) { pTail = pAlgConfig->pMemRec[1].base; datId = DAT_copy ((void *) pShadowTail, (void *) pTail, pageSize); DAT_wait (datId); } if (pBufConfig->sizeofElement == 4) { Log_info0("DIB: SyncScan - Inside pBufConfig->sizeofElement == 4"); // GJ Debug stride = 2; pTail += 1; // point at MSB pShadowTail += 1; } else stride = 1; // ......................................................................... // scan until out of available data or a sync found scanCount = 0; zeroCount = pDevExt->zeroCount; scanState = pDevExt->scanState; pSync = pDevExt->pSync.pMdInt; Log_info4("DIB: Entered DIB_syncScan with zeroCount = %d & scanState = %d, stride = %d, pSync = 0x%x", zeroCount, scanState, stride, pSync); // GJ Debug // scan until out of available data or a sync found for (i=0; i < numLeft; i++) { MdInt tail = pTail[i*stride]; // assumes SCANNED_NONE = 0 if (!scanState) { if (tail == IEC_PA) { // since above code handles ongoing sync we are // safe to check for extended sync here. i.e. // two zeros before PA. if (zeroCount >= 2) { scanState = SCANNED_IEC_PA; pSync = &pShadowTail[i*stride]; } } else if (tail == DTS14_SYNC_A) { scanState = SCANNED_DTS14_SYNC_A; pSync = &pShadowTail[i*stride]; } else if (tail == DTS16_SYNC_A) { scanState = SCANNED_DTS16_SYNC_A; pSync = &pShadowTail[i*stride]; } // limit count to prevent wrap around zeroCount = min (zeroCount+1,INT_MAX - 1); if (tail != 0x0000) zeroCount = 0; // don't start counting until we get the first non-zero // sample while UNKNOWN. Note we don't have to worry // about the other scanCount increments since these // only occur after the first non-zero sample. // // so don't count unless // . we are already started counting (in this call) || // . we started counting in an earlier scanForSync (timeout has changed) || // . the last sample was non-zero if (scanCount || (tail != 0x0000) || timeoutChanged) { //Log_info3("DIB: DIB_syncScan scanCount = %d tail = %d timeoutChanged = %d", scanCount, tail, timeoutChanged); // GJ Debug scanCount += 1; } continue; } // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, switch (scanState) { case SCANNED_DTS16_SYNC_A: if (tail == DTS16_SYNC_B) { scanState = SCANNED_DTS16_SYNC_B; scanCount += 1; } else scanState = SCANNED_NONE; break; // wait for header data to get payload size via // nblks/fsize case SCANNED_DTS16_SYNC_B: // use extended sync if ((short)(tail & 0xFC00) == DTS16_SYNC_C) { scanState = SCANNED_DTS16_SYNC_C; scanCount += 1; } else scanState = SCANNED_NONE; break; // ````````````````````````````````````````````````````````````````````````` // check for 2nd word of DTS-14 sync case SCANNED_DTS14_SYNC_A: if (tail == DTS14_SYNC_B) { scanState = SCANNED_DTS14_SYNC_B; scanCount += 1; } else scanState = SCANNED_NONE; break; // check for 3rd word of DTS-14 sync case SCANNED_DTS14_SYNC_B: // if here then looking for extended 38 bit sync if ((short)(tail & 0xFFF0) == DTS14_SYNC_C) { scanState = SCANNED_DTS14_SYNC_C; scanCount += 1; } else scanState = SCANNED_NONE; break; // wait for header data to get payload size via // nblks/fsize case SCANNED_DTS14_SYNC_C: scanState = SCANNED_DTS14_SYNC_D; scanCount += 1; break; // ````````````````````````````````````````````````````````````````````````` // if here then all of header is buffered case SCANNED_DTS16_SYNC_C: case SCANNED_DTS14_SYNC_D: // update sync to point at beginning of DTS header as syncScanDTS uses this info pDevExt->scanState = scanState; pDevExt->pSync.pMdInt = pSync; status = DIB_FTABLE_syncScanDTS (device, pBufConfig, pTimeout, (XDAS_UInt16 *) &pShadowTail[i*stride]); scanState = pDevExt->scanState; if (status) return status; foundDTS = 1; if (pDevExt->syncState == SYNC_ONE) goto syncScanExit; break; // ````````````````````````````````````````````````````````````````````````` // note that the round about detection of IEC only // happens for the first sync so the extra states are OK. case SCANNED_IEC_PA: if (tail == IEC_PB) { scanState = SCANNED_IEC_PB; scanCount += 1; Log_info0("DIB: SyncScan Inside case - SCANNED_IEC_PA - if path"); // GJ Debug } else { Log_info0("DIB: SyncScan Inside case - SCANNED_IEC_PA - else path"); // GJ Debug scanState = SCANNED_NONE; } break; case SCANNED_IEC_PB: // Update scanCount here since, at this point, we are confident that // this is a proper IEC stream. Regardless if we ignore it our not. // Therefore we want to properly signal that this data has been scanned. scanCount += 1; // check for IEC pause packets at this time and if required ignore them. // By construction we are guaranteed to have tail=PC at this time. if ((pBufConfig->pBufStatus->mode == MODE_NO_ZERORUNRESTART) || (pBufConfig->pBufStatus->mode == MODE_NO_ZERORUN)) { MdInt pc = tail & 0x1F; if ((pc == 0) || (pc == 3)) { scanState = SCANNED_NONE; break; } } scanState = SCANNED_IEC_PC; break; case SCANNED_IEC_PC: pLocalTail = pSync; IncrementPtr (pBufConfig, (Ptr *) &pLocalTail, 2); pc = *pLocalTail & 0x1F; pDevExt->headerSize = IEC_HEADER_SIZE; Log_info0("DIB: Sync Scan - Inside case: SCANNED_IEC_PC"); // GJ Debug // Handle DTSHD subtype (LBR) if (pc == 0x11) { pDevExt->headerSize +=6; DTSHDSubType = (*pLocalTail & 0x700)>>8; } // DDP or THD if (pc == 21 || pc ==22) { TRACE((&TR_MOD, "Dolby: useIECSubType is 0x%x.\n", pBufConfig->pBufStatus->useIECSubType)); if (pBufConfig->pBufStatus->useIECSubType == 1) { unsigned char IECSubType = *pLocalTail & 0x60; TRACE((&TR_MOD, "Dolby: IECSubType is 0x%x.\n", IECSubType)); if (IECSubType != 0) { pDevExt->sourceProgram = PAF_SOURCE_UNKNOWN; pDevExt->frameLength = 0; } } } // don't know how to support other types if (pc > 22) { Log_info1("DIB: Unknown IEC type 0x%x encountered.\n", pc); // GJ Debug return DIBERR_SYNC; } pDevExt->syncState = SYNC_ONE; pBufConfig->pntr.pMdInt = pSync; pDevExt->sourceProgram = iecPafSource[pc]; Log_info2("source is %d. pc is %d.", iecPafSource[pc], pc); // GJ Debug //TRACE((&TR_MOD, "source is %d. pc is %d.\n", iecPafSource[pc], pc)); if (pc == 0x11 && DTSHDSubType == 3 && (PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD] <=48000.0)) pDevExt->sourceProgram = PAF_SOURCE_DXP; // LBR is 23 pDevExt->frameLength = pDevExt->pIECFrameLength[pc]; pDevExt->lengthofData = pDevExt->frameLength; if (pc == 1) pDevExt->frameLength = 4288; else if (pc == 0x11) { pDevExt->frameLength = (pDevExt->pIECFrameLength[pc] << DTSHDSubType); pDevExt->lengthofData = pDevExt->frameLength; } goto syncScanExit; } // switch } // for // ............................................................................. syncScanExit: Log_info4("DIB inside syncScanExit. pTimeout = %d, scanCount = %d, zeroCount = %d, numLeft = %d", *pTimeout,scanCount, zeroCount, numLeft ); // GJ Debug pDevExt->zeroCount = zeroCount; pDevExt->scanState = scanState; pDevExt->pSync.pMdInt = pSync; if (pDevExt->zeroCount >= 2 * pBufConfig->pBufStatus->zeroRunTrigger) pBufConfig->pBufStatus->zeroRun = 1; else pBufConfig->pBufStatus->zeroRun = 0; // If detected an initial DTS sync in a previous buffer then add the // number of samples in this buffer to the tally. // TODO: should we add numLeft instead of lengthofData? if (!foundDTS && pDevExt->numSamplesSinceDTS) pDevExt->numSamplesSinceDTS += pBufConfig->lengthofData; if (*pTimeout > scanCount) *pTimeout -= scanCount; else { *pTimeout = 0; return 0; } // This flushes the current scanned buffer if a sync is not found // Note that this code is not executed when *pTimeout = 0. // TODO: should this be moved elsewhere. Like in requestFrame? // seems like this should be done in request frame for continuous modes // and in getSync for traditional modes. // What does it mean that this is not executed when we have timed out to PCM if (pDevExt->syncState == SYNC_NONE || pDevExt->syncState == SYNC_AUTO) { IncrementPtr (pBufConfig, (Ptr *) &pBufConfig->pntr.pMdInt, numLeft); return 0; } return 0; } // DIB_syncScan // ----------------------------------------------------------------------------- // Assumes scanState is SCANNED_DTS16_SYNC_C or SCANNED_DTS14_SYNC_D Int DIB_syncScanDTS (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 *pTimeout, XDAS_UInt16 *pHeaderEnd) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; Int sourceProgram = (pDevExt->scanState == SCANNED_DTS14_SYNC_D) ? PAF_SOURCE_DTS14 : PAF_SOURCE_DTS16; float sampleRate = PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD]; MdInt *pLocalTail, pc, pd; int nblks; // compute repetition rate as predicted by DTS header pLocalTail = pDevExt->pSync.pMdInt; IncrementPtr (pBufConfig, (Ptr *) &pLocalTail, 2); pc = *pLocalTail; if (pDevExt->scanState == SCANNED_DTS16_SYNC_C) nblks = (pc & 0x01FC) >> 2; else { IncrementPtr (pBufConfig, (Ptr *) &pLocalTail, 1); pd = *pLocalTail; nblks = (pc & 0x7) << 4; nblks |= (pd & 0x3C00) >> 10; } // if samplerate > 44.1k and DTS16 bit CD then report as DTS-DVD // this is a work around to the possibility that DTS-DVD is being // sent but, due to the variance in input recording, we may have // missed the IEC header. This is predicated on the enable register if (pBufConfig->pBufStatus->reportDTS16AsDTSForLargeSampleRate && (sampleRate > 44100) && (sourceProgram == PAF_SOURCE_DTS16)) sourceProgram = PAF_SOURCE_DTS; // point at LSB, if neceesary, so that space calculation is correct if (pBufConfig->sizeofElement == 4) pHeaderEnd -= 1; // If in PCM mode then require double sync, at an appropriate spacing, // in order to determine DTS validity. if (pDevExt->syncState == SYNC_PCM) { int diff; // If we have started counting, i.e. found a previous sync, // then compute sync spacing. if (pDevExt->numSamplesSinceDTS) { // determine distance since last sync // pHeaderEnd, which points at the end of the DTS header, is guaranteed // to be in the active buffer. Whereas the pointer to the beginning of the header (pSync) // may have occured in the previous buffer. diff = ((int) pHeaderEnd - (int) pBufConfig->pntr.pVoid); if (diff < 0) diff += pBufConfig->sizeofBuffer; diff /= pBufConfig->sizeofElement; diff += pDevExt->numSamplesSinceDTS; // if spacing incorrect then reset sample count to // force next conditional to be true. if (diff != (nblks+1)*32*2) pDevExt->numSamplesSinceDTS = 0; } // If this is the 1st sync detected or if this is the second sync // but the spacing between DTS syncs did not match that predicted by // NBLKS, then this is not DTS data. Therefore the previous DTS sync // word was not valid and so it is safe to reset the count based on // this secondary sync word. This latter sync may or may not be valid; // we don't know yet. In both cases init sync spacing count, reset // scan state, and continue. Note that there is a positive, albeit // quite small, probability of falsing in a pathological case where // the PCM data, interpreted as a DTS header and used to compute NBLKS, // actually matches the fake DTS syncs in the PCM file. if (!pDevExt->numSamplesSinceDTS) { diff = (int) pBufConfig->head.pVoid - (int) pHeaderEnd; if (diff <= 0) diff += pBufConfig->sizeofBuffer; diff /= pBufConfig->sizeofElement; pDevExt->numSamplesSinceDTS = diff; pDevExt->scanState = SCANNED_NONE; return 0; } } //SYNC_PCM pDevExt->lengthofData = (nblks+1)*32*2; if (pDevExt->scanState == SCANNED_DTS16_SYNC_C) pDevExt->frameLength = pDevExt->lengthofData + 4; else pDevExt->frameLength = pDevExt->lengthofData + 6; pDevExt->syncState = SYNC_ONE; pBufConfig->pntr = pDevExt->pSync; pDevExt->sourceProgram = sourceProgram; return 0; } //DIB_syncScanDTS // ----------------------------------------------------------------------------- // This function is responsible for verifying bitstream sync (if applicable) and // configuring the sizes of the next frame of data. Int DIB_initFrame (DEV2_Handle device, PAF_InpBufConfig *pBufConfig) { DIB_DeviceExtension * restrict pDevExt = (DIB_DeviceExtension *) device->object; MdInt * restrict pTail; MdInt pa, pb, pc; unsigned char DTSHDSubType; PAF_UnionPointer ac3SearchPtr; // MID 810 // TODO: is this needed anymore? can we combine above and this? // I don't think this is needed since pSync is guaranteed to be // valid under all cases where this function is called. if (!(pDevExt->scanState == SCANNED_DTS14_SYNC_D || pDevExt->scanState == SCANNED_DTS16_SYNC_C || pDevExt->scanState == SCANNED_IEC_PC )) return 0; // minimum possible distance from current IEC sync to next is 1856 words // capture this here before we update pSync following ac3SearchPtr = pDevExt->pSync; // for steady state compute expected sync location if (pDevExt->syncState == SYNC_ONGOING) IncrementPtr (pBufConfig, &pDevExt->pSync.pVoid, pBufConfig->lengthofData); pTail = pDevExt->pSync.pMdInt; pa = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); pb = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); pc = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); switch (pDevExt->scanState) { // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, case SCANNED_DTS14_SYNC_D: // check sync (extended sync checked above for 1st sync) if ((pa != DTS14_SYNC_A) || (pb != DTS14_SYNC_B) || ((pc & 0xFC00) != (DTS14_SYNC_C & 0xFC00))) return DIBERR_SYNC; break; // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, case SCANNED_DTS16_SYNC_C: // check sync (extended sync checked above for 1st sync) if ((pa != DTS16_SYNC_A) || (pb != DTS16_SYNC_B)) return DIBERR_SYNC; break; // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, case SCANNED_IEC_PC: // check for sync // special handling for AC3 variable bit rate (VBR) // start looking for sync at max payload sync location and // scan forward. Note that getSync() has waited for // sufficient data to arrive so that we can determine reliably // the presence or absence of a correct sync. if ((pa != IEC_PA) || (pb != IEC_PB)) { PAF_SIO_IALG_Obj *pObj = pDevExt->pSioIalg; PAF_SIO_IALG_Config *pAlgConfig = &pObj->config; int scan1, scan2, searchIdx, datId; const int bufEnd = (int) pBufConfig->base.pVoid + pBufConfig->sizeofBuffer; // only extend IEC search in the case of AC3 if (pDevExt->sourceProgram != PAF_SOURCE_AC3) return DIBERR_SYNC; // move search ptr to earliest possible location of next sync IncrementPtr (pBufConfig, &ac3SearchPtr.pVoid, 1856); // compute number of samples between earliest possible sync location // (ac3SearchPtr) and latest possible sync location (head) scan1 = (int) pBufConfig->head.pVoid - (int) ac3SearchPtr.pVoid; if (scan1 < 0) { // here if search will wrap around so split search into two // halves to accomodate circular buffer scan1 = bufEnd - (int) ac3SearchPtr.pVoid; scan2 = (int) pBufConfig->head.pVoid - (int) pBufConfig->base.pVoid; } else scan2 = 0; // page if necessary (assume so if second memRec present) if (pAlgConfig->numRec > 1) { // if invalid buffer or if page buffer not big enough for either split then error if (!pAlgConfig->pMemRec[1].base || (pAlgConfig->pMemRec[1].size < max(scan1,scan2))) return DIBERR_UNSPECIFIED; pTail = (MdInt *) pAlgConfig->pMemRec[1].base; datId = DAT_copy (ac3SearchPtr.pVoid, (void *) pTail, scan1); DAT_wait (datId); } else pTail = ac3SearchPtr.pMdInt; // convert to number of words scan1 /= pBufConfig->sizeofElement; // if non-zero must be IEC header, otherwise sync error // update pointer after check so that it remains // pointed at first non-zero word when breaking searchIdx = 0; while (scan1--) { if (*pTail != 0) { // force skip of any possible split scan since we found non-zero word scan2 = 0; break; } *pTail++; searchIdx++; } // perform second half of circular buffer search if necessary if (scan2) { // page if necessary, note no need to check valid buffer // or space since this is ensured in first scan if (pAlgConfig->numRec > 1) { pTail = (MdInt *) pAlgConfig->pMemRec[1].base; datId = DAT_copy (pBufConfig->base.pVoid, (void *) pTail, scan2); DAT_wait (datId); } else pTail = pBufConfig->base.pMdInt; // convert to number of words scan2 /= pBufConfig->sizeofElement; while (scan2--) { if (*pTail != 0) break; *pTail++; searchIdx++; } } // if using paging buffer then translate search pointer back into circular buffer if (pAlgConfig->numRec > 1) { pTail = ac3SearchPtr.pMdInt; IncrementPtr (pBufConfig, (Ptr *) &pTail, searchIdx); } // update sync in expection of success, if it is not a sync then no // harm since it will be ignored then reset pDevExt->pSync.pMdInt = pTail; // above search only scans for the first non-zero word. // here is common check to make sure that non-zero data is an IEC sync. pa = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); pb = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); pc = *pTail; IncrementPtr (pBufConfig, (Ptr *) &pTail, 1); if ((pa != IEC_PA) || (pb != IEC_PB)) return DIBERR_SYNC; } // compute possible DTSHD sub type before masking pc DTSHDSubType = (pc & 0x700) >> 8; // mask pc to get data type only pc = pc & 0x1F; // don't know how to support other types // this also ensures that the below array access is bounded if (pc > 22) return DIBERR_SYNC; // continuing frame must be same as current type otherwise // we return error to force reset of decode and input // classification state machines if (pDevExt->sourceProgram != iecPafSource[pc]) { if (DTSHDSubType == 3 && (PAF_ASP_sampleRateHzTable[pBufConfig->pBufStatus->sampleRateStatus][PAF_SAMPLERATEHZ_STD] <= 48000.0)) { if (pDevExt->sourceProgram != PAF_SOURCE_DXP) return DIBERR_SYNC; } else return DIBERR_SYNC; } break; // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, } //switch return 0; } // DIB_initFrame // ----------------------------------------------------------------------------- Int DIB_waitForData (DEV2_Handle device, PAF_InpBufConfig *pBufConfig, XDAS_UInt32 count ) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *) device->object; DEV2_Handle pChild = (DEV2_Handle) &pDevExt->child; Int status, lock; Log_info2("DIB_waitForData.%d count = %d", __LINE__, count); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d count = %d\n", __LINE__, count)); while (GetNumAvail(pBufConfig) < count) { PAF_SIO_InputStatus inputStatus; // query underlying device for lock status & check lock override register // dont wait without lock status = SIO2_ctrl (pChild, (Uns)PAF_SIO_CONTROL_GET_INPUT_STATUS, (Arg) &inputStatus); if (status) { Log_info2("DIB_waitForData.%d SIO2_ctrl() returned %d", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d SIO2_ctrl() returned %d\n", __LINE__, status)); return status; } lock = inputStatus.lock; #ifndef IGNORE_LOCK_OVERRIDE if ((pBufConfig->pBufStatus->lockOverride & (XDAS_Int8)0x80) == 0) { Log_info1("DIB_waitForData.%d lock = lockOverride\n", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d lock = lockOverride\n", __LINE__)); lock = pBufConfig->pBufStatus->lockOverride; } #endif if (!lock) { Log_info1("DIB_waitForData.%d no lock, return DIBERR_SYNC\n", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d no lock, return DIBERR_SYNC\n", __LINE__)); return DIBERR_SYNC; } // check that decoding still requested -- allows for status // register to be updated via IOS to cancel autoProcessing if (pDevExt->pDecodeStatus) { if (pDevExt->pDecodeStatus->sourceSelect == PAF_SOURCE_NONE) { Log_info1("DIB_waitForData.%d sourceSelect is NONE, return DIBERR_SYNC", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d sourceSelect is NONE, return DIBERR_SYNC\n", __LINE__)); return DIBERR_SYNC; } } Log_info1("DIB_waitForData.%d calling DIB_FTABLE_reclaimChild()", __LINE__); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d calling DIB_FTABLE_reclaimChild()\n", __LINE__)); status = DIB_FTABLE_reclaimChild (device, pBufConfig); if(status) { Log_info2("DIB_waitForData.%d DIB_FTABLE_reclaimChild() returned %d", __LINE__, status); // GJ Debug //TRACE((&TR_MOD, "DIB_waitForData.%d DIB_FTABLE_reclaimChild() returned %d\n", __LINE__, status)); return status; } } return 0; } // DIB_waitForData // ----------------------------------------------------------------------------- #ifdef IEC_ENCODE // FS9 only supports PCM input so return error if not PCM. Int DIB_requestFrame_957 (DEV2_Handle device, PAF_InpBufConfig *pBufConfig) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *) device->object; int i, head, tail, avail, status; if (pDevExt->sourceProgram != PAF_SOURCE_PCM) return DIBERR_SYNC; // if in steady state then update tail pointer to indicate we are done, i.e. no // longer own, the last frame of data. if (pDevExt->running > 1) IncrementPtr (pBufConfig, &pBufConfig->pntr.pVoid, pBufConfig->lengthofData); pDevExt->lengthofData = pBufConfig->stride*pDevExt->pcmFrameLength; pDevExt->frameLength = pDevExt->lengthofData; // note that due to MID 1037 it is required to check the return status after this call status = DIB_FTABLE_issueChild (device, pBufConfig, pDevExt->lengthofData, 0); if (status) return status; // add extra input delay to account for peak encoder mips for (i=0; i < 4; i++) { head = (int) pBufConfig->futureHead.pVoid; tail = (int) pBufConfig->pntr.pVoid; // compute how much data we have including outstanding requests if (head >= tail) avail = head - tail; else avail = head - tail + pBufConfig->sizeofBuffer; // convert to words avail /= pBufConfig->sizeofElement; if (avail < 4*pBufConfig->lengthofData) { status = DIB_FTABLE_issueChild (device, pBufConfig, pBufConfig->lengthofData, 0); if (status) return status; } } pBufConfig->frameLength = pDevExt->frameLength; pBufConfig->lengthofData = pDevExt->lengthofData; if (pDevExt->running < 3) pDevExt->running++; return 0; } // DIB_requestFrame_957 #endif /* IEC_ENCODE */ // ----------------------------------------------------------------------------- #ifdef DSD_OVER_SPDIF Int DIB_requestFrame_patch (DEV2_Handle device, PAF_InpBufConfig *pBufConfig ) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; int status; status = DIB_requestFrame (device, pBufConfig); // For testing DSD over SPDIF i.e. 1 pin vs actual over 6 pin pDevExt->numSamplesExtra += pDevExt->lengthofData; pDevExt->lengthofData *=6; pDevExt->numSamplesExtra -= pDevExt->lengthofData; return status; } // DIB_requestFrame Int DIB_getSync_patch (DEV2_Handle device, PAF_InpBufConfig *pBufConfig ) { DIB_DeviceExtension *pDevExt = (DIB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; int status; status=DIB_getSync (device, pBufConfig ); if(status) return status; pBufConfig->sizeofElement = 2; status = SIO2_ctrl (pChild,(Uns)PAF_SIO_CONTROL_SET_WORDSIZE,pBufConfig->sizeofElement); if (status) return status; // compute and use *effective buffer size* { int sizeofStride = pBufConfig->sizeofElement*pBufConfig->stride; pBufConfig->sizeofBuffer = pBufConfig->allocation/sizeofStride*sizeofStride; } //.......................................................................... return 0; } // DIB_getSync_patch #endif /* DSD_OVER_SPDIF */ // -----------------------------------------------------------------------------