//Receiver thread static void hostreqclient_func(unsigned int argc, void *argv) { int32_t success; int32_t i, nothing; while(1) { //Run forever waiting for a callback to happen // wait for the semaphore to say that there is a message success = os_semaphore_obtain(&hostreq_client_message_available); assert( success == 0 ); while(1) { //Read until we can read no more on all interfaces nothing = 0; for(i=0;i<hostreq_client.num_connections;i++) { success = vchi_msg_dequeue(hostreq_client.client_handle[i], hostreq_client.response_buffer, sizeof(hostreq_client.response_buffer), &hostreq_client.response_length, VCHI_FLAGS_NONE); if(success == 0) { hostreq_request_handler(i, &hostreq_client); } else { nothing++; } } //When there is nothing on all interfaces, wait for a callback if(nothing == hostreq_client.num_connections) { break; } } } }
static void bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle) { struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param; int32_t status; uint32_t msg_len; VC_AUDIO_MSG_T m; if (reason != VCHI_CALLBACK_MSG_AVAILABLE) return; status = vchi_msg_dequeue(sc->vchi_handle, &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { sc->msg_result = m.u.result.success; cv_signal(&sc->msg_avail_cv); } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { struct bcm2835_audio_chinfo *ch = m.u.complete.cookie; int count = m.u.complete.count & 0xffff; int perr = (m.u.complete.count & (1U << 30)) != 0; ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer); ch->free_buffer += count; if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) { chn_intr(ch->channel); cv_signal(&sc->data_cv); } } else printf("%s: unknown m.type: %d\n", __func__, m.type); }
/****************************************************************************** NAME vc_gencmd_read_response SYNOPSIS int vc_gencmd_read_response FUNCTION Block until something comes back RETURNS Error code from dequeue message ******************************************************************************/ int vc_gencmd_read_response (char *response, int maxlen) { int i = 0; int success = 0; int ret_code = 0; int32_t sem_ok = 0; //Note this will ALWAYS reset response buffer and overwrite any partially read responses do { //TODO : we need to deal with messages coming through on more than one connections properly //At the moment it will always try to read the first connection if there is something there for(i = 0; i < gencmd_client.num_connections; i++) { //Check if there is something in the queue, if so return immediately //otherwise wait for the semaphore and read again success = (int) vchi_msg_dequeue( gencmd_client.open_handle[i], gencmd_client.response_buffer, sizeof(gencmd_client.response_buffer), &gencmd_client.response_length, VCHI_FLAGS_NONE); if(success == 0) { ret_code = VC_VTOH32( *(int *)gencmd_client.response_buffer ); break; } else { gencmd_client.response_length = 0; } } } while(!gencmd_client.response_length && (sem_ok = os_semaphore_obtain( &gencmd_message_available_semaphore)) == 0); if(gencmd_client.response_length && sem_ok == 0) { gencmd_client.response_length -= sizeof(int); //first word is error code memcpy(response, gencmd_client.response_buffer+sizeof(int), (size_t) OS_MIN((int)gencmd_client.response_length, (int)maxlen)); } // If we read anything, return the VideoCore code. Error codes < 0 mean we failed to // read anything... //How do we let the caller know the response code of gencmd? //return ret_code; return success; }
/*********************************************************** * Name: cecservice_notify_func * * Arguments: CEC service state * * Description: This is the notification task which receives all CEC * service notifications * * Returns: does not return * ***********************************************************/ static void cecservice_notify_func( unsigned int argc, void *argv ) { int32_t success; CECSERVICE_HOST_STATE_T *state = (CECSERVICE_HOST_STATE_T *) argv; //first send a dummy message to the Videocore to let it know we are ready cecservice_send_command(VC_CEC_END_OF_LIST, NULL, 0, 0); while(1) { success = os_semaphore_obtain(&cecservice_notify_available_semaphore); vcos_assert(!success && state->initialised); do { uint32_t reason, param1, param2; //Get all notifications in the queue success = vchi_msg_dequeue( state->notify_handle[0], state->notify_buffer, sizeof(state->notify_buffer), &state->notify_length, VCHI_FLAGS_NONE ); if(success != 0 || state->notify_length < sizeof(uint32_t)*3 ) { continue; } lock_obtain(); //Check what notification it is and update ourselves accordingly before notifying the host app //All notifications are of format: reason, param1, param2 (all 32-bit unsigned int) reason = VC_VTOH32(state->notify_buffer[0]), param1 = VC_VTOH32(state->notify_buffer[1]), param2 = VC_VTOH32(state->notify_buffer[2]); //Unlike the TV service we have nothing to store here, so just call the callback lock_release(); //Now callback the host app if(state->notify_fn) { (*state->notify_fn)(state->notify_data, reason, param1, param2); } } while(success == 0 && state->notify_length >= sizeof(uint32_t)*3); //read the next message if any } //while (1) }
/*********************************************************** * Name: dispmanx_notify_handle * * Arguments: not used * * Description: this purely notifies the update callback * * Returns: does not return * ***********************************************************/ static void *dispmanx_notify_func( void *arg ) { int32_t success; VCOS_STATUS_T status; (void)arg; while (1) { DISPMANX_UPDATE_HANDLE_T handle; status = vcos_event_wait(&dispmanx_notify_available_event); if (status != VCOS_SUCCESS || !dispmanx_client.initialised) break; success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE ); if (success != 0) continue; handle = (DISPMANX_UPDATE_HANDLE_T)dispmanx_client.notify_buffer[0]; if (handle) { // This is the response to an update submit // Decrement the use count - the corresponding "use" is in vc_dispmanx_update_submit. vchi_service_release(dispmanx_client.notify_handle[0]); if (dispmanx_client.update_callback ) { vcos_assert( dispmanx_client.pending_update_handle == handle); dispmanx_client.update_callback(handle, dispmanx_client.update_callback_param); } } else { // This is a vsync notification if (dispmanx_client.vsync_callback ) { dispmanx_client.vsync_callback(handle, dispmanx_client.vsync_callback_param); } } } return 0; }
static void bcm2835_audio_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle) { struct bcm2835_audio_info *sc = (struct bcm2835_audio_info *)param; int32_t status; uint32_t msg_len; VC_AUDIO_MSG_T m; if (reason != VCHI_CALLBACK_MSG_AVAILABLE) return; status = vchi_msg_dequeue(sc->vchi_handle, &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { if (m.u.result.success) { device_printf(sc->dev, "msg type %08x failed\n", m.type); } } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { struct bcm2835_audio_chinfo *ch = m.u.complete.cookie; int count = m.u.complete.count & 0xffff; int perr = (m.u.complete.count & (1U << 30)) != 0; ch->callbacks++; if (perr) ch->underruns++; BCM2835_AUDIO_LOCK(sc); if (ch->playback_state != PLAYBACK_IDLE) { /* Prevent LOR */ BCM2835_AUDIO_UNLOCK(sc); chn_intr(sc->pch.channel); BCM2835_AUDIO_LOCK(sc); } /* We should check again, state might have changed */ if (ch->playback_state != PLAYBACK_IDLE) { if (!perr) { if ((ch->available_space + count)> VCHIQ_AUDIO_BUFFER_SIZE) { device_printf(sc->dev, "inconsistent data in callback:\n"); device_printf(sc->dev, "available_space == %d, count = %d, perr=%d\n", ch->available_space, count, perr); device_printf(sc->dev, "retrieved_samples = %lld, submitted_samples = %lld\n", ch->retrieved_samples, ch->submitted_samples); } ch->available_space += count; ch->retrieved_samples += count; } if (perr || (ch->available_space >= VCHIQ_AUDIO_PACKET_SIZE)) cv_signal(&sc->worker_cv); } BCM2835_AUDIO_UNLOCK(sc); } else printf("%s: unknown m.type: %d\n", __func__, m.type); }
/*********************************************************** * Name: dispmanx_wait_for_reply * * Arguments: response buffer, buffer length * * Description: blocked until something is in the buffer * * Returns error code of vchi * ***********************************************************/ static int32_t dispmanx_wait_for_reply(void *response, uint32_t max_length) { int32_t success = 0; uint32_t length_read = 0; do { //TODO : we need to deal with messages coming through on more than one connections properly //At the moment it will always try to read the first connection if there is something there //Check if there is something in the queue, if so return immediately //otherwise wait for the semaphore and read again success = vchi_msg_dequeue( dispmanx_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE ); } while( length_read == 0 && vcos_event_wait(&dispmanx_message_available_event) == VCOS_SUCCESS ); return success; }
static void audio_vchi_callback(void *param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle) { AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param; int32_t status; int32_t msg_len; VC_AUDIO_MSG_T m; LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n", instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle); if (reason != VCHI_CALLBACK_MSG_AVAILABLE) { return; } if (!instance) { LOG_ERR(" .. instance is null\n"); BUG(); return; } if (!instance->vchi_handle[0]) { LOG_ERR(" .. instance->vchi_handle[0] is null\n"); BUG(); return; } status = vchi_msg_dequeue(instance->vchi_handle[0], &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { LOG_DBG (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n", instance, m.u.result.success); instance->result = m.u.result.success; complete(&instance->msg_avail_comp); } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { bcm2835_alsa_stream_t *alsa_stream = instance->alsa_stream; irq_handler_t callback = (irq_handler_t) m.u.complete.callback; LOG_DBG (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n", instance, m.u.complete.count); if (alsa_stream && callback) { atomic_add(m.u.complete.count, &alsa_stream->retrieved); callback(0, alsa_stream); } else { LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n", alsa_stream, callback); } } else { LOG_ERR(" .. unexpected m.type=%d\n", m.type); } LOG_DBG(" .. OUT\n"); }
/*********************************************************** * Name: cecservice_wait_for_reply * * Arguments: response buffer, buffer length * * Description: blocked until something is in the buffer * * Returns error code of vchi * ***********************************************************/ static int32_t cecservice_wait_for_reply(void *response, uint32_t max_length) { int32_t success = 0; int32_t sem_ok = 0; uint32_t length_read = 0; do { //TODO : we need to deal with messages coming through on more than one connections properly //At the moment it will always try to read the first connection if there is something there //Check if there is something in the queue, if so return immediately //otherwise wait for the semaphore and read again success = vchi_msg_dequeue( cecservice_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE ); } while( length_read == 0 && (sem_ok = os_semaphore_obtain( &cecservice_message_available_semaphore)) == 0); return success; }
/** * <DFN>vc_hdcp2_service_wait_for_reply</DFN> blocks until a response comes back * from Videocore. * * @param client_handle is the vchi client handle * * @param sema is the signalling semaphore indicating a reply * * @param response is the reponse buffer * * @param max_length is the maximum length of the buffer * * @param actual_length will be set to the actual length of the buffer (or zero if error) * * @return zero if successful, vchi error code otherwise */ int32_t vc_hdcp2_service_wait_for_reply(VCHI_SERVICE_HANDLE_T client_handle, VCOS_SEMAPHORE_T *sema, void *response, uint32_t max_length, uint32_t *actual_length) { int32_t success = 0; VCOS_STATUS_T status; uint32_t length_read = 0; vcos_assert(sema); vcos_assert(response && max_length); do { //TODO : we need to deal with messages coming through on more than one connections properly //At the moment it will always try to read the first connection if there is something there //Check if there is something in the queue, if so return immediately //otherwise wait for the semaphore and read again success = vchi_msg_dequeue( client_handle, response, max_length, &length_read, VCHI_FLAGS_NONE ); } while( length_read == 0 || (status = vcos_semaphore_trywait(sema)) != VCOS_SUCCESS); if(vcos_verify(*actual_length)) { *actual_length = (success == 0)? length_read : 0; } return success; }
/*********************************************************** * Name: dispmanx_notify_handle * * Arguments: not used * * Description: this purely notifies the update callback * * Returns: does not return * ***********************************************************/ static void *dispmanx_notify_func( void *arg ) { int32_t success; VCOS_STATUS_T status; (void)arg; while(1) { status = vcos_event_wait(&dispmanx_notify_available_event); if(status != VCOS_SUCCESS || !dispmanx_client.initialised) break; success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE ); vchi_service_release(dispmanx_client.notify_handle[0]); // corresponding use in vc_dispmanx_update_submit if(success != 0) continue; if(dispmanx_client.update_callback ) { vcos_assert( dispmanx_client.pending_update_handle == (DISPMANX_UPDATE_HANDLE_T) dispmanx_client.notify_buffer[1]); dispmanx_client.update_callback((DISPMANX_UPDATE_HANDLE_T) dispmanx_client.notify_buffer[1], dispmanx_client.update_callback_param); } } return 0; }
int32_t vc_vchi_fb_read(VC_VCHI_FB_HANDLE_T handle, uint32_t res_handle, void *buf, int32_t size) { int32_t ret, success = 0; FB_INSTANCE_T *instance = handle; uint32_t msg_len; VC_FB_MSG_HDR_T *msg_hdr; VC_FB_READ_T *fb_read; VC_FB_RESULT_T result; if (handle == NULL) { LOG_ERR("%s: invalid handle", __func__); ret = -1; goto out; } if (buf == NULL) { LOG_ERR("%s: invalid buffer pointer", __func__); ret = -1; goto out; } if (size <= 0) { LOG_ERR("%s: invalid buffer size %d", __func__, size); ret = -1; goto out; } mutex_lock(&instance->vchi_mutex); vchi_service_use(instance->vchi_handle[0]); LOG_INFO("%s: enter", __func__); msg_len = sizeof(*msg_hdr) + sizeof(*fb_read); memset(instance->msg_buf, 0, msg_len); msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf; msg_hdr->type = VC_FB_MSG_TYPE_READ; fb_read = (VC_FB_READ_T *) msg_hdr->body; fb_read->res_handle = res_handle; fb_read->size = size; /* Send the message to the videocore */ success = vchi_msg_queue(instance->vchi_handle[0], instance->msg_buf, msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); if (success != 0) { LOG_ERR("%s: failed to queue message (success=%d)", __func__, success); ret = -1; goto unlock; } LOG_INFO("%s: done sending msg", __func__); /* We are expecting a reply from the videocore */ down(&instance->msg_avail); success = vchi_msg_dequeue(instance->vchi_handle[0], &result, sizeof(result), &msg_len, VCHI_FLAGS_NONE); LOG_INFO("%s: got reply message %x", __func__, result.success); if (success != 0) { LOG_ERR("%s: failed to dequeue message (success=%d)", __func__, success); ret = -1; goto unlock; } else if (msg_len != sizeof(result)) { LOG_ERR("%s: incorrect message length %u (expected=%u)", __func__, msg_len, sizeof(result)); ret = -1; goto unlock; } LOG_INFO("%s: all good do bulk_receive %x", __func__, result.success); success = vchi_bulk_queue_receive(instance->vchi_handle[0], buf, size, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, 0); if (success != 0) LOG_ERR("%s: vchi_bulk_queue_receive failed", __func__); unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); ret = success; LOG_INFO("%s: exit", __func__); out: return ret; }
int32_t vc_vchi_fb_cfg(VC_VCHI_FB_HANDLE_T handle, VC_FB_CFG_T * cfg, VC_FB_CFG_RESULT_T * cfg_result) { int32_t ret; FB_INSTANCE_T *instance = handle; int32_t success; uint32_t msg_len; VC_FB_MSG_HDR_T *msg_hdr; if (handle == NULL) { LOG_ERR("%s: invalid handle", __func__); ret = -1; goto out; } if (cfg == NULL) { LOG_ERR("%s: invalid cfg pointer", __func__); ret = -1; goto out; } if (cfg_result == NULL) { LOG_ERR("%s: invalid cfg_result pointer", __func__); ret = -1; goto out; } mutex_lock(&instance->vchi_mutex); vchi_service_use(instance->vchi_handle[0]); msg_len = sizeof(*msg_hdr) + sizeof(*cfg); memset(instance->msg_buf, 0, msg_len); msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf; msg_hdr->type = VC_FB_MSG_TYPE_CFG; /* Copy the user buffer into the message buffer */ memcpy(msg_hdr->body, cfg, sizeof(*cfg)); /* Send the message to the videocore */ success = vchi_msg_queue(instance->vchi_handle[0], instance->msg_buf, msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); if (success != 0) { LOG_ERR("%s: failed to queue message (success=%d)", __func__, success); ret = -1; goto unlock; } /* We are expecting a reply from the videocore */ down(&instance->msg_avail); success = vchi_msg_dequeue(instance->vchi_handle[0], cfg_result, sizeof(*cfg_result), &msg_len, VCHI_FLAGS_NONE); if (success != 0) { LOG_ERR("%s: failed to dequeue message (success=%d)", __func__, success); ret = -1; goto unlock; } else if (msg_len != sizeof(*cfg_result)) { LOG_ERR("%s: incorrect message length %u (expected=%u)", __func__, msg_len, sizeof(*cfg_result)); ret = -1; goto unlock; } ret = cfg_result->success ? -1 : 0; unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); out: return ret; }
int32_t vc_vchi_fb_swap(VC_VCHI_FB_HANDLE_T handle, uint32_t res_handle, uint32_t active_frame) { int ret; FB_INSTANCE_T *instance = handle; int32_t success; uint32_t msg_len; VC_FB_MSG_HDR_T *msg_hdr; VC_FB_SWAP_T *swap; VC_FB_RESULT_T result; if (handle == NULL) { LOG_ERR("%s: invalid handle %p", __func__, handle); return -1; } mutex_lock(&instance->vchi_mutex); vchi_service_use(instance->vchi_handle[0]); msg_len = sizeof(*msg_hdr) + sizeof(*swap); memset(instance->msg_buf, 0, msg_len); msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf; msg_hdr->type = VC_FB_MSG_TYPE_SWAP; swap = (VC_FB_SWAP_T *) msg_hdr->body; swap->res_handle = res_handle; swap->active_frame = active_frame; /* Send the message to the videocore */ success = vchi_msg_queue(instance->vchi_handle[0], instance->msg_buf, msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); if (success != 0) { LOG_ERR("%s: failed to queue message (success=%d)", __func__, success); ret = -1; goto unlock; } /* We are expecting a reply from the videocore */ down(&instance->msg_avail); success = vchi_msg_dequeue(instance->vchi_handle[0], &result, sizeof(result), &msg_len, VCHI_FLAGS_NONE); if (success != 0) { LOG_ERR("%s: failed to dequeue message (success=%d)", __func__, success); ret = -1; goto unlock; } else if (msg_len != sizeof(result)) { LOG_ERR("%s: incorrect message length %u (expected=%u)", __func__, msg_len, sizeof(result)); ret = -1; goto unlock; } ret = result.success ? -1 : 0; unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); return ret; }
int32_t vc_vchi_fb_alloc(VC_VCHI_FB_HANDLE_T handle, VC_FB_ALLOC_T * alloc, VC_FB_ALLOC_RESULT_T * alloc_result) { FB_INSTANCE_T *instance = handle; int32_t success; uint32_t msg_len; VC_FB_MSG_HDR_T *msg_hdr; int32_t ret = -1; if (handle == NULL) { LOG_ERR("%s: invalid handle %p", __func__, handle); return -1; } if (alloc == NULL) { LOG_ERR("%s: invalid alloc pointer %p", __func__, alloc); return -1; } /* TODO check individual alloc member values */ if (alloc_result == NULL) { LOG_ERR("%s: invalid alloc_result pointer 0x%p", __func__, alloc_result); return -1; } mutex_lock(&instance->vchi_mutex); vchi_service_use(instance->vchi_handle[0]); msg_len = sizeof(*msg_hdr) + sizeof(*alloc); memset(instance->msg_buf, 0, msg_len); msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf; msg_hdr->type = VC_FB_MSG_TYPE_ALLOC; /* Copy the user buffer into the message buffer */ memcpy(msg_hdr->body, alloc, sizeof(*alloc)); /* Send the message to the videocore */ success = vchi_msg_queue(instance->vchi_handle[0], instance->msg_buf, msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); if (success != 0) { LOG_ERR("%s: failed to queue message (success=%d)", __func__, success); goto unlock; } /* We are expecting a reply from the videocore */ down(&instance->msg_avail); success = vchi_msg_dequeue(instance->vchi_handle[0], alloc_result, sizeof(*alloc_result), &msg_len, VCHI_FLAGS_NONE); if (success != 0) { LOG_ERR("%s: failed to dequeue message (success=%d)", __func__, success); goto unlock; } else if (msg_len != sizeof(*alloc_result)) { LOG_ERR("%s: incorrect message length %u (expected=%u)", __func__, msg_len, sizeof(*alloc_result)); goto unlock; } /* success if we got to here */ ret = 0; unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); return ret; }
int32_t vc_vchi_fb_get_scrn_info(VC_VCHI_FB_HANDLE_T handle, VC_FB_SCRN scrn, VC_FB_SCRN_INFO_T * info) { int ret; FB_INSTANCE_T *instance = handle; int32_t success; uint32_t msg_len; VC_FB_MSG_HDR_T *msg_hdr; VC_FB_GET_SCRN_INFO_T *get_scrn_info; if (handle == NULL) { LOG_ERR("%s: invalid handle %p", __func__, handle); return -1; } if (scrn >= VC_FB_SCRN_MAX) { LOG_ERR("%s: invalid screen %u", __func__, scrn); return -1; } if (info == NULL) { LOG_ERR("%s: invalid info pointer %p", __func__, info); return -1; } mutex_lock(&instance->vchi_mutex); vchi_service_use(instance->vchi_handle[0]); msg_len = sizeof(*msg_hdr) + sizeof(*get_scrn_info); memset(instance->msg_buf, 0, msg_len); msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf; msg_hdr->type = VC_FB_MSG_TYPE_GET_SCRN_INFO; get_scrn_info = (VC_FB_GET_SCRN_INFO_T *) msg_hdr->body; get_scrn_info->scrn = scrn; /* Send the message to the videocore */ success = vchi_msg_queue(instance->vchi_handle[0], instance->msg_buf, msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); if (success != 0) { LOG_ERR("%s: failed to queue message (success=%d)", __func__, success); ret = -1; goto unlock; } /* We are expecting a reply from the videocore */ down(&instance->msg_avail); success = vchi_msg_dequeue(instance->vchi_handle[0], info, sizeof(*info), &msg_len, VCHI_FLAGS_NONE); if (success != 0) { LOG_ERR("%s: failed to dequeue message (success=%d)", __func__, success); ret = -1; goto unlock; } else if (msg_len != sizeof(*info)) { LOG_ERR("%s: incorrect message length %u (expected=%u)", __func__, msg_len, sizeof(*info)); ret = -1; goto unlock; } ret = 0; unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); return ret; }