/*
 *  ======== process ========
 *  This is the stub-implementation for the process method
 */
static XDAS_Int32 process(ISCALE_Handle h, XDAS_Int8 *inBuf,
    XDAS_Int8 *outBuf, ISCALE_InArgs *inArgs, ISCALE_OutArgs *outArgs)
{
    XDAS_Int32 retVal;
    VISA_Handle visa = (VISA_Handle)h;
    _SCALE_Msg *msg;

    /* get a message appropriate for this algorithm */
    if ((msg = (_SCALE_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (SCALE_ERUNTIME);
    }

    /* Specify the processing command that the skeleton should do */
    msg->visa.cmd = _SCALE_CPROCESS;

    /* inBuf is a pointer, so we have to convert it */
    msg->cmd.process.inBuf = (XDAS_Int8 *)
        Memory_getBufferPhysicalAddress(inBuf, inArgs->inBufSize, NULL);

    if (msg->cmd.process.inBuf == NULL) {
        retVal = SCALE_ERUNTIME;
        goto exit;
    }

    /* Similarly with outBuf. Note that inArgs and outArgs contain no
     * pointers, so we can simply copy the entire original structure.
     */
    msg->cmd.process.outBuf = (XDAS_Int8 *)
        Memory_getBufferPhysicalAddress(outBuf, inArgs->outBufSize, NULL);

    if (msg->cmd.process.outBuf == NULL) {
        retVal = SCALE_ERUNTIME;
        goto exit;
    }

    /* inArgs has no pointers, so simply copy the struct fields into the msg */
    msg->cmd.process.inArgs = *inArgs;

    /* Note that outArgs is *output* and need not be provided to the skel */

    /* send the message to the skeleton and wait for completion */
    retVal = VISA_call(visa, (VISA_Msg *)&msg);

    /* copy out the outArgs */
    *outArgs = msg->cmd.process.outArgs;

    /* Note that we need not copy inArgs out of the msg. */

    /*
     * Note that we don't have to do any reverse address translation, as the
     * originally provided buffers haven't changed.
     */

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
static int copySparseSingleBufDescArrayWithV2P(XDM1_SingleBufDesc *pDest,
    XDM1_SingleBufDesc *pSrc, XDAS_Int32 numBufs, XDAS_Int32 maxBufs)
{
    int i, foundBufs;

    for (i = 0, foundBufs = 0; ((foundBufs < numBufs) && (i < maxBufs)); i++) {
        if (pSrc[i].buf != NULL) {
            /* valid member of sparse array, convert it */
            pDest[i].bufSize =pSrc[i].bufSize;

            pDest[i].buf = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(pSrc[i].buf, pSrc[i].bufSize,
                    NULL);

            if (pDest[i].buf == NULL) {
                foundBufs = -1;
                break;
            }

            /* Clear .accessMask; the local processor won't access this buf */
            pDest[i].accessMask = 0;

            /* found, and handled, another buffer. */
            foundBufs++;
        }
        else {
            /* empty member of sparse array, no conversion needed. */
            pDest[i].bufSize = 0;
            pDest[i].buf = NULL;
        }
    }

    return (foundBufs);
}
示例#3
0
/******************************************************************************
 * Buffer_create
 ******************************************************************************/
Buffer_Handle Buffer_create(Int32 size, Buffer_Attrs *attrs)
{
    Buffer_Handle hBuf;
    UInt32        objSize;

    if (attrs == NULL) {
        Dmai_err0("Must provide attrs\n");
        return NULL;
    }

    if (attrs->type != Buffer_Type_BASIC &&
        attrs->type != Buffer_Type_GRAPHICS) {

        Dmai_err1("Unknown Buffer type (%d)\n", attrs->type);
        return NULL;
    }

    objSize = attrs->type == Buffer_Type_GRAPHICS ? sizeof(_BufferGfx_Object) :
                                                    sizeof(_Buffer_Object);

    hBuf = (Buffer_Handle) calloc(1, objSize);

    if (hBuf == NULL) {
        Dmai_err0("Failed to allocate space for Buffer Object\n");
        return NULL;
    }

    _Buffer_init(hBuf, size, attrs);

    if (!attrs->reference) {
        hBuf->userPtr = (Int8*)Memory_alloc(size, &attrs->memParams);

        if (hBuf->userPtr == NULL) {
            printf("Failed to allocate memory.\n");
            free(hBuf);
            return NULL;
        }

        hBuf->physPtr = Memory_getBufferPhysicalAddress(hBuf->userPtr,
                                                        size, NULL);

        Dmai_dbg3("Alloc Buffer of size %u at 0x%x (0x%x phys)\n",
                  (Uns) size, (Uns) hBuf->userPtr, (Uns) hBuf->physPtr);
    }

    hBuf->reference = attrs->reference;

    return hBuf;
}
示例#4
0
/*
 *  ======== ceapp_allocContigBuf ========
 */
char *ceapp_allocContigBuf(int bufSize, char *description)
{
    char *buf;

    printf("CEapp-> Allocating contiguous buffer for '%s' of size %d...\n",
            description, bufSize);

    buf = (char *)Memory_contigAlloc(bufSize, Memory_DEFAULTALIGNMENT);

    if (buf == NULL) {
        printf("CEapp-> ERROR: Failed to allocate contiguous memory block.\n");
    }
    else {
        printf("CEapp-> Contiguous buffer allocated OK (phys. addr=0x%x)\n",
            (int)Memory_getBufferPhysicalAddress(buf, bufSize, NULL));
    }
    return buf;
}
示例#5
0
/******************************************************************************
 * Buffer_setUserPtr
 ******************************************************************************/
Int Buffer_setUserPtr(Buffer_Handle hBuf, Int8 *ptr)
{
    assert(hBuf);

    if (!hBuf->reference) {
        return Dmai_EINVAL;
    }

    hBuf->userPtr = ptr;

    if (ptr) {
        hBuf->physPtr = Memory_getBufferPhysicalAddress(hBuf->userPtr, 4, NULL);
    }
    else {
        hBuf->physPtr = 0;
    }

    Dmai_dbg2("Set user pointer 0x%x (physical 0x%x)\n",
              (Uns) hBuf->userPtr, (Uns) hBuf->physPtr);

    return Dmai_EOK;
}
static int copySingleBufDescArrayWithV2P(XDM1_SingleBufDesc *pDest,
    XDM1_SingleBufDesc *pSrc, XDAS_Int32 maxBufs)
{
    int i;

    for (i = 0; (i < maxBufs) && (pSrc[i].buf != NULL); i++) {
        /* found another, convert it */
        pDest[i].bufSize = pSrc[i].bufSize;

        pDest[i].buf = (XDAS_Int8 *)
            Memory_getBufferPhysicalAddress(pSrc[i].buf, pSrc[i].bufSize,
                    NULL);

        if (pDest[i].buf == NULL) {
            i = -1;
            break;
        }

        /* Clear .accessMask; the local processor won't access this buf */
        pDest[i].accessMask = 0;
    }

    return (i);
}
/*
 *  ======== marshallMsg ========
 */
static XDAS_Int32 marshallMsg(IAUDDEC_Handle h, XDM_BufDesc *inBufs,
    XDM_BufDesc *outBufs, IAUDDEC_InArgs *inArgs, IAUDDEC_OutArgs *outArgs,
    _AUDDEC_Msg **pmsg)
{
    XDAS_Int32 retVal = IAUDDEC_EOK;
    VISA_Handle visa = (VISA_Handle)h;
    _AUDDEC_Msg *msg;
    Int i;
    IAUDDEC_OutArgs *pMsgOutArgs;
    Int payloadSize;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((inArgs == NULL) || (inArgs->size < sizeof(IAUDDEC_InArgs)) ||
            (outArgs == NULL) || (outArgs->size < sizeof(IAUDDEC_OutArgs))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (AUDDEC_EFAIL);
    }

    /*
     * Initialize extendedError to zero so we don't return something
     * uninitialized in extendedError.
     */
    outArgs->extendedError = 0;

    if (pmsg == NULL) {
        return (AUDDEC_EFAIL);
    }

    /* make sure it'll all fit! */
    payloadSize = sizeof(VISA_MsgHeader) +
            (sizeof(msg->cmd.process.inBufs) * XDM_MAX_IO_BUFFERS) +
            sizeof(msg->cmd.process.numInBufs) +
            (sizeof(msg->cmd.process.inBufSizes[0]) * XDM_MAX_IO_BUFFERS) +
            (sizeof(msg->cmd.process.outBufs) * XDM_MAX_IO_BUFFERS) +
            sizeof(msg->cmd.process.numOutBufs) +
            (sizeof(msg->cmd.process.outBufSizes[0]) * XDM_MAX_IO_BUFFERS) +
            inArgs->size + outArgs->size;

    if (payloadSize > VISA_getMaxMsgSize(visa)) {
        /* Can't handle these large extended args. */
        Log_print2(Diags_USER6,
                "[+6] process> invalid arguments - too big (0x%x > 0x%x).  "
                "Validate .size fields", payloadSize,
                VISA_getMaxMsgSize(visa));

        return (IAUDDEC_EFAIL);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_AUDDEC_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IAUDDEC_ERUNTIME);
    }

    /*
     * Marshall the command: copy the client-passed arguments into flattened
     * message data structures, converting every pointer address to alg.
     * data buffer into physical address.
     */

    /* First specify the processing command that the skeleton should do */
    msg->visa.cmd = _AUDDEC_CPROCESS;

    /* commentary follows for marshalling the inBufs argument: */

    /* 1) inBufs->numBufs is a plain integer, we just copy it */
    msg->cmd.process.numInBufs = inBufs->numBufs;

    /* 2) inBufs->bufSizes is an array of integers, we copy them all */
    for (i = 0; i < inBufs->numBufs; i++) {
        msg->cmd.process.inBufSizes[i] = inBufs->bufSizes[i];
    }

    /* 3) inBufs->bufs is a pointer to an array of pointers, so we take
     * individual pointers, convert them, and store in the the message
     * counterpart of inBufs->bufs
     */
    for (i = 0; i < inBufs->numBufs; i++) {
        msg->cmd.process.inBufs[i] = (XDAS_Int8 *)
            Memory_getBufferPhysicalAddress(inBufs->bufs[i],
                inBufs->bufSizes[i], NULL);

        if (msg->cmd.process.inBufs[i] == NULL) {
            retVal = AUDDEC_ERUNTIME;
            goto exit;
        }
    }

    /* we're done (with inBufs). Because msg->cmd.process is non-cacheable
     * and contiguous (it has been allocated by MSGQ), we don't have to do
     * anything else.
     */

    /* Now we repeat the procedure for outBufs. Note that
     * inArgs and outArgs contain no pointers, so we can simply copy the
     * entire original structure, accounting for the first "size" field.
     */
    msg->cmd.process.numOutBufs = outBufs->numBufs;
    for (i = 0; i < outBufs->numBufs; i++) {
        msg->cmd.process.outBufSizes[i] = outBufs->bufSizes[i];
    }

    for (i = 0; i < outBufs->numBufs; i++) {
        msg->cmd.process.outBufs[i] = (XDAS_Int8 *)
            Memory_getBufferPhysicalAddress(outBufs->bufs[i],
                outBufs->bufSizes[i], NULL);

        if (msg->cmd.process.outBufs[i] == NULL) {
            retVal = AUDDEC_ERUNTIME;
            goto exit;
        }
    }

    /* inArgs has no pointers so simply memcpy "size" bytes into the msg */
    memcpy(&(msg->cmd.process.inArgs), inArgs, inArgs->size);

    /* point at outArgs and set the "size" */
    pMsgOutArgs = (IAUDDEC_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) +
        inArgs->size);

    /* set the size field - the rest is filled in by the codec */
    /* TODO:H probably want to zero out the rest of the outArgs struct */
    pMsgOutArgs->size = outArgs->size;

    *pmsg = msg;

    return (retVal);

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
/* Default implementation for _chain */
static GstFlowReturn
gst_tidmai_base_video_dualencoder_default_realize_instance (GstTIDmaiBaseVideoDualEncoder *video_dualencoder,
	GstTIDmaiDualEncInstance *encoder_instance, GstBuffer *entry_buffer)
{

  GST_DEBUG_OBJECT (video_dualencoder, "Entry gst_tidmai_base_video_dualencoder_default_realize_instance");
  
  /* Only for test */
  //GstClockTime time_start, time_start2, time_end, time_end2;
  //GstClockTimeDiff time_diff;
  Buffer_Attrs	Attrs; 
  Buffer_Handle outBufHandle;
  //Buffer_Attrs	inAttrs; 
  //Buffer_Handle inBufHandle;
  GstTIDmaiVideoInfo *video_info;
  UInt32 phys = 10;
  Bool isContiguous = FALSE;
  
  //time_start = gst_util_get_timestamp ();
  
  int ret;
  GstBuffer *buffer_push_out;
  
  /* Tests if the buffer  */
  phys = Memory_getBufferPhysicalAddress(
                    GST_BUFFER_DATA(entry_buffer),
                    GST_BUFFER_SIZE(entry_buffer),
							&isContiguous);
	
  if(phys == 0) {
	GST_ERROR_OBJECT (video_dualencoder, "Entry buffer isn't CMEM");
	return GST_FLOW_NOT_SUPPORTED;
  }
  else {
	GST_DEBUG_OBJECT (video_dualencoder, "Using buffers with contiguos memory");
	encoder_instance->input_buffer = entry_buffer;
  }
	
  /* Check for the output_buffer */
  if (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->submitted_output_buffers == NULL) {
    
	video_info = (GstTIDmaiVideoInfo *) GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->high_resolution_encoder->media_info;
	GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->inBufSize = (video_info->width * video_info->height) * 1.8;
	
	
    if (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize == 0) {
      /* Default value for the out buffer size */
      GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize =
          GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->inBufSize * 5;
    }

    /* Add the free memory slice to the list */
    struct cmemSlice *slice = g_malloc0 (sizeof (struct cmemSlice));
    slice->start = 0;
    slice->end = GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize;
    slice->size = GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize;
#ifdef GLIB_2_31_AND_UP
    g_mutex_init(&(GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeMutex));
#else
    GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeMutex  = g_mutex_new();
#endif
    GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeSlices =
        g_list_append (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->freeSlices, slice);

    /* Allocate the circular buffer */
	
	Attrs = Buffer_Attrs_DEFAULT;
	Attrs.useMask = gst_tidmaibuffertransport_GST_FREE;
	
	outBufHandle = Buffer_create(GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->outBufSize, &Attrs);
	
	GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder)->submitted_output_buffers = 
		gst_tidmaibuffertransport_new(outBufHandle, NULL, NULL, FALSE);
	
  }
  /* Encode the actual buffer */
  buffer_push_out =  gst_tidmai_base_dualencoder_encode (GST_TI_DMAI_BASE_DUALENCODER (video_dualencoder), 
						encoder_instance);

  
   	  
  gst_buffer_copy_metadata(buffer_push_out, entry_buffer, 
    GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS); 
  
  
  //time_end = gst_util_get_timestamp ();
   
    
  //time_diff = GST_CLOCK_DIFF (time_start, time_end);
  //g_print ("DualEncoder time: %" G_GUINT64_FORMAT " ns.\n", time_diff);
    
    
  /* push the buffer and check for any error */
  //time_start2 = gst_util_get_timestamp ();
	
  GST_BUFFER_CAPS (buffer_push_out) = gst_caps_ref(GST_PAD_CAPS(encoder_instance->src_pad)); 
  
  ret =
      gst_pad_push (encoder_instance->src_pad,
			buffer_push_out);
  
			
    //time_end2 = gst_util_get_timestamp ();
    
    
    //time_diff = GST_CLOCK_DIFF (time_start2, time_end2);
    
  //g_print ("\nPush time: %" G_GUINT64_FORMAT " ns.\n\n", time_diff);
    
    
  if (GST_FLOW_OK != ret) {
    GST_ERROR_OBJECT (video_dualencoder, "Push buffer return with error: %d",
        ret);
  }
 
  GST_DEBUG_OBJECT (video_dualencoder, "Leave gst_tidmai_base_video_dualencoder_default_realize_instance");
  
  return ret;
}
示例#9
0
/*
 *  ======== marshallMsg ========
 */
static XDAS_Int32 marshallMsg(IVIDDEC2_Handle h, XDM1_BufDesc *inBufs,
    XDM_BufDesc *outBufs, IVIDDEC2_InArgs *inArgs, IVIDDEC2_OutArgs *outArgs,
    _VIDDEC2_Msg **pmsg)
{
    XDAS_Int32 retVal = IVIDDEC2_EOK;
    VISA_Handle visa = (VISA_Handle)h;
    _VIDDEC2_Msg *msg;
    Int i;
    IVIDDEC2_OutArgs *pMsgOutArgs;
    Int numBufs;
    Int payloadSize;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((inArgs == NULL) || (inArgs->size < sizeof(IVIDDEC2_InArgs)) ||
            (outArgs == NULL) || (outArgs->size < sizeof(IVIDDEC2_OutArgs))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IVIDDEC2_EFAIL);
    }

    if (pmsg == NULL) {
        return (IVIDDEC2_EFAIL);
    }

    /* make sure it'll all fit! */
    payloadSize = sizeof(VISA_MsgHeader) + (sizeof(*inBufs)) +
            (sizeof(outBufs[0]) * XDM_MAX_IO_BUFFERS) +
            sizeof(msg->cmd.process.numOutBufs) +
            (sizeof(msg->cmd.process.outBufSizes[0]) * XDM_MAX_IO_BUFFERS) +
            inArgs->size + outArgs->size;

    if (payloadSize > VISA_getMaxMsgSize(visa)) {
        /* Can't handle these large extended args. */
        Log_print2(Diags_USER6,
                "[+6] process> invalid arguments - too big (0x%x > 0x%x).  "
                "Validate .size fields", payloadSize,
                VISA_getMaxMsgSize(visa));

        return (IVIDDEC2_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_VIDDEC2_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IVIDDEC2_EFAIL);
    }

    /* zero out msg->cmd (not msg->visa!) */
    memset(&(msg->cmd), 0, sizeof(msg->cmd));

    /*
     * Marshall the command: copy the client-passed arguments into flattened
     * message data structures, converting every pointer address to alg.
     * data buffer into physical address.
     */

    /* First specify the processing command that the skeleton should do */
    msg->visa.cmd = _VIDDEC2_CPROCESS;

    /* commentary follows for marshalling the inBufs argument: */

    /* 1) inBufs->numBufs is a plain integer, we just copy it */
    msg->cmd.process.inBufs.numBufs = inBufs->numBufs;

    /*
     * 2) inBufs->bufSizes is a sparse array of integers, we copy them all.
     *
     * 3) inBufs->bufs is a pointer to a sparse array of pointers, so we take
     * individual pointers, convert them if non-NULL, and store them in the
     * message counterpart of inBufs->bufs.
     */
    for (i = 0, numBufs = 0;
         ((numBufs < inBufs->numBufs) && (i < XDM_MAX_IO_BUFFERS)); i++) {
        if (inBufs->descs[i].buf != NULL) {
            /* valid member of sparse array, convert it */
            msg->cmd.process.inBufs.descs[i].bufSize = inBufs->descs[i].bufSize;

            msg->cmd.process.inBufs.descs[i].buf = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(inBufs->descs[i].buf,
                    inBufs->descs[i].bufSize, NULL);

            if (msg->cmd.process.inBufs.descs[i].buf == NULL) {
                retVal = IVIDDEC2_EFAIL;
                goto exit;
            }

            /* Clear .accessMask; the local processor won't access this buf */
            inBufs->descs[i].accessMask = 0;

            /* found, and handled, another buffer. */
            numBufs++;
        }
        else {
            /* empty member of sparse array, no conversion needed. */
            msg->cmd.process.inBufs.descs[i].bufSize = 0;
            msg->cmd.process.inBufs.descs[i].buf = NULL;
        }
    }

    if (VISA_isChecked()) {
        /* check that we found inBufs->numBufs pointers in inBufs->bufs[] */
        Assert_isTrue(inBufs->numBufs == numBufs, (Assert_Id)NULL);
    }

    /* we're done (with inBufs). Because msg->cmd.process is non-cacheable
     * and contiguous (it has been allocated by MSGQ), we don't have to do
     * anything else.
     */

    /* Now we repeat the procedure for outBufs. Note that
     * inArgs contains no pointers, so we can simply copy the
     * entire original structure, accounting for the first "size" field.
     */
    msg->cmd.process.numOutBufs = outBufs->numBufs;

    for (i = 0, numBufs = 0;
         ((numBufs < outBufs->numBufs) && (i < XDM_MAX_IO_BUFFERS)); i++) {

        if (outBufs->bufs[i] != NULL) {
            /* valid member of sparse array, convert it */
            msg->cmd.process.outBufSizes[i] = outBufs->bufSizes[i];

            msg->cmd.process.outBufs[i] = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(outBufs->bufs[i],
                    outBufs->bufSizes[i], NULL);

            if (msg->cmd.process.outBufs[i] == NULL) {
                /* TODO:M - should add at least a trace statement when trace
                 * is supported.  Another good idea is to return something
                 * more clear than EFAIL.
                 */
                retVal = IVIDDEC2_EFAIL;
                goto exit;
            }

            /* found, and handled, another buffer. */
            numBufs++;
        }
        else {
            /* empty member of sparse array, no conversion needed */
            msg->cmd.process.outBufSizes[i] = 0;
            msg->cmd.process.outBufs[i] = NULL;
        }
    }

    if (VISA_isChecked()) {
        /* check that we found outBufs->numBufs pointers in outBufs->bufs[] */
        Assert_isTrue(outBufs->numBufs == numBufs, (Assert_Id)NULL);
    }

    /* inArgs has no pointers so simply memcpy "size" bytes into the msg */
    memcpy(&(msg->cmd.process.inArgs), inArgs, inArgs->size);

    /* point at outArgs and set the "size" */
    pMsgOutArgs = (IVIDDEC2_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) +
        inArgs->size);

    /* set the size field - the rest is filled in by the codec */
    pMsgOutArgs->size = outArgs->size;

    *pmsg = msg;

    return (retVal);

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
示例#10
0
/*
 *  ======== control ========
 *  This is the stub-implementation for the control method
 */
