173b1d14bd30ea7847b26323869262c4b0307c7e
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
112 {
113 DOB_STATE_IDLE,
114 DOB_STATE_CLOCKING,
115 DOB_STATE_RUNNING
116 };
118 // modes (in outBufStatus)
119 enum
120 {
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] =
131 {
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)
165 {
166 //TODO: determine how to clean up
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)
182 {
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;
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)
302 {
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)
326 {
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)
345 {
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)
474 {
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;
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)
566 {
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)
634 {
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)
646 {
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)
700 {
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)
728 {
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)
780 {
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 // -----------------------------------------------------------------------------