]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - procsdk_audio_x_xx_xx_xx/test_dsp/mob/mob.c
I/O update
[processor-sdk/performance-audio-sr.git] / procsdk_audio_x_xx_xx_xx / test_dsp / mob / mob.c
2 /*
3 * Copyright (C) 2004-2014 Texas Instruments Incorporated - http://www.ti.com/
4 * All rights reserved.  
5 *
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 // -----------------------------------------------------------------------------
173 Int DOB_ctrl (DEV2_Handle  device, Uns code, Arg arg)
175     DOB_DeviceExtension  *pDevExt = (DOB_DeviceExtension *)device->object;
176     DEV2_Handle            pChild  = (DEV2_Handle)&pDevExt->child;
177     Int                   status  = SYS_OK;
180     switch (code) {
181         case PAF_SIO_CONTROL_GET_CHILD_DEVICE:
182             *((Arg *)arg) = (Arg) pChild;
183             break;
185         case PAF_SIO_CONTROL_OUTPUT_START_CLOCKS:
186             // only start clocks if not running
187             if (pDevExt->state == DOB_STATE_IDLE) {
188                 // pass to child 
189                 status = DEV2_ctrl (pChild, code, arg);
190                 if (status)
191                     return status;
193                 status = DOB_FTABLE_startClocks (device);
194             }
195             break;
197         case PAF_SIO_CONTROL_OPEN:
198             //TODO: check that we are idle?
199             pDevExt->rateX = 1.;            
200             status = DEV2_ctrl (pChild, code, arg);
201             if (status)
202                 return status;
203             break;
204             
205         case PAF_SIO_CONTROL_SET_RATEX:
206         {
207             float rateX = *(float *)arg;
208             int errno = SYS_OK;
210             if (pDevExt->rateX != rateX) {
211                 status = DEV2_idle (device,0);
212                 if (status)
213                     return status;
214                 errno = DOBERR_RATECHANGE;
215             } 
217             // pass call to child device to effect rate change
218             status = DEV2_ctrl (pChild, code, arg);
219             if (status)
220                 return status;
222             pDevExt->rateX = rateX;
223             return errno;
224         }
225         // comment to remove compiler warning
226         //        break;
228         case PAF_SIO_CONTROL_IDLE:
230             // do nothing if not running
231             if (pDevExt->state == DOB_STATE_IDLE)
232                 return SYS_OK;
234             if (arg) {
235                 // flush data (and keep clocks)
236                 DOB_FTABLE_shutdown (device);
237                 status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, arg);
238                 if (!status)
239                     pDevExt->state = DOB_STATE_CLOCKING;
240             }
241             else {
242                 // truncate data (stops clocks)
243                 DEV2_idle (device, 0);
244                 status = DEV2_ctrl (pChild, code, arg);
245             }
246             break;
248         case PAF_SIO_CONTROL_SET_BUFSTATUSADDR:
249             pDevExt->pBufStatus = (PAF_OutBufStatus *) arg;
250             break;
252         case PAF_SIO_CONTROL_SET_ENCSTATUSADDR:
253             pDevExt->pEncStatus = (PAF_EncodeStatus *) arg;
254             break;
256         case PAF_SIO_CONTROL_SET_NUMBUF:
257             pChild->nbufs = (Uns) arg;
258             break;
260         case PAF_SIO_CONTROL_SET_MAX_NUMBUF:
261             // set max first since used by realloc function
262             pDevExt->maxNumBuf = (XDAS_UInt8) arg;
263             status = DOB_FTABLE_reallocFrames (device);
264             break;
266         // return number of DMA events vs. request size          
267         // only update if not in error state (i.e. status = 0)
268         case PAF_SIO_CONTROL_GET_NUM_EVENTS:
269             if (!arg)
270                 return DOBERR_UNSPECIFIED;
271             status = DEV2_ctrl (pChild, code, arg);
272             if (!status)
273                 *((Int *)arg) -= pChild->nbufs * pDevExt->lengthofFrame;
274             break;
276         default:
277             status = DEV2_ctrl (pChild, code, arg);
278             break;
279     } //switch
281     return status;
282 } // DOB_ctrl
284 // -----------------------------------------------------------------------------
286 Int DOB_idle (DEV2_Handle device, Bool flush)
288     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
289     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
290     Int                    status;
293     status = DEV2_idle (pChild, flush); 
294     if (status != SYS_OK)
295         return status;
297     status = DOB_FTABLE_shutdown (device);
299     pDevExt->state = DOB_STATE_IDLE;
301     return status;
302 } // DOB_idle
304 static Queue_Handle dobFrameQue;
306 // -----------------------------------------------------------------------------
307 // This function is called before main and hence no devices yet running.
308 // Therefore we need not worry about context switching.
310 Void DOB_init (Void)
312         Error_Block eb;
313     // allocate global parameter que. If it fails we we cause an
314     // exception and hence later code can assume it is valid without checking.
316         Error_init(&eb);
318     dobFrameQue = Queue_create (NULL, &eb);
319     if (!dobFrameQue) {
320         Log_info1 ("DOB_init failed after Queue_create:", SYS_EALLOC);
321         return;
322     }
324 } // DOB_init
326 // -----------------------------------------------------------------------------
328 Int DOB_issue (DEV2_Handle device)
330     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
331     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
332     DEV2_Frame             *pChildFrame;
333     DEV2_Frame             *pParentFrame;
334     PAF_OutBufConfig      *pBufConfig;
335     Int                    status, xferSize, i, numXfers, prec, wordSize, numChan, encSelect;
337     Log_info0("In MOB Issue");
339     // need valid status pointers
340     if (!pDevExt->pBufStatus || !pDevExt->pEncStatus)
341         return SIO2_EINVAL;
343     pParentFrame = Queue_get (device->todevice);
344     if (!pParentFrame->addr)
345         return SIO2_EINVAL;
346     pBufConfig = (PAF_OutBufConfig *) pParentFrame->addr;
347     Queue_put (device->fromdevice, pParentFrame);
349     Log_info0("Still In MOB Issue - 1");
351     //maybe overkill getting this each time
352     //  assume error in control calls indicates pParams == NULL -- for now
353     //  and so take default (8,4,24)
354     // For bit-exact over 1394, we force the stride to be 8
355     pBufConfig->stride = 8; 
356     if (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED) {
357         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan );
358         if (status == SYS_OK)
359             pBufConfig->stride = numChan;
360     }
362     pBufConfig->sizeofElement = 4;
363     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize );
364     if (status == SYS_OK)
365         pBufConfig->sizeofElement = wordSize;
367     pBufConfig->precision = 24;
368     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_PRECISION, (Arg) &prec );
369     if (status == SYS_OK)
370         pBufConfig->precision = prec;
372     xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
374     //start output by sending nBufs buffer times of zeros
375     if (pDevExt->state < DOB_STATE_RUNNING) {
377         Log_info0("Still In MOB Issue - state < DOB_STATE_RUNNING ");
379         // latch length of frame for use later in ctrl
380         pDevExt->lengthofFrame = pBufConfig->lengthofFrame;
382         // reset buffer pointers -- not really correct if user is managing the buffer memory
383         //  as provided by the DOB interface, however since we don't really support user
384         //  management this is fine and cleans up the framework level interface
385         pBufConfig->pntr = pBufConfig->base;
386         pBufConfig->head = pBufConfig->base;
387         // init sizeofBuffer (needed by encoder)
388         pBufConfig->sizeofBuffer = pBufConfig->allocation;
390         // divide buffer into equal sized segments. We assume any one transfer
391         // will be <= this size. Effectively each DEV2_Frame is assigned a unique
392         // segment of the buffer. This simplifies bookeeping and limits passing
393         // side information between issue and reclaim.
394         pChildFrame = Queue_head (&((SIO2_Handle)pChild)->framelist);
395         for (i=0; i < pDevExt->maxNumBuf; i++) {
396             pChildFrame->arg = (Arg) ((int) pBufConfig->pntr.pVoid + i*pBufConfig->sizeofBuffer/pDevExt->maxNumBuf);
397             pChildFrame = Queue_next ((Queue_Elem *) pChildFrame);
398         }
400         // Update DIT status registers based on encoder selected
401         encSelect = pDevExt->pEncStatus->select;
402         status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_SET_DITSTATUS, (Arg) &encSelect );
403         if (status != SYS_OK)
404             return status;
406         numXfers = pChild->nbufs;
407     }
408     else
409     {
410         numXfers = 1;
411         Log_info0("Still In MOB Issue - numXfers = 1; ");
412     }
414     // IEC encapsulation performed based on mode
415     if (pDevExt->pBufStatus->mode == OB_MODE_IEC) 
416         return DOB_FTABLE_issueIEC (device, pBufConfig);
418     for (i=0; i < numXfers; i++) {
419         pChildFrame = Queue_get (&((SIO2_Handle)pChild)->framelist);
420         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
421             return SIO2_EBADIO;
423         // If kickstarting then send zeros unless we need marker then send data.
424         if ((pDevExt->state < DOB_STATE_RUNNING) &&
425             (pDevExt->pBufStatus->markerMode == PAF_OB_MARKER_DISABLED))
426             pChildFrame->addr = NULL;
427         else
428             pChildFrame->addr = (Ptr) pChildFrame->arg; 
429         pChildFrame->size = xferSize;
431         Queue_put (pChild->todevice, pChildFrame);
432         status = DEV2_issue(pChild);
433         if (status != SYS_OK)
434             return status;
435     }
436     pDevExt->state = DOB_STATE_RUNNING;
438     Log_info0("Leaving MOB Issue with state=RUNNING");
440     return SYS_OK;
441 } // DOB_issue
443 // -----------------------------------------------------------------------------
444 // TODO:
445 //  . This assumes full payload provided once every other frame. Need to count
446 //    down number of bytes per frame given encoder select and insert IEC header
447 //    only at the beginning of a frame. 
448 //  . Should we add a frame/configurable delay. This might be needed in order to
449 //    get an accurate pd(payload) value. Is this required for VBR support? 
450 //    Is this not needed otherwise? i.e. for CBR
451 //  . Do we need to dynamically create/add new DEV2_Frames to support minimum memory
452 //    memory requirements?
453 //    Maybe not since all cases can be covered with two requests?
454 //          .    payload + (fill for this frame + fill of all next frame)
455 //          . OR payload + (payload next frame + fill next frame)
456 //
457 Int DOB_issueIEC (DEV2_Handle device, PAF_OutBufConfig  *pBufConfig)
459     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
460     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
461     Int                    pc = iecFromPafSource[pDevExt->pEncStatus->select];
462     DEV2_Frame             *pChildFrame;
463     Int                    i, numBytes, status;
464     Int xferSize = pBufConfig->stride * pBufConfig->sizeofElement * pBufConfig->lengthofFrame;
468     if (pDevExt->state == DOB_STATE_RUNNING) {
469         Log_info0("In MOB IssueIEC running state");
471         numBytes = pBufConfig->head.pSmInt - pBufConfig->pntr.pSmInt;
474         pChildFrame = Queue_get (&((SIO2_Handle)pChild)->framelist);
475         if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
476             return SIO2_EBADIO;
478         pChildFrame->size = xferSize;
479         
480         if (numBytes > 0) {
481             MdInt *pMdInt = (MdInt *) pBufConfig->pntr.pMdInt;
482             SmInt *pSmInt = (char*) pBufConfig->pntr.pSmInt - IEC_HEADER_SIZE;
483             Int numBits = numBytes*8;
485             // HACK -- assume payload fits in single transmission (e.g. when using MPE)
486             // so therefore insert IEC header each time there is new data
487             pSmInt[0] = 0x72;
488             pSmInt[1] = 0xf8;
489             pSmInt[2] = 0x1f;
490             pSmInt[3] = 0x4e;
491             pSmInt[4] = pc;
492             pSmInt[5] = 0x00;
493             pSmInt[6] = numBits & 0xFF;
494             pSmInt[7] = (numBits & 0xFF00) >> 8;
496             // byte swap for IEC transmission
497             for (i=0; i < numBytes/2+1; i++) {
498                 MdInt temp = *pMdInt; 
499                 *pMdInt++ = ((temp & 0xFF) << 8) | ((temp & (0xFF00)) >> 8);
500             }
502             pChildFrame->addr = pSmInt;
504             // HACK
505             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + pBufConfig->sizeofBuffer/2;
506             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt; 
507         }
508         else {
509             // reset pointers
510             pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
511             pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
512             pChildFrame->addr = NULL; // send zero data
513         }
515         Queue_put (pChild->todevice, pChildFrame);
516         status = DEV2_issue(pChild);
517         if (status != SYS_OK)
518             return status;
520     } //DOB_STATE_RUNNING
521     else {
522         // when kick-started send nbufs of zeroes
523         for (i=0; i < pChild->nbufs; i++) {
524             pChildFrame = Queue_get (&((SIO2_Handle)pChild)->framelist);
525             if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
526                 return SIO2_EBADIO;
528             pChildFrame->size = xferSize;
529             pChildFrame->addr = NULL; // send zero data
531             Queue_put (pChild->todevice, pChildFrame);
532             status = DEV2_issue(pChild);
533             if (status != SYS_OK)
534                 return status;
535         }
537         // set effective base to base+header
538         pBufConfig->pntr.pSmInt = pBufConfig->base.pSmInt + IEC_HEADER_SIZE;
539         pBufConfig->head.pSmInt = pBufConfig->pntr.pSmInt;
541         pDevExt->state = DOB_STATE_RUNNING;
542     }
544     return SYS_OK;
545 } //DOB_issueIEC
547 // -----------------------------------------------------------------------------
549 Int DOB_open (DEV2_Handle device, String name)
551     DOB_DeviceExtension   *pDevExt;
552     DEV2_Handle             pChild;
553     DEV2_Device            *entry;
554     Int                    status;
555     Error_Block eb;
557         Error_init(&eb);
559     name = DEV2_match (name, &entry);
560     if (entry == NULL) {
561         Log_info1 ("DOB_open failed after DEV2_match:", SIO2_ENODEV);
562         return SIO2_ENODEV;
563     }
565     if (!(pDevExt = Memory_alloc(device->bufSeg, sizeof(DOB_DeviceExtension), 0, &eb)))
566     {
567         Log_info1 ("DOB open failed after Memory_alloc:", SYS_EALLOC);
568         return SYS_EALLOC;
569     }
570     pDevExt->state = DOB_STATE_IDLE;
571     pDevExt->maxNumBuf = 0;
572     pDevExt->rateX = 0.;
573     pDevExt->pBufStatus = NULL;
574     pDevExt->pEncStatus = NULL;
575     device->object = (Ptr)pDevExt;
577     pChild = (DEV2_Handle)&pDevExt->child;
578     pChild->fromdevice = Queue_create(NULL, &eb);
579     pChild->todevice = Queue_create(NULL, &eb);
580     if (pChild->fromdevice == NULL || pChild->todevice == NULL) {
581         Log_info1 ("DOB open failed after Queue_create:", SYS_EALLOC);
582         return SYS_EALLOC;
583     }
585     pChild->bufsize = 0;
586     pChild->nbufs = 0;
587     pChild->bufSeg = device->bufSeg;
588     pChild->mode = device->mode;
589     pChild->timeout = device->timeout;
590     pChild->align = device->align;
591     pChild->devid = entry->devid;
592     pChild->params = entry->params;
593     pChild->fxns = *(DEV2_Fxns *)(entry->fxns);
594     ((SIO2_Handle)pChild)->model = ((SIO2_Handle)device)->model;
596     // Create frame queue -- actual frames created via DOB_ctrl
597     Queue_construct(&((SIO2_Handle)pChild)->framelist, NULL); //Queue_new (&((SIO2_Handle)pChild)->framelist);
599     // open underlying device
600     if ((status = DEV2_open (pChild, name)) != SYS_OK)
601         return status;
603     // use dev match to fetch function table pointer for DOB
604     name = DEV2_match ("/DOB", &entry);
605     if (entry == NULL) {
606         Log_info1 ("DOB open failed after DEV2_match of DOB:", SIO2_ENODEV);
607         return SIO2_ENODEV;
608     }
609     pDevExt->pFxns = (DOB_Fxns *) entry->fxns;
611     return SYS_OK;
612 } // DOB_open
614 // -----------------------------------------------------------------------------
616 #if 0
617 Bool DOB_ready (DEV2_Handle device, SEM_Handle sem)
619     DOB_DeviceExtension  *pDevExt = (DOB_DeviceExtension *)device->object;
620     DEV2_Handle            pChild = (DEV2_Handle)&pDevExt->child;
623     return (DEV_ready (pChild, sem));
624 } // DOB_ready
625 #endif
627 // -----------------------------------------------------------------------------
629 Int DOB_reclaim (DEV2_Handle device)
631     DOB_DeviceExtension    *pDevExt = (DOB_DeviceExtension *)device->object;
632     DEV2_Handle              pChild  = (DEV2_Handle)&pDevExt->child;
633     DEV2_Frame              *pChildFrame;
634     DEV2_Frame              *pParentFrame;
635     PAF_OutBufConfig       *pBufConfig;
636     Int                     status;
639     Log_info0("In MOB Reclaim");
640     if (pDevExt->state != DOB_STATE_RUNNING)
641         return DOBERR_NOTRUNNING;
643     // if no available frames then wait for one to free o/w pull one from queue
644     if (Queue_empty (&((SIO2_Handle)pChild)->framelist)) {
645         status = DEV2_reclaim (pChild);
646         if (status != SYS_OK)
647             return status;
648         pChildFrame = Queue_get (pChild->fromdevice);
650         // place frame at end of queue to be used later by issue
651         // since queue was empty this will place it on the head of the queue
652         Queue_put (&((SIO2_Handle)pChild)->framelist, pChildFrame);
653     }
654     else
655         // since queue is not empty then get head of queue which will be the next one used by issue
656         pChildFrame = Queue_head (&((SIO2_Handle)pChild)->framelist);
658     // if in IEC mode then don't update ptrs (this is done by issueIEC),
659     // otherwise we assume encoder is PCE and we need these updates
660     if (pDevExt->pBufStatus->mode != OB_MODE_IEC) {
662         // Since DOB uses a single frame interface we know that, since we
663         // are in reclaim, the head of the queue is valid. Also we only support
664         // a common bufconfig so we know it is unique. The value of the addr
665         // is set by the framework via the pbuf parameter of SIO2_issue. Also
666         // the size is set by SIO2_issue using the nbytes parameter so no need to set 
667         // it here.
668         pParentFrame = (DEV2_Frame *) Queue_head (device->fromdevice);
669         pBufConfig   = (PAF_OutBufConfig *) pParentFrame->addr;
671         // setup info for encoder (which is called subsequent to this reclaim)
672         //   since each DEV2_Frame is mapped to a unique buffer segment (in issue)
673         //   we can safely use the argument of the frame to inform the encoder.
674         pBufConfig->lengthofData = 0;
675         pBufConfig->pntr.pVoid = (Ptr) pChildFrame->arg;
676     }
677     Log_info0("Leaving MOB Reclaim");
678     return SYS_OK;
679 } // DOB_reclaim
681 // -----------------------------------------------------------------------------
683 Int DOB_shutdown (DEV2_Handle device)
685     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
686     DEV2_Handle             pChild  = (DEV2_Handle)&pDevExt->child;
687     int error;
690     // wait for remaining data to play out -- for now mja
691     // this cannot result in an infinite wait since there are only a
692     // finite number of SIO frames.
693     while (!(error = DEV2_reclaim(pChild)));
695     if (error == PAF_SIO_ERROR_FATAL)
696         return error;
698     // reset queues 
699     while (!Queue_empty(device->todevice))
700         Queue_enqueue (device->fromdevice, Queue_dequeue(device->todevice));
702     while (!Queue_empty(device->fromdevice))
703         Queue_enqueue(&((SIO2_Handle) device)->framelist, Queue_dequeue(device->fromdevice));
705     return SYS_OK;
706 } // DOB_shutdown
708 // -----------------------------------------------------------------------------
709 // assume this is called only when idle?
711 Int DOB_startClocks (DEV2_Handle device)
713     DOB_DeviceExtension   *pDevExt = (DOB_DeviceExtension *)device->object;
714     DEV2_Handle             pChild = (DEV2_Handle)&pDevExt->child;
715     DEV2_Frame             *pChildFrame;
716     Int                    status, xferSize, wordSize, numChan;
719     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_NUMCHANNELS, (Arg) &numChan);
720     if (status != SYS_OK)
721         return status;
723     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_GET_WORDSIZE, (Arg) &wordSize);
724     if (status != SYS_OK)
725         return status;
727     // specify minimal transfer size while still maintaining channel alignment
728     //xferSize = numChan * wordSize * 1;
729     xferSize = numChan * wordSize * 4;  // GJ: Experiment with longer startup transfers
731     pChildFrame = Queue_get (&((SIO2_Handle)pChild)->framelist);
732     if (pChildFrame == (DEV2_Frame *)&((SIO2_Handle)pChild)->framelist)
733         return SIO2_EBADIO;
735     pChildFrame->addr = NULL; // send zero data
736     pChildFrame->arg = NULL;
737     pChildFrame->size = xferSize;
739     Queue_put (pChild->todevice, pChildFrame);
740     status = DEV2_issue (pChild);
741     if (status != SYS_OK)
742         return status;
744     // idle underlying device while maintaining clocks
745     status = DOB_FTABLE_shutdown (device);
746     if (status != SYS_OK)
747         return status;
749     status = DEV2_ctrl (pChild, PAF_SIO_CONTROL_IDLE_WITH_CLOCKS, NULL);
750     if (status != SYS_OK)
751         return status;
753     pDevExt->state = DOB_STATE_CLOCKING;
755     return status;
756 } // DOB_startClocks
758 // -----------------------------------------------------------------------------
760 Int DOB_reallocFrames (DEV2_Handle device)
762     DOB_DeviceExtension   *pDevExt   = (DOB_DeviceExtension *)device->object;
763     DEV2_Handle             pChild    = (DEV2_Handle)&pDevExt->child;
764     Queue_Handle            pChildQue = &((SIO2_Handle)pChild)->framelist;
765     DEV2_Frame             *pFrame;
766     Int                    i;
769     // first pull off any frames from the child frame queue and place in holder
770     while (!Queue_empty (pChildQue)) {
771        pFrame = (DEV2_Frame *) Queue_get (pChildQue);
772        Queue_put (dobFrameQue, (Queue_Elem *) pFrame);
773     }
775     // next pull frames from holder and place onto child queue. If there aren't
776     // enough in the holder then allocate from memory. We only support
777     // ISSUERECLAIM mode so size = 0
778     for (i=0; i < pDevExt->maxNumBuf; i++) {
779         if (Queue_empty (dobFrameQue))
780             pFrame = DEV2_mkframe (0, 0, 0); 
781         else
782             pFrame = (DEV2_Frame *) Queue_get (dobFrameQue);
784         if (!pFrame)
785             return SYS_EALLOC;            
787         Queue_put (pChildQue, (Queue_Elem *) pFrame);
788     }
790     return SYS_OK;
791 } //DOB_reallocFrames
793 // -----------------------------------------------------------------------------