static XDAS_Int32 control(IVIDDEC2_Handle h, IVIDDEC2_Cmd id,
     IVIDDEC2_DynamicParams *params, IVIDDEC2_Status *status)
{
    XDAS_Int32 retVal;
    VISA_Handle visa = (VISA_Handle)h;
    _VIDDEC2_Msg *msg;
    IVIDDEC2_Status *pMsgStatus;
    XDAS_Int8 *virtAddr = NULL;
    Int payloadSize;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((params == NULL) || (params->size < sizeof(IVIDDEC2_DynamicParams)) ||
            (status == NULL) || (status->size < sizeof(IVIDDEC2_Status))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IVIDDEC2_EFAIL);
    }

    /*
     * Initialize extendedError to zero so we don't return something
     * uninitialized in extendedError.
     */
    status->extendedError = 0;

    /* make sure it'll all fit! */
    payloadSize = sizeof(VISA_MsgHeader) + sizeof(id) + params->size +
            status->size;

    if (payloadSize > VISA_getMaxMsgSize(visa)) {
        /* Can't handle these large extended args. */
        Log_print2(Diags_USER6,
                "[+6] control> invalid arguments - too big (0x%x > 0x%x).  "
                "Validate .size fields", payloadSize,
                VISA_getMaxMsgSize(visa));

        return (IVIDDEC2_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_VIDDEC2_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IVIDDEC2_EFAIL);
    }

    /* marshall the command */
    msg->visa.cmd = _VIDDEC2_CCONTROL;

    msg->cmd.control.id = id;

    /* params has no pointers so simply memcpy "size" bytes into the msg */
    memcpy(&(msg->cmd.control.params), params, params->size);

    /* unmarshall status based on the "size" of params */
    pMsgStatus = (IVIDDEC2_Status *)((UInt)(&(msg->cmd.control.params)) +
        params->size);

    /*
     * Initialize the .size and .data fields - the rest are filled in by
     * the codec.
     */
    pMsgStatus->size = status->size;

    if (status->data.buf != NULL) {
        pMsgStatus->data.bufSize = status->data.bufSize;

        /* save it for later */
        virtAddr = status->data.buf;

        pMsgStatus->data.buf = (XDAS_Int8 *)
            Memory_getBufferPhysicalAddress(status->data.buf,
                status->data.bufSize, NULL);

        if (pMsgStatus->data.buf == NULL) {
            retVal = IVIDDEC2_EFAIL;
            goto exit;
        }
    }
    else {
        /* Place null into the msg so the skel knows it's invalid */
        pMsgStatus->data.buf = NULL;
    }

    /* send the message to the skeleton and wait for completion */
    retVal = VISA_call(visa, (VISA_Msg *)&msg);

    /* ensure we get CCONTROL msg (ensure async CPROCESS pipeline drained) */
    Assert_isTrue(msg->visa.cmd == _VIDDEC2_CCONTROL, (Assert_Id)NULL);

    /* unmarshall status */
    pMsgStatus = (IVIDDEC2_Status *)((UInt)(&(msg->cmd.control.params)) +
        params->size);

    if (VISA_isChecked()) {
        /* ensure codec didn't modify status->size */
        Assert_isTrue(pMsgStatus->size == status->size, (Assert_Id)NULL);

        /*
         * TODO:L  Should we also check that pMsgStatus->data.buf is the same
         * after the call as before?
         */
    }

    memcpy(status, pMsgStatus, status->size);

    /*
     * And finally, restore status->data.buf to its original value.  Note that
     * this works even when status->data.buf was NULL because virtAddr is
     * initialized to NULL.
     *
     * While potentially more confusing, this is just as correct as
     * (and faster than!) calling Memory_getVirtualBuffer().
     */
    status->data.buf = virtAddr;

    /* Clear .accessMask; the local processor didn't access the buffer */
    status->data.accessMask = 0;

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
/*
 *  ======== control ========
 *  This is the stub-implementation for the control method
 */
