]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - pasdk/test_dsp/sio_dev2/sio2.c
0064c801502e12c3125ea38d2b7e06379405355c
[processor-sdk/performance-audio-sr.git] / pasdk / test_dsp / sio_dev2 / sio2.c
2 /*
3 Copyright (c) 2016, 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  *  ======== sio2.c ========
38  *  Stream I/O Manager
39  */
41 #include <xdc/std.h>
42 #include <xdc/runtime/Error.h>
43 #include <xdc/runtime/Memory.h>
44 #include <xdc/runtime/Log.h>
45 #include <xdc/runtime/IHeap.h>
47 #include <stddef.h>
49 #include <ti/sysbios/BIOS.h>
50 #include <ti/sysbios/knl/Queue.h>
51 #include <ti/sysbios/heaps/HeapMem.h>
53 #include "sio2.h"
55 #define _BOTH_
57 extern const ti_sysbios_heaps_HeapMem_Handle heapMemDdr3;
58 #define HEAPDDR3 (IHeap_Handle)heapMemDdr3
60 __FAR__ SIO2_Attrs SIO2_ATTRS = {
61     2,                  /* nbufs */
62         0,                  /* bufSeg, not segid */
63     0,                  /* align */
64     FALSE,              /* flush */
65     SIO2_STANDARD,      /* model */
66     BIOS_WAIT_FOREVER,  /* timeout */
67     NULL                /* callback */
68 };
70 /*
71  *  ======== SIO2_create ========
72  */
73 SIO2_Handle SIO2_create(String name, Int mode, size_t bufsize,
74         SIO2_Attrs *attrs)
75 {
76     Int           i;
77     Int           errno = SIO2_ENOMEM;   /* for use after "goto delete" */
78     DEV2_Device  *entry;
79     DEV2_Handle   device;                       /* == stream */
80     DEV2_Frame   *frame;
81     SIO2_Handle   stream;
82     Queue_Handle  queue;
83     Error_Block   eb;
85     if (attrs == NULL) {
86         attrs = &SIO2_ATTRS;
87     }
88     name = DEV2_match(name, &entry);
90     if (entry == NULL) {
91         /*
92          * We print the passed name instead of the module name ("SIO2")
93          * for a more informative error message.
94          *
95          * If DEV2_match() matches, name no longer points to the original
96          * device name, but if entry is NULL, name is unchanged.
97          */
98         Log_error1("Device %s not found", (IArg)name);
99         return (NULL);
100     }
102     if (entry->type != DEV2_SIOTYPE) {
103         Log_error2("SIO2_create: Device %s invalid type: %d",
104                 (IArg)name, entry->type);
105         return (NULL);
106     }
108     Error_init(&eb);
109     stream = (SIO2_Handle)Memory_calloc(NULL /* attrs->bufSeg? */, sizeof(SIO2_Obj), 0, &eb);
111     if (stream == NULL) {
112         Log_error1("SIO2_create: Memory_calloc() failed from bufSeg:%d!", (IArg)attrs->bufSeg);
113         return (NULL);
114     }
116     stream->flush = attrs->flush;       /* save flush flag for closing */
117     stream->model = attrs->model;
118     stream->pfxns = NULL;               /* NULL for all dynamic SIO2 */
120     /*
121      * Initialize  now since SIO2_delete() will check if the
122      * framelist is empty, so the queue must be initialized.
123      */
124     Queue_construct(&stream->framelist, NULL);
126     /* first field in SIO2_Obj is a DEV2_Obj */
127     device = (DEV2_Handle)stream;
129     /* fill in device object fields */
130     device->mode = mode;                /* DEV2_INPUT or DEV2_OUTPUT */
131     device->devid = entry->devid;       /* meaning depends on device */
132     device->bufsize = bufsize;          /* size to be allocated per buffer */
133     device->align = attrs->align;       /* buffer alignment */
134     device->nbufs = attrs->nbufs;       /* max # of buffers allowed */
135     device->bufSeg = attrs->bufSeg;     /* allocation memory segment */
136     device->params = entry->params;     /* device parameters handle */
137     device->timeout = attrs->timeout;   /* timeout used by DEV2_reclaim() */
138     device->callback = attrs->callback; /* callback parameters */
140     /* assign pointer to driver function table */
141     device->fxns = *(DEV2_Fxns *)(entry->fxns); 
143     /* 
144      * create todevice and fromdevice queues;
145      */
146     if ((queue = Queue_create(NULL, &eb)) == NULL) {
147         goto delete;
148     };
149     device->todevice = queue;
150     
151     if ((queue = Queue_create(NULL, &eb)) == NULL) {
152         goto delete;
153     };
154     device->fromdevice = queue;
156     /*
157      * Do not allocate buffers in SIO2_ISSUERECLAIM model since the application
158      * will provide the buffers.
159      */
160     if (attrs->model == SIO2_ISSUERECLAIM) {
161         bufsize = 0;
162     }
164     /* allocate the frame objects, put on framelist queue */
165     for (i = device->nbufs; i > 0; i--) {
166         frame = DEV2_mkframe(attrs->bufSeg, bufsize, attrs->align);
167         if (frame == NULL) {
168             goto delete;
169         }
171         Queue_put(Queue_handle(&stream->framelist), (Queue_Elem *)frame);
172     }
174     /* Call the device-specific open function using DEV2_open macro */
175     if ((errno = DEV2_open(device, name)) != SIO2_OK) {
177         /* open function returned an error */
178 delete:
179         /*
180          * Since SIO2_delete() calls idle and close before freeing
181          * the device frames and buffers, we bind SYS_zero() to 
182          * make these effectively nops.  This allows us to save space
183          * by not having a special _SIO2_rmstream() function.
184          */
185         device->fxns.idle = DEV2_IDLE;
186         device->fxns.close = DEV2_CLOSE;
188         /*
189          *  WARNING!  This is used by SIO2_delete() to make sure that
190          *  it doesn't traverse the 'todevice' queue.  There's a strong
191          *  dependancy between SIO2_create() and SIO2_delete().
192          */
193         device->nbufs = 0;
195         SIO2_delete(stream);
197         /*
198          * errno could be SIO2_ENOMEM here, so we need to cover the most
199          * restrictive case for the SYS_errors[] array.  Although 0s are
200          * the wrong parameters for a SIO2_ENOMEM message, they're better
201          * than random garbage, and it's OK to pass too many for others.
202          */
203         Log_error1("SIO2_create: DEV2_open() error: %d", errno);
205         return (NULL);
206     }
208     /* device-specific open function was successful */
209     return (stream);
212 /*
213  *  ======== SIO2_delete ========
214  */
215 Int SIO2_delete(SIO2_Handle stream)
217     DEV2_Handle   device = (DEV2_Handle)stream;
218     Queue_Handle  queue;
219     DEV2_Frame   *frame;
220     Int           status;
221 #if defined(_BOTH_)
222     Int           nbufs;
223 #endif
224     status = DEV2_idle(device, stream->flush);  /* idle device(s) */
226     if (status != SIO2_OK) {
227         return (status);        /* idle failed */
228     }
230 #if defined(_BOTH_)
231     /*
232      * Pull all frames back from the device level and free them.
233      * In SIO2_ISSUERECLAIM mode, the client must call SIO2_reclaim()
234      * to get back all frames before calling SIO2_delete().
235      */
236     if (stream->model == SIO2_STANDARD) {
237         nbufs = device->nbufs - 1;
239         /*
240          * Handle the boundary case, where SIO2_delete() is called
241          * before nbufs I/O operations have occurred.
242          */
243         queue = Queue_handle(&(stream->framelist));
244         while ((frame = Queue_get(queue)) != (DEV2_Frame *)queue) {
245             DEV2_rmframe(frame, device->bufSeg, device->bufsize);
246             nbufs--;
247         }
249         /*
250          * Get any outstanding frames back and free them.
251          */
252         for (; nbufs > 0; nbufs--) {
253             status = DEV2_reclaim(device);
255             if (status != SIO2_OK) {
256                 return (status);
257             }
259             frame = Queue_get(device->fromdevice);
260             DEV2_rmframe(frame, device->bufSeg, device->bufsize);
261         }
263         /*
264          * Free the standard frame object, but not the buffer.  The
265          * application has the buffer.
266          */
267         if (stream->standardFrame) {
268             DEV2_rmframe(stream->standardFrame, 0, 0);
269         }
270     }
271     else {
272         queue = Queue_handle(&stream->framelist);
273         while ((frame = Queue_get(queue)) != (DEV2_Frame *)queue) {
274             DEV2_rmframe(frame, device->bufSeg, 0);
275         }
276     }
277 #else
278     
279     queue = Queue_handle(&stream->framelist);
280     while ((frame = Queue_get(queue)) != (DEV2_Frame *)queue) {
281         DEV2_rmframe(frame, device->bufSeg, 0);
282     }
283 #endif
284         
285     status = DEV2_close(device);                /* close device(s) */
286     if (status != SIO2_OK) {
287         return (status);
288     }
290     if (device->todevice) {
291         Queue_delete(&device->todevice);
292     }
293     if (device->fromdevice) {
294         Queue_delete(&device->fromdevice);
295     }
297     /* free stream object */
298     Memory_free(0, stream, sizeof(SIO2_Obj));
300     /* return status from idle and close (above) */
301     return (status);
304 /*
305  *  ======== SIO2_get ========
306  *
307  *  Exchange an empty buffer with a non-empty buffer from "stream".
308  *  Before: "ppbuf" points to empty buffer;
309  *  After: "ppbuf" points to non-empty buffer.
310  */
311 Int SIO2_get(SIO2_Handle stream, Ptr *ppbuf)
313     DEV2_Handle dev;
314     DEV2_Frame  *frame;
315     Int         status;
317     dev = (DEV2_Handle)stream;
319     /*
320      * This will only execute the first time SIO2_get() is called.
321      * Copy all frames from framelist to the device's todevice queue.
322      * The device is issued all empty frames the first time SIO2_get()
323      * is called.
324      */
325     while ((frame = (DEV2_Frame *)Queue_get(Queue_handle(&stream->framelist))) !=
326                 (DEV2_Frame *)&stream->framelist ) {
327         Queue_put(dev->todevice, (Queue_Elem *)frame);
328         status = DEV2_issue(dev);
329         if (status != SIO2_OK) {
330             return (status * -1);
331         }
332     }
334     frame = stream->standardFrame;
336     /* load the frame with the buffer pointed to by ppbuf */
337     frame->addr = *ppbuf;
338     frame->size = dev->bufsize;
340     /* put the frame on the todevice queue */
341     Queue_put(dev->todevice, (Queue_Elem *)frame);
343     /* send the frame to the device */
344     status = DEV2_issue(dev);
345     if (status != SIO2_OK) {
346         return (status * -1);
347     }
349     /* wait for an input frame to be available */
350     status = DEV2_reclaim(dev);
351     if (status != SIO2_OK) {
352         return (status * -1);
353     }
355     frame = (DEV2_Frame *)Queue_get(dev->fromdevice);
357     stream->standardFrame = frame;
359     *ppbuf = frame->addr;
361     return (frame->size);
364 /*
365  *  ======== _SIO2_idle ========
366  *  _SIO2_idle is called by SIO2_idle() and SIO2_flush() macros
367  */
368 Int _SIO2_idle(SIO2_Handle stream, Bool flush)
370     DEV2_Handle   device = (DEV2_Handle)stream;
371     Int           status;
372 #if defined(_BOTH_)
373     Queue_Handle  queue;
374     DEV2_Frame   *frame;
375     Int           nbufs;
376 #endif
378     status = DEV2_idle(device, flush);  /* idle device(s) */
380     if (status != SIO2_OK) {
381         return (status);
382     }
384 #if defined(_BOTH_)
385     /*
386      * For standard model, pull all frames back from the device level and
387      * put them on the stream's framelist.
388      */
389     if (stream->model == SIO2_STANDARD) {
390         nbufs = device->nbufs - 1;
392         /*
393          * Handle the boundary case, where SIO2_idle() is called
394          * before nbufs I/O operations have occurred.  Count the
395          * number of frames on the framelist.
396          */
397         queue = Queue_handle(&stream->framelist);
398         frame = Queue_head(queue);
399         while (frame != (DEV2_Frame *)queue) {
400             frame = Queue_next((Queue_Elem *)frame);
401             nbufs--;
402         }
404         /*
405          * Get any outstanding frames back from the device and
406          * put them onto the stream's framelist.
407          */
408         for (; nbufs > 0; nbufs--) {
409             if ((status = DEV2_reclaim(device)) != SIO2_OK) {
410                 return (status);
411             }
412             frame = Queue_get(device->fromdevice);
413             Queue_put(Queue_handle(&stream->framelist), (Queue_Elem *)frame);
414         }
415     }
416 #endif
418     return (SIO2_OK);
421 /*
422  *  ======== SIO2_issue ========
423  *
424  *  Send buffer "pbuf" of size "nbytes" to "stream" with arguments "arg".
425  *  Used for both input and output.  Returns to caller without blocking.
426  *
427  *  "stream" must have been created using attrs.mode = SIO2_ISSUERECLAIM.
428  */
429 Int SIO2_issue(SIO2_Handle stream, Ptr pbuf, size_t nbytes, Arg arg)
431     DEV2_Handle dev;
432     DEV2_Frame  *frame;
433     Int         status;
436     dev = (DEV2_Handle)stream;
438     /* get a valid frame from the stream's framelist queue or return error */
439     frame = (DEV2_Frame *)Queue_get(Queue_handle(&stream->framelist));
440     if (frame == (DEV2_Frame *)&stream->framelist) {
441         return (DEV2_EBADIO);
442     }
444     /* load the frame with the buffer pointed to by pbuf */
445     frame->addr = pbuf;
446     frame->size = nbytes;
447     frame->arg = arg;
449     /* put the frame on the todevice queue */
450     Queue_put(dev->todevice, (Queue_Elem *)frame);
452     /* call the device's issue function to send the buffer to the stream */
453     status = DEV2_issue(dev);
455     return (status);
458 /*
459  *  ======== SIO2_put ========
460  * 
461  *  Exchange a non-empty buffer "buf" of size "nbytes" with an empty buffer 
462  *  from "stream".
463  *  Before: "ppbuf" points to non-empty buffer;
464  *  After: "ppbuf" points to empty buffer.
465  *
466  */
467 Int SIO2_put(SIO2_Handle stream, Ptr *ppbuf, size_t nbytes)
469     DEV2_Handle dev;
470     DEV2_Frame  *frame;
471     Int         status;
473     dev = (DEV2_Handle)stream;
474     frame = stream->standardFrame;
475     frame->size = nbytes;
476     frame->addr = *ppbuf;
478     Queue_put(dev->todevice, (Queue_Elem *)frame);
480     DEV2_issue(dev);
482     if ( (frame = (DEV2_Frame *)Queue_get(Queue_handle(&stream->framelist))) !=
483                 (DEV2_Frame *)&stream->framelist ) {
485         /* free frame is available -- no need to call DEV2_reclaim() */
486         stream->standardFrame = frame;
487     }
488     else {
490         /* reclaim frame from device */
491         status = DEV2_reclaim(dev);
492         if (status != SIO2_OK) {
493             return (status * -1);
494         }
496         frame = (DEV2_Frame *)Queue_get(dev->fromdevice);
497         stream->standardFrame = frame;
498     }
500     *ppbuf = frame->addr;
502     return (frame->size);
505 /*
506  *  ======== SIO2_reclaimx ========
507  *
508  *  Extended version of SIO2_reclaim().  Identical to SIO2_reclaim() but adds
509  *  new parameter that will return the frame status field.  This allows the 
510  *  IOM driver to pass frame-specific status information up to the application.
511  *
512  *  Applications still check return value of SIO2_reclaimx() (< 0 for error),
513  *  and >= 0 for success (frame size).
514  *
515  *  See SDSsq41555 for more.
516  */
517 Int SIO2_reclaimx(SIO2_Handle stream, Ptr *ppbuf, Arg *parg, Int *pfstatus)
519     DEV2_Handle dev;
520     DEV2_Frame  *frame;
521     size_t      size;
522     Int         status;
524     dev = (DEV2_Handle)stream;
526     status = DEV2_reclaim(dev);
528     if (status == SIO2_OK) {
529         frame = (DEV2_Frame *)Queue_get(dev->fromdevice);
531         *ppbuf = frame->addr;
533         if (parg != NULL) {
534             *parg = frame->arg;
535         }
537         if (pfstatus != NULL) {
538             *pfstatus = frame->status;
539         }
541         size = frame->size;
543         /*
544          * Return frame to free list (size saved above for return).
545          */
546         frame->size = 0;
547         Queue_put(Queue_handle(&stream->framelist), (Queue_Elem *)frame);
549         return (size);
550     }
551     else {
552         return (status * -1);
553     }
556 /*
557  * ======== SIO2_reclaim ========
558  */
559 Int SIO2_reclaim(SIO2_Handle stream, Ptr *ppbuf, Arg *parg)
561     DEV2_Handle dev;
562     DEV2_Frame  *frame;
563     size_t      size;
564     Int         status;
566     dev = (DEV2_Handle)stream;
568     status = DEV2_reclaim(dev);
570     if (status == SIO2_OK) {
571         frame = (DEV2_Frame *)Queue_get(dev->fromdevice);
573         *ppbuf = frame->addr;
574         if (parg != NULL) {
575             *parg = frame->arg;
576         }
577         size = frame->size;
579         /*
580          * Return frame to free list (size saved above for return).
581          */
582         frame->size = 0;
583         Queue_put(Queue_handle(&stream->framelist), (Queue_Elem *)frame);
585         return (size);
586     }
587     else {
588         return (status * -1);
589     }
592 /*
593  *  ======== SIO2_select ========
594  */
595 Uns SIO2_select(SIO2_Handle streamtab[], Int n, Uns timeout)
597     Int               i;
598     Uns               mask = 1;
599     Uns               ready = 0;
600     Semaphore_Struct  sem;            /* local variable on stack! */
601     Semaphore_Params  semParams;
602     SIO2_Handle      *stream;
603 #if defined(_BOTH_)
604     DEV2_Frame       *frame;
605 #endif
607     Semaphore_Params_init(&semParams);
608     semParams.mode = Semaphore_Mode_BINARY;
609     Semaphore_construct(&sem, 0, &semParams);
611     stream = streamtab;
613     for (i = n; i > 0; i--, stream++) {
615 #if defined(_BOTH_)
616         if ( (*stream)->model == SIO2_STANDARD ) {
617             if ((*stream)->dobj.mode == DEV2_INPUT) {
618                 /* 
619                  * Make sure input device has been primed and started.  This
620                  * is typically done by SIO2_get() but it is possible for
621                  * SIO2_select() to be called before SIO2_get().  This code is
622                  * identical to the code in SIO2_get() -- it may make sense to
623                  * make this loop into a separate function (_SIO2_primeget()?)
624                  * to save code space.
625                  */
626                 while ( (frame = (DEV2_Frame *)Queue_get(Queue_handle(
627                              &(*stream)->framelist))) !=
628                         (DEV2_Frame *)&(*stream)->framelist ) {
629                     Queue_put((*stream)->dobj.todevice, (Queue_Elem *)frame);
630                     DEV2_issue((DEV2_Handle)*stream);
631         
632                     /* what can we do if DEV2_issue fails? */
633                 }
634             }
635             else {
636                 /*
637                  * Initial calls to SIO2_put() pull frames from the stream's
638                  * framelist instead of calling DEV2_reclaim().  Frames are
639                  * never put back onto framelist in SIO2_STANDARD model.
640                  */
641                 if (!Queue_empty(Queue_handle(&(*stream)->framelist))) {
642                     ready = 1;
643                 }
644             }
645         }
646 #endif
648         /* see if device is ready and register call back */
649         if (DEV2_ready((DEV2_Handle)*stream, Semaphore_handle(&sem))) {
650             ready = 1;
651         }
652     }
654     if (!ready) {
655         /* wait until device is ready */
656         Semaphore_pend(Semaphore_handle(&sem), timeout);
657     }
659     ready = 0;
661     stream = streamtab;
663     for (i = n; i > 0; i--, stream++) {
664         /* see if device is ready and un-register call back */
665         if (DEV2_ready((DEV2_Handle)*stream, NULL)) {
666             ready |= mask;
667         }
669 #if defined(_BOTH_)
670         else {
671             /*
672              * This will only be true for DEV2_OUTPUT mode.
673              * We don't need to check if mode == DEV2_OUTPUT here since
674              * framelist will have been emptied for DEV2_INPUT mode (above).
675              */
676             if ( ((*stream)->model == SIO2_STANDARD) &&
677                         (!Queue_empty(Queue_handle(&(*stream)->framelist))) ) {
678                 ready |= mask;
679             }
680         }
681 #endif
683         mask = mask << 1;
684     }
686     return (ready);
689 /*
690  *  ======== SIO2_staticbuf ========
691  *  Return static buffer created for gconf streams.
692  *
693  *  The SIO2_Obj macro puts all static frames on 'stream->framelist'.
694  *
695  *  Returns 0 if no static buffer exists.
696  *  SIO2_staticbuf can only be called once for each static buffer.
697  */
698 Int SIO2_staticbuf(SIO2_Handle stream, Ptr *ppbuf)
700     DEV2_Frame  *frame;
701     Int         size;
702 #if defined(_BOTH_)
703     if (stream->model == SIO2_STANDARD) {
704         frame = stream->standardFrame;
706         size = frame->size;
707         frame->size = 0;
709         *ppbuf = frame->addr;
710     }
711     else {
712         frame = Queue_get(Queue_handle(&stream->framelist));
714         size = frame->size;
715         frame->size = 0;
717         *ppbuf = frame->addr;
719         Queue_put(Queue_handle(&stream->framelist), (Queue_Elem *)frame);
720     }
721 #else
723     frame = Queue_get(Queue_handle(&stream->framelist));
725     size = frame->size;
726     frame->size = 0;
728     *ppbuf = frame->addr;
730     Queue_put(Queue_handle(&stream->framelist), frame);
732 #endif
734     return (size);