]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - mfp/cedev.git/blob - packages/ti/sdo/ce/speech1/sphenc1_stubs.c
BIOS: Initial commit of BIOS-only content
[mfp/cedev.git] / packages / ti / sdo / ce / speech1 / sphenc1_stubs.c
1 /*
2  * Copyright (c) 2013, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 /*
34  *  ======== sphenc1_stubs.c ========
35  *  This file contains an implemenation of the ISPHENC1 interface for the
36  *  speech encoder class of algorithms.
37  *
38  *  These functions are the "client-side" of a "remote" implementation.
39  *
40  */
42 /* This define must precede inclusion of any xdc header files */
43 #define Registry_CURDESC ti_sdo_ce_speech1_sphenc1_desc
45 #include <xdc/std.h>
46 #include <xdc/runtime/Assert.h>
47 #include <xdc/runtime/Diags.h>
48 #include <xdc/runtime/Log.h>
49 #include <xdc/runtime/Registry.h>
51 #include <ti/sdo/ce/visa.h>
52 #include <ti/xdais/dm/isphenc1.h>
53 #include <ti/sdo/ce/osal/Memory.h>
55 #include <string.h>  /* for memcpy and memset. */
57 #include "sphenc1.h"
58 #include "_sphenc1.h"
60 extern Registry_Desc ti_sdo_ce_speech1_sphenc1_desc;
63 static XDAS_Int32 process(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
64     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
65     ISPHENC1_OutArgs *outArgs);
66 static XDAS_Int32 processAsync(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
67     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
68     ISPHENC1_OutArgs *outArgs);
69 static XDAS_Int32 processWait(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
70     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
71     ISPHENC1_OutArgs *outArgs, UInt timeout);
72 static XDAS_Int32 control(ISPHENC1_Handle h, ISPHENC1_Cmd id,
73     ISPHENC1_DynamicParams *params, ISPHENC1_Status *status);
74 static XDAS_Int32 marshallMsg(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
75     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
76     ISPHENC1_OutArgs *outArgs, _SPHENC1_Msg **pmsg);
77 static Void unmarshallMsg(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
78     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
79     ISPHENC1_OutArgs *outArgs, _SPHENC1_Msg *msg);
82 ISPHENC1_Fxns SPHENC1_STUBS = {
83     {&SPHENC1_STUBS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
84     process, control,
85 };
88 /*
89  *  ======== marshallMsg ========
90  */
91 static XDAS_Int32 marshallMsg(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
92     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
93     ISPHENC1_OutArgs *outArgs, _SPHENC1_Msg **pmsg)
94 {
95     XDAS_Int32 retVal = ISPHENC1_EOK;
96     VISA_Handle visa = (VISA_Handle)h;
97     _SPHENC1_Msg *msg;
98     ISPHENC1_OutArgs *pMsgOutArgs;
99     Int payloadSize;
101     /*
102      * Validate arguments.  Do we want to do this _every_ time, or just in
103      * checked builds?
104      */
105     if ((inArgs == NULL) || (inArgs->size < sizeof(ISPHENC1_InArgs)) ||
106             (outArgs == NULL) || (outArgs->size < sizeof(ISPHENC1_OutArgs))) {
108         /* invalid args, could even assert here, it's a spec violation. */
109         return (SPHENC1_EFAIL);
110     }
112     if (pmsg == NULL) {
113         return (SPHENC1_EFAIL);
114     }
116     /* make sure it'll all fit! */
117     payloadSize = sizeof(VISA_MsgHeader) + sizeof(*inBuf) + sizeof(*outBuf) +
118             inArgs->size + outArgs->size;
120     if (payloadSize > VISA_getMaxMsgSize(visa)) {
121         /* Can't handle these large extended args. */
122         Log_print2(Diags_USER6,
123                 "[+6] process> invalid arguments - too big (0x%x > 0x%x).  "
124                 "Validate .size fields", payloadSize,
125                 VISA_getMaxMsgSize(visa));
127         return (SPHENC1_EUNSUPPORTED);
128     }
130     /* get a message appropriate for this algorithm */
131     if ((msg = (_SPHENC1_Msg *)VISA_allocMsg(visa)) == NULL) {
132         return (ISPHENC1_EFAIL);
133     }
135     /* zero out msg->cmd (not msg->visa!) */
136     memset(&(msg->cmd), 0, sizeof(msg->cmd));
138     /*
139      * Marshall the command: copy the client-passed arguments into flattened
140      * message data structures, converting every pointer address to alg.
141      * data buffer into physical address.
142      */
144     /* First specify the processing command that the skeleton should do */
145     msg->visa.cmd = _SPHENC1_CPROCESS;
147     /* commentary follows for marshalling the inBuf argument: */
149     /* 1) inBuf->bufSize is an integer, just copy it */
150     msg->cmd.process.inBuf.bufSize = inBuf->bufSize;
152     /*
153      * 2) inBuf->buf is a pointer, so we convert it and store it
154      * in the message
155      */
156     msg->cmd.process.inBuf.buf = (XDAS_Int8 *)
157         Memory_getBufferPhysicalAddress(inBuf->buf,
158             inBuf->bufSize, NULL);
160     if (msg->cmd.process.inBuf.buf == NULL) {
161         retVal = SPHENC1_EFAIL;
162         goto exit;
163     }
165     /* Clear .accessMask; the local processor won't access this buf */
166     inBuf->accessMask = 0;
168     /* we're done (with inBuf).  Because msg->cmd.process is non-cacheable
169      * and contiguous (it has been allocated by MSGQ), we don't have to do
170      * anything else.
171      */
173     /* Now we repeat the procedure for outBuf. Note that
174      * inArgs and outArgs contain no pointers, so we can simply copy the
175      * entire original structure.
176      */
177     msg->cmd.process.outBuf.bufSize = outBuf->bufSize;
179     msg->cmd.process.outBuf.buf = (XDAS_Int8 *)
180         Memory_getBufferPhysicalAddress(outBuf->buf, outBuf->bufSize, NULL);
182     if (msg->cmd.process.outBuf.buf == NULL) {
183         retVal = SPHENC1_EFAIL;
184         goto exit;
185     }
187     /* Clear .accessMask; the local processor won't access this buf */
188     outBuf->accessMask = 0;
190     /* inArgs has a pointer.  First, blindly copy all inArgs into the msg... */
191     memcpy(&(msg->cmd.process.inArgs), inArgs, inArgs->size);
193     /* ... then translate the single pointer if necessary */
194     if (inArgs->data.buf != NULL) {
195         msg->cmd.process.inArgs.data.buf = (XDAS_Int8 *)
196             Memory_getBufferPhysicalAddress(inArgs->data.buf,
197                 inArgs->data.bufSize, NULL);
198         if (msg->cmd.process.inArgs.data.buf == NULL) {
199             retVal = ISPHENC1_EFAIL;
200             goto exit;
201         }
203         /* Clear .accessMask; the local processor won't access this buf */
204         inArgs->data.accessMask = 0;
205     }
207     /* point at outArgs and set the "size" */
208     pMsgOutArgs = (ISPHENC1_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) +
209         inArgs->size);
211     /* set the size field - the rest is filled in by the codec */
212     pMsgOutArgs->size = outArgs->size;
214     *pmsg = msg;
216     return retVal;
218 exit:
219     VISA_freeMsg(visa, (VISA_Msg)msg);
221     return retVal;
224 /*
225  *  ======== unmarshallMsg ========
226  */
227 static Void unmarshallMsg(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
228     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
229     ISPHENC1_OutArgs *outArgs, _SPHENC1_Msg *msg)
231     VISA_Handle visa = (VISA_Handle)h;
232     ISPHENC1_OutArgs *pMsgOutArgs;
234     /* Do a wholesale replace of skeleton returned structure. */
235     pMsgOutArgs = (ISPHENC1_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) +
236         inArgs->size);
238     if (VISA_isChecked()) {
239         /* ensure the codec didn't change outArgs->size */
240         Assert_isTrue(pMsgOutArgs->size == outArgs->size, (Assert_Id)NULL);
241     }
243     memcpy(outArgs, pMsgOutArgs, outArgs->size);
245     /* outBuf->bufSize is an _out_ field (set by the alg) so copy it here. */
246     outBuf->bufSize = msg->cmd.process.outBuf.bufSize;
248     /*
249      * Note, we can keep the original outBuf, since the caller's
250      * outBuf already contains the virtual buffer pointers.
251      *
252      * Note also that we did *nothing* with inBuf nor inArgs.
253      *
254      * Note also that we _don't_ update inBuf->accessMask
255      * or inArgs->data.accessMask.
256      * That's accurate, since the local processor  _didn't_
257      * access these buffers.
258      */
260     VISA_freeMsg(visa, (VISA_Msg)msg);
262     return;
265 /*
266  *  ======== process ========
267  *  This is the sync stub-implementation for the process method
268  */
269 static XDAS_Int32 process(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
270     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
271     ISPHENC1_OutArgs *outArgs)
273     XDAS_Int32 retVal;
274     _SPHENC1_Msg *msg;
275     VISA_Handle visa = (VISA_Handle)h;
277     retVal = marshallMsg(h, inBuf, outBuf, inArgs, outArgs, &msg);
278     if (retVal != ISPHENC1_EOK) {
279         return (retVal);
280     }
282     /* send the message to the skeleton and wait for completion */
283     retVal = VISA_call(visa, (VISA_Msg *)&msg);
285     /* Regardless of return value, unmarshall outArgs. */
286     unmarshallMsg(h, inBuf, outBuf, inArgs, outArgs, msg);
288     return (retVal);
291 /*
292  *  ======== processAsync ========
293  *  This is the async stub-implementation for the process method
294  */
295 static XDAS_Int32 processAsync(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
296     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
297     ISPHENC1_OutArgs *outArgs)
299     XDAS_Int32 retVal;
300     _SPHENC1_Msg *msg;
301     VISA_Handle visa = (VISA_Handle)h;
303     retVal = marshallMsg(h, inBuf, outBuf, inArgs, outArgs, &msg);
304     if (retVal != ISPHENC1_EOK) {
305         return retVal;
306     }
308     /* send the message to the skeleton without waiting for completion */
309     retVal = VISA_callAsync(visa, (VISA_Msg *)&msg);
311     return (retVal);
314 /*
315  *  ======== processWait ========
316  */
317 static XDAS_Int32 processWait(ISPHENC1_Handle h, XDM1_SingleBufDesc *inBuf,
318     XDM1_SingleBufDesc *outBuf, ISPHENC1_InArgs *inArgs,
319     ISPHENC1_OutArgs *outArgs, UInt timeout)
321     XDAS_Int32 retVal;
322     _SPHENC1_Msg *msg;
323     VISA_Handle visa = (VISA_Handle)h;
325     Assert_isTrue(!VISA_isLocal(visa), (Assert_Id)NULL);
327     /* wait for completion of "last" message */
328     retVal = VISA_wait(visa, (VISA_Msg *)&msg, timeout);
330     /* Unmarshall outArgs if there is a msg to unmarshall. */
331     if (msg != NULL) {
332         Assert_isTrue(msg->visa.cmd == _SPHENC1_CPROCESS, (Assert_Id)NULL);
334         unmarshallMsg(h, inBuf, outBuf, inArgs, outArgs, msg);
335     }
337     return (retVal);
340 /*
341  *  ======== control ========
342  *  This is the stub-implementation for the control method
343  */
344 static XDAS_Int32 control(ISPHENC1_Handle h, ISPHENC1_Cmd id,
345          ISPHENC1_DynamicParams *params, ISPHENC1_Status *status)
347     XDAS_Int32 retVal;
348     VISA_Handle visa = (VISA_Handle)h;
349     _SPHENC1_Msg *msg;
350     ISPHENC1_Status *pMsgStatus;
351     XDAS_Int8 *virtAddr = NULL;
352     Int payloadSize;
354     /*
355      * Validate arguments.  Do we want to do this _every_ time, or just in
356      * checked builds?
357      */
358     if ((params == NULL) || (params->size < sizeof(ISPHENC1_DynamicParams)) ||
359             (status == NULL) || (status->size < sizeof(ISPHENC1_Status))) {
361         /* invalid args, could even assert here, it's a spec violation. */
362         return (SPHENC1_EFAIL);
363     }
365     /*
366      * Initialize extendedError to zero so we don't return something
367      * uninitialized in extendedError.
368      */
369     status->extendedError = 0;
371     /* make sure it'll all fit! */
372     payloadSize = sizeof(VISA_MsgHeader) + sizeof(id) + params->size +
373             status->size;
375     if (payloadSize > VISA_getMaxMsgSize(visa)) {
376         /* Can't handle these large extended args. */
377         Log_print2(Diags_USER6,
378                 "[+6] control> invalid arguments - too big (0x%x > 0x%x).  "
379                 "Validate .size fields", payloadSize,
380                 VISA_getMaxMsgSize(visa));
382         return (SPHENC1_EUNSUPPORTED);
383     }
385     /* get a message appropriate for this algorithm */
386     if ((msg = (_SPHENC1_Msg *)VISA_allocMsg(visa)) == NULL) {
387         return (ISPHENC1_EFAIL);
388     }
390     /* marshall the command */
391     msg->visa.cmd = _SPHENC1_CCONTROL;
393     msg->cmd.control.id = id;
395     /* params has no pointers so simply memcpy "size" bytes into the msg */
396     memcpy(&(msg->cmd.control.params), params, params->size);
398     /* unmarshall status based on the "size" of params */
399     pMsgStatus = (ISPHENC1_Status *)((UInt)(&(msg->cmd.control.params)) +
400         params->size);
402     /*
403      * Initialize the .size and .data fields - the rest are filled in by
404      * the codec.
405      */
406     pMsgStatus->size = status->size;
408     if (status->data.buf != NULL) {
409         pMsgStatus->data.bufSize = status->data.bufSize;
411         /* save it for later */
412         virtAddr = status->data.buf;
414         pMsgStatus->data.buf = (XDAS_Int8 *)
415             Memory_getBufferPhysicalAddress(status->data.buf,
416                 status->data.bufSize, NULL);
418         if (pMsgStatus->data.buf == NULL) {
419             retVal = ISPHENC1_EFAIL;
420             goto exit;
421         }
422     }
423     else {
424         /* Place null into the msg so the skel knows it's invalid */
425         pMsgStatus->data.buf = NULL;
426     }
428     /* send the message to the skeleton and wait for completion */
429     retVal = VISA_call(visa, (VISA_Msg *)&msg);
431     /* ensure we get CCONTROL msg (ensure async CPROCESS pipeline drained) */
432     Assert_isTrue(msg->visa.cmd == _SPHENC1_CCONTROL, (Assert_Id)NULL);
434     /* unmarshall status */
435     pMsgStatus = (ISPHENC1_Status *)((UInt)(&(msg->cmd.control.params)) +
436         params->size);
438     if (VISA_isChecked()) {
439         /* ensure codec didn't modify status->size */
440         Assert_isTrue(pMsgStatus->size == status->size, (Assert_Id)NULL);
442         /*
443          * TODO:L  Should we also check that pMsgStatus->data.buf is the same
444          * after the call as before?
445          */
446     }
448     memcpy(status, pMsgStatus, status->size);
450     /*
451      * And finally, restore status->data.buf to its original value.  Note that
452      * this works even when status->data.buf was NULL because virtAddr is
453      * initialized to NULL.
454      *
455      * While potentially more confusing, this is just as correct as
456      * (and faster than!) calling Memory_getVirtualBuffer().
457      */
458     status->data.buf = virtAddr;
460     /* Clear .accessMask; the local processor didn't access the buffer */
461     status->data.accessMask = 0;
463 exit:
464     VISA_freeMsg(visa, (VISA_Msg)msg);
466     return (retVal);
469 /*
470  *  ======== SPHENC1_processAsync ========
471  */
472 XDAS_Int32 SPHENC1_processAsync(SPHENC1_Handle handle,
473     XDM1_SingleBufDesc *inBuf, XDM1_SingleBufDesc *outBuf,
474     SPHENC1_InArgs *inArgs, SPHENC1_OutArgs *outArgs)
476     XDAS_Int32 retVal = SPHENC1_EFAIL;
478     /*
479      * Note, we do this because someday we may allow dynamically changing
480      * the global 'VISA_isChecked()' value on the fly.  If we allow that,
481      * we need to ensure the value stays consistent in the context of this call.
482      */
483     Bool checked = VISA_isChecked();
485     Log_print5(Diags_ENTRY, "[+E] SPHENC1_processAsync> "
486             "Enter (handle=0x%x, inBuf=0x%x, outBuf=0x%x, inArgs=0x%x, "
487             "outArgs=0x%x)",
488             (IArg)handle, (IArg)inBuf, (IArg)outBuf, (IArg)inArgs,
489             (IArg)outArgs);
491     if (handle) {
492         ISPHENC1_Handle alg = VISA_getAlgHandle((VISA_Handle)handle);
494         if (alg != NULL) {
495             if (checked) {
497 #if 0 /* Most will complain at this.  It's probably a different check level */
498                 /* validate inArgs with ranges. */
499                 if ((inArgs->nullTrafficChannel != ISPEECH1_NULLTRAFFICMODE_OFF)
500                     && (inArgs->nullTrafficChannel !=
501                         ISPEECH1_NULLTRAFFICMODE_ON)) {
503                     Log_print2(Diags_USER7,
504                             "[+7] ERROR> app provided codec (0x%x) with out of range "
505                             "inArgs->nullTrafficChannel field (0x%x)",
506                             (IArg)alg, (IArg)(inArgs->nullTrafficChannel));
507                 }
508 #endif
510                 /*
511                  * Zero out the outArgs struct (except for .size field);
512                  * it's write-only to the codec, so the app shouldn't pass
513                  * values through it, nor should the codec expect to
514                  * receive values through it.
515                  */
516                 memset((void *)((XDAS_Int32)(outArgs) + sizeof(outArgs->size)),
517                     0, (sizeof(*outArgs) - sizeof(outArgs->size)));
518             }
520             retVal = processAsync(alg, inBuf, outBuf, inArgs, outArgs);
522             if (checked) {
523 #if 0 /* Most will complain at this.  It's probably a different check level */
524                 /* validate outArgs with ranges. */
525                 if ((outArgs->frameType != ISPHENC1_FTYPE_SPEECH)
526                     && (outArgs->frameType != ISPHENC1_FTYPE_SIDFRAME)
527                     && (outArgs->frameType != ISPHENC1_FTYPE_NODATA)) {
529                     Log_print2(Diags_USER7,
530                             "[+7] ERROR> codec (0x%x) provided out of range "
531                             "outArgs->frameType (0x%x)",
532                             (IArg)alg, (IArg)(outArgs->frameType));
533                 }
534 #endif
535             }
536         }
537     }
539     Log_print2(Diags_EXIT, "[+X] SPHENC1_processAsync> "
540             "Exit (handle=0x%x, retVal=0x%x)", (IArg)handle, (IArg)retVal);
542     return retVal;
546 /*
547  *  ======== SPHENC1_processWait ========
548  */
549 XDAS_Int32 SPHENC1_processWait(SPHENC1_Handle handle,
550     XDM1_SingleBufDesc *inBuf, XDM1_SingleBufDesc *outBuf,
551     SPHENC1_InArgs *inArgs, SPHENC1_OutArgs *outArgs, UInt timeout)
553     XDAS_Int32 retVal = SPHENC1_EFAIL;
554     SPHENC1_InArgs refInArgs;
556     /*
557      * Note, we do this because someday we may allow dynamically changing
558      * the global 'VISA_isChecked()' value on the fly.  If we allow that,
559      * we need to ensure the value stays consistent in the context of this call.
560      */
561     Bool checked = VISA_isChecked();
563     Log_print5(Diags_ENTRY, "[+E] SPHENC1_processWait> "
564             "Enter (handle=0x%x, inBuf=0x%x, outBuf=0x%x, inArgs=0x%x, "
565             "outArgs=0x%x)",
566             (IArg)handle, (IArg)inBuf, (IArg)outBuf, (IArg)inArgs,
567             (IArg)outArgs);
569     if (handle) {
570         ISPHENC1_Handle alg = VISA_getAlgHandle((VISA_Handle)handle);
572         if (alg != NULL) {
573             if (checked) {
574                 /*
575                  * Make a reference copy of inArgs so we can check that
576                  * the codec didn't modify them during process().
577                  */
578                 refInArgs = *inArgs;
579             }
581             retVal = processWait(alg, inBuf, outBuf, inArgs, outArgs,
582                     timeout);
584             if (checked) {
585                 /* ensure the codec didn't modify the read-only inArgs */
586                 if (memcmp(&refInArgs, inArgs, sizeof(*inArgs)) != 0) {
587                     Log_print1(Diags_USER7,
588                             "[+7] ERROR> codec (0x%x) modified read-only inArgs "
589                             "struct!", (IArg)alg);
590                 }
591             }
592         }
593     }
595     Log_print2(Diags_EXIT, "[+X] SPHENC1_processWait> "
596             "Exit (handle=0x%x, retVal=0x%x)", (IArg)handle, (IArg)retVal);
598     return retVal;