static XDAS_Int32 control(IVIDDEC2BACK_Handle h, XDM_Context *context,
     IVIDDEC2_Status *status)
{
    XDAS_Int32 retVal;
    VISA_Handle visa = (VISA_Handle)h;
    _VIDDEC2BACK_Msg *msg;
//    IVIDDEC2_Status *pMsgStatus;
//    XDAS_Int8 *virtAddr = NULL;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((context == NULL) || (status == NULL) ||
            (status->size < sizeof(IVIDDEC2_Status))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IVIDDEC2_EFAIL);
    }

    if (/* size of "stuff to marshall" > message size */
        (sizeof(VISA_MsgHeader) + sizeof(*context) + status->size)
            > sizeof(_VIDDEC2BACK_Msg)) {

        /* Can't handle these large extended args. */
        Log_print0(Diags_USER6,
                "[+6] control> invalid arguments - validate .size fields");

        return (IVIDDEC2_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_VIDDEC2BACK_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IVIDDEC2_EFAIL);
    }

    /* marshall the command */
    msg->visa.cmd = _VIDDEC2BACK_CCONTROL;

    /*
     * Initialize the .size and .data fields - the rest are filled in by
     * the codec.
     */
    msg->cmd.control.status.size = status->size;

#if 0
    if (status->data.buf != NULL) {
        pMsgStatus->data.bufSize = status->data.bufSize;

        /* save it for later */
        virtAddr = status->data.buf;

        pMsgStatus->data.buf = (XDAS_Int8 *)
            Memory_getBufferPhysicalAddress(status->data.buf,
                status->data.bufSize, NULL);

        if (pMsgStatus->data.buf == NULL) {
            retVal = IVIDDEC2_EFAIL;
            goto exit;
        }
    }
    else {
        /* Place null into the msg so the skel knows it's invalid */
        pMsgStatus->data.buf = NULL;
    }
