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