/* 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 //for sscanf #include #include #include "mob.h" #include "moberr.h" #include #include #include #include #include #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); //Int DOB_close(DEV2_Handle device); Int DOB_ctrl (DEV2_Handle device, Uns code, Arg Arg); Int DOB_idle (DEV2_Handle device, Bool Flush); Int DOB_issue (DEV2_Handle device); Int DOB_open (DEV2_Handle device, String Name); //Bool DOB_ready (DEV2_Handle device, SEM_Handle Sem); Int DOB_reclaim (DEV2_Handle device); Int DOB_shutdown (DEV2_Handle device); Int DOB_startClocks (DEV2_Handle device); Int DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig *pBufConfig); Int DOB_reallocFrames (DEV2_Handle device); // Driver function table. DOB_Fxns DOB_FXNS = { NULL, //DOB_close, DOB_ctrl, DOB_idle, DOB_issue, DOB_open, NULL, //DOB_ready, DOB_reclaim, DOB_shutdown, DOB_startClocks, DOB_issueIEC, DOB_reallocFrames }; // macros assume pDevExt is available and pDevExt->pFxns is valid #define DOB_FTABLE_shutdown(_a) (*pDevExt->pFxns->shutdown)(_a) #define DOB_FTABLE_startClocks(_a) (*pDevExt->pFxns->startClocks)(_a) #define DOB_FTABLE_issueIEC(_a,_b) (*pDevExt->pFxns->issueIEC)(_a,_b) #define DOB_FTABLE_reallocFrames(_a) (*pDevExt->pFxns->reallocFrames)(_a) enum { DOB_STATE_IDLE, DOB_STATE_CLOCKING, DOB_STATE_RUNNING }; // modes (in outBufStatus) enum { OB_MODE_DISABLED, OB_MODE_ENABLED, OB_MODE_IEC }; #define IEC_HEADER_SIZE 8 // in bytes (PA/PB/PC/PD) // only MP3 is supported for now const SmUns iecFromPafSource [PAF_SOURCE_N] = { 0, // PAF_SOURCE_UNKNOWN 0, // PAF_SOURCE_NONE 0, // PAF_SOURCE_PASS 0, // PAF_SOURCE_SNG 0, // PAF_SOURCE_AUTO 0, // PAF_SOURCE_BITSTREAM 0, // PAF_SOURCE_DTSALL 0, // PAF_SOURCE_PCMAUTO 0, // PAF_SOURCE_PCM 0, // PAF_SOURCE_PC8 0, // PAF_SOURCE_AC3 0, // PAF_SOURCE_DTS 0, // PAF_SOURCE_AAC 0, // PAF_SOURCE_MPEG 0, // PAF_SOURCE_DTS12 0, // PAF_SOURCE_DTS13 0, // PAF_SOURCE_DTS14 0, // PAF_SOURCE_DTS16 0, // PAF_SOURCE_WMA9PRO 5, // PAF_SOURCE_MP3 0, // PAF_SOURCE_DSD1 0, // PAF_SOURCE_DSD2 0, // PAF_SOURCE_DSD3 }; // HACK -- grab table from dib.c // indexed by PC value from IEC header // IEC framelengths (in 16bit words) extern const MdUns iecFrameLength[19]; // ----------------------------------------------------------------------------- Int DOB_close (DEV2_Handle device) { //TODO: determine how to clean up return (SIO2_EBADIO); } // DOB_close // GJ Debug Counters Uint32 gMobStart_Idle=0; Uint32 gMobIdle_ClocksElse=0; Uint32 gMobIdle_ClocksIf=0; Uint32 gMobOutRateX_Cnt=0; Uint32 gMobStart_Open=0; Uint32 gMobStart_Clocks=0; Uint32 gMobRateXChanged=0; // ----------------------------------------------------------------------------- Int DOB_ctrl (DEV2_Handle device, Uns code, Arg arg) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; Int status = SYS_OK; switch (code) { case PAF_SIO_CONTROL_GET_CHILD_DEVICE: *((Arg *)arg) = (Arg) pChild; break; case PAF_SIO_CONTROL_OUTPUT_START_CLOCKS: // only start clocks if not running if (pDevExt->state == DOB_STATE_IDLE) { // pass to child status = DEV2_ctrl (pChild, code, arg); if (status) return status; status = DOB_FTABLE_startClocks (device); gMobStart_Idle++; } break; case PAF_SIO_CONTROL_OPEN: //TODO: check that we are idle? pDevExt->rateX = 1.; status = DEV2_ctrl (pChild, code, arg); gMobStart_Open++; if (status) return status; break; case PAF_SIO_CONTROL_SET_RATEX: { float rateX = *(float *)arg; int errno = SYS_OK; gMobOutRateX_Cnt++; if (pDevExt->rateX != rateX) { status = DEV2_idle (device,0); gMobRateXChanged++; if (status) return status; errno = DOBERR_RATECHANGE; } // pass call to child device to effect rate change status = DEV2_ctrl (pChild, code, arg); if (status) return status; pDevExt->rateX = rateX; return errno; } // comment to remove compiler warning // break; case PAF_SIO_CONTROL_IDLE: // do nothing if not running if (pDevExt->state == DOB_STATE_IDLE) return SYS_OK; if (arg) { // flush data (and keep clocks) DOB_FTABLE_shutdown (device); gMobIdle_ClocksIf++; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, arg); if (!status) pDevExt->state = DOB_STATE_CLOCKING; } else { // truncate data (stops clocks) DEV2_idle (device, 0); status = DEV2_ctrl (pChild, code, arg); gMobIdle_ClocksElse++; } break; case PAF_SIO_CONTROL_SET_BUFSTATUSADDR: pDevExt->pBufStatus = (PAF_OutBufStatus *) arg; break; case PAF_SIO_CONTROL_SET_ENCSTATUSADDR: pDevExt->pEncStatus = (PAF_EncodeStatus *) arg; break; case PAF_SIO_CONTROL_SET_NUMBUF: pChild->nbufs = (Uns) arg; break; case PAF_SIO_CONTROL_SET_MAX_NUMBUF: // set max first since used by realloc function pDevExt->maxNumBuf = (XDAS_UInt8) arg; status = DOB_FTABLE_reallocFrames (device); 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 DOBERR_UNSPECIFIED; status = DEV2_ctrl (pChild, code, arg); if (!status) *((Int *)arg) -= pChild->nbufs * pDevExt->lengthofFrame; break; default: status = DEV2_ctrl (pChild, code, arg); break; } //switch return status; } // DOB_ctrl // ----------------------------------------------------------------------------- Int DOB_idle (DEV2_Handle device, Bool flush) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; Int status; status = DEV2_idle (pChild, flush); if (status != SYS_OK) return status; status = DOB_FTABLE_shutdown (device); pDevExt->state = DOB_STATE_IDLE; return status; } // DOB_idle static Queue_Struct dobFrameQue; // ----------------------------------------------------------------------------- // This function is called before main and hence no devices yet running. // Therefore we need not worry about context switching. Void DOB_init (Void) { Error_Block eb; // allocate global parameter que. If it fails we we cause an // exception and hence later code can assume it is valid without checking. Error_init(&eb); //dobFrameQue = Queue_create (NULL, &eb); Queue_construct (&dobFrameQue, NULL); if (Queue_handle(&dobFrameQue) == NULL) { Log_info1 ("DOB_init failed after Queue_construct:", SYS_EALLOC); return; } } // DOB_init // ----------------------------------------------------------------------------- Int DOB_issue (DEV2_Handle device) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; DEV2_Frame *pChildFrame; DEV2_Frame *pParentFrame; PAF_OutBufConfig *pBufConfig; Int status, xferSize, i, numXfers, prec, wordSize, numChan, encSelect; Log_info0("In MOB Issue"); // need valid status pointers if (!pDevExt->pBufStatus || !pDevExt->pEncStatus) return SIO2_EINVAL; pParentFrame = Queue_get (device->todevice); if (!pParentFrame->addr) return SIO2_EINVAL; pBufConfig = (PAF_OutBufConfig *) pParentFrame->addr; Queue_put (device->fromdevice, (Queue_Elem *)pParentFrame); Log_info0("Still In MOB Issue - 1"); //maybe overkill getting this each time // assume error in control calls indicates pParams == NULL -- for now // and so take default (8,4,24) // For bit-exact over 1394, we force the stride to be 8 pBufConfig->stride = 8; if (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED) { status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan ); if (status == SYS_OK) pBufConfig->stride = numChan; } pBufConfig->sizeofElement = 4; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize ); if (status == SYS_OK) pBufConfig->sizeofElement = wordSize; pBufConfig->precision = 24; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_PRECISION, (Arg) &prec ); if (status == SYS_OK) pBufConfig->precision = prec; xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame; //start output by sending nBufs buffer times of zeros if (pDevExt->state < DOB_STATE_RUNNING) { Log_info0("Still In MOB Issue - state < DOB_STATE_RUNNING "); // latch length of frame for use later in ctrl pDevExt->lengthofFrame = pBufConfig->lengthofFrame; // reset buffer pointers -- not really correct if user is managing the buffer memory // as provided by the DOB interface, however since we don't really support user // management this is fine and cleans up the framework level interface pBufConfig->pntr = pBufConfig->base; pBufConfig->head = pBufConfig->base; // init sizeofBuffer (needed by encoder) pBufConfig->sizeofBuffer = pBufConfig->allocation; // divide buffer into equal sized segments. We assume any one transfer // will be <= this size. Effectively each DEV2_Frame is assigned a unique // segment of the buffer. This simplifies bookeeping and limits passing // side information between issue and reclaim. pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist)); for (i=0; i < pDevExt->maxNumBuf; i++) { pChildFrame->arg = (Arg) ((int) pBufConfig->pntr.pVoid + i*pBufConfig->sizeofBuffer/pDevExt->maxNumBuf); pChildFrame = Queue_next ((Queue_Elem *) pChildFrame); } // Update DIT status registers based on encoder selected encSelect = pDevExt->pEncStatus->select; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_SET_DITSTATUS, (Arg) &encSelect ); if (status != SYS_OK) return status; numXfers = pChild->nbufs; } else { numXfers = 1; Log_info0("Still In MOB Issue - numXfers = 1; "); } // IEC encapsulation performed based on mode if (pDevExt->pBufStatus->mode == OB_MODE_IEC) return DOB_FTABLE_issueIEC (device, pBufConfig); for (i=0; i < numXfers; i++) { pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist)); if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist) return SIO2_EBADIO; // If kickstarting then send zeros unless we need marker then send data. if ((pDevExt->state < DOB_STATE_RUNNING) && (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED)) pChildFrame->addr = NULL; else pChildFrame->addr = (Ptr) pChildFrame->arg; pChildFrame->size = xferSize; Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame); status = DEV2_issue(pChild); if (status != SYS_OK) return status; } pDevExt->state = DOB_STATE_RUNNING; Log_info0("Leaving MOB Issue with state=RUNNING"); return SYS_OK; } // DOB_issue // ----------------------------------------------------------------------------- // TODO: // . This assumes full payload provided once every other frame. Need to count // down number of bytes per frame given encoder select and insert IEC header // only at the beginning of a frame. // . Should we add a frame/configurable delay. This might be needed in order to // get an accurate pd(payload) value. Is this required for VBR support? // Is this not needed otherwise? i.e. for CBR // . Do we need to dynamically create/add new DEV2_Frames to support minimum memory // memory requirements? // Maybe not since all cases can be covered with two requests? // . payload + (fill for this frame + fill of all next frame) // . OR payload + (payload next frame + fill next frame) // Int DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig *pBufConfig) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; Int pc = iecFromPafSource[pDevExt->pEncStatus->select]; DEV2_Frame *pChildFrame; Int i, numBytes, status; Int xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame; if (pDevExt->state == DOB_STATE_RUNNING) { Log_info0("In MOB IssueIEC running state"); numBytes = pBufConfig->head.pSmInt - pBufConfig->pntr.pSmInt; pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist)); if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist) return SIO2_EBADIO; pChildFrame->size = xferSize; if (numBytes > 0) { MdInt *pMdInt = (MdInt *) pBufConfig->pntr.pMdInt; SmInt *pSmInt = (char*) pBufConfig->pntr.pSmInt - IEC_HEADER_SIZE; Int numBits = numBytes*8; // HACK -- assume payload fits in single transmission (e.g. when using MPE) // so therefore insert IEC header each time there is new data pSmInt[0] = 0x72; pSmInt[1] = 0xf8; pSmInt[2] = 0x1f; pSmInt[3] = 0x4e; pSmInt[4] = pc; pSmInt[5] = 0x00; pSmInt[6] = numBits & 0xFF; pSmInt[7] = (numBits & 0xFF00) >> 8; // byte swap for IEC transmission for (i=0; i < numBytes/2+1; i++) { MdInt temp = *pMdInt; *pMdInt++ = ((temp & 0xFF) << 8) | ((temp & (0xFF00)) >> 8); } pChildFrame->addr = pSmInt; // HACK pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + pBufConfig->sizeofBuffer/2; pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; } else { // reset pointers pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE; pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; pChildFrame->addr = NULL; // send zero data } Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame); status = DEV2_issue(pChild); if (status != SYS_OK) return status; } //DOB_STATE_RUNNING else { // when kick-started send nbufs of zeroes for (i=0; i < pChild->nbufs; i++) { pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist)); if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist) return SIO2_EBADIO; pChildFrame->size = xferSize; pChildFrame->addr = NULL; // send zero data Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame); status = DEV2_issue(pChild); if (status != SYS_OK) return status; } // set effective base to base+header pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE; pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; pDevExt->state = DOB_STATE_RUNNING; } return SYS_OK; } //DOB_issueIEC // ----------------------------------------------------------------------------- Int DOB_open (DEV2_Handle device, String name) { DOB_DeviceExtension *pDevExt; DEV2_Handle pChild; DEV2_Device *entry; Int status; Error_Block eb; Error_init(&eb); name = DEV2_match (name, &entry); if (entry == NULL) { Log_info1 ("DOB_open failed after DEV2_match:", SIO2_ENODEV); return SIO2_ENODEV; } if (!(pDevExt = Memory_alloc(device->bufSeg, sizeof(DOB_DeviceExtension), 0, &eb))) { Log_info1 ("DOB open failed after Memory_alloc:", SYS_EALLOC); return SYS_EALLOC; } pDevExt->state = DOB_STATE_IDLE; pDevExt->maxNumBuf = 0; pDevExt->rateX = 0.; pDevExt->pBufStatus = NULL; pDevExt->pEncStatus = 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 ("DOB open failed after Queue_create:", SYS_EALLOC); return SYS_EALLOC; } pChild->bufsize = 0; pChild->nbufs = 0; 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 frame queue -- actual frames created via DOB_ctrl Queue_construct(&((SIO2_Handle)pChild)->framelist, NULL); //Queue_new (&((SIO2_Handle)pChild)->framelist); // open underlying device if ((status = DEV2_open (pChild, name)) != SYS_OK) return status; // use dev match to fetch function table pointer for DOB name = DEV2_match ("/DOB", &entry); if (entry == NULL) { Log_info1 ("DOB open failed after DEV2_match of DOB:", SIO2_ENODEV); return SIO2_ENODEV; } pDevExt->pFxns = (DOB_Fxns *) entry->fxns; return SYS_OK; } // DOB_open // ----------------------------------------------------------------------------- #if 0 Bool DOB_ready (DEV2_Handle device, SEM_Handle sem) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; return (DEV_ready (pChild, sem)); } // DOB_ready #endif // ----------------------------------------------------------------------------- Int DOB_reclaim (DEV2_Handle device) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; DEV2_Frame *pChildFrame; DEV2_Frame *pParentFrame; PAF_OutBufConfig *pBufConfig; Int status; Log_info0("In MOB Reclaim"); if (pDevExt->state != DOB_STATE_RUNNING) return DOBERR_NOTRUNNING; // if no available frames then wait for one to free o/w pull one from queue if (Queue_empty (Queue_handle(&((SIO2_Handle)pChild)->framelist))) { status = DEV2_reclaim (pChild); if (status != SYS_OK) return status; pChildFrame = Queue_get (pChild->fromdevice); // place frame at end of queue to be used later by issue // since queue was empty this will place it on the head of the queue Queue_put (Queue_handle(&((SIO2_Handle)pChild)->framelist), (Queue_Elem *)pChildFrame); } else // since queue is not empty then get head of queue which will be the next one used by issue pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist)); // if in IEC mode then don't update ptrs (this is done by issueIEC), // otherwise we assume encoder is PCE and we need these updates if (pDevExt->pBufStatus->mode != OB_MODE_IEC) { // Since DOB uses a single frame interface we know that, since we // are in reclaim, the head of the queue is valid. Also we only support // a common bufconfig so we know it is unique. The value of the addr // is set by the framework via the pbuf parameter of SIO2_issue. Also // the size is set by SIO2_issue using the nbytes parameter so no need to set // it here. pParentFrame = (DEV2_Frame *) Queue_head (device->fromdevice); pBufConfig = (PAF_OutBufConfig *) pParentFrame->addr; // setup info for encoder (which is called subsequent to this reclaim) // since each DEV2_Frame is mapped to a unique buffer segment (in issue) // we can safely use the argument of the frame to inform the encoder. pBufConfig->lengthofData = 0; pBufConfig->pntr.pVoid = (Ptr) pChildFrame->arg; } Log_info0("Leaving MOB Reclaim"); return SYS_OK; } // DOB_reclaim // ----------------------------------------------------------------------------- Int DOB_shutdown (DEV2_Handle device) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; int error; // wait for remaining data to play out -- for now mja // this cannot result in an infinite wait since there are only a // finite number of SIO frames. while (!(error = DEV2_reclaim(pChild))); if (error == PAF_SIO_ERROR_FATAL) return error; // reset queues 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)); return SYS_OK; } // DOB_shutdown // ----------------------------------------------------------------------------- // assume this is called only when idle? Int DOB_startClocks (DEV2_Handle device) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; DEV2_Frame *pChildFrame; Int status, xferSize, wordSize, numChan; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan); if (status != SYS_OK) return status; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize); if (status != SYS_OK) return status; // specify minimal transfer size while still maintaining channel alignment //xferSize = numChan * wordSize * 1; xferSize = numChan * wordSize * 4; // GJ: Experiment with longer startup transfers pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist)); if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist) return SIO2_EBADIO; pChildFrame->addr = NULL; // send zero data pChildFrame->arg = NULL; pChildFrame->size = xferSize; Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame); status = DEV2_issue (pChild); if (status != SYS_OK) return status; // idle underlying device while maintaining clocks status = DOB_FTABLE_shutdown (device); if (status != SYS_OK) return status; status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, NULL); if (status != SYS_OK) return status; pDevExt->state = DOB_STATE_CLOCKING; gMobStart_Clocks++; Log_info0("Leaving DOB_startClocks with DOB_STATE_CLOCKING"); return status; } // DOB_startClocks // ----------------------------------------------------------------------------- Int DOB_reallocFrames (DEV2_Handle device) { DOB_DeviceExtension *pDevExt = (DOB_DeviceExtension *)device->object; DEV2_Handle pChild = (DEV2_Handle)&pDevExt->child; Queue_Handle pChildQue = Queue_handle(&((SIO2_Handle)pChild)->framelist); DEV2_Frame *pFrame; Int i; // first pull off any frames from the child frame queue and place in holder while (!Queue_empty (pChildQue)) { pFrame = (DEV2_Frame *) Queue_get (pChildQue); Queue_put (Queue_handle(&dobFrameQue), (Queue_Elem *) pFrame); } // next pull frames from holder and place onto child queue. If there aren't // enough in the holder then allocate from memory. We only support // ISSUERECLAIM mode so size = 0 for (i=0; i < pDevExt->maxNumBuf; i++) { if (Queue_empty (Queue_handle(&dobFrameQue))) pFrame = DEV2_mkframe (0, 0, 0); else pFrame = (DEV2_Frame *) Queue_get (Queue_handle(&dobFrameQue)); if (!pFrame) return SYS_EALLOC; Queue_put (pChildQue, (Queue_Elem *) pFrame); } return SYS_OK; } //DOB_reallocFrames // -----------------------------------------------------------------------------