#endif
    /* send the message to the skeleton and wait for completion */
    retVal = VISA_call(visa, (VISA_Msg *)&msg);

    /* ensure we get CCONTROL msg (ensure async CPROCESS pipeline drained) */
    Assert_isTrue(msg->visa.cmd == _VIDDEC2BACK_CCONTROL, (Assert_Id)NULL);

    if (VISA_isChecked()) {
        /* ensure codec didn't modify status->size */
        Assert_isTrue(msg->cmd.control.status.size == status->size,
                (Assert_Id)NULL);

        /*
         * TODO:L  Should we also check that pMsgStatus->data.buf is the same
         * after the call as before?
         */
    }
    memcpy(status, &(msg->cmd.control.status), status->size);
#if 0
    /*
     * And finally, restore status->data.buf to its original value.  Note that
     * this works even when status->data.buf was NULL because virtAddr is
     * initialized to NULL.
     *
     * While potentially more confusing, this is just as correct as
     * (and faster than!) calling Memory_getVirtualBuffer().
     */
    status->data.buf = virtAddr;

    /* Clear .accessMask; the local processor didn't access the buffer */
    status->data.accessMask = 0;
#endif

//exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
/*
 *  ======== marshallMsg ========
 */
static XDAS_Int32 marshallMsg(IVIDDEC2BACK_Handle h, XDM_Context *context,
        IVIDDEC2_OutArgs *outArgs,  _VIDDEC2BACK_Msg **pmsg)
{
    XDAS_Int32 retVal = IVIDDEC2_EOK;
    VISA_Handle visa = (VISA_Handle)h;
    _VIDDEC2BACK_Msg *msg;
    Int numBufs;

    Assert_isTrue(pmsg != NULL, (Assert_Id)NULL);

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((context == NULL) || (outArgs == NULL) ||
            (outArgs->size < sizeof(IVIDDEC2_OutArgs))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IVIDDEC2_EFAIL);
    }

    if (/* size of "stuff to marshall" > message size */
        (sizeof(VISA_MsgHeader) + sizeof(XDM_Context) +
            outArgs->size) > sizeof(_VIDDEC2BACK_Msg)) {

        /* Can't handle these large extended args. */
        Log_print0(Diags_USER6,
                "[+6] process> invalid arguments - outArgs.size field is too"
                " large");

        return (IVIDDEC2_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_VIDDEC2BACK_Msg *)VISA_allocMsg(visa)) == NULL) {
        Log_print0(Diags_USER6, "[+6] process> VISA_allocMsg failed");

        return (IVIDDEC2_EFAIL);
    }

    /* zero out msg->cmd (not msg->visa!) */
    memset(&(msg->cmd), 0, sizeof(msg->cmd));

    /*
     * Marshall the command: copy the client-passed arguments into flattened
     * message data structures, converting every pointer address to alg.
     * data buffer into physical address.
     */

    /* First specify the processing command that the skeleton should do */
    msg->visa.cmd = _VIDDEC2BACK_CPROCESS;

    /* address translation of XDM_Context buffers */
    if (context->algContext.buf != NULL) {
        msg->cmd.process.context.algContext.bufSize =
                context->algContext.bufSize;

        msg->cmd.process.context.algContext.buf = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(context->algContext.buf,
                    context->algContext.bufSize, NULL);

            if (msg->cmd.process.context.algContext.buf == NULL) {
                retVal = IVIDDEC2_EFAIL;
                goto exit;
            }
    }

    /* context->num*Bufs are plain integers, just copy them */
    msg->cmd.process.context.numInBufs = context->numInBufs;
    msg->cmd.process.context.numOutBufs = context->numOutBufs;
    msg->cmd.process.context.numInOutBufs = context->numInOutBufs;

    /* address translate inBufs */
    numBufs =
        copySparseSingleBufDescArrayWithV2P(msg->cmd.process.context.inBufs,
                context->inBufs, context->numInBufs, XDM_MAX_CONTEXT_BUFFERS);

    if (numBufs == -1) {
        retVal = IVIDDEC2_EFAIL;
        goto exit;
    }

    if (VISA_isChecked()) {
        /* check that we found context->numInBufs in context->inBufs */
        Assert_isTrue(context->numInBufs == numBufs, (Assert_Id)NULL);
    }

    /* Repeat the procedure for outBufs and intermediateBufs. */
    numBufs =
        copySparseSingleBufDescArrayWithV2P(msg->cmd.process.context.outBufs,
                context->outBufs, context->numOutBufs, XDM_MAX_CONTEXT_BUFFERS);

    if (numBufs == -1) {
        retVal = IVIDDEC2_EFAIL;
        goto exit;
    }

    if (VISA_isChecked()) {
        /* check that we found context->numOutBufs in context->outBufs */
        Assert_isTrue(context->numOutBufs == numBufs, (Assert_Id)NULL);
    }

    numBufs =
        copySingleBufDescArrayWithV2P(msg->cmd.process.context.intermediateBufs,
                context->intermediateBufs, XDM_MAX_CONTEXT_BUFFERS);

    if (numBufs == -1) {
        retVal = IVIDDEC2_EFAIL;
        goto exit;
    }

    /* VIDDEC2BACK doesn't support any in/out buffers */
    if (VISA_isChecked()) {
        Assert_isTrue(context->numInOutBufs == 0, (Assert_Id)NULL);
    }

    /* outArgs has no 'inputs', so only .size needs marshalled */
    msg->cmd.process.outArgs.size = outArgs->size;

    *pmsg = msg;

    return (retVal);

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return retVal;
}
示例#13
0
文件: ce.c 项目: guyz/dsp
 int cont_alloc_frames(struct frame_format *ff, unsigned bufsize,
                  struct frame **fr, unsigned *nf) {
    int buf_w = ff->width, buf_h = ff->height;
    
    uint8_t *p = NULL;
    uint8_t *pp = NULL;
    unsigned y_offset;
    int i, clear_count;

    mem_params.type = Memory_CONTIGHEAP;
    mem_params.flags = Memory_NONCACHED;
    mem_params.align = 16; 

    input_buf = Memory_alloc(INPUT_BUFFER_SIZE, &mem_params);
    if (!input_buf) {
        fprintf(stderr, "Error allocating input buffer\n");
	return -1;  
    }

    ce_frame_size = buf_w * buf_h * 2;

    num_frames = bufsize / ce_frame_size;
    y_offset = buf_w * buf_h;

    fprintf(stderr, "MAIN CE Memory Manager: using %d CMEM HEAP allocated frame buffers, with size: %u\n", num_frames, ce_frame_size);

    frames = malloc(num_frames * sizeof(*frames));

    for (i = 0; i < num_frames; i++) {
	p = Memory_alloc(ce_frame_size, &mem_params);
    	if (!p) {
            fprintf(stderr, "Error allocating frame buffer %d on CMEM\n", i);
	    goto err;    
        }

	pp = (uint8_t *)Memory_getBufferPhysicalAddress(p, ce_frame_size, NULL);

        frames[i].virt[0] = p;
        frames[i].virt[1] = p + y_offset;
        frames[i].virt[2] = p + y_offset + buf_w / 2;
        frames[i].phys[0] = pp;
        frames[i].phys[1] = pp + y_offset;
        frames[i].phys[2] = pp + y_offset + buf_w / 2;
        frames[i].linesize[0] = ff->width;
        frames[i].linesize[1] = ff->width;
        frames[i].linesize[2] = ff->width;
    }

    ff->y_stride  = ff->width;
    ff->uv_stride = ff->width;

    *fr = frames;
    *nf = num_frames;

    return 0;

err:
    clear_count = i;
    for (i=0; i<clear_count; i++) {
	if (!frames) break;
	Memory_free(frames[i].virt[0], ce_frame_size, &mem_params);
    }

    Memory_free(input_buf, INPUT_BUFFER_SIZE, &mem_params);
    if (frames) free(frames);
    return -1;
}
示例#14
0
/*****************************************************************************
 * gst_tidmaiaccel_prepare_output_buffer
 *    Function is used to allocate output buffer
 *****************************************************************************/
