173b1d14bd30ea7847b26323869262c4b0307c7e
[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_ClocksElse=0;
174 Uint32 gMobIdle_ClocksIf=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                 status = DOB_FTABLE_startClocks (device);
202                 gMobStart_Idle++;
203             }
204             break;
206         case PAF_SIO_CONTROL_OPEN:
207             //TODO: check that we are idle?
208             pDevExt->rateX = 1.;            
209             status = DEV2_ctrl (pChild, code, arg);
210             gMobStart_Open++;
211             if (status)
212                 return status;
213             break;
214             
215         case PAF_SIO_CONTROL_SET_RATEX:
216         {
217             float rateX = *(float *)arg;
218             int errno = SYS_OK;
220             gMobOutRateX_Cnt++;
222             if (pDevExt->rateX != rateX) {
223                 status = DEV2_idle (device,0);
224                 gMobRateXChanged++;
225                 if (status)
226                     return status;
227                 errno = DOBERR_RATECHANGE;
228             } 
230             // pass call to child device to effect rate change
231             status = DEV2_ctrl (pChild, code, arg);
232             if (status)
233                 return status;
235             pDevExt->rateX = rateX;
236             return errno;
237         }
238         // comment to remove compiler warning
239         //        break;
241         case PAF_SIO_CONTROL_IDLE:
243             // do nothing if not running
244             if (pDevExt->state == DOB_STATE_IDLE)
245                 return SYS_OK;
247             if (arg) {
248                 // flush data (and keep clocks)
249                 DOB_FTABLE_shutdown (device);
250                 gMobIdle_ClocksIf++;
251                 status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, arg);
252                 if (!status)
253                     pDevExt->state = DOB_STATE_CLOCKING;
254             }
255             else {
256                 // truncate data (stops clocks)
257                 DEV2_idle (device, 0);
258                 status = DEV2_ctrl (pChild, code, arg);
259                 gMobIdle_ClocksElse++;
260             }
261             break;
263         case PAF_SIO_CONTROL_SET_BUFSTATUSADDR:
264             pDevExt->pBufStatus = (PAF_OutBufStatus *) arg;
265             break;
267         case PAF_SIO_CONTROL_SET_ENCSTATUSADDR:
268             pDevExt->pEncStatus = (PAF_EncodeStatus *) arg;
269             break;
271         case PAF_SIO_CONTROL_SET_NUMBUF:
272             pChild->nbufs = (Uns) arg;
273             break;
275         case PAF_SIO_CONTROL_SET_MAX_NUMBUF:
276             // set max first since used by realloc function
277             pDevExt->maxNumBuf = (XDAS_UInt8) arg;
278             status = DOB_FTABLE_reallocFrames (device);
279             break;
281         // return number of DMA events vs. request size          
282         // only update if not in error state (i.e. status = 0)
283         case PAF_SIO_CONTROL_GET_NUM_EVENTS:
284             if (!arg)
285                 return DOBERR_UNSPECIFIED;
286             status = DEV2_ctrl (pChild, code, arg);
287             if (!status)
288                 *((Int *)arg) -= pChild->nbufs * pDevExt->lengthofFrame;
289             break;
291         default:
292             status = DEV2_ctrl (pChild, code, arg);
293             break;
294     } //switch
296     return status;
297 } // DOB_ctrl
299 // -----------------------------------------------------------------------------
301 Int DOB_idle (DEV2_Handle device, Bool flush)
303     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
304     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
305     Int                    status;
308     status = DEV2_idle (pChild, flush); 
309     if (status != SYS_OK)
310         return status;
312     status = DOB_FTABLE_shutdown (device);
314     pDevExt->state = DOB_STATE_IDLE;
316     return status;
317 } // DOB_idle
319 static Queue_Struct dobFrameQue;
321 // -----------------------------------------------------------------------------
322 // This function is called before main and hence no devices yet running.
323 // Therefore we need not worry about context switching.
325 Void DOB_init (Void)
327         Error_Block eb;
328     // allocate global parameter que. If it fails we we cause an
329     // exception and hence later code can assume it is valid without checking.
331         Error_init(&eb);
333     //dobFrameQue = Queue_create (NULL, &eb);
334         Queue_construct (&dobFrameQue, NULL);
335     if (Queue_handle(&dobFrameQue) == NULL) {
336         Log_info1 ("DOB_init failed after Queue_construct:", SYS_EALLOC);
337         return;
338     }
340 } // DOB_init
342 // -----------------------------------------------------------------------------
344 Int DOB_issue (DEV2_Handle device)
346     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
347     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
348     DEV2_Frame             *pChildFrame;
349     DEV2_Frame             *pParentFrame;
350     PAF_OutBufConfig      *pBufConfig;
351     Int                    status, xferSize, i, numXfers, prec, wordSize, numChan, encSelect;
353     Log_info0("In MOB Issue");
355     // need valid status pointers
356     if (!pDevExt->pBufStatus || !pDevExt->pEncStatus)
357         return SIO2_EINVAL;
359     pParentFrame = Queue_get (device->todevice);
360     if (!pParentFrame->addr)
361         return SIO2_EINVAL;
362     pBufConfig = (PAF_OutBufConfig *) pParentFrame->addr;
363     Queue_put (device->fromdevice, (Queue_Elem *)pParentFrame);
365     Log_info0("Still In MOB Issue - 1");
367     //maybe overkill getting this each time
368     //  assume error in control calls indicates pParams == NULL -- for now
369     //  and so take default (8,4,24)
370     // For bit-exact over 1394, we force the stride to be 8
371     pBufConfig->stride = 8; 
372     if (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED) {
373         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan );
374         if (status == SYS_OK)
375             pBufConfig->stride = numChan;
376     }
378     pBufConfig->sizeofElement = 4;
379     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize );
380     if (status == SYS_OK)
381         pBufConfig->sizeofElement = wordSize;
383     pBufConfig->precision = 24;
384     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_PRECISION, (Arg) &prec );
385     if (status == SYS_OK)
386         pBufConfig->precision = prec;
388     xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
390     //start output by sending nBufs buffer times of zeros
391     if (pDevExt->state < DOB_STATE_RUNNING) {
393         Log_info0("Still In MOB Issue - state < DOB_STATE_RUNNING ");
395         // latch length of frame for use later in ctrl
396         pDevExt->lengthofFrame = pBufConfig->lengthofFrame;
398         // reset buffer pointers -- not really correct if user is managing the buffer memory
399         //  as provided by the DOB interface, however since we don't really support user
400         //  management this is fine and cleans up the framework level interface
401         pBufConfig->pntr = pBufConfig->base;
402         pBufConfig->head = pBufConfig->base;
403         // init sizeofBuffer (needed by encoder)
404         pBufConfig->sizeofBuffer = pBufConfig->allocation;
406         // divide buffer into equal sized segments. We assume any one transfer
407         // will be <= this size. Effectively each DEV2_Frame is assigned a unique
408         // segment of the buffer. This simplifies bookeeping and limits passing
409         // side information between issue and reclaim.
410         pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist));
411         for (i=0; i < pDevExt->maxNumBuf; i++) {
412             pChildFrame->arg = (Arg) ((int) pBufConfig->pntr.pVoid + i*pBufConfig->sizeofBuffer/pDevExt->maxNumBuf);
413             pChildFrame = Queue_next ((Queue_Elem *) pChildFrame);
414         }
416         // Update DIT status registers based on encoder selected
417         encSelect = pDevExt->pEncStatus->select;
418         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_SET_DITSTATUS, (Arg) &encSelect );
419         if (status != SYS_OK)
420             return status;
422         numXfers = pChild->nbufs;
423     }
424     else
425     {
426         numXfers = 1;
427         Log_info0("Still In MOB Issue - numXfers = 1; ");
428     }
430     // IEC encapsulation performed based on mode
431     if (pDevExt->pBufStatus->mode == OB_MODE_IEC) 
432         return DOB_FTABLE_issueIEC (device, pBufConfig);
434     for (i=0; i < numXfers; i++) {
435         pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
436         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
437             return SIO2_EBADIO;
439         // If kickstarting then send zeros unless we need marker then send data.
440         if ((pDevExt->state < DOB_STATE_RUNNING) &&
441             (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED))
442             pChildFrame->addr = NULL;
443         else
444             pChildFrame->addr = (Ptr) pChildFrame->arg; 
445         pChildFrame->size = xferSize;
447         Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
448         status = DEV2_issue(pChild);
449         if (status != SYS_OK)
450             return status;
451     }
452     pDevExt->state = DOB_STATE_RUNNING;
454     Log_info0("Leaving MOB Issue with state=RUNNING");
456     return SYS_OK;
457 } // DOB_issue
459 // -----------------------------------------------------------------------------
460 // TODO:
461 //  . This assumes full payload provided once every other frame. Need to count
462 //    down number of bytes per frame given encoder select and insert IEC header
463 //    only at the beginning of a frame. 
464 //  . Should we add a frame/configurable delay. This might be needed in order to
465 //    get an accurate pd(payload) value. Is this required for VBR support? 
466 //    Is this not needed otherwise? i.e. for CBR
467 //  . Do we need to dynamically create/add new DEV2_Frames to support minimum memory
468 //    memory requirements?
469 //    Maybe not since all cases can be covered with two requests?
470 //          .    payload + (fill for this frame + fill of all next frame)
471 //          . OR payload + (payload next frame + fill next frame)
472 //
473 Int DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig  *pBufConfig)
475     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
476     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
477     Int                    pc = iecFromPafSource[pDevExt->pEncStatus->select];
478     DEV2_Frame             *pChildFrame;
479     Int                    i, numBytes, status;
480     Int xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
484     if (pDevExt->state == DOB_STATE_RUNNING) {
485         Log_info0("In MOB IssueIEC running state");
487         numBytes = pBufConfig->head.pSmInt - pBufConfig->pntr.pSmInt;
490         pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
491         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
492             return SIO2_EBADIO;
494         pChildFrame->size = xferSize;
495         
496         if (numBytes > 0) {
497             MdInt *pMdInt = (MdInt *) pBufConfig->pntr.pMdInt;
498             SmInt *pSmInt = (char*) pBufConfig->pntr.pSmInt - IEC_HEADER_SIZE;
499             Int numBits = numBytes*8;
501             // HACK -- assume payload fits in single transmission (e.g. when using MPE)
502             // so therefore insert IEC header each time there is new data
503             pSmInt[0] = 0x72;
504             pSmInt[1] = 0xf8;
505             pSmInt[2] = 0x1f;
506             pSmInt[3] = 0x4e;
507             pSmInt[4] = pc;
508             pSmInt[5] = 0x00;
509             pSmInt[6] = numBits & 0xFF;
510             pSmInt[7] = (numBits & 0xFF00) >> 8;
512             // byte swap for IEC transmission
513             for (i=0; i < numBytes/2+1; i++) {
514                 MdInt temp = *pMdInt; 
515                 *pMdInt++ = ((temp & 0xFF) << 8) | ((temp & (0xFF00)) >> 8);
516             }
518             pChildFrame->addr = pSmInt;
520             // HACK
521             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + pBufConfig->sizeofBuffer/2;
522             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; 
523         }
524         else {
525             // reset pointers
526             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
527             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
528             pChildFrame->addr = NULL; // send zero data
529         }
531         Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
532         status = DEV2_issue(pChild);
533         if (status != SYS_OK)
534             return status;
536     } //DOB_STATE_RUNNING
537     else {
538         // when kick-started send nbufs of zeroes
539         for (i=0; i < pChild->nbufs; i++) {
540             pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
541             if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
542                 return SIO2_EBADIO;
544             pChildFrame->size = xferSize;
545             pChildFrame->addr = NULL; // send zero data
547             Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
548             status = DEV2_issue(pChild);
549             if (status != SYS_OK)
550                 return status;
551         }
553         // set effective base to base+header
554         pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
555         pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
557         pDevExt->state = DOB_STATE_RUNNING;
558     }
560     return SYS_OK;
561 } //DOB_issueIEC
563 // -----------------------------------------------------------------------------
565 Int DOB_open (DEV2_Handle device, String name)
567     DOB_DeviceExtension   *pDevExt;
568     DEV2_Handle             pChild;
569     DEV2_Device            *entry;
570     Int                    status;
571     Error_Block eb;
573         Error_init(&eb);
575     name = DEV2_match (name, &entry);
576     if (entry == NULL) {
577         Log_info1 ("DOB_open failed after DEV2_match:", SIO2_ENODEV);
578         return SIO2_ENODEV;
579     }
581     if (!(pDevExt = Memory_alloc(device->bufSeg, sizeof(DOB_DeviceExtension), 0, &eb)))
582     {
583         Log_info1 ("DOB open failed after Memory_alloc:", SYS_EALLOC);
584         return SYS_EALLOC;
585     }
586     pDevExt->state = DOB_STATE_IDLE;
587     pDevExt->maxNumBuf = 0;
588     pDevExt->rateX = 0.;
589     pDevExt->pBufStatus = NULL;
590     pDevExt->pEncStatus = NULL;
591     device->object = (Ptr)pDevExt;
593     pChild = (DEV2_Handle)&pDevExt->child;
594     pChild->fromdevice = Queue_create(NULL, &eb);
595     pChild->todevice = Queue_create(NULL, &eb);
596     if (pChild->fromdevice == NULL || pChild->todevice == NULL) {
597         Log_info1 ("DOB open failed after Queue_create:", SYS_EALLOC);
598         return SYS_EALLOC;
599     }
601     pChild->bufsize = 0;
602     pChild->nbufs = 0;
603     pChild->bufSeg = device->bufSeg;
604     pChild->mode = device->mode;
605     pChild->timeout = device->timeout;
606     pChild->align = device->align;
607     pChild->devid = entry->devid;
608     pChild->params = entry->params;
609     pChild->fxns = *(DEV2_Fxns *)(entry->fxns);
610     ((SIO2_Handle)pChild)->model = ((SIO2_Handle)device)->model;
612     // Create frame queue -- actual frames created via DOB_ctrl
613     Queue_construct(&((SIO2_Handle)pChild)->framelist, NULL); //Queue_new (&((SIO2_Handle)pChild)->framelist);
615     // open underlying device
616     if ((status = DEV2_open (pChild, name)) != SYS_OK)
617         return status;
619     // use dev match to fetch function table pointer for DOB
620     name = DEV2_match ("/DOB", &entry);
621     if (entry == NULL) {
622         Log_info1 ("DOB open failed after DEV2_match of DOB:", SIO2_ENODEV);
623         return SIO2_ENODEV;
624     }
625     pDevExt->pFxns = (DOB_Fxns *) entry->fxns;
627     return SYS_OK;
628 } // DOB_open
630 // -----------------------------------------------------------------------------
632 #if 0
633 Bool DOB_ready (DEV2_Handle device, SEM_Handle sem)
635     DOB_DeviceExtension  *pDevExt = (DOB_DeviceExtension *)device->object;
636     DEV2_Handle            pChild = (DEV2_Handle)&pDevExt->child;
639     return (DEV_ready (pChild, sem));
640 } // DOB_ready
641 #endif
643 // -----------------------------------------------------------------------------
645 Int DOB_reclaim (DEV2_Handle device)
647     DOB_DeviceExtension    *pDevExt = (DOB_DeviceExtension *)device->object;
648     DEV2_Handle              pChild  = (DEV2_Handle)&pDevExt->child;
649     DEV2_Frame              *pChildFrame;
650     DEV2_Frame              *pParentFrame;
651     PAF_OutBufConfig       *pBufConfig;
652     Int                     status;
655     Log_info0("In MOB Reclaim");
656     if (pDevExt->state != DOB_STATE_RUNNING)
657         return DOBERR_NOTRUNNING;
659     // if no available frames then wait for one to free o/w pull one from queue
660     if (Queue_empty (Queue_handle(&((SIO2_Handle)pChild)->framelist))) {
661         status = DEV2_reclaim (pChild);
662         if (status != SYS_OK)
663             return status;
664         pChildFrame = Queue_get (pChild->fromdevice);
666         // place frame at end of queue to be used later by issue
667         // since queue was empty this will place it on the head of the queue
668         Queue_put (Queue_handle(&((SIO2_Handle)pChild)->framelist), (Queue_Elem *)pChildFrame);
669     }
670     else
671         // since queue is not empty then get head of queue which will be the next one used by issue
672         pChildFrame = Queue_head (Queue_handle(&((SIO2_Handle)pChild)->framelist));
674     // if in IEC mode then don't update ptrs (this is done by issueIEC),
675     // otherwise we assume encoder is PCE and we need these updates
676     if (pDevExt->pBufStatus->mode != OB_MODE_IEC) {
678         // Since DOB uses a single frame interface we know that, since we
679         // are in reclaim, the head of the queue is valid. Also we only support
680         // a common bufconfig so we know it is unique. The value of the addr
681         // is set by the framework via the pbuf parameter of SIO2_issue. Also
682         // the size is set by SIO2_issue using the nbytes parameter so no need to set 
683         // it here.
684         pParentFrame = (DEV2_Frame *) Queue_head (device->fromdevice);
685         pBufConfig   = (PAF_OutBufConfig *) pParentFrame->addr;
687         // setup info for encoder (which is called subsequent to this reclaim)
688         //   since each DEV2_Frame is mapped to a unique buffer segment (in issue)
689         //   we can safely use the argument of the frame to inform the encoder.
690         pBufConfig->lengthofData = 0;
691         pBufConfig->pntr.pVoid = (Ptr) pChildFrame->arg;
692     }
693     Log_info0("Leaving MOB Reclaim");
694     return SYS_OK;
695 } // DOB_reclaim
697 // -----------------------------------------------------------------------------
699 Int DOB_shutdown (DEV2_Handle device)
701     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
702     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
703     int error;
706     // wait for remaining data to play out -- for now mja
707     // this cannot result in an infinite wait since there are only a
708     // finite number of SIO frames.
709     while (!(error = DEV2_reclaim(pChild)));
711     if (error == PAF_SIO_ERROR_FATAL)
712         return error;
714     // reset queues 
715     while (!Queue_empty(device->todevice))
716         Queue_enqueue (device->fromdevice, Queue_dequeue(device->todevice));
718     while (!Queue_empty(device->fromdevice))
719         Queue_enqueue(Queue_handle(&((SIO2_Handle) device)->framelist), Queue_dequeue(device->fromdevice));
721     return SYS_OK;
722 } // DOB_shutdown
724 // -----------------------------------------------------------------------------
725 // assume this is called only when idle?
727 Int DOB_startClocks (DEV2_Handle device)
729     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
730     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
731     DEV2_Frame             *pChildFrame;
732     Int                    status, xferSize, wordSize, numChan;
735     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan);
736     if (status != SYS_OK)
737         return status;
739     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize);
740     if (status != SYS_OK)
741         return status;
743     // specify minimal transfer size while still maintaining channel alignment
744     //xferSize = numChan * wordSize * 1;
745     xferSize = numChan * wordSize * 4;  // GJ: Experiment with longer startup transfers
747     pChildFrame = Queue_get (Queue_handle(&((SIO2_Handle)pChild)->framelist));
748     if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
749         return SIO2_EBADIO;
751     pChildFrame->addr = NULL; // send zero data
752     pChildFrame->arg = NULL;
753     pChildFrame->size = xferSize;
755     Queue_put (pChild->todevice, (Queue_Elem *)pChildFrame);
756     status = DEV2_issue (pChild);
757     if (status != SYS_OK)
758         return status;
760     // idle underlying device while maintaining clocks
761     status = DOB_FTABLE_shutdown (device);
762     if (status != SYS_OK)
763         return status;
765     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, NULL);
766     if (status != SYS_OK)
767         return status;
769     pDevExt->state = DOB_STATE_CLOCKING;
771     gMobStart_Clocks++;
772     Log_info0("Leaving DOB_startClocks with DOB_STATE_CLOCKING");
774     return status;
775 } // DOB_startClocks
777 // -----------------------------------------------------------------------------
779 Int DOB_reallocFrames (DEV2_Handle device)
781     DOB_DeviceExtension   *pDevExt   = (DOB_DeviceExtension *)device->object;
782     DEV2_Handle             pChild    = (DEV2_Handle)&pDevExt->child;
783     Queue_Handle            pChildQue = Queue_handle(&((SIO2_Handle)pChild)->framelist);
784     DEV2_Frame             *pFrame;
785     Int                    i;
788     // first pull off any frames from the child frame queue and place in holder
789     while (!Queue_empty (pChildQue)) {
790        pFrame = (DEV2_Frame *) Queue_get (pChildQue);
791        Queue_put (Queue_handle(&dobFrameQue), (Queue_Elem *) pFrame);
792     }
794     // next pull frames from holder and place onto child queue. If there aren't
795     // enough in the holder then allocate from memory. We only support
796     // ISSUERECLAIM mode so size = 0
797     for (i=0; i < pDevExt->maxNumBuf; i++) {
798         if (Queue_empty (Queue_handle(&dobFrameQue)))
799             pFrame = DEV2_mkframe (0, 0, 0); 
800         else
801             pFrame = (DEV2_Frame *) Queue_get (Queue_handle(&dobFrameQue));
803         if (!pFrame)
804             return SYS_EALLOC;            
806         Queue_put (pChildQue, (Queue_Elem *) pFrame);
807     }
809     return SYS_OK;
810 } //DOB_reallocFrames
812 // -----------------------------------------------------------------------------