/* Copyright (c) 2012, Broadcom Europe Ltd All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "vchost.h" #include "interface/vcos/vcos.h" #include "vcinclude/common.h" #include "vc_vchi_gencmd.h" #include "interface/vchi/vchi.h" #include "interface/vchi/common/endian.h" #include "interface/vmcs_host/vc_gencmd_defs.h" #ifdef HAVE_GENCMD_VERSION extern const char *gencmd_get_build_version(void); #error #endif /****************************************************************************** Local types and defines. ******************************************************************************/ #define GENCMD_MAX_LENGTH 512 typedef struct { VCHI_SERVICE_HANDLE_T open_handle[VCHI_MAX_NUM_CONNECTIONS]; uint32_t msg_flag[VCHI_MAX_NUM_CONNECTIONS]; char command_buffer[GENCMD_MAX_LENGTH+1]; char response_buffer[GENCMDSERVICE_MSGFIFO_SIZE]; uint32_t response_length; //Length of response minus the error code int num_connections; VCOS_MUTEX_T lock; int initialised; VCOS_EVENT_T message_available_event; } GENCMD_SERVICE_T; static GENCMD_SERVICE_T gencmd_client; /****************************************************************************** Static function. ******************************************************************************/ static void gencmd_callback( void *callback_param, VCHI_CALLBACK_REASON_T reason, void *msg_handle ); static __inline int lock_obtain (void) { int ret = -1; if(gencmd_client.initialised && vcos_mutex_lock(&gencmd_client.lock) == VCOS_SUCCESS) { ret = 0; } return ret; } static __inline void lock_release (void) { vcos_mutex_unlock(&gencmd_client.lock); } int use_gencmd_service(void) { int ret = 0; int i=0; for(i = 0; i < gencmd_client.num_connections; i++) { ret = (ret == 0) ? vchi_service_use(gencmd_client.open_handle[i]) : ret; } return ret; } int release_gencmd_service(void) { int ret = 0; int i=0; for(i = 0; i < gencmd_client.num_connections; i++) { ret = (ret == 0) ? vchi_service_release(gencmd_client.open_handle[i]) : ret; } return ret; } //call vc_vchi_gencmd_init to initialise int vc_gencmd_init() { assert(0); return 0; } /****************************************************************************** NAME vc_vchi_gencmd_init SYNOPSIS void vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) FUNCTION Initialise the general command service for use. A negative return value indicates failure (which may mean it has not been started on VideoCore). RETURNS int ******************************************************************************/ void vc_vchi_gencmd_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) { VCOS_STATUS_T status; int32_t success; int i; if (gencmd_client.initialised) return; // record the number of connections memset( &gencmd_client, 0, sizeof(GENCMD_SERVICE_T) ); gencmd_client.num_connections = (int) num_connections; status = vcos_mutex_create(&gencmd_client.lock, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); status = vcos_event_create(&gencmd_client.message_available_event, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); for (i=0; i= 0 && length < GENCMD_MAX_LENGTH) { int i; use_gencmd_service(); for( i=0; i= 0) { ret = vc_gencmd_read_response(response, maxlen); } release_gencmd_service(); return ret; } /****************************************************************************** NAME vc_gencmd_string_property SYNOPSIS int vc_gencmd_string_property(char *text, char *property, char **value, int *length) FUNCTION Given a text string, containing items of the form property=value, look for the named property and return the value. The start of the value is returned, along with its length. The value may contain spaces, in which case it is enclosed in double quotes. The double quotes are not included in the return parameters. Return non-zero if the property is found. RETURNS int ******************************************************************************/ int vc_gencmd_string_property(char *text, const char *property, char **value, int *length) { #define READING_PROPERTY 0 #define READING_VALUE 1 #define READING_VALUE_QUOTED 2 int state = READING_PROPERTY; int delimiter = 1, match = 0, len = (int)strlen(property); char *prop_start=text, *value_start=text; for (; *text; text++) { int ch = *text; switch (state) { case READING_PROPERTY: if (delimiter) prop_start = text; if (isspace(ch)) delimiter = 1; else if (ch == '=') { delimiter = 1; match = (text-prop_start==len && strncmp(prop_start, property, (size_t)(text-prop_start))==0); state = READING_VALUE; } else delimiter = 0; break; case READING_VALUE: if (delimiter) value_start = text; if (isspace(ch)) { if (match) goto success; delimiter = 1; state = READING_PROPERTY; } else if (delimiter && ch == '"') { delimiter = 1; state = READING_VALUE_QUOTED; } else delimiter = 0; break; case READING_VALUE_QUOTED: if (delimiter) value_start = text; if (ch == '"') { if (match) goto success; delimiter = 1; state = READING_PROPERTY; } else delimiter = 0; break; } } if (match) goto success; return 0; success: *value = value_start; *length = text - value_start; return 1; } /****************************************************************************** NAME vc_gencmd_number_property SYNOPSIS int vc_gencmd_number_property(char *text, char *property, int *number) FUNCTION Given a text string, containing items of the form property=value, look for the named property and return the numeric value. If such a numeric value is successfully found, return 1; otherwise return 0. RETURNS int ******************************************************************************/ int vc_gencmd_number_property(char *text, const char *property, int *number) { char *value, temp; int length, retval; if (vc_gencmd_string_property(text, property, &value, &length) == 0) return 0; temp = value[length]; value[length] = 0; /* coverity[secure_coding] - this is not insecure */ retval = sscanf(value, "0x%x", (unsigned int*)number); if (retval != 1) /* coverity[secure_coding] - this is not insecure */ retval = sscanf(value, "%d", number); value[length] = temp; return retval; } /****************************************************************************** NAME vc_gencmd_until SYNOPSIS int vc_gencmd_until(const char *cmd, const char *error_string, int timeout); FUNCTION Sends the command repeatedly, until one of the following situations occurs: The specified response string is found within the gencmd response. The specified error string is found within the gencmd response. The timeout is reached. The timeout is a rough value, do not use it for precise timing. RETURNS 0 if the requested response was detected. 1 if the error string is detected or the timeout is reached. ******************************************************************************/ int vc_gencmd_until( char *cmd, const char *property, char *value, const char *error_string, int timeout) { char response[128]; int length; char *ret_value; int ret = 1; use_gencmd_service(); for (;timeout > 0; timeout -= 10) { vc_gencmd(response, (int)sizeof(response), cmd); if (strstr(response,error_string)) { ret = 1; break; } else if (vc_gencmd_string_property(response, property, &ret_value, &length) && strncmp(value,ret_value,(size_t)length)==0) { ret = 0; break; } vcos_sleep(10); } release_gencmd_service(); return ret; }