static GstFlowReturn gst_tidmaiaccel_prepare_output_buffer (GstBaseTransform
    *trans, GstBuffer *inBuf, gint size, GstCaps *caps, GstBuffer **outBuf)
{
    GstTIDmaiaccel *dmaiaccel = GST_TIDMAIACCEL(trans);
    Buffer_Handle   hOutBuf;
    Bool isContiguous = FALSE;
    UInt32 phys = 0;

    /* Always check if the buffer is contiguous */
    phys = Memory_getBufferPhysicalAddress(
                    GST_BUFFER_DATA(inBuf),
                    GST_BUFFER_SIZE(inBuf),
                    &isContiguous);

    if (isContiguous && dmaiaccel->width){
        GST_DEBUG("Is contiguous video buffer");

        Memory_registerContigBuf((UInt32)GST_BUFFER_DATA(inBuf),
            GST_BUFFER_SIZE(inBuf),phys);
        /* This is a contiguous buffer, create a dmai buffer transport */
        BufferGfx_Attrs gfxAttrs    = BufferGfx_Attrs_DEFAULT;

        gfxAttrs.bAttrs.reference   = TRUE;
        gfxAttrs.dim.width          = dmaiaccel->width;
        gfxAttrs.dim.height         = dmaiaccel->height;
        gfxAttrs.colorSpace         = dmaiaccel->colorSpace;
        gfxAttrs.dim.lineLength     = dmaiaccel->lineLength;

        hOutBuf = Buffer_create(GST_BUFFER_SIZE(inBuf), &gfxAttrs.bAttrs);
        BufferGfx_setDimensions(hOutBuf,&gfxAttrs.dim);
        BufferGfx_setColorSpace(hOutBuf,gfxAttrs.colorSpace);
        Buffer_setUserPtr(hOutBuf, (Int8*)GST_BUFFER_DATA(inBuf));
        Buffer_setNumBytesUsed(hOutBuf, GST_BUFFER_SIZE(inBuf));
        *outBuf = gst_tidmaibuffertransport_new(hOutBuf, NULL, NULL, FALSE);
        gst_buffer_set_data(*outBuf, (guint8*) Buffer_getUserPtr(hOutBuf),
            Buffer_getSize(hOutBuf));
        gst_buffer_copy_metadata(*outBuf,inBuf,GST_BUFFER_COPY_ALL);
        gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad));

        /* We need to grab a reference to the input buffer since we have 
         * a pointer to his buffer */
        gst_buffer_ref(inBuf);

        gst_tidmaibuffertransport_set_release_callback(
            (GstTIDmaiBufferTransport *)*outBuf,
            dmaiaccel_release_cb,inBuf);

        return GST_FLOW_OK;
    } else {
        GST_DEBUG("Copying into contiguous video buffer");
        /* This is a contiguous buffer, create a dmai buffer transport */
        if (!dmaiaccel->bufTabAllocated){
            /* Initialize our buffer tab */
            BufferGfx_Attrs gfxAttrs    = BufferGfx_Attrs_DEFAULT;

            gfxAttrs.dim.width          = dmaiaccel->width;
            gfxAttrs.dim.height         = dmaiaccel->height;
            gfxAttrs.colorSpace         = dmaiaccel->colorSpace;
            gfxAttrs.dim.lineLength     = dmaiaccel->lineLength;

            dmaiaccel->hOutBufTab =
                        BufTab_create(2, GST_BUFFER_SIZE(inBuf),
                            BufferGfx_getBufferAttrs(&gfxAttrs));
            pthread_mutex_init(&dmaiaccel->bufTabMutex, NULL);
            pthread_cond_init(&dmaiaccel->bufTabCond, NULL);
            if (dmaiaccel->hOutBufTab == NULL) {
                GST_ELEMENT_ERROR(dmaiaccel,RESOURCE,NO_SPACE_LEFT,(NULL),
                    ("failed to create output buffer tab"));
                return GST_FLOW_ERROR;
            }
            dmaiaccel->bufTabAllocated = TRUE;
        }

        pthread_mutex_lock(&dmaiaccel->bufTabMutex);
        hOutBuf = BufTab_getFreeBuf(dmaiaccel->hOutBufTab);
        if (hOutBuf == NULL) {
            GST_INFO("Failed to get free buffer, waiting on bufTab\n");
            pthread_cond_wait(&dmaiaccel->bufTabCond, &dmaiaccel->bufTabMutex);

            hOutBuf = BufTab_getFreeBuf(dmaiaccel->hOutBufTab);

            if (hOutBuf == NULL) {
                GST_ELEMENT_ERROR(dmaiaccel,RESOURCE,NO_SPACE_LEFT,(NULL),
                    ("failed to get a free contiguous buffer from BufTab"));
                pthread_mutex_unlock(&dmaiaccel->bufTabMutex);
                return GST_FLOW_ERROR;
            }
        }
        pthread_mutex_unlock(&dmaiaccel->bufTabMutex);

        memcpy(Buffer_getUserPtr(hOutBuf),GST_BUFFER_DATA(inBuf),
            GST_BUFFER_SIZE(inBuf));
        Buffer_setNumBytesUsed(hOutBuf, GST_BUFFER_SIZE(inBuf));
        *outBuf = gst_tidmaibuffertransport_new(hOutBuf, &dmaiaccel->bufTabMutex,
            &dmaiaccel->bufTabCond, FALSE);
        gst_buffer_set_data(*outBuf, (guint8*) Buffer_getUserPtr(hOutBuf),
            Buffer_getSize(hOutBuf));
        gst_buffer_copy_metadata(*outBuf,inBuf,GST_BUFFER_COPY_ALL);
        gst_buffer_set_caps(*outBuf, GST_PAD_CAPS(trans->srcpad));

        return GST_FLOW_OK;
    }
}
/*
 *  ======== marshallMsg ========
 */
