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#define MAX_ATTEMPTS 15 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 87OMX_U8 pBufferError[RPC_PACKET_SIZE]; 88 89void *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 103RPC_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 == MAX_ATTEMPTS) 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/* ===========================================================================*/ 199RPC_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/* ===========================================================================*/ 283void *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 OMX_PTR pBuff = pBufferError; 295 296 maxfd = 297 (pRPCCtx->fd_killcb > 298 pRPCCtx->fd_omx ? pRPCCtx->fd_killcb : pRPCCtx->fd_omx) + 1; 299 while (1) 300 { 301 FD_ZERO(&readfds); 302 FD_SET(pRPCCtx->fd_omx, &readfds); 303 FD_SET(pRPCCtx->fd_killcb, &readfds); 304 305 DOMX_DEBUG("Waiting for messages from remote core"); 306 status = select(maxfd, &readfds, NULL, NULL, NULL); 307 RPC_assert(status > 0, RPC_OMX_ErrorUndefined, 308 "select failed"); 309 310 if (FD_ISSET(pRPCCtx->fd_killcb, &readfds)) 311 { 312 DOMX_DEBUG("Recd. kill message - exiting the thread"); 313 break; 314 } 315 316 if (FD_ISSET(pRPCCtx->fd_omx, &readfds)) 317 { 318 DOMX_DEBUG("Recd. omx message"); 319 RPC_getPacket(nPacketSize, pBuffer); 320 status = read(pRPCCtx->fd_omx, pBuffer, nPacketSize); 321 if(status < 0) 322 { 323 if(errno == ENXIO) 324 { 325 for(nFxnIdx = 0; nFxnIdx < RPC_OMX_MAX_FUNCTION_LIST; nFxnIdx++) 326 { 327 ((struct omx_packet *) pBufferError)->result = OMX_ErrorHardware; 328 TIMM_OSAL_WriteToPipe(pRPCCtx->pMsgPipe[nFxnIdx], &pBuff, RPC_MSG_SIZE_FOR_PIPE, TIMM_OSAL_SUSPEND); 329 if(eError != TIMM_OSAL_ERR_NONE) 330 DOMX_ERROR("Write to pipe failed"); 331 } 332 /*Indicate fatal error and exit*/ 333 RPC_assert(0, RPC_OMX_ErrorHardware, 334 "Remote processor fatal error"); 335 } 336 else 337 { 338 RPC_assert(0, RPC_OMX_ErrorUndefined, 339 "read failed"); 340 } 341 } 342 343 nPos = 0; 344 nFxnIdx = ((struct omx_packet *) pBuffer)->fxn_idx; 345 /*Indices from static table will have bit 31 set */ 346 if (nFxnIdx & 0x80000000) 347 nFxnIdx &= 0x0FFFFFFF; 348 RPC_assert(nFxnIdx < RPC_OMX_MAX_FUNCTION_LIST, 349 RPC_OMX_ErrorUndefined, 350 "Bad function index recd"); 351 switch (nFxnIdx) 352 { 353 case RPC_OMX_FXN_IDX_EVENTHANDLER: 354 RPC_SKEL_EventHandler(((struct omx_packet *) 355 pBuffer)->data); 356 RPC_freePacket(pBuffer); 357 pBuffer = NULL; 358 break; 359 case RPC_OMX_FXN_IDX_EMPTYBUFFERDONE: 360 RPC_SKEL_EmptyBufferDone(((struct omx_packet *) 361 pBuffer)->data); 362 RPC_freePacket(pBuffer); 363 pBuffer = NULL; 364 break; 365 case RPC_OMX_FXN_IDX_FILLBUFFERDONE: 366 RPC_SKEL_FillBufferDone(((struct omx_packet *) 367 pBuffer)->data); 368 RPC_freePacket(pBuffer); 369 pBuffer = NULL; 370 break; 371 default: 372 eError = 373 TIMM_OSAL_WriteToPipe(pRPCCtx-> 374 pMsgPipe[nFxnIdx], &pBuffer, 375 RPC_MSG_SIZE_FOR_PIPE, TIMM_OSAL_SUSPEND); 376 RPC_assert(eError == TIMM_OSAL_ERR_NONE, 377 RPC_OMX_ErrorUndefined, 378 "Write to pipe failed"); 379 break; 380 } 381 } 382EXIT: 383 if (eRPCError != RPC_OMX_ErrorNone) 384 { 385 //AD TODO: Send error CB to client and then go back in loop to wait for killfd 386 if (pBuffer != NULL) 387 { 388 RPC_freePacket(pBuffer); 389 pBuffer = NULL; 390 } 391 /*Report all hardware errors as fatal and exit from listener thread*/ 392 if (eRPCError == RPC_OMX_ErrorHardware) 393 { 394 /*Implicit detail: pAppData is proxy component handle updated during 395 RPC_GetHandle*/ 396 hComp = (OMX_COMPONENTTYPE *) pRPCCtx->pAppData; 397 if(hComp != NULL) 398 { 399 pCompPrv = (PROXY_COMPONENT_PRIVATE *) hComp->pComponentPrivate; 400 /*Indicate fatal error. Users are expected to cleanup the OMX instance 401 to ensure all resources are cleaned up.*/ 402 pCompPrv->proxyEventHandler(hComp, pCompPrv->pILAppData, OMX_EventError, 403 OMX_ErrorHardware, 0, NULL); 404 } 405 break; 406 } 407 } 408 } 409 return (void*)0; 410} 411