PASDK-218: Added debug counters + Restored start-up size to 1 Frame
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / mob / mob.c
2 /*
3 Copyright (c) 2017, Texas Instruments Incorporated - http://www.ti.com/
4 All rights reserved.
6 * Redistribution and use in source and binary forms, with or without 
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
36 //
37 //
38 // Stacking Input Buffer Driver implementations
39 //
40 //
41 // Derived from /c/ti/c6000/src/drivers/dgs.c
43 #include <xdc/std.h>
44 #include <xdc/cfg/global.h>
45 #include <xdc/runtime/Error.h>
46 #include <xdc/runtime/Log.h>
47 #include <xdc/runtime/System.h>
48 #include <xdc/runtime/Memory.h>
49 #include <xdc/runtime/IHeap.h>
50 #include <ti/sysbios/knl/Queue.h>
51 #include <ti/sysbios/knl/Semaphore.h>
52 #include <ti/sysbios/heaps/HeapMem.h>
54 #include <stdio.h> //for sscanf
55 #include <dev2.h>
56 #include <sio2.h>
58 #include "mob.h"
59 #include "moberr.h"
61 #include <outbuf.h>
62 #include <pafsio.h>
63 #include <pafdec.h>
64 #include <pafenc.h>
66 #include <string.h>
67 #include <pafhjt.h>
69 typedef xdc_Short MdInt;
70 typedef xdc_UShort MdUns;
71 typedef xdc_Char SmInt;
72 typedef xdc_UChar SmUns;
74 extern const ti_sysbios_heaps_HeapMem_Handle heapMemDdr3;
75 #define HEAPMALLOC (IHeap_Handle)heapMemDdr3
76 extern HeapMem_Handle DEV2_memSpaceToHeap (IALG_MemSpace space);
78 //Int   DOB_close(DEV2_Handle device);
79 Int   DOB_ctrl (DEV2_Handle device, Uns code, Arg Arg);
80 Int   DOB_idle (DEV2_Handle device, Bool Flush);
81 Int   DOB_issue (DEV2_Handle device);
82 Int   DOB_open (DEV2_Handle device, String Name);
83 //Bool  DOB_ready (DEV2_Handle device, SEM_Handle Sem);
84 Int   DOB_reclaim (DEV2_Handle device);
85 Int   DOB_shutdown (DEV2_Handle device);
86 Int   DOB_startClocks (DEV2_Handle device);
87 Int   DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig  *pBufConfig);
88 Int   DOB_reallocFrames (DEV2_Handle device);
90 // Driver function table.
91 DOB_Fxns DOB_FXNS  = {
92     NULL, //DOB_close,          
93     DOB_ctrl,           
94     DOB_idle,           
95     DOB_issue,          
96     DOB_open,           
97     NULL, //DOB_ready,          
98     DOB_reclaim,        
99     DOB_shutdown,
100     DOB_startClocks,
101     DOB_issueIEC,
102     DOB_reallocFrames
103 };
105 // macros assume pDevExt is available and pDevExt->pFxns is valid
106 #define DOB_FTABLE_shutdown(_a)       (*pDevExt->pFxns->shutdown)(_a)
107 #define DOB_FTABLE_startClocks(_a)    (*pDevExt->pFxns->startClocks)(_a)
108 #define DOB_FTABLE_issueIEC(_a,_b)    (*pDevExt->pFxns->issueIEC)(_a,_b)
109 #define DOB_FTABLE_reallocFrames(_a)  (*pDevExt->pFxns->reallocFrames)(_a)
111 enum
113     DOB_STATE_IDLE,
114     DOB_STATE_CLOCKING,
115     DOB_STATE_RUNNING
116 };
118 // modes (in outBufStatus)
119 enum
121     OB_MODE_DISABLED,
122     OB_MODE_ENABLED,
123     OB_MODE_IEC
124 };
127 #define IEC_HEADER_SIZE   8 // in bytes (PA/PB/PC/PD)
129 // only MP3 is supported for now
130 const SmUns iecFromPafSource [PAF_SOURCE_N] = 
132     0,      // PAF_SOURCE_UNKNOWN
133     0,      // PAF_SOURCE_NONE
134     0,      // PAF_SOURCE_PASS
135     0,      // PAF_SOURCE_SNG
136     0,      // PAF_SOURCE_AUTO
137     0,      // PAF_SOURCE_BITSTREAM
138     0,      // PAF_SOURCE_DTSALL
139     0,      // PAF_SOURCE_PCMAUTO
140     0,      // PAF_SOURCE_PCM
141     0,      // PAF_SOURCE_PC8
142     0,      // PAF_SOURCE_AC3
143     0,      // PAF_SOURCE_DTS
144     0,      // PAF_SOURCE_AAC
145     0,      // PAF_SOURCE_MPEG
146     0,      // PAF_SOURCE_DTS12
147     0,      // PAF_SOURCE_DTS13
148     0,      // PAF_SOURCE_DTS14
149     0,      // PAF_SOURCE_DTS16
150     0,      // PAF_SOURCE_WMA9PRO
151     5,      // PAF_SOURCE_MP3
152     0,      // PAF_SOURCE_DSD1
153     0,      // PAF_SOURCE_DSD2
154     0,      // PAF_SOURCE_DSD3   
155 };
157 // HACK -- grab table from dib.c
158 // indexed by PC value from IEC header
159 // IEC framelengths (in 16bit words)
160 extern const MdUns iecFrameLength[19];
162 // -----------------------------------------------------------------------------
164 Int DOB_close (DEV2_Handle device)
166     //TODO: determine how to clean up
167     
168     return (SIO2_EBADIO);
169 } // DOB_close
171 // GJ Debug Counters
172 Uint32 gMobStart_Idle=0;
173 Uint32 gMobIdle_Ctrl=0;
174 Uint32 gMobIdle_API=0;
175 Uint32 gMobOutRateX_Cnt=0;
176 Uint32 gMobStart_Open=0;
177 Uint32 gMobStart_Clocks=0;
178 Uint32 gMobRateXChanged=0;
179 // -----------------------------------------------------------------------------
181 Int DOB_ctrl (DEV2_Handle  device, Uns code, Arg arg)
183     DOB_DeviceExtension  *pDevExt = (DOB_DeviceExtension *)device->object;
184     DEV2_Handle            pChild  = (DEV2_Handle)&pDevExt->child;
185     Int                   status  = SYS_OK;
188     switch (code) {
189         case PAF_SIO_CONTROL_GET_CHILD_DEVICE:
190             *((Arg *)arg) = (Arg) pChild;
191             break;
193         case PAF_SIO_CONTROL_OUTPUT_START_CLOCKS:
194             // only start clocks if not running
195             if (pDevExt->state == DOB_STATE_IDLE) {
196                 // pass to child 
197                 status = DEV2_ctrl (pChild, code, arg);
198                 if (status)
199                     return status;
201                 Log_info0("MOB: Inside PAF_SIO_CONTROL_OUTPUT_START_CLOCKS, starting output clocks ");
202                 status = DOB_FTABLE_startClocks (device);
203                 gMobStart_Idle++;
204             }
205             break;
207         case PAF_SIO_CONTROL_OPEN:
208             //TODO: check that we are idle?
209             pDevExt->rateX = 1.;            
210             status = DEV2_ctrl (pChild, code, arg);
211             gMobStart_Open++;
212             if (status)
213                 return status;
214             break;
215             
216         case PAF_SIO_CONTROL_SET_RATEX:
217         {
218             float rateX = *(float *)arg;
219             int errno = SYS_OK;
221             gMobOutRateX_Cnt++;
223             if (pDevExt->rateX != rateX) {
224                 status = DEV2_idle (device,0);
225                 gMobRateXChanged++;
226                 if (status)
227                     return status;
228                 errno = DOBERR_RATECHANGE;
229             } 
231             // pass call to child device to effect rate change
232             status = DEV2_ctrl (pChild, code, arg);
233             if (status)
234                 return status;
236             pDevExt->rateX = rateX;
237             return errno;
238         }
239         // comment to remove compiler warning
240         //        break;
242         case PAF_SIO_CONTROL_IDLE:
244             // do nothing if not running
245             if (pDevExt->state == DOB_STATE_IDLE)
246                 return SYS_OK;
248             gMobIdle_Ctrl++;
250             if (arg) {
251                 // flush data (and keep clocks)
252                 DOB_FTABLE_shutdown (device);
253                 //gMobIdle_ClocksIf++;
254                 status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, arg);
255                 if (!status)
256                     pDevExt->state = DOB_STATE_CLOCKING;
257             }
258             else {
259                 // truncate data (stops clocks)
260                 DEV2_idle (device, 0);
261                 status = DEV2_ctrl (pChild, code, arg);
262                 //gMobIdle_ClocksElse++;
263             }
264             break;
266         case PAF_SIO_CONTROL_SET_BUFSTATUSADDR:
267             pDevExt->pBufStatus = (PAF_OutBufStatus *) arg;
268             break;
270         case PAF_SIO_CONTROL_SET_ENCSTATUSADDR:
271             pDevExt->pEncStatus = (PAF_EncodeStatus *) arg;
272             break;
274         case PAF_SIO_CONTROL_SET_NUMBUF:
275             pChild->nbufs = (Uns) arg;
276             break;
278         case PAF_SIO_CONTROL_SET_MAX_NUMBUF:
279             // set max first since used by realloc function
280             pDevExt->maxNumBuf = (XDAS_UInt8) arg;
281             status = DOB_FTABLE_reallocFrames (device);
282             break;
284         // return number of DMA events vs. request size          
285         // only update if not in error state (i.e. status = 0)
286         case PAF_SIO_CONTROL_GET_NUM_EVENTS:
287             if (!arg)
288                 return DOBERR_UNSPECIFIED;
289             status = DEV2_ctrl (pChild, code, arg);
290             if (!status)
291                 *((Int *)arg) -= pChild->nbufs * pDevExt->lengthofFrame;
292             break;
294         default:
295             status = DEV2_ctrl (pChild, code, arg);
296             break;
297     } //switch
299     return status;
300 } // DOB_ctrl
302 // -----------------------------------------------------------------------------
304 Int DOB_idle (DEV2_Handle device, Bool flush)
306     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
307     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
308     Int                    status;
310     gMobIdle_API++;
312     status = DEV2_idle (pChild, flush); 
313     if (status != SYS_OK)
314         return status;
316     status = DOB_FTABLE_shutdown (device);
318     pDevExt->state = DOB_STATE_IDLE;
320     return status;
321 } // DOB_idle
323 static Queue_Struct dobFrameQue;
325 // -----------------------------------------------------------------------------
326 // This function is called before main and hence no devices yet running.
327 // Therefore we need not worry about context switching.
329 Void DOB_init (Void)
331         Error_Block eb;
332     // allocate global parameter que. If it fails we we cause an
333     // exception and hence later code can assume it is valid without checking.
335         Error_init(&eb);
337     //dobFrameQue = Queue_create (NULL, &eb);
338         Queue_construct (&dobFrameQue, NULL);
339     if (Queue_handle(&dobFrameQue) == NULL) {
340         Log_info1 ("DOB_init failed after Queue_construct:", SYS_EALLOC);
341         return;
342     }
344 } // DOB_init
346 // -----------------------------------------------------------------------------
348 Int DOB_issue (DEV2_Handle device)
350     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
351     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
352     DEV2_Frame             *pChildFrame;
353     DEV2_Frame             *pParentFrame;
354     PAF_OutBufConfig      *pBufConfig;
355     Int                    status, xferSize, i, numXfers, prec, wordSize, numChan, encSelect;
357     Log_info0("In MOB Issue");
359     // need valid status pointers
360     if (!pDevExt->pBufStatus || !pDevExt->pEncStatus)
361         return SIO2_EINVAL;
363     pParentFrame = Queue_get (device->todevice);
364     if (!pParentFrame->addr)
365         return SIO2_EINVAL;
366     pBufConfig = (PAF_OutBufConfig *) pParentFrame->addr;
367     Queue_put (device->fromdevice, (Queue_Elem *)pParentFrame);
369     Log_info0("Still In MOB Issue - 1");
371     //maybe overkill getting this each time
372     //  assume error in control calls indicates pParams == NULL -- for now
373     //  and so take default (8,4,24)
374     // For bit-exact over 1394, we force the stride to be 8
375     pBufConfig->stride = 8; 
376     if (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED) {
377         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan );
378         if (status == SYS_OK)
379             pBufConfig->stride = numChan;
380     }
382     pBufConfig->sizeofElement = 4;
383     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize );
384     if (status == SYS_OK)
385         pBufConfig->sizeofElement = wordSize;
387     pBufConfig->precision = 24;
388     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_PRECISION, (Arg) &prec );
389     if (status == SYS_OK)
390         pBufConfig->precision = prec;
392     xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
394     //start output by sending nBufs buffer times of zeros
395     if (pDevExt->state < DOB_STATE_RUNNING) {
397         Log_info0("Still In MOB Issue - state < DOB_STATE_RUNNING ");
399         // latch length of frame for use later in ctrl
400         pDevExt->lengthofFrame = pBufConfig->lengthofFrame;
402         // reset buffer pointers -- not really correct if user is managing the buffer memory
403         //  as provided by the DOB interface, however since we don't really support user
404         //  management this is fine and cleans up the framework level interface
405         pBufConfig->pntr = pBufConfig->base;
406         pBufConfig->head = pBufConfig->base;
407         // init sizeofBuffer (needed by encoder)
408         pBufConfig->sizeofBuffer = pBufConfig->allocation;
410         // divide buffer into equal sized segments. We assume any one transfer
411         // will be <= this size. Effectively each DEV2_Frame is assigned a unique
412         // segment of the buffer. This simplifies bookeeping and limits passing
413         // side information between issue and reclaim.
414         pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist));
415         for (i=0; i < pDevExt->maxNumBuf; i++) {
416             pChildFrame->arg = (Arg) ((int) pBufConfig->pntr.pVoid + i*pBufConfig->sizeofBuffer/pDevExt->maxNumBuf);
417             pChildFrame = Queue_next ((Queue_Elem *) pChildFrame);
418         }
420         // Update DIT status registers based on encoder selected
421         encSelect = pDevExt->pEncStatus->select;
422         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_SET_DITSTATUS, (Arg) &encSelect );
423         if (status != SYS_OK)
424             return status;
426         numXfers = pChild->nbufs;
427     }
428     else
429     {
430         numXfers = 1;
431         Log_info0("Still In MOB Issue - numXfers = 1; ");
432     }
434     // IEC encapsulation performed based on mode
435     if (pDevExt->pBufStatus->mode == OB_MODE_IEC) 
436         return DOB_FTABLE_issueIEC (device, pBufConfig);
438     for (i=0; i < numXfers; i++) {
439         pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
440         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
441             return SIO2_EBADIO;
443         // If kickstarting then send zeros unless we need marker then send data.
444         if ((pDevExt->state < DOB_STATE_RUNNING) &&
445             (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED))
446             pChildFrame->addr = NULL;
447         else
448             pChildFrame->addr = (Ptr) pChildFrame->arg; 
449         pChildFrame->size = xferSize;
451         Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
452         status = DEV2_issue(pChild);
453         if (status != SYS_OK)
454             return status;
455     }
456     pDevExt->state = DOB_STATE_RUNNING;
458     Log_info0("Leaving MOB Issue with state=RUNNING");
460     return SYS_OK;
461 } // DOB_issue
463 // -----------------------------------------------------------------------------
464 // TODO:
465 //  . This assumes full payload provided once every other frame. Need to count
466 //    down number of bytes per frame given encoder select and insert IEC header
467 //    only at the beginning of a frame. 
468 //  . Should we add a frame/configurable delay. This might be needed in order to
469 //    get an accurate pd(payload) value. Is this required for VBR support? 
470 //    Is this not needed otherwise? i.e. for CBR
471 //  . Do we need to dynamically create/add new DEV2_Frames to support minimum memory
472 //    memory requirements?
473 //    Maybe not since all cases can be covered with two requests?
474 //          .    payload + (fill for this frame + fill of all next frame)
475 //          . OR payload + (payload next frame + fill next frame)
476 //
477 Int DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig  *pBufConfig)
479     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
480     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
481     Int                    pc = iecFromPafSource[pDevExt->pEncStatus->select];
482     DEV2_Frame             *pChildFrame;
483     Int                    i, numBytes, status;
484     Int xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
488     if (pDevExt->state == DOB_STATE_RUNNING) {
489         Log_info0("In MOB IssueIEC running state");
491         numBytes = pBufConfig->head.pSmInt - pBufConfig->pntr.pSmInt;
494         pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
495         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
496             return SIO2_EBADIO;
498         pChildFrame->size = xferSize;
499         
500         if (numBytes > 0) {
501             MdInt *pMdInt = (MdInt *) pBufConfig->pntr.pMdInt;
502             SmInt *pSmInt = (char*) pBufConfig->pntr.pSmInt - IEC_HEADER_SIZE;
503             Int numBits = numBytes*8;
505             // HACK -- assume payload fits in single transmission (e.g. when using MPE)
506             // so therefore insert IEC header each time there is new data
507             pSmInt[0] = 0x72;
508             pSmInt[1] = 0xf8;
509             pSmInt[2] = 0x1f;
510             pSmInt[3] = 0x4e;
511             pSmInt[4] = pc;
512             pSmInt[5] = 0x00;
513             pSmInt[6] = numBits & 0xFF;
514             pSmInt[7] = (numBits & 0xFF00) >> 8;
516             // byte swap for IEC transmission
517             for (i=0; i < numBytes/2+1; i++) {
518                 MdInt temp = *pMdInt; 
519                 *pMdInt++ = ((temp & 0xFF) << 8) | ((temp & (0xFF00)) >> 8);
520             }
522             pChildFrame->addr = pSmInt;
524             // HACK
525             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + pBufConfig->sizeofBuffer/2;
526             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; 
527         }
528         else {
529             // reset pointers
530             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
531             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
532             pChildFrame->addr = NULL; // send zero data
533         }
535         Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
536         status = DEV2_issue(pChild);
537         if (status != SYS_OK)
538             return status;
540     } //DOB_STATE_RUNNING
541     else {
542         // when kick-started send nbufs of zeroes
543         for (i=0; i < pChild->nbufs; i++) {
544             pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
545             if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
546                 return SIO2_EBADIO;
548             pChildFrame->size = xferSize;
549             pChildFrame->addr = NULL; // send zero data
551             Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
552             status = DEV2_issue(pChild);
553             if (status != SYS_OK)
554                 return status;
555         }
557         // set effective base to base+header
558         pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
559         pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
561         pDevExt->state = DOB_STATE_RUNNING;
562     }
564     return SYS_OK;
565 } //DOB_issueIEC
567 // -----------------------------------------------------------------------------
569 Int DOB_open (DEV2_Handle device, String name)
571     DOB_DeviceExtension   *pDevExt;
572     DEV2_Handle             pChild;
573     DEV2_Device            *entry;
574     Int                    status;
575     Error_Block eb;
577         Error_init(&eb);
579     name = DEV2_match (name, &entry);
580     if (entry == NULL) {
581         Log_info1 ("DOB_open failed after DEV2_match:", SIO2_ENODEV);
582         return SIO2_ENODEV;
583     }
585     if (!(pDevExt = Memory_alloc(device->bufSeg, sizeof(DOB_DeviceExtension), 0, &eb)))
586     {
587         Log_info1 ("DOB open failed after Memory_alloc:", SYS_EALLOC);
588         return SYS_EALLOC;
589     }
590     pDevExt->state = DOB_STATE_IDLE;
591     pDevExt->maxNumBuf = 0;
592     pDevExt->rateX = 0.;
593     pDevExt->pBufStatus = NULL;
594     pDevExt->pEncStatus = NULL;
595     device->object = (Ptr)pDevExt;
597     pChild = (DEV2_Handle)&pDevExt->child;
598     pChild->fromdevice = Queue_create(NULL, &eb);
599     pChild->todevice = Queue_create(NULL, &eb);
600     if (pChild->fromdevice == NULL || pChild->todevice == NULL) {
601         Log_info1 ("DOB open failed after Queue_create:", SYS_EALLOC);
602         return SYS_EALLOC;
603     }
605     pChild->bufsize = 0;
606     pChild->nbufs = 0;
607     pChild->bufSeg = device->bufSeg;
608     pChild->mode = device->mode;
609     pChild->timeout = device->timeout;
610     pChild->align = device->align;
611     pChild->devid = entry->devid;
612     pChild->params = entry->params;
613     pChild->fxns = *(DEV2_Fxns *)(entry->fxns);
614     ((SIO2_Handle)pChild)->model = ((SIO2_Handle)device)->model;
616     // Create frame queue -- actual frames created via DOB_ctrl
617     Queue_construct(&((SIO2_Handle)pChild)->framelist, NULL); //Queue_new (&((SIO2_Handle)pChild)->framelist);
619     // open underlying device
620     if ((status = DEV2_open (pChild, name)) != SYS_OK)
621         return status;
623     // use dev match to fetch function table pointer for DOB
624     name = DEV2_match ("/DOB", &entry);
625     if (entry == NULL) {
626         Log_info1 ("DOB open failed after DEV2_match of DOB:", SIO2_ENODEV);
627         return SIO2_ENODEV;
628     }
629     pDevExt->pFxns = (DOB_Fxns *) entry->fxns;
631     return SYS_OK;
632 } // DOB_open
634 // -----------------------------------------------------------------------------
636 #if 0
637 Bool DOB_ready (DEV2_Handle device, SEM_Handle sem)
639     DOB_DeviceExtension  *pDevExt = (DOB_DeviceExtension *)device->object;
640     DEV2_Handle            pChild = (DEV2_Handle)&pDevExt->child;
643     return (DEV_ready (pChild, sem));
644 } // DOB_ready
645 #endif
647 // -----------------------------------------------------------------------------
649 Int DOB_reclaim (DEV2_Handle device)
651     DOB_DeviceExtension    *pDevExt = (DOB_DeviceExtension *)device->object;
652     DEV2_Handle              pChild  = (DEV2_Handle)&pDevExt->child;
653     DEV2_Frame              *pChildFrame;
654     DEV2_Frame              *pParentFrame;
655     PAF_OutBufConfig       *pBufConfig;
656     Int                     status;
659     Log_info0("In MOB Reclaim");
660     if (pDevExt->state != DOB_STATE_RUNNING)
661         return DOBERR_NOTRUNNING;
663     // if no available frames then wait for one to free o/w pull one from queue
664     if (Queue_empty (Queue_handle(&((SIO2_Handle)pChild)->framelist))) {
665         status = DEV2_reclaim (pChild);
666         if (status != SYS_OK)
667             return status;
668         pChildFrame = Queue_get (pChild->fromdevice);
670         // place frame at end of queue to be used later by issue
671         // since queue was empty this will place it on the head of the queue
672         Queue_put (Queue_handle(&((SIO2_Handle)pChild)->framelist), (Queue_Elem *)pChildFrame);
673     }
674     else
675         // since queue is not empty then get head of queue which will be the next one used by issue
676         pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist));
678     // if in IEC mode then don't update ptrs (this is done by issueIEC),
679     // otherwise we assume encoder is PCE and we need these updates
680     if (pDevExt->pBufStatus->mode != OB_MODE_IEC) {
682         // Since DOB uses a single frame interface we know that, since we
683         // are in reclaim, the head of the queue is valid. Also we only support
684         // a common bufconfig so we know it is unique. The value of the addr
685         // is set by the framework via the pbuf parameter of SIO2_issue. Also
686         // the size is set by SIO2_issue using the nbytes parameter so no need to set 
687         // it here.
688         pParentFrame = (DEV2_Frame *) Queue_head (device->fromdevice);
689         pBufConfig   = (PAF_OutBufConfig *) pParentFrame->addr;
691         // setup info for encoder (which is called subsequent to this reclaim)
692         //   since each DEV2_Frame is mapped to a unique buffer segment (in issue)
693         //   we can safely use the argument of the frame to inform the encoder.
694         pBufConfig->lengthofData = 0;
695         pBufConfig->pntr.pVoid = (Ptr) pChildFrame->arg;
696     }
697     Log_info0("Leaving MOB Reclaim");
698     return SYS_OK;
699 } // DOB_reclaim
701 // -----------------------------------------------------------------------------
703 Int DOB_shutdown (DEV2_Handle device)
705     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
706     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
707     int error;
710     // wait for remaining data to play out -- for now mja
711     // this cannot result in an infinite wait since there are only a
712     // finite number of SIO frames.
713     while (!(error = DEV2_reclaim(pChild)));
715     if (error == PAF_SIO_ERROR_FATAL)
716         return error;
718     // reset queues 
719     while (!Queue_empty(device->todevice))
720         Queue_enqueue (device->fromdevice, Queue_dequeue(device->todevice));
722     while (!Queue_empty(device->fromdevice))
723         Queue_enqueue(Queue_handle(&((SIO2_Handle) device)->framelist), Queue_dequeue(device->fromdevice));
725     return SYS_OK;
726 } // DOB_shutdown
728 // -----------------------------------------------------------------------------
729 // assume this is called only when idle?
731 Int DOB_startClocks (DEV2_Handle device)
733     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
734     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
735     DEV2_Frame             *pChildFrame;
736     Int                    status, xferSize, wordSize, numChan;
739     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan);
740     if (status != SYS_OK)
741         return status;
743     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize);
744     if (status != SYS_OK)
745         return status;
747     // specify minimal transfer size while still maintaining channel alignment
748     //xferSize = numChan * wordSize * 1;
749     xferSize = numChan * wordSize * 1;  // GJ: Experiment with longer startup transfers
751     pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
752     if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
753         return SIO2_EBADIO;
755     pChildFrame->addr = NULL; // send zero data
756     pChildFrame->arg = NULL;
757     pChildFrame->size = xferSize;
759     Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
760     status = DEV2_issue (pChild);
761     if (status != SYS_OK)
762         return status;
764     // idle underlying device while maintaining clocks
765     status = DOB_FTABLE_shutdown (device);
766     if (status != SYS_OK)
767         return status;
769     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, NULL);
770     if (status != SYS_OK)
771         return status;
773     pDevExt->state = DOB_STATE_CLOCKING;
775     gMobStart_Clocks++;
776     Log_info0("Leaving DOB_startClocks with DOB_STATE_CLOCKING");
778     return status;
779 } // DOB_startClocks
781 // -----------------------------------------------------------------------------
783 Int DOB_reallocFrames (DEV2_Handle device)
785     DOB_DeviceExtension   *pDevExt   = (DOB_DeviceExtension *)device->object;
786     DEV2_Handle             pChild    = (DEV2_Handle)&pDevExt->child;
787     Queue_Handle            pChildQue = Queue_handle(&((SIO2_Handle)pChild)->framelist);
788     DEV2_Frame             *pFrame;
789     Int                    i;
792     // first pull off any frames from the child frame queue and place in holder
793     while (!Queue_empty (pChildQue)) {
794        pFrame = (DEV2_Frame *) Queue_get (pChildQue);
795        Queue_put (Queue_handle(&dobFrameQue), (Queue_Elem *) pFrame);
796     }
798     // next pull frames from holder and place onto child queue. If there aren't
799     // enough in the holder then allocate from memory. We only support
800     // ISSUERECLAIM mode so size = 0
801     for (i=0; i < pDevExt->maxNumBuf; i++) {
802         if (Queue_empty (Queue_handle(&dobFrameQue)))
803             pFrame = DEV2_mkframe (0, 0, 0); 
804         else
805             pFrame = (DEV2_Frame *) Queue_get (Queue_handle(&dobFrameQue));
807         if (!pFrame)
808             return SYS_EALLOC;            
810         Queue_put (pChildQue, (Queue_Elem *) pFrame);
811     }
813     return SYS_OK;
814 } //DOB_reallocFrames
816 // -----------------------------------------------------------------------------