]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blobdiff - pasdk/test_dsp/framework/audioStreamOutIo.c
PASDK-577:Add McASP LLD ch reset before McASP LLD ch delete
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / framework / audioStreamOutIo.c
index 336c2915d45c06a79a0779b86c0305bbb12198b7..9562fed315c93cb63067ceb924c3a1dca2053584 100644 (file)
@@ -58,12 +58,137 @@ All rights reserved.
 #define DEC_OUTNUMBUF_MAP(X) \
       pP->poutNumBufMap[z]->map[(X) >= pP->poutNumBufMap[z]->length ? 0 : (X)]
 
-#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
+//#define STRIDE_WORST_CASE 32  // 4-byte (32-bit) word, 2 slots, 4 serializers
 
 extern Ptr hMcaspTxChan;
 extern Int d10Initialized;
 
 
+// Select Output devices
+Int asopSelectDevices(
+    const PAF_SIO_Params *pOutCfg, 
+    PAF_AST_IoOut *pOut
+)
+{
+    mcaspLLDconfig *pReqLldCfg;
+    Ptr mcaspChanHandle;
+    Aud_STATUS status;
+
+    if ((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) 
+    {
+        return ASOP_IO_ERR_IO_UNINIT;
+    }
+
+    // Deactivate currently active Output device
+    if (pOut->hMcaspChan != NULL)
+    {
+        
+        // check McASP LLD control API
+        mcaspControlChan(pOut->hMcaspChan, MCASP_CHAN_RESET, NULL);
+        // Delete McASP LLD channel
+        status = mcaspDeleteChan(pOut->hMcaspChan);
+        if (status != Aud_EOK)
+        {
+            Log_info0("asopSelectDevices(): McASP channel deletion failed!\n");
+            return ASOP_IO_ERR_MCASP_CFG;
+        }
+        
+        pOut->hMcaspChan = NULL;            // reset active McASP LLD handle
+        pOut->pLldCfg->hMcaspChan = NULL;   // reset McASP LLD handle for active McASP LLD configuration
+        pOut->pLldCfg = NULL;               // reset pointer to active McASP LLD configuration
+    }
+
+    // Activate requested device
+    if (pOutCfg != NULL)
+    {
+        //
+        // Device other than OutNone selected
+        //
+        
+        pReqLldCfg = (mcaspLLDconfig *)pOutCfg->sio.pConfig;
+        if (pReqLldCfg->hMcaspChan == NULL) 
+        {
+            // Create McASP LLD channel
+            mcaspChanHandle = NULL;
+            status = mcasplldChanCreate(pReqLldCfg, &mcaspChanHandle);
+            if (status != Aud_EOK) {
+                Log_info0("asopSelectDevices(): McASP channel creation failed!\n");
+                return ASOP_IO_ERR_MCASP_CFG;
+            }
+
+            pReqLldCfg->hMcaspChan = mcaspChanHandle;   // set McASP LLD handle for requested McASP LLD configuration
+            pOut->pLldCfg = pReqLldCfg;                 // set pointer to active McASP LLD configuration
+            pOut->hMcaspChan = pReqLldCfg->hMcaspChan;  // set active McASP LLD handle
+            
+            // configure stride according to selected McASP LLD configuration
+            pOut->stride = pReqLldCfg->mcaspChanParams->noOfSerRequested * 
+                pReqLldCfg->mcaspChanParams->noOfChannels;
+        }
+    }
+    else
+    {
+        //
+        // OutNone device selected
+        //
+        
+        pOut->hMcaspChan = NULL;    // reset active McASP LLD handle
+        pOut->pLldCfg = NULL;       // reset pointer to active McASP LLD configuration
+    }
+
+    return ASOP_IO_SOK;
+}
+
+// Check if Output device SIO selection changed
+Int checkOutDevSioSelUpdate(
+    const PAF_ASOT_Params *pP, 
+    PAF_ASOT_Config *pAsotCfg,
+    Int z, 
+    Bool *pOutDevSelUpdate
+)
+{
+    PAF_AST_Config *pAstCfg;
+    
+    pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
+
+    if ((z < OUTPUT1) || (z >= OUTPUTN))
+    {
+        *pOutDevSelUpdate = FALSE;
+        return ASOP_IO_ERR_INV_PARAMS;
+    }
+    
+    *pOutDevSelUpdate = (Bool)(pAstCfg->xOut[z].outBufStatus.sioSelect >= 0);
+
+    return ASOP_IO_SOK;
+}
+
+// Check if any Output device SIO selection changed
+Int checkAnyOutDevSioSelUpdate(
+    const PAF_ASOT_Params *pP, 
+    PAF_ASOT_Config *pAsotCfg,
+    Bool *pOutDevSelUpdate
+)
+{
+    PAF_AST_Config *pAstCfg;
+    Int outDevSelUpdate;
+    Int z;
+    
+    pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
+
+    outDevSelUpdate = FALSE;
+    for (z=OUTPUT1; z < OUTPUTN; z++) 
+    {
+        if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
+        {
+            outDevSelUpdate = TRUE;
+            break;
+        }
+    }
+    
+    *pOutDevSelUpdate = outDevSelUpdate;
+
+    return ASOP_IO_SOK;
+}
+
 // -----------------------------------------------------------------------------
 // ASOT Decoding Function Helper - SIO Driver Change
 //
@@ -165,10 +290,12 @@ Int asopSetCheckRateX(
                 return ((getVal & 0xff) | ASPERR_RATE_CHECK);
             }
 #endif // FL, New IO
+            // FL: ugly little experiment
+            //*(volatile UInt32 *)0x23400B0 |= 7;
         }
     }
 
