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 // 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)
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 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;
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)
305 {
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)
330 {
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)
349 {
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)
478 {
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;
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)
570 {
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)
638 {
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)
650 {
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)
704 {
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)
732 {
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)
784 {
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 // -----------------------------------------------------------------------------