Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2010, 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  *  @file  omx_rpc_stub.c
     35  *         This file contains methods that provides the functionality for
     36  *         the OpenMAX1.1 DOMX Framework RPC Stub implementations.
     37  *
     38  *  @path \WTSD_DucatiMMSW\framework\domx\omx_rpc\src
     39  *
     40  *  @rev 1.0
     41  */
     42 
     43 
     44 /******************************************************************
     45  *   INCLUDE FILES
     46  ******************************************************************/
     47 /* ----- system and platform files ----------------------------*/
     48 #include <errno.h>
     49 //#include <errno-base.h>
     50 
     51 #include <fcntl.h>
     52 #include <sys/ioctl.h>
     53 #include <sys/eventfd.h>
     54 #include <unistd.h>
     55 #include <string.h>
     56 #include <stdio.h>
     57 
     58 #include <OMX_Types.h>
     59 #include <timm_osal_interfaces.h>
     60 #include <timm_osal_trace.h>
     61 
     62 
     63 /*-------program files ----------------------------------------*/
     64 #include "omx_rpc.h"
     65 #include "omx_proxy_common.h"
     66 #include "omx_rpc_stub.h"
     67 #include "omx_rpc_skel.h"
     68 #include "omx_rpc_internal.h"
     69 #include "omx_rpc_utils.h"
     70 
     71 #include "rpmsg_omx_defs.h"
     72 
     73 #define RPC_MSGPIPE_SIZE (4)
     74 #define RPC_MSG_SIZE_FOR_PIPE (sizeof(OMX_PTR))
     75 
     76 
     77 #define RPC_getPacket(nPacketSize, pPacket) do { \
     78     pPacket = TIMM_OSAL_Malloc(nPacketSize, TIMM_OSAL_TRUE, 0, TIMMOSAL_MEM_SEGMENT_INT); \
     79     RPC_assert(pPacket != NULL, RPC_OMX_ErrorInsufficientResources, \
     80            "Error Allocating RCM Message Frame"); \
     81     } while(0)
     82 
     83 #define RPC_freePacket(pPacket) do { \
     84     if(pPacket != NULL) TIMM_OSAL_Free(pPacket); \
     85     } while(0)
     86 
     87 
     88 
     89 void *RPC_CallbackThread(void *data);
     90 
     91 
     92 /* ===========================================================================*/
     93 /**
     94 * @name RPC_InstanceInit()
     95 * @brief RPC instance init is used for initialization. It is called once for
     96 *        every instance of an OMX component.
     97 * @param cComponentName [IN] : Name of the component.
     98 * @param phRPCCtx [OUT] : RPC Context structure - to be filled in and returned
     99 * @return RPC_OMX_ErrorNone = Successful
    100 */
    101 /* ===========================================================================*/
    102 
    103 RPC_OMX_ERRORTYPE RPC_InstanceInit(OMX_STRING cComponentName,
    104     OMX_HANDLETYPE * phRPCCtx)
    105 {
    106 	RPC_OMX_ERRORTYPE eRPCError = RPC_OMX_ErrorNone;
    107 	RPC_OMX_CONTEXT *pRPCCtx = NULL;
    108 	OMX_S32 status = 0;
    109 	struct omx_conn_req sReq = { .name = "OMX" };
    110 	TIMM_OSAL_ERRORTYPE eError = TIMM_OSAL_ERR_NONE;
    111 	OMX_U32 i = 0, nAttempts = 0;
    112 
    113 	*(RPC_OMX_CONTEXT **) phRPCCtx = NULL;
    114 
    115 	//pthread_t cbThread;
    116 
    117 //	sReq.name = "OMX";
    118 
    119 	/*pRPCCtx contains context information for each instance */
    120 	pRPCCtx =
    121 	    (RPC_OMX_CONTEXT *) TIMM_OSAL_Malloc(sizeof(RPC_OMX_CONTEXT),
    122 	    TIMM_OSAL_TRUE, 0, TIMMOSAL_MEM_SEGMENT_INT);
    123 	RPC_assert(pRPCCtx != NULL, RPC_OMX_ErrorInsufficientResources,
    124 	    "Malloc failed");
    125 	TIMM_OSAL_Memset(pRPCCtx, 0, sizeof(RPC_OMX_CONTEXT));
    126 
    127 	/*Assuming that open maintains an internal count for multi instance */
    128 	DOMX_DEBUG("Calling open on the device");
    129 	while (1)
    130 	{
    131 		pRPCCtx->fd_omx = open("/dev/rpmsg-omx1", O_RDWR);
    132 		if(pRPCCtx->fd_omx >= 0 || errno != ENOENT || nAttempts == 15)
    133 			break;
    134 		DOMX_DEBUG("errno from open= %d, REATTEMPTING OPEN!!!!",errno);
    135 		nAttempts++;
    136 		usleep(1000000);
    137 	}
    138 	if(pRPCCtx->fd_omx < 0)
    139 	{
    140 		DOMX_ERROR("Can't open device, errorno from open = %d",errno);
    141 		eError = RPC_OMX_ErrorInsufficientResources;
    142 		goto EXIT;
    143 	}
    144 	DOMX_DEBUG("Open was successful, pRPCCtx->fd_omx = %d",
    145 	    pRPCCtx->fd_omx);
    146 //AD
    147 //      strncpy(sReq.name, cComponentName, OMX_MAX_STRINGNAME_SIZE);
    148 
    149 	DOMX_DEBUG("Calling ioctl");
    150 	status = ioctl(pRPCCtx->fd_omx, OMX_IOCCONNECT, &sReq);
    151 	RPC_assert(status >= 0, RPC_OMX_ErrorInsufficientResources,
    152 	    "Can't connect");
    153 
    154 	for (i = 0; i < RPC_OMX_MAX_FUNCTION_LIST; i++)
    155 	{
    156 		eError =
    157 		    TIMM_OSAL_CreatePipe(&(pRPCCtx->pMsgPipe[i]),
    158 		    RPC_MSGPIPE_SIZE, RPC_MSG_SIZE_FOR_PIPE, 1);
    159 		RPC_assert(eError == TIMM_OSAL_ERR_NONE,
    160 		    RPC_OMX_ErrorInsufficientResources,
    161 		    "Pipe creation failed");
    162 	}
    163 
    164 	DOMX_DEBUG("Creating event fd");
    165 	pRPCCtx->fd_killcb = eventfd(0, 0);
    166 	RPC_assert(pRPCCtx->fd_killcb >= 0,
    167 	    RPC_OMX_ErrorInsufficientResources, "Can't create kill fd");
    168 	/*Create a listener/server thread to listen for Ducati callbacks */
    169 	DOMX_DEBUG("Create listener thread");
    170 	status =
    171 	    pthread_create(&(pRPCCtx->cbThread), NULL, RPC_CallbackThread,
    172 	    pRPCCtx);
    173 	RPC_assert(status == 0, RPC_OMX_ErrorInsufficientResources,
    174 	    "Can't create cb thread");
    175 
    176       EXIT:
    177 	if (eRPCError != RPC_OMX_ErrorNone)
    178 	{
    179 		RPC_InstanceDeInit(pRPCCtx);
    180 	}
    181 	else
    182 	{
    183 		*(RPC_OMX_CONTEXT **) phRPCCtx = pRPCCtx;
    184 	}
    185 	return eRPCError;
    186 }
    187 
    188 
    189 
    190 /* ===========================================================================*/
    191 /**
    192 * @name RPC_InstanceDeInit()
    193 * @brief RPC instance deinit is used for tear down. It is called once when an
    194 *        instance of OMX component is going down.
    195 * @param phRPCCtx [IN] : RPC Context structure.
    196 * @return RPC_OMX_ErrorNone = Successful
    197 */
    198 /* ===========================================================================*/
    199 RPC_OMX_ERRORTYPE RPC_InstanceDeInit(OMX_HANDLETYPE hRPCCtx)
    200 {
    201 	RPC_OMX_ERRORTYPE eRPCError = RPC_OMX_ErrorNone;
    202 	TIMM_OSAL_ERRORTYPE eError = TIMM_OSAL_ERR_NONE;
    203 	RPC_OMX_CONTEXT *pRPCCtx = (RPC_OMX_CONTEXT *) hRPCCtx;
    204 	OMX_S32 status = 0;
    205 	OMX_U32 i = 0;
    206 	OMX_U64 nKillEvent = 1;
    207 
    208 	RPC_assert(hRPCCtx != NULL, RPC_OMX_ErrorUndefined,
    209 	    "NULL context handle supplied to RPC Deinit");
    210 
    211 	if (pRPCCtx->fd_killcb)
    212 	{
    213 		status =
    214 		    write(pRPCCtx->fd_killcb, &nKillEvent, sizeof(OMX_U64));
    215 		if (status <= 0)
    216 		{
    217 			DOMX_ERROR
    218 			    ("Write to kill fd failed - cb thread may not exit");
    219 			eRPCError = RPC_OMX_ErrorUndefined;
    220 		} else if (pRPCCtx->cbThread)
    221 		{
    222 			DOMX_DEBUG("Waiting for cb thread to exit");
    223 			status = pthread_join(pRPCCtx->cbThread, NULL);
    224 			if (status != 0)
    225 			{
    226 				DOMX_ERROR("Join for cb thread failed");
    227 				eRPCError = RPC_OMX_ErrorUndefined;
    228 			}
    229 		}
    230 		DOMX_DEBUG("Closing the kill fd");
    231 		status = close(pRPCCtx->fd_killcb);
    232 		pRPCCtx->fd_killcb = 0;
    233 		if (status != 0)
    234 		{
    235 			DOMX_ERROR("Close failed on kill fd");
    236 			eRPCError = RPC_OMX_ErrorUndefined;
    237 		}
    238 	}
    239 
    240 	for (i = 0; i < RPC_OMX_MAX_FUNCTION_LIST; i++)
    241 	{
    242 		if (pRPCCtx->pMsgPipe[i])
    243 		{
    244 			eError = TIMM_OSAL_DeletePipe(pRPCCtx->pMsgPipe[i]);
    245 			pRPCCtx->pMsgPipe[i] = NULL;
    246 			if (eError != TIMM_OSAL_ERR_NONE)
    247 			{
    248 				DOMX_ERROR("Pipe deletion failed");
    249 				eRPCError = RPC_OMX_ErrorUndefined;
    250 			}
    251 		}
    252 	}
    253 
    254 	DOMX_DEBUG("Closing the omx fd");
    255 	if (pRPCCtx->fd_omx)
    256 	{
    257 		status = close(pRPCCtx->fd_omx);
    258 		pRPCCtx->fd_omx = 0;
    259 		if (status != 0)
    260 		{
    261 			DOMX_ERROR("Close failed on omx fd");
    262 			eRPCError = RPC_OMX_ErrorUndefined;
    263 		}
    264 	}
    265 
    266 	TIMM_OSAL_Free(pRPCCtx);
    267 
    268 	EXIT:
    269 		return eRPCError;
    270 }
    271 
    272 
    273 
    274 /* ===========================================================================*/
    275 /**
    276 * @name RPC_CallbackThread()
    277 * @brief This is the entry function of the thread which keeps spinning, waiting
    278 *        for messages from Ducati.
    279 * @param data [IN] : The RPC Context structure is passed here.
    280 * @return RPC_OMX_ErrorNone = Successful
    281 */
    282 /* ===========================================================================*/
    283 void *RPC_CallbackThread(void *data)
    284 {
    285 	OMX_PTR pBuffer = NULL;
    286 	RPC_OMX_CONTEXT *pRPCCtx = (RPC_OMX_CONTEXT *) data;
    287 	fd_set readfds;
    288 	OMX_S32 maxfd = 0, status = 0;
    289 	OMX_U32 nFxnIdx = 0, nPacketSize = RPC_PACKET_SIZE, nPos = 0;
    290 	RPC_OMX_ERRORTYPE eRPCError = RPC_OMX_ErrorNone;
    291 	TIMM_OSAL_ERRORTYPE eError = TIMM_OSAL_ERR_NONE;
    292 	OMX_COMPONENTTYPE *hComp = NULL;
    293 	PROXY_COMPONENT_PRIVATE *pCompPrv = NULL;
    294 
    295 	maxfd =
    296 	    (pRPCCtx->fd_killcb >
    297 	    pRPCCtx->fd_omx ? pRPCCtx->fd_killcb : pRPCCtx->fd_omx) + 1;
    298 	while (1)
    299 	{
    300 		FD_ZERO(&readfds);
    301 		FD_SET(pRPCCtx->fd_omx, &readfds);
    302 		FD_SET(pRPCCtx->fd_killcb, &readfds);
    303 
    304 		DOMX_DEBUG("Waiting for messages from remote core");
    305 		status = select(maxfd, &readfds, NULL, NULL, NULL);
    306 		RPC_assert(status > 0, RPC_OMX_ErrorUndefined,
    307 		    "select failed");
    308 
    309 		if (FD_ISSET(pRPCCtx->fd_killcb, &readfds))
    310 		{
    311 			DOMX_DEBUG("Recd. kill message - exiting the thread");
    312 			break;
    313 		}
    314 
    315 		if (FD_ISSET(pRPCCtx->fd_omx, &readfds))
    316 		{
    317 			DOMX_DEBUG("Recd. omx message");
    318 			RPC_getPacket(nPacketSize, pBuffer);
    319 			status = read(pRPCCtx->fd_omx, pBuffer, nPacketSize);
    320             if(status < 0)
    321             {
    322                 if(errno == ENXIO)
    323                 {
    324                     /*Indicate fatal error and exit*/
    325                     RPC_assert(0, RPC_OMX_ErrorHardware,
    326                     "Remote processor fatal error");
    327                 }
    328                 else
    329                 {
    330                     RPC_assert(0, RPC_OMX_ErrorUndefined,
    331                     "read failed");
    332                 }
    333             }
    334 
    335 			nPos = 0;
    336 			nFxnIdx = ((struct omx_packet *) pBuffer)->fxn_idx;
    337 			/*Indices from static table will have bit 31 set */
    338 			if (nFxnIdx & 0x80000000)
    339 				nFxnIdx &= 0x0FFFFFFF;
    340 			RPC_assert(nFxnIdx < RPC_OMX_MAX_FUNCTION_LIST,
    341 			    RPC_OMX_ErrorUndefined,
    342 			    "Bad function index recd");
    343 			switch (nFxnIdx)
    344 			{
    345 			case RPC_OMX_FXN_IDX_EVENTHANDLER:
    346 				RPC_SKEL_EventHandler(((struct omx_packet *)
    347 					pBuffer)->data);
    348 				RPC_freePacket(pBuffer);
    349 				pBuffer = NULL;
    350 				break;
    351 			case RPC_OMX_FXN_IDX_EMPTYBUFFERDONE:
    352 				RPC_SKEL_EmptyBufferDone(((struct omx_packet *)
    353 					pBuffer)->data);
    354 				RPC_freePacket(pBuffer);
    355 				pBuffer = NULL;
    356 				break;
    357 			case RPC_OMX_FXN_IDX_FILLBUFFERDONE:
    358 				RPC_SKEL_FillBufferDone(((struct omx_packet *)
    359 					pBuffer)->data);
    360 				RPC_freePacket(pBuffer);
    361 				pBuffer = NULL;
    362 				break;
    363 			default:
    364 				eError =
    365 				    TIMM_OSAL_WriteToPipe(pRPCCtx->
    366 				    pMsgPipe[nFxnIdx], &pBuffer,
    367 				    RPC_MSG_SIZE_FOR_PIPE, TIMM_OSAL_SUSPEND);
    368 				RPC_assert(eError == TIMM_OSAL_ERR_NONE,
    369 				    RPC_OMX_ErrorUndefined,
    370 				    "Write to pipe failed");
    371 				break;
    372 			}
    373 		}
    374 EXIT:
    375 		if (eRPCError != RPC_OMX_ErrorNone)
    376 		{
    377 			//AD TODO: Send error CB to client and then go back in loop to wait for killfd
    378 			if (pBuffer != NULL)
    379 			{
    380 				RPC_freePacket(pBuffer);
    381 				pBuffer = NULL;
    382 			}
    383 			/*Report all hardware errors as fatal and exit from listener thread*/
    384 			if (eRPCError == RPC_OMX_ErrorHardware)
    385 			{
    386 				/*Implicit detail: pAppData is proxy component handle updated during
    387                   RPC_GetHandle*/
    388 				hComp = (OMX_COMPONENTTYPE *) pRPCCtx->pAppData;
    389                 if(hComp != NULL)
    390 				{
    391 					pCompPrv = (PROXY_COMPONENT_PRIVATE *) hComp->pComponentPrivate;
    392                     /*Indicate fatal error. Users are expected to cleanup the OMX instance
    393                     to ensure all resources are cleaned up.*/
    394 					pCompPrv->proxyEventHandler(hComp, pCompPrv->pILAppData, OMX_EventError,
    395 												OMX_ErrorHardware, 0, NULL);
    396 				}
    397 				break;
    398 			}
    399 		}
    400 	}
    401         return (void*)0;
    402 }
    403