/*********************************************************** * Name: vc_cec_receive_message * * Arguments: * pointer to initiator * pointer to follower * buffer to hold payload (max. 15 bytes) * pointer to length * * Description * Retrieve the most recent message, if there is no * pending message, both initiator and follower will * be set to 0xF, otherwise length is set to length * of message minus the header byte. * * Returns: if the command is successful (zero) or not (non-zero) * command is deemed successful even if there is no * pending message ***********************************************************/ VCHPRE_ int VCHPOST_ vc_cec_receive_message(uint32_t *initiator, uint32_t *follower, uint8_t *buffer, uint32_t *length) { int success = -1; vcos_assert(initiator && follower && buffer && length); success = cecservice_send_command_reply( VC_CEC_RECEIVE_MSG, NULL, 0, &cecservice_client.rx_msg, sizeof(CEC_RECEIVE_MSG_RESP_T)); if(success == 0) { cecservice_client.rx_msg.initiator = VC_VTOH32(cecservice_client.rx_msg.initiator); cecservice_client.rx_msg.follower = VC_VTOH32(cecservice_client.rx_msg.follower); cecservice_client.rx_msg.length = VC_VTOH32(cecservice_client.rx_msg.length); *initiator = cecservice_client.rx_msg.initiator; *follower = cecservice_client.rx_msg.follower; *length = cecservice_client.rx_msg.length; if(*length > 0) { memcpy(buffer, cecservice_client.rx_msg.payload, *length); } } else { *initiator = (uint32_t) CEC_AllDevices_eUnRegistered; *follower = (uint32_t) CEC_AllDevices_eUnRegistered; *length = 0L; } 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 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 = -1; int ret_code = 0; int32_t sem_ok = 0; if(lock_obtain() == 0) { //Note this will ALWAYS reset response buffer and overwrite any partially read responses use_gencmd_service(); 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 event 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) { #ifdef __NetBSD__ uint32_t v; #endif #ifdef __NetBSD__ memcpy(&v, gencmd_client.response_buffer, sizeof(v)); ret_code = VC_VTOH32(v); #else ret_code = VC_VTOH32( *(int *)gencmd_client.response_buffer ); #endif break; } else { gencmd_client.response_length = 0; } } } while(!gencmd_client.response_length && vcos_event_wait(&gencmd_client.message_available_event) == VCOS_SUCCESS); 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) vcos_min((int)gencmd_client.response_length, (int)maxlen)); } release_gencmd_service(); lock_release(); } // 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; }
int vc_host_get_app (void) { int status; uint32_t buffer; // Read app id. status = vc_host_read_consecutive(&buffer, VC_APP_ADDRESS, 4, 0); vc_assert(status == 0); return VC_VTOH32(buffer); }
/*********************************************************** * Name: vc_cec_get_physical_address * * Arguments: * pointer to physical address (returned as 16-bit packed value) * * Description * Get the physical address * * Returns: if the command is successful (zero) or not (non-zero) * If failed, physical address argument will not be changed * A physical address of 0xFFFF means CEC is not supported ***********************************************************/ VCHPRE_ int VCHPOST_ vc_cec_get_physical_address(uint16_t *physical_address) { uint32_t response; int32_t success = cecservice_send_command_reply( VC_CEC_GET_PHYSICAL_ADDR, NULL, 0, &response, sizeof(response)); if(success == 0) { *physical_address = (uint16_t)(VC_VTOH32(response) & 0xFFFF); } return success; }
/*********************************************************** * Name: vc_cec_get_logical_address * * Arguments: * pointer to logical address * * Description * Get the logical address, if one is being allocated * 0xF (unregistered) will be returned * * Returns: if the command is successful (zero) or not (non-zero) * logical_address is not modified if command failed ***********************************************************/ VCHPRE_ int VCHPOST_ vc_cec_get_logical_address(CEC_AllDevices_T *logical_address) { uint32_t response; int32_t success = cecservice_send_command_reply( VC_CEC_GET_LOGICAL_ADDR, NULL, 0, &response, sizeof(response)); if(success == 0) { *logical_address = (CEC_AllDevices_T)(VC_VTOH32(response) & 0xF); } return success; }
/*********************************************************** * Name: vc_dispmanx_display_get_info * * Arguments: * DISPMANX_DISPLAY_HANDLE_T display * DISPMANX_MODEINFO_T * pinfo * * Description: * * Returns: VCHI error * ***********************************************************/ VCHPRE_ int VCHPOST_ vc_dispmanx_display_get_info (DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_MODEINFO_T *pinfo) { GET_INFO_DATA_T info; int32_t success; display = VC_HTOV32(display); success = dispmanx_send_command_reply (EDispmanDisplayGetInfo, &display, sizeof(display), &info, sizeof(info)); if(success == 0) { pinfo->width = VC_VTOH32(info.width); pinfo->height = VC_VTOH32(info.height); pinfo->transform = (VC_IMAGE_TRANSFORM_T)VC_VTOH32(info.transform); pinfo->input_format = (DISPLAY_INPUT_FORMAT_T)VC_VTOH32(info.input_format); } return (int) success; }
/*********************************************************** * Name: dispmanx_get_handle * * Arguments: command, parameter buffer, parameter legnth * * Description: same as dispmanx_send_command but returns uint instead * * Returns: handle * ***********************************************************/ static uint32_t dispmanx_get_handle( uint32_t command, void *buffer, uint32_t length) { VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, {buffer, length} }; uint32_t success = 0; uint32_t response = 0; lock_obtain(); success += vchi_msg_queuev( dispmanx_client.client_handle[0], vector, sizeof(vector)/sizeof(vector[0]), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); if(success == 0) success = dispmanx_wait_for_reply(&response, sizeof(response)); lock_release(); return VC_VTOH32(response); }
/*********************************************************** * Name: vc_cec_get_topology * * Arguments: * pointer to topology struct * * Description * Get the topology * * Returns: if the command is successful (zero) or not (non-zero) * If successful, the topology will be set, otherwise it is unchanged * A topology with 1 device (us) means CEC is not supported * If there is no topology available, this also returns a failure. ***********************************************************/ VCHPRE_ int VCHPOST_ vc_cec_get_topology( VC_CEC_TOPOLOGY_T* topology) { int32_t success = cecservice_send_command( VC_CEC_GET_TOPOLOGY, NULL, 0, 1); if(success == 0) { success = cecservice_wait_for_bulk_receive(cecservice_client.topology, sizeof(VC_CEC_TOPOLOGY_T)); } if(success == 0) { int i; cecservice_client.topology->active_mask = VC_VTOH16(cecservice_client.topology->active_mask); cecservice_client.topology->num_devices = VC_VTOH16(cecservice_client.topology->num_devices); for(i = 0; i < 15; i++) { cecservice_client.topology->device_attr[i] = VC_VTOH32(cecservice_client.topology->device_attr[i]); } memcpy(topology, cecservice_client.topology, sizeof(VC_CEC_TOPOLOGY_T)); } return success; }
static int32_t dispmanx_send_command( uint32_t command, void *buffer, uint32_t length) { VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, {buffer, length} }; int32_t success = 0, response = -1; lock_obtain(); success = vchi_msg_queuev( dispmanx_client.client_handle[0], vector, sizeof(vector)/sizeof(vector[0]), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); if(success == 0 && !(command & DISPMANX_NO_REPLY_MASK)) { //otherwise only wait for a reply if we ask for one success = dispmanx_wait_for_reply(&response, sizeof(response)); } else { //Not waiting for a reply, send the success code back instead response = success; } lock_release(); return VC_VTOH32(response); }
static int32_t cecservice_send_command( uint32_t command, const void *buffer, uint32_t length, uint32_t has_reply) { VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, {buffer, length} }; int32_t success = 0; int32_t response; lock_obtain(); success = vchi_msg_queuev(cecservice_client.client_handle[0], vector, sizeof(vector)/sizeof(vector[0]), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); vcos_assert( success == 0 ); if(success == 0 && has_reply) { //otherwise only wait for a reply if we ask for one success = cecservice_wait_for_reply(&response, sizeof(response)); response = VC_VTOH32(response); } else { //No reply expected or failed to send, send the success code back instead response = success; } vcos_assert(success == 0); lock_release(); return response; }