-    return 0;
+    return ASOP_IO_SOK;
 } //asopSetCheckRateX
 
 // -----------------------------------------------------------------------------
@@ -199,6 +326,7 @@ Int asopStartOutput(
     Int zMD;
     PAF_SIO_IALG_Obj    *pObj;
     PAF_SIO_IALG_Config *pAlgConfig;
+    ioPhyCtl_t ioPhyCtl;
 
 
     pAstCfg = pAsotCfg->pAstCfg; // get pointer to common (shared) configuration
@@ -227,27 +355,38 @@ Int asopStartOutput(
 // Need to Revisit: Starting Clocks here seems logical & also manages the McASP without spurious underruns .
 #if 0
             // if device selected and valid then enable stat tracking if
-                       // required and start clocking
-                       if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
-                       {
-                               TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
-                               errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
-                               if (errno)
-                               {
-                                       TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
-                                       SIO_idle(pAstCfg->xOut[z].hTxSio);
-                                       if (!errno)
-                                       {
-                                               errno = ASPERR_DEVOUT + errme;
-                                       }
-                               }
-                       }
+            // required and start clocking
+            if ((pAstCfg->xOut[z].outBufStatus.sioSelect < 0) && (pAstCfg->xOut[z].hTxSio))
+            {
+                TRACE_VERBOSE0("PAF_ASOT_startOutput: start SIO clocks");
+                errme = SIO_ctrl(pAstCfg->xOut[z].hTxSio, PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, 0);
+                if (errno)
+                {
+                    TRACE_VERBOSE2("PAF_ASOT_startOutput: errme 0x%x, errno 0x%x", errme, errno);
+                    SIO_idle(pAstCfg->xOut[z].hTxSio);
+                    if (!errno)
+                    {
+                        errno = ASPERR_DEVOUT + errme;
+                    }
+                }
+            }
 #endif            
 
             // Set sample count so that DOB knows how much data to send
             pAstCfg->xOut[z].outBufConfig.lengthofFrame =
                 pAstCfg->xEnc[zE].encodeInStruct.pAudioFrame->sampleCount;
 
+#if 1 // FL, New IO: add similar thing to be figured out
+            // Update framework Phy transfer size
+            pOut[z].phyXferSize = pAstCfg->xOut[z].outBufConfig.lengthofFrame * pOut[z].stride * WORD_SIZE_PCM;
+            // Update IO Phy transfer size
+            ioPhyCtl.code = IOPHY_CTL_FRAME_SIZE;
+            ioPhyCtl.params.xferFrameSize = pOut[z].phyXferSize;
+            ioPhyControl(pOut[z].hIoPhy, &ioPhyCtl);
+            // Update IO Buff delay to match Phy transfer size
+            ioBuffAdjustDelay(pOut[z].hIoBuff, pOut[z].phyXferSize * (NUM_PRIME_XFERS+1));
+#endif
+
             if (pAstCfg->xOut[z].outBufStatus.markerMode == PAF_OB_MARKER_ENABLED)
             {
                 pObj = (PAF_SIO_IALG_Obj *) pAstCfg->xOut[z].outChainData.head->alg;
@@ -296,7 +435,7 @@ Int asopStartOutput(
         }
     }
 
-    return 0;
+    return ASOP_IO_SOK;
 } /* asopStartOutput */
 
 // -----------------------------------------------------------------------------
@@ -322,7 +461,7 @@ Int asopStopOutput(
     PAF_AST_IoOut  *pOut;
     Int as;                     /* Audio Stream Number (1, 2, etc.) */
     Int z;                      /* output counter */
-    Int errno = 0, getVal;
+    Int errno, getVal;
     Int zS, zX;
     PAF_SIO_IALG_Obj    *pObj;
     PAF_SIO_IALG_Config *pAlgConfig;
@@ -332,6 +471,7 @@ Int asopStopOutput(
     as = pAstCfg->as;
     (void)as;  // clear compiler warning in case not used with tracing disabled
 
+    errno = ASOP_IO_SOK;
     for (z=OUTPUT1; z < OUTPUTN; z++) 
     {
         if (pOut[z].hIoPhy) 
@@ -426,55 +566,62 @@ Int asopStopOutput(
     return errno;
 } //asopStopOutput
 
-// FL, New IO: this function is currently a stub
-// FL, New IO: need to McASP/EDMA configuration using SAP configuration from Output shortcut
-// Select Output devices
-Int asopSelectDevices(PAF_AST_IoOut *pOut)
-{
-    if((pOut->hIoBuff == NULL) || (pOut->hIoPhy == NULL) || (!d10Initialized)) {
-        return -1;
-    }
-
-    pOut->hMcaspChan = hMcaspTxChan;
-
-    return 0;
-}
-
 /*===========================================================================
  * Initialize I/O components for output processing
 ============================================================================*/
 Int asopIoCompsInit(
-    PAF_AST_OutBuf *pOutBuf, 
-    PAF_AST_IoOut *pOutIo
+    Int16 strAfSampleCount,     // stream audio frame sample count
+    PAF_AST_OutBuf *pOutBuf,    // pointer to Output Buffer
+    PAF_AST_IoOut *pOutIo       // pointer to Output IO
 )
 {
-    // Initialize I/O BUFF and I/O PHY components for output task
     ioBuffParams_t ioBuffParams;
     ioPhyParams_t  ioPhyParams;
 
-    ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
-    ioBuffParams.size         = pOutBuf->outBufConfig.allocation/STRIDE_WORST_CASE*STRIDE_WORST_CASE;
-    ioBuffParams.sync         = IOBUff_READ_SYNC;
-    ioBuffParams.nominalDelay = OUTPUT_FRAME_SIZE * (NUM_PRIME_XFERS+1);
-    if(ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
-    {
-        return -1;   // to remove magic number
-    }
-
-    ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
-    ioPhyParams.xferFrameSize   = OUTPUT_FRAME_SIZE;
-    ioPhyParams.mcaspChanHandle = hMcaspTxChan;
-    ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
-    if(ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
+    if (pOutIo->hMcaspChan != NULL)
     {
-        return -1;   // to remove magic number
-    }
+        // Initialize I/O BUFF and I/O PHY components for output task
+        ioBuffParams.base         = pOutBuf->outBufConfig.base.pVoid;
+        // Set IO buffer size to multiple of audio frame sample count x stride x size of element.
+        // This ensures no split buffers will be allocated on Output buffer wrap.
+        ioBuffParams.size         = pOutBuf->outBufConfig.allocation/(strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM)*
+            (strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM);
+        ioBuffParams.sync         = IOBUff_READ_SYNC;
+        ioBuffParams.nominalDelay = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM * (NUM_PRIME_XFERS+1);
+        if (ioBuffInit(pOutIo->hIoBuff, &ioBuffParams) != IOBUFF_NOERR) 
+        {
+            return ASOP_IO_ERR_IOBUFF_INIT;   // to remove magic number
+        }
 
-    pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
+        ioPhyParams.ioBuffHandle    = pOutIo->hIoBuff;
+        ioPhyParams.xferFrameSize   = strAfSampleCount * pOutIo->stride * WORD_SIZE_PCM;
+        ioPhyParams.mcaspChanHandle = pOutIo->hMcaspChan;
+        ioPhyParams.ioBuffOp        = IOPHY_IOBUFFOP_READ;
+        if (ioPhyInit(pOutIo->hIoPhy, &ioPhyParams) != IOPHY_NOERR) 
+        {
+            return ASOP_IO_ERR_IOPHY_INIT;   // to remove magic number
+        }
 
-    return 0;
+        pOutIo->phyXferSize = ioPhyParams.xferFrameSize;
+        
+        pOutIo->ioBuffBuf2AllocCnt = 0; // initialize buffer2 alloc count (indicates Output buffer wrap)
+        pOutIo->errIoBuffOvrCnt = 0;    // initialize IO buff overflow count
+        pOutIo->errIoBuffUndCnt = 0;    // initialize IO buff underflow count
+    }
+    
+    return ASOP_IO_SOK;
 } /* asopIoCompsInit */
 
+/*======================================================================================
+ *  This function checks whether the I/O physical layer has been initialized
+ *====================================================================================*/
+Bool asopIoPhyCheckInit(Void)
+{
+    if (!d10Initialized)
+        return FALSE;
+    else 
+        return TRUE;
+}
 
 /*======================================================================================
  *  I/O physical layer prime operation required by McASP LLD
@@ -493,98 +640,192 @@ Void asopIoPhyPrime(
     }
 } /* asipIoPhyPrime */
 
+// Initialize Output buffer configuration
+Int asopInitOutBufConfig(
+    PAF_AST_OutBuf *pOutBuf, 
+    PAF_AST_IoOut *pOutIo
+)
+{
+    PAF_OutBufConfig *pOutBufCfg;
+    ioBuffHandle_t hIoBuff;
+    ioBuffInfo_t outBuffInfo;
+    
+    pOutBufCfg = &pOutBuf->outBufConfig;
+    hIoBuff = pOutIo->hIoBuff;
+    
+    pOutBufCfg->stride = pOutIo->stride;
+    pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
+    pOutBufCfg->precision = 24;
+    
+    ioBuffGetInfo(hIoBuff, &outBuffInfo);
+    pOutBufCfg->base.pLgInt = outBuffInfo.base;
+    pOutBufCfg->sizeofBuffer = outBuffInfo.size;
+    
+    pOutBuf->pOutBuf = &(pOutBuf->outBufConfig);
+    
+    return ASOP_IO_SOK;
+}
 
-/*======================================================================================
- *  This function starts an I/O PHY transfer for output
- *====================================================================================*/
-Void asopPhyTransferStart(
-    PAF_AST_IoOut *pOut
+Int asopGetOutBufPtrs(
+    PAF_AST_IoOut *pOutIo,
+    size_t writeSize
 )
 {
-    if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
+    void *buff1, *buff2;
+    size_t size1, size2;
+    Int status;
+
+    status = ioBuffGetWritePtrs(pOutIo->hIoBuff, writeSize,
+                                &buff1, &size1, &buff2, &size2);
+    if (status == IOBUFF_ERR_OVERFLOW)
     {
-        mcaspTxReset();
-        mcaspTxCreate();
-        pOut->hMcaspChan = hMcaspTxChan;
+        pOutIo->errIoBuffOvrCnt++;
+        //System_printf ("asopGetOutBufPtrs: output buff overflow\n"); // debug
+
+        // skip processing since output buffer overflows
+        return ASOP_IO_ERR_OUTBUF_OVERFLOW;
     }
-    else 
+    else if (status == IOBUFF_ERR_UNDERFLOW)
     {
-        if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
-        {
-            // Output buffer underflows!
-            System_abort("\nOutput buffer underflows!\n");
-        }
-        else {
-            // Output buffer operates normally
-            ;
-        }
+        pOutIo->errIoBuffUndCnt++;
+        //System_printf ("asopGetOutBufPtrs: output buff underflow\n"); // debug
+
+        // already underflows and remain in underflow
     }
+    
+    if ((buff2 != NULL) || (size2 != 0))
+    {
+        // Two buffers allocated indicates split buffer allocation on buffer wrap.
+        pOutIo->ioBuffBuf2AllocCnt++; // increment count of allocated buffer2
+    }
+
+    // save buffer pointers & sizes for later write complete
+    pOutIo->buff1 = buff1;
+    pOutIo->size1 = size1;
+    pOutIo->buff2 = buff2;
+    pOutIo->size2 = size2;
+
+    return ASOP_IO_SOK;
 }
 
-// Write output buffers with encoded data
-Int asopWriteOpBuffers(
-    PAF_OutBufConfig *pOpBufCfg, 
-    PAF_AST_IoOut *pOut
+#if 0
+// Update Output buffer configuration.
+// This is needed for proper operation of PCM encoder.
+Int asopUpdateOutBufConfig(
+    PAF_AST_OutBuf *pOutBuf, 
+    PAF_AST_IoOut *pOutIo
 )
 {
-    PAF_UnionPointer pntr;
+    PAF_OutBufConfig *pOutBufCfg;
+    ioBuffHandle_t hIoBuff;
+    ioBuffInfo_t outBuffInfo;
     void *buff1, *buff2;
-    size_t size1, size2;
-    int status;
+    size_t size1, size2, total_write_size;
+    Int status;
+
+    pOutBufCfg = &pOutBuf->outBufConfig;
+    hIoBuff = pOutIo->hIoBuff;
 
-    pntr = pOpBufCfg->pntr; // get output buffer pointer
+    // FL, New IO: original code can change these values in every DOB issue
+    //  Need to determine if this is required or not.
+    pOutBufCfg->stride = pOutIo->stride;
+    pOutBufCfg->sizeofElement = WORD_SIZE_PCM;
+    pOutBufCfg->precision = 24;
     
-    status = ioBuffGetWritePtrs(pOut->hIoBuff, pOut->phyXferSize,
+    //JXTODO: to replace hard coded write size
+    // Get write pointers of output memory pool
+    total_write_size = pOutBufCfg->lengthofFrame * pOutBufCfg->stride * pOutBufCfg->sizeofElement;
+    status = ioBuffGetWritePtrs(hIoBuff, total_write_size,
         &buff1, &size1, &buff2, &size2);
     if (status == IOBUFF_ERR_OVERFLOW) 
     {
-        /* skip processing since output buffer overflows */
-        return IOBUFF_ERR_OVERFLOW;   // to use a different error code
-    }
+        pOutIo->errIoBuffOvrCnt++;
+        //System_printf ("asopUpdateOutBufConfig: output buff overflow\n"); // debug
 
-    // Copy data to output buffer to be transmitted by McASP
-    memcpy(buff1, &pntr.pSmInt[0], size1);
-    Cache_wbInv(buff1, size1, Cache_Type_ALL,TRUE);
+        // skip processing since output buffer overflows        
+        return ASOP_IO_ERR_OUTBUF_OVERFLOW;
+    }
+    else if (status == IOBUFF_ERR_UNDERFLOW) 
+    {
+        pOutIo->errIoBuffUndCnt++;
+        //System_printf ("asopUpdateOutBufConfig: output buff underflow\n"); // debug
+        
+        // already underflows and remain in underflow
+    }
+#if 0
+    // Update Output buffer pointer for Encoder
+    pOutBufCfg->pntr.pLgInt = buff1;
+    if ((buff2 != NULL) || (size2 != 0))
+    {
+        // buff2 should always be NULL for Output & size2 should always be 0 for Output.
+        // Track this here.
+        pOutIo->ioBuffBuf2AllocCnt++; // debug
+    }
+#endif
+    // save buffer pointers & sizes for later write complete
+    pOutIo->buff1 = buff1;
+    pOutIo->size1 = size1;
+    pOutIo->buff2 = buff2;
+    pOutIo->size2 = size2;
+    
+    return ASOP_IO_SOK;
+}
+#endif
 
-    ioBuffWriteComplete(pOut->hIoBuff, buff1, size1);
+// Mark Output buffers write complete
+Int asopMarkOutBuffsWriteComplete(
+    PAF_AST_OutBuf *pOutBuf, 
+    PAF_AST_IoOut *pOutIo
+)
+{
+    ioBuffHandle_t hIoBuff;
+    void *buff1, *buff2;
+    size_t size1, size2;
+    
+    // get buffer pointers & sizes from previous IO Buff write allocation
+    buff1 = pOutIo->buff1;
+    size1 = pOutIo->size1;
+    buff2 = pOutIo->buff2; // this should always be NULL for Output
+    size2 = pOutIo->size2; // this should always be 0 for Output
+    
+    hIoBuff = pOutIo->hIoBuff;
+    
+    ioBuffWriteComplete(hIoBuff, buff1, size1);
 
     if (buff2 != NULL) 
     {
-      memcpy(buff2, &pntr.pSmInt[size1], size2);
-      Cache_wbInv(buff2, size2, Cache_Type_ALL,TRUE);
-
-      ioBuffWriteComplete(pOut->hIoBuff, buff2, size2);
+        ioBuffWriteComplete(hIoBuff, buff2, size2);
     }
-
-    return 0;
+    
+    return ASOP_IO_SOK;
 }
 
-// Check if at least one Output device SIO selection changed
-Int checkOutDevSelUpdate(
-    const PAF_ASOT_Params *pP, 
-    PAF_ASOT_Config *pAsotCfg,
-    Int *pOutDevSelUpdate
+/*======================================================================================
+ *  This function starts an I/O PHY transfer for output
+ *====================================================================================*/
+Void asopPhyTransferStart(
+    PAF_AST_IoOut *pOut
 )
 {
-    PAF_AST_Config *pAstCfg;
-    Int outDevSelUpdate;
-    Int z;
-    
-    pAstCfg = pAsotCfg->pAstCfg; // get pointer to AST common (shared) configuration
-
-    outDevSelUpdate = 0;
-    for (z=OUTPUT1; z < OUTPUTN; z++) 
+    if(mcaspCheckOverUnderRun(pOut->hMcaspChan)) 
     {
-        if (pAstCfg->xOut[z].outBufStatus.sioSelect >= 0)
+        //mcaspTxReset();
+        //mcaspTxCreate();
+        //pOut->hMcaspChan = hMcaspTxChan;
+        System_abort("\nMcASP for output underruns! %d!\n");
+    }
+    else 
+    {
+        if(ioPhyXferSubmit(pOut->hIoPhy) == IOPHY_ERR_BUFF_UNDERFLOW) 
         {
-            outDevSelUpdate = 1;
-            break;
+            // Output buffer underflows!
+            System_abort("\nOutput buffer underflows!\n");
+        }
+        else {
+            // Output buffer operates normally
+            ;
         }
     }
-    
-    *pOutDevSelUpdate = outDevSelUpdate;
-
-    return 0;
 }
 
 /* nothing past this point */