/* ---------------------------------------------------------------------- * received response to an ILCS command * -------------------------------------------------------------------- */ static void vc_ilcs_command( uint32_t cmd, uint32_t xid, unsigned char *msg, int len ) { // execute this function call unsigned char resp[VC_ILCS_MAX_CMD_LENGTH]; int rlen = -1; if ( cmd >= IL_FUNCTION_MAX_NUM ) { assert(0); return; } VCIL_FN_T *fn = &vcilcs_fns[ cmd ]; if ( !fn ) { assert(0); return; } //logging_message( LOGGING_VMCS_VERBOSE, "ilcs_poll_fifo: executing xid:%x", xid ); // at this point we are executing in ILCS task context (videocore side). // FIXME: can this cause ilcs_execute_function() calls from within bowels of openmaxil? (*fn)( msg, len, resp, &rlen ); // make sure rlen has been initialised by the function assert( rlen != -1 ); // if rlen is zero, then we don't send a response if ( rlen ) vc_ilcs_transmit( IL_RESPONSE, xid, resp, rlen, NULL, 0 ); }
/* ---------------------------------------------------------------------- * received response to an ILCS command * -------------------------------------------------------------------- */ static void vc_ilcs_command( uint32_t cmd, uint32_t xid, unsigned char *msg, int len ) { // execute this function call unsigned char resp[VC_ILCS_MAX_CMD_LENGTH]; int rlen = -1; VCIL_FN_T *fn; if ( cmd >= IL_FUNCTION_MAX_NUM ) { vc_assert(0); return; } fn = &vcilcs_fns[ cmd ]; if ( !fn ) { vc_assert(0); return; } // at this point we are executing in ILCS task context (host side). // NOTE: this cause vc_ilcs_execute_function() calls from within bowels of openmaxil? (*fn)( msg, len, resp, &rlen ); // make sure rlen has been initialised by the function vc_assert( rlen != -1 ); // if rlen is zero, then we don't send a response if ( rlen ) vc_ilcs_transmit( IL_RESPONSE, xid, resp, rlen, NULL, 0 ); }
static void vc_ilcs_command_usr( uint32_t cmd, uint32_t xid, unsigned char *msg, int msglen ) { int rlen; uint8_t resp[VC_ILCS_MAX_CMD_LENGTH]; vcilcs_inb_put(cmd, xid, msg, msglen, resp, &rlen); // no responce is expected iommediately, it'll be sent asynch. if ( rlen ) vc_ilcs_transmit( IL_RESPONSE, xid, resp, rlen,NULL,0 ); }
int vc_ilcsinb_sendresp(vc_ilcsinb_t* msgptr) { vc_ilcs_transmit(IL_RESPONSE, msgptr->xid, msgptr->resp, msgptr->resplen,NULL,0); return 0; }
/* ---------------------------------------------------------------------- * send a string to the host side IL component service. if resp is NULL * then there is no response to this call, so we should not wait for one. * * returns response, written to 'resp' pointer * -------------------------------------------------------------------- */ void vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *resp, int resplen ) { VC_ILCS_WAIT_T *wait; int num; // the host MUST receive a response assert( resp ); // need to atomically find free ->wait entry os_semaphore_obtain( &vc_ilcsg.wait_sem ); for (;;) { num = 0; while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp ) num++; if ( num < VC_ILCS_MAX_WAITING ) break; assert( num < VC_ILCS_MAX_WAITING ); // might be a fatal error if another thread is relying // on this call completing before it can complete // we'll pause until we can carry on and hope that's sufficient. os_semaphore_release( &vc_ilcsg.wait_sem ); os_sleep( 10 ); // 10 msec os_semaphore_obtain( &vc_ilcsg.wait_sem ); } wait = &vc_ilcsg.wait[num]; wait->resp = resp; wait->xid = vc_ilcsg.next_xid++; os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND ); os_semaphore_obtain( &wait->sem ); // at this point, ->wait is exclusively ours () os_semaphore_release( &vc_ilcsg.wait_sem ); // write the command header. vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 ); if ( !os_thread_current(vc_ilcsg.thread) ) { os_semaphore_obtain( &wait->sem ); } else { // we're the vcilcs task, so wait for, and handle, incoming // messages while we're not completed for (;;) { // wait->sem will not be released until we process the response message if ( vc_ilcs_process_message() == 0 ) { // there were no more messages in the fifo; need to wait os_semaphore_obtain( &vc_ilcsg.rxmsg_sem ); continue; } // did the last message release wait->sem ? if ( !os_semaphore_obtained(&wait->sem) ) break; } } // safe to do the following - the assignment of NULL is effectively atomic os_semaphore_destroy( &wait->sem ); wait->resp = NULL; }
/* ---------------------------------------------------------------------- * send a string to the host side IL component service. if resp is NULL * then there is no response to this call, so we should not wait for one. * * returns 0 on successful call made, -1 on failure to send call. * on success, the response is written to 'resp' pointer * -------------------------------------------------------------------- */ int vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *bulk, int bulk_len, void *resp ) { VC_ILCS_WAIT_T *wait; int i, num; // the host MUST receive a response vc_assert( resp ); // need to atomically find free ->wait entry os_semaphore_obtain( &vc_ilcsg.wait_sem ); // we try a number of times then give up with an error message // rather than just deadlocking for (i=0; i<VC_ILCS_WAIT_TIMEOUT; i++) { num = 0; while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp ) num++; if ( num < VC_ILCS_MAX_WAITING || i == VC_ILCS_WAIT_TIMEOUT-1) break; // might be a fatal error if another thread is relying // on this call completing before it can complete // we'll pause until we can carry on and hope that's sufficient. os_semaphore_release( &vc_ilcsg.wait_sem ); os_sleep( 10 ); // 10 msec // if we're the vcilcs thread, then the waiters might need // us to handle their response, so try and clear those now if(os_thread_is_running(&vc_ilcsg.thread)) while(vc_ilcs_process_message(0)); os_logging_message( "%s: wait for sem", __FUNCTION__); os_semaphore_obtain( &vc_ilcsg.wait_sem ); } if(num == VC_ILCS_MAX_WAITING) { // failed to send message. vc_assert(0); os_semaphore_release( &vc_ilcsg.wait_sem ); return -1; } wait = &vc_ilcsg.wait[num]; wait->resp = resp; wait->xid = vc_ilcsg.next_xid++; os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND ); os_semaphore_obtain( &wait->sem ); // at this point, ->wait is exclusively ours () os_semaphore_release( &vc_ilcsg.wait_sem ); if(bulk) os_semaphore_obtain( &vc_ilcsg.send_sem); // write the command header. vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 ); if(bulk) { int result; result = vchi_bulk_queue_transmit( vc_ilcsg.vchi_handle, // call to VCHI bulk, bulk_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); vc_assert(result == 0); os_semaphore_release( &vc_ilcsg.send_sem); } if ( !os_thread_is_running(&vc_ilcsg.thread) ) { os_semaphore_obtain( &wait->sem ); } else { // we're the vcilcs task, so wait for, and handle, incoming // messages while we're not completed for (;;) { // wait->sem will not be released until we process the response message vc_ilcs_process_message(1); // did the last message release wait->sem ? if ( !os_semaphore_obtained(&wait->sem) ) break; } } // safe to do the following - the assignment of NULL is effectively atomic os_semaphore_destroy( &wait->sem ); wait->resp = NULL; return 0; }