static XDAS_Int32 marshallMsg(IVIDENC1_Handle h, IVIDEO1_BufDescIn *inBufs,
    XDM_BufDesc *outBufs, IVIDENC1_InArgs *inArgs, IVIDENC1_OutArgs *outArgs,
    _VIDENC1_Msg **pmsg)
{
    XDAS_Int32 retVal = IVIDENC1_EOK;
    VISA_Handle visa = (VISA_Handle)h;
    _VIDENC1_Msg *msg;
    Int i;
    IVIDENC1_OutArgs *pMsgOutArgs;
    Int numBufs;
    Int payloadSize;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((inArgs == NULL) || (inArgs->size < sizeof(IVIDENC1_InArgs)) ||
            (outArgs == NULL) || (outArgs->size < sizeof(IVIDENC1_OutArgs))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IVIDENC1_EFAIL);
    }

    /*
     * Initialize extendedError to zero so we don't return something
     * uninitialized in extendedError.
     */
    outArgs->extendedError = 0;

    if (pmsg == NULL) {
        return (IVIDENC1_EFAIL);
    }

    /* make sure it'll all fit! */
    payloadSize = sizeof(VISA_MsgHeader) + sizeof(*inBufs) +
            (sizeof(msg->cmd.process.outBufs) * XDM_MAX_IO_BUFFERS) +
            sizeof(msg->cmd.process.numOutBufs) +
            (sizeof(msg->cmd.process.outBufSizes[0]) * XDM_MAX_IO_BUFFERS) +
            inArgs->size + outArgs->size;

    if (payloadSize > VISA_getMaxMsgSize(visa)) {
        /* Can't handle these large extended args. */
        Log_print2(Diags_USER6,
                "[+6] process> invalid arguments - too big (0x%x > 0x%x).  "
                "Validate .size fields", payloadSize,
                VISA_getMaxMsgSize(visa));

        return (IVIDENC1_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_VIDENC1_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IVIDENC1_EFAIL);
    }

    /* zero out msg->cmd (not msg->visa!) */
    memset(&(msg->cmd), 0, sizeof(msg->cmd));

    /*
     * Marshall the command: copy the client-passed arguments into flattened
     * message data structures, converting every pointer address to alg.
     * data buffer into physical address.
     */

    /* First specify the processing command that the skeleton should do */
    msg->visa.cmd = _VIDENC1_CPROCESS;

    /* commentary follows for marshalling the inBufs argument: */

    /* 1) copy integers */
    msg->cmd.process.inBufs.numBufs     = inBufs->numBufs;
    msg->cmd.process.inBufs.frameWidth  = inBufs->frameWidth;
    msg->cmd.process.inBufs.frameHeight = inBufs->frameHeight;
    msg->cmd.process.inBufs.framePitch  = inBufs->framePitch;

    /*
     * inBufs->bufDesc is a sparse array of buffer descriptors.  Convert them
     * if non-NULL.
     */
    for (i = 0, numBufs = 0; i < XDM_MAX_IO_BUFFERS; i++) {
        if (inBufs->bufDesc[i].buf != NULL) {
            /* valid member of sparse array, copy .bufSize convert .buf */
            msg->cmd.process.inBufs.bufDesc[i].bufSize =
                inBufs->bufDesc[i].bufSize;

            msg->cmd.process.inBufs.bufDesc[i].buf = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(inBufs->bufDesc[i].buf,
                    inBufs->bufDesc[i].bufSize, NULL);

            if (msg->cmd.process.inBufs.bufDesc[i].buf == NULL) {
                retVal = IVIDENC1_EFAIL;
                goto exit;
            }

            /* Clear .accessMask; the local processor won't access this buf */
            inBufs->bufDesc[i].accessMask = 0;

            /* found, and handled, another buffer.  See if it's the last one */
            if (++numBufs == inBufs->numBufs) {
                break;
            }
        }
        else {
            /* empty member of sparse array, no conversion needed. */
            msg->cmd.process.inBufs.bufDesc[i].bufSize = 0;
            msg->cmd.process.inBufs.bufDesc[i].buf = NULL;
        }
    }

    /* we're done (with inBufs). Because msg->cmd.process is non-cacheable
     * and contiguous (it has been allocated by MSGQ), we don't have to do
     * anything else.
     */

    /* Repeat the procedure for outBufs. */
    msg->cmd.process.numOutBufs = outBufs->numBufs;

    for (i = 0, numBufs = 0; i < XDM_MAX_IO_BUFFERS; i++) {
        if (outBufs->bufs[i] != NULL) {
            /* valid member of sparse array, convert it */
            msg->cmd.process.outBufSizes[i] = outBufs->bufSizes[i];

            msg->cmd.process.outBufs[i] = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(outBufs->bufs[i],
                    outBufs->bufSizes[i], NULL);

            if (msg->cmd.process.outBufs[i] == NULL) {
                /* TODO:M - should add at least a trace statement when trace
                 * is supported.  Another good idea is to return something
                 * more clear than EFAIL.
                 */
                retVal = IVIDENC1_EFAIL;
                goto exit;
            }

            /* found, and handled, another buffer.  See if it's the last one */
            if (++numBufs == outBufs->numBufs) {
                break;
            }
        }
        else {
            /* empty member of sparse array, no conversion needed */
            msg->cmd.process.outBufSizes[i] = 0;
            msg->cmd.process.outBufs[i] = NULL;
        }
    }

    /* inArgs has no pointers so simply memcpy "size" bytes into the msg */
    memcpy(&(msg->cmd.process.inArgs), inArgs, inArgs->size);

    /* point at outArgs and set the "size" */
    pMsgOutArgs = (IVIDENC1_OutArgs *)((UInt)(&(msg->cmd.process.inArgs)) +
        inArgs->size);

    /* set the size field - the rest is filled in by the codec */
    pMsgOutArgs->size = outArgs->size;

    /*
     * Note that although outArgs contains pointers, they're not provided
     * by the application via the outArgs struct.  Rather the actual buffers
     * are provided by the application to the algorithm via outBufs.
     * So, the addresses in outArgs are output only, and do not require
     * address translation _before_ calling process().  They _do_ require
     * adress translation _after_ process(), as the algorithm may have written
     * physical addresses into the pointers.
     */

    *pmsg = msg;

    return (retVal);

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}
/*
 *  ======== control ========
 *  This is the stub-implementation for the control method
 */
static XDAS_Int32 control(IUNIVERSAL_Handle h, IUNIVERSAL_Cmd id,
    IUNIVERSAL_DynamicParams *dynParams, IUNIVERSAL_Status *status)
{
    XDAS_Int32 retVal;
    VISA_Handle visa = (VISA_Handle)h;
    _UNIVERSAL_Msg *msg;
    IUNIVERSAL_Status *pMsgStatus;
    XDAS_Int8 *virtAddr[XDM_MAX_IO_BUFFERS];
    Int i;
    Int numBufs;
    Int payloadSize;

    /*
     * Validate arguments.  Do we want to do this _every_ time, or just in
     * checked builds?
     */
    if ((dynParams == NULL) ||
            (dynParams->size < sizeof(IUNIVERSAL_DynamicParams)) ||
            (status == NULL) || (status->size < sizeof(IUNIVERSAL_Status))) {

        /* invalid args, could even assert here, it's a spec violation. */
        return (IUNIVERSAL_EFAIL);
    }

    /*
     * Initialize extendedError to zero so we don't return something
     * uninitialized in extendedError.
     */
    status->extendedError = 0;

    /* make sure it'll all fit! */
    payloadSize = sizeof(VISA_MsgHeader) + sizeof(id) + dynParams->size +
            status->size;

    if (payloadSize > VISA_getMaxMsgSize(visa)) {
        /* Can't handle these large extended args. */
        Log_print2(Diags_USER6,
                "[+6] control> invalid arguments - too big (0x%x > 0x%x).  "
                "Validate .size fields", payloadSize,
                VISA_getMaxMsgSize(visa));

        return (IUNIVERSAL_EUNSUPPORTED);
    }

    /* get a message appropriate for this algorithm */
    if ((msg = (_UNIVERSAL_Msg *)VISA_allocMsg(visa)) == NULL) {
        return (IUNIVERSAL_EFAIL);
    }

    /* marshall the command */
    msg->visa.cmd = _UNIVERSAL_CCONTROL;

    msg->cmd.control.id = id;

    /* dynParams has no pointers so simply memcpy "size" bytes into the msg */
    memcpy(&(msg->cmd.control.dynParams), dynParams, dynParams->size);

    /* point at status based on the "size" of dynParams */
    pMsgStatus =
        (IUNIVERSAL_Status *)((UInt)(&(msg->cmd.control.dynParams)) +
            dynParams->size);

    /*
     * Initialize the .size and .data fields - the rest are filled in by
     * the codec.
     */
    pMsgStatus->size = status->size;

    /* 1) pMsgStatus->data.numBufs is a plain integer, we just copy it */
    pMsgStatus->data.numBufs = status->data.numBufs;

    /*
     * status->data.descs[] is a sparse array of buffer descriptors.  Convert
     * them if non-NULL.
     */
    for (i = 0, numBufs = 0;
         ((numBufs < status->data.numBufs) && (i < XDM_MAX_IO_BUFFERS)); i++) {

        if (status->data.descs[i].buf != NULL) {
            /* valid member of sparse array, convert it */
            pMsgStatus->data.descs[i].bufSize = status->data.descs[i].bufSize;

            /* save it for later */
            virtAddr[i] = status->data.descs[i].buf;

            pMsgStatus->data.descs[i].buf = (XDAS_Int8 *)
                Memory_getBufferPhysicalAddress(status->data.descs[i].buf,
                    status->data.descs[i].bufSize, NULL);

            if (pMsgStatus->data.descs[i].buf == NULL) {
                retVal = IUNIVERSAL_EFAIL;
                goto exit;
            }

            /* found, and handled, another buffer. */
            numBufs++;
        }
        else {
            /* empty member of sparse array, no conversion needed. */
            pMsgStatus->data.descs[i].bufSize = 0;
            pMsgStatus->data.descs[i].buf = NULL;

            virtAddr[i] = NULL;

        }
    }

    if (VISA_isChecked()) {
        /* check that we found inBufs->numBufs pointers in inBufs->bufs[] */
        Assert_isTrue(status->data.numBufs == numBufs, (Assert_Id)NULL);
    }

    /* send the message to the skeleton and wait for completion */
    retVal = VISA_call(visa, (VISA_Msg *)&msg);

    /* ensure we get CCONTROL msg (ensure async CPROCESS pipeline drained) */
    Assert_isTrue(msg->visa.cmd == _UNIVERSAL_CCONTROL, (Assert_Id)NULL);

    /* unmarshall status */
    pMsgStatus =
        (IUNIVERSAL_Status *)((UInt)(&(msg->cmd.control.dynParams)) +
            dynParams->size);

    if (VISA_isChecked()) {
        /* ensure codec didn't modify status->size */
        Assert_isTrue(pMsgStatus->size == status->size, (Assert_Id)NULL);

        /*
         * TODO:L  Should we also check that pMsgStatus->data.buf is the same
         * after the call as before?
         */
    }

    memcpy(status, pMsgStatus, status->size);

    /*
     * And finally, restore status->data.descs[].buf's to their original values.
     *
     * While potentially more confusing, this is just as correct as
     * (and faster than!) calling Memory_getVirtualBuffer().
     */
    for (i = 0, numBufs = 0;
         (numBufs < status->data.numBufs) && (i < XDM_MAX_IO_BUFFERS); i++) {

        status->data.descs[i].buf = virtAddr[i];

        /* Clear .accessMask; the local processor didn't access the buffer */
        status->data.descs[i].accessMask = 0;

        if (virtAddr[i] != NULL) {
            numBufs++;
        }
    }

exit:
    VISA_freeMsg(visa, (VISA_Msg)msg);

    return (retVal);
}