diff options
-rw-r--r-- | build-aux/qmi-codegen/Client.py | 46 | ||||
-rw-r--r-- | build-aux/qmi-codegen/Message.py | 5 | ||||
-rw-r--r-- | build-aux/qmi-codegen/MessageList.py | 85 | ||||
-rw-r--r-- | docs/reference/libqmi-glib/libqmi-glib-common.sections | 18 | ||||
-rw-r--r-- | docs/reference/libqmi-glib/libqmi-glib-docs.xml | 1 | ||||
-rw-r--r-- | src/libqmi-glib/Makefile.am | 2 | ||||
-rw-r--r-- | src/libqmi-glib/libqmi-glib.h | 1 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-device.c | 226 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-device.h | 34 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message-context.c | 123 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message-context.h | 74 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message.c | 121 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-message.h | 30 | ||||
-rw-r--r-- | src/libqmi-glib/qmi-proxy.c | 3 |
14 files changed, 627 insertions, 142 deletions
diff --git a/build-aux/qmi-codegen/Client.py b/build-aux/qmi-codegen/Client.py index 1e342ae..32e1e0d 100644 --- a/build-aux/qmi-codegen/Client.py +++ b/build-aux/qmi-codegen/Client.py @@ -278,6 +278,7 @@ class Client: continue translations['message_name'] = message.name + translations['message_vendor_id'] = message.vendor translations['message_underscore'] = utils.build_underscore_name(message.name) translations['message_fullname_underscore'] = utils.build_underscore_name(message.fullname) translations['input_camelcase'] = utils.build_camelcase_name(message.input.fullname) @@ -370,7 +371,7 @@ class Client: ' QmiMessage *reply;\n' ' ${output_camelcase} *output;\n' '\n' - ' reply = qmi_device_command_finish (device, res, &error);\n' + ' reply = qmi_device_command_full_finish (device, res, &error);\n' ' if (!reply) {\n') if message.abort: @@ -461,7 +462,13 @@ class Client: ' GSimpleAsyncResult *result;\n' ' QmiMessage *request;\n' ' GError *error = NULL;\n' - ' guint16 transaction_id;\n' + ' guint16 transaction_id;\n') + + if message.vendor is not None: + template += ( + ' QmiMessageContext *context;\n') + + template += ( '\n' ' result = g_simple_async_result_new (G_OBJECT (self),\n' ' callback,\n' @@ -490,15 +497,36 @@ class Client: ' "transaction-id",\n' ' GUINT_TO_POINTER (transaction_id));\n') + if message.vendor is not None: + template += ( + '\n' + ' context = qmi_message_context_new ();\n' + ' qmi_message_context_set_vendor_id (context, ${message_vendor_id});\n') + template += ( '\n' - ' qmi_device_command (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),\n' - ' request,\n' - ' timeout,\n' - ' cancellable,\n' - ' (GAsyncReadyCallback)${message_underscore}_ready,\n' - ' result);\n' - ' qmi_message_unref (request);\n' + ' qmi_device_command_full (QMI_DEVICE (qmi_client_peek_device (QMI_CLIENT (self))),\n' + ' request,\n') + + if message.vendor is not None: + template += ( + ' context,\n') + else: + template += ( + ' NULL,\n') + + template += ( + ' timeout,\n' + ' cancellable,\n' + ' (GAsyncReadyCallback)${message_underscore}_ready,\n' + ' result);\n' + ' qmi_message_unref (request);\n') + + if message.vendor is not None: + template += ( + ' qmi_message_context_unref (context);\n') + + template += ( '}\n' '\n') cfile.write(string.Template(template).substitute(translations)) diff --git a/build-aux/qmi-codegen/Message.py b/build-aux/qmi-codegen/Message.py index aae9561..9c78cf5 100644 --- a/build-aux/qmi-codegen/Message.py +++ b/build-aux/qmi-codegen/Message.py @@ -45,6 +45,11 @@ class Message: self.static = True if 'scope' in dictionary and dictionary['scope'] == 'library-only' else False self.abort = True if 'abort' in dictionary and dictionary['abort'] == 'yes' else False + # The vendor id if this command is vendor specific + self.vendor = dictionary['vendor'] if 'vendor' in dictionary else None + if self.type == 'Indication' and self.vendor is not None: + raise ValueError('Vendor-specific indications unsupported') + # The message prefix self.prefix = 'Qmi ' + self.type diff --git a/build-aux/qmi-codegen/MessageList.py b/build-aux/qmi-codegen/MessageList.py index bbd020f..4331b90 100644 --- a/build-aux/qmi-codegen/MessageList.py +++ b/build-aux/qmi-codegen/MessageList.py @@ -73,8 +73,13 @@ class MessageList: if message.type == 'Message': translations['enum_name'] = message.id_enum_name translations['enum_value'] = message.id - enum_template = ( - ' ${enum_name} = ${enum_value},\n') + if message.vendor is None: + enum_template = ( + ' ${enum_name} = ${enum_value},\n') + else: + translations['vendor'] = message.vendor + enum_template = ( + ' ${enum_name} = ${enum_value}, /* vendor ${vendor} */\n') template += string.Template(enum_template).substitute(translations) template += ( @@ -118,6 +123,7 @@ class MessageList: 'G_GNUC_INTERNAL\n' 'gchar *__qmi_message_${service}_get_printable (\n' ' QmiMessage *self,\n' + ' QmiMessageContext *context,\n' ' const gchar *line_prefix);\n' '\n' '#endif\n' @@ -129,6 +135,7 @@ class MessageList: 'gchar *\n' '__qmi_message_${service}_get_printable (\n' ' QmiMessage *self,\n' + ' QmiMessageContext *context,\n' ' const gchar *line_prefix)\n' '{\n' ' if (qmi_message_is_indication (self)) {\n' @@ -138,7 +145,6 @@ class MessageList: if message.type == 'Indication': translations['enum_name'] = message.id_enum_name translations['message_underscore'] = utils.build_underscore_name (message.name) - translations['enum_value'] = message.id inner_template = ( ' case ${enum_name}:\n' ' return indication_${message_underscore}_get_printable (self, line_prefix);\n') @@ -149,21 +155,39 @@ class MessageList: ' return NULL;\n' ' }\n' ' } else {\n' - ' switch (qmi_message_get_message_id (self)) {\n') + ' guint16 vendor_id;\n' + '\n' + ' vendor_id = (context ? qmi_message_context_get_vendor_id (context) : QMI_MESSAGE_VENDOR_GENERIC);\n' + ' if (vendor_id == QMI_MESSAGE_VENDOR_GENERIC) {\n' + ' switch (qmi_message_get_message_id (self)) {\n') for message in self.list: - if message.type == 'Message': + if message.type == 'Message' and message.vendor is None: translations['enum_name'] = message.id_enum_name translations['message_underscore'] = utils.build_underscore_name (message.name) - translations['enum_value'] = message.id inner_template = ( - ' case ${enum_name}:\n' - ' return message_${message_underscore}_get_printable (self, line_prefix);\n') + ' case ${enum_name}:\n' + ' return message_${message_underscore}_get_printable (self, line_prefix);\n') template += string.Template(inner_template).substitute(translations) template += ( - ' default:\n' - ' return NULL;\n' + ' default:\n' + ' return NULL;\n' + ' }\n' + ' } else {\n') + + for message in self.list: + if message.type == 'Message' and message.vendor is not None: + translations['enum_name'] = message.id_enum_name + translations['message_underscore'] = utils.build_underscore_name (message.name) + translations['message_vendor'] = message.vendor + inner_template = ( + ' if (vendor_id == ${message_vendor} && (qmi_message_get_message_id (self) == ${enum_name}))\n' + ' return message_${message_underscore}_get_printable (self, line_prefix);\n') + template += string.Template(inner_template).substitute(translations) + + template += ( + ' return NULL;\n' ' }\n' ' }\n' '}\n') @@ -184,6 +208,7 @@ class MessageList: 'G_GNUC_INTERNAL\n' 'gboolean __qmi_message_${service}_get_version_introduced (\n' ' QmiMessage *self,\n' + ' QmiMessageContext *context,\n' ' guint *major,\n' ' guint *minor);\n' '\n' @@ -196,27 +221,53 @@ class MessageList: 'gboolean\n' '__qmi_message_${service}_get_version_introduced (\n' ' QmiMessage *self,\n' + ' QmiMessageContext *context,\n' ' guint *major,\n' ' guint *minor)\n' '{\n' - ' switch (qmi_message_get_message_id (self)) {\n') + ' guint16 vendor_id;\n' + '\n' + ' vendor_id = (context ? qmi_message_context_get_vendor_id (context) : QMI_MESSAGE_VENDOR_GENERIC);\n' + ' if (vendor_id == QMI_MESSAGE_VENDOR_GENERIC) {\n' + ' switch (qmi_message_get_message_id (self)) {\n') for message in self.list: - if message.type == 'Message': + if message.type == 'Message' and message.vendor is None: + # Only add if we know the version info + if message.version_info != []: + translations['enum_name'] = message.id_enum_name + translations['message_major'] = message.version_info[0] + translations['message_minor'] = message.version_info[1] + inner_template = ( + ' case ${enum_name}:\n' + ' *major = ${message_major};\n' + ' *minor = ${message_minor};\n' + ' return TRUE;\n') + template += string.Template(inner_template).substitute(translations) + + template += ( + ' default:\n' + ' return FALSE;\n' + ' }\n' + ' } else {\n') + + for message in self.list: + if message.type == 'Message' and message.vendor is not None: # Only add if we know the version info if message.version_info != []: translations['enum_name'] = message.id_enum_name translations['message_major'] = message.version_info[0] translations['message_minor'] = message.version_info[1] + translations['message_vendor'] = message.vendor inner_template = ( - ' case ${enum_name}:\n' - ' *major = ${message_major};\n' - ' *minor = ${message_minor};\n' - ' return TRUE;\n') + ' if (vendor_id == ${message_vendor} && (qmi_message_get_message_id (self) == ${enum_name})) {\n' + ' *major = ${message_major};\n' + ' *minor = ${message_minor};\n' + ' return TRUE;\n' + ' }\n') template += string.Template(inner_template).substitute(translations) template += ( - ' default:\n' ' return FALSE;\n' ' }\n' '}\n') diff --git a/docs/reference/libqmi-glib/libqmi-glib-common.sections b/docs/reference/libqmi-glib/libqmi-glib-common.sections index a81af67..6edf5fe 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-common.sections +++ b/docs/reference/libqmi-glib/libqmi-glib-common.sections @@ -73,6 +73,8 @@ qmi_device_set_instance_id qmi_device_set_instance_id_finish qmi_device_command qmi_device_command_finish +qmi_device_command_full +qmi_device_command_full_finish qmi_device_get_service_version_info qmi_device_get_service_version_info_finish qmi_device_open_flags_build_string_from_mask @@ -1060,6 +1062,7 @@ qmi_message_get_message_id qmi_message_get_length qmi_message_get_raw qmi_message_get_version_introduced +qmi_message_get_version_introduced_full <SUBSECTION TLV writer> qmi_message_tlv_write_init qmi_message_tlv_write_reset @@ -1097,10 +1100,25 @@ qmi_message_add_raw_tlv qmi_message_set_transaction_id <SUBSECTION Printable> qmi_message_get_printable +qmi_message_get_printable_full qmi_message_get_tlv_printable </SECTION> <SECTION> +<FILE>qmi-message-context</FILE> +QMI_MESSAGE_VENDOR_GENERIC +QmiMessageContext +qmi_message_context_new +qmi_message_context_ref +qmi_message_context_unref +<SUBSECTION Vendor> +qmi_message_context_set_vendor_id +qmi_message_context_get_vendor_id +<SUBSECTION Standard> +qmi_message_context_get_type +</SECTION> + +<SECTION> <FILE>qmi-utils</FILE> QmiEndian <SUBSECTION Traces> diff --git a/docs/reference/libqmi-glib/libqmi-glib-docs.xml b/docs/reference/libqmi-glib/libqmi-glib-docs.xml index 07f9795..55f4ec8 100644 --- a/docs/reference/libqmi-glib/libqmi-glib-docs.xml +++ b/docs/reference/libqmi-glib/libqmi-glib-docs.xml @@ -45,6 +45,7 @@ <title>Core</title> <xi:include href="xml/qmi-version.xml"/> <xi:include href="xml/qmi-message.xml"/> + <xi:include href="xml/qmi-message-context.xml"/> <xi:include href="xml/qmi-device.xml"/> <xi:include href="xml/qmi-client.xml"/> <xi:include href="xml/qmi-proxy.xml"/> diff --git a/src/libqmi-glib/Makefile.am b/src/libqmi-glib/Makefile.am index 8731de7..e379b0b 100644 --- a/src/libqmi-glib/Makefile.am +++ b/src/libqmi-glib/Makefile.am @@ -35,6 +35,7 @@ libqmi_glib_la_SOURCES = \ qmi-utils.h qmi-utils.c \ qmi-compat.h qmi-compat.c \ qmi-message.h qmi-message.c \ + qmi-message-context.h qmi-message-context.c \ qmi-device.h qmi-device.c \ qmi-client.h qmi-client.c \ qmi-proxy.h qmi-proxy.c @@ -68,6 +69,7 @@ include_HEADERS = \ qmi-enums-voice.h \ qmi-utils.h \ qmi-message.h \ + qmi-message-context.h \ qmi-device.h \ qmi-client.h \ qmi-proxy.h diff --git a/src/libqmi-glib/libqmi-glib.h b/src/libqmi-glib/libqmi-glib.h index f954342..1e1459e 100644 --- a/src/libqmi-glib/libqmi-glib.h +++ b/src/libqmi-glib/libqmi-glib.h @@ -33,6 +33,7 @@ #include "qmi-client.h" #include "qmi-proxy.h" #include "qmi-message.h" +#include "qmi-message-context.h" #include "qmi-enums.h" #include "qmi-utils.h" diff --git a/src/libqmi-glib/qmi-device.c b/src/libqmi-glib/qmi-device.c index d93044d..6f7ed48 100644 --- a/src/libqmi-glib/qmi-device.c +++ b/src/libqmi-glib/qmi-device.c @@ -18,7 +18,7 @@ * Boston, MA 02110-1301 USA. * * Copyright (C) 2012 Lanedo GmbH - * Copyright (C) 2012-2015 Aleksander Morgado <aleksander@aleksander.es> + * Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es> */ #include <config.h> @@ -143,25 +143,28 @@ typedef struct { } TransactionWaitContext; typedef struct { - QmiMessage *message; - GSimpleAsyncResult *result; - GSource *timeout_source; - GCancellable *cancellable; - gulong cancellable_id; + QmiMessage *message; + QmiMessageContext *message_context; + GSimpleAsyncResult *result; + GSource *timeout_source; + GCancellable *cancellable; + gulong cancellable_id; TransactionWaitContext *wait_ctx; } Transaction; static Transaction * -transaction_new (QmiDevice *self, - QmiMessage *message, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +transaction_new (QmiDevice *self, + QmiMessage *message, + QmiMessageContext *message_context, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { Transaction *tr; tr = g_slice_new0 (Transaction); tr->message = qmi_message_ref (message); + tr->message_context = (message_context ? qmi_message_context_ref (message_context) : NULL); tr->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, @@ -200,6 +203,8 @@ transaction_complete_and_free (Transaction *tr, g_simple_async_result_complete_in_idle (tr->result); g_object_unref (tr->result); + if (tr->message_context) + qmi_message_context_unref (tr->message_context); qmi_message_unref (tr->message); g_slice_free (Transaction, tr); } @@ -1590,32 +1595,69 @@ report_indication (QmiClient *client, } static void -process_message (QmiDevice *self, - QmiMessage *message) -{ - if (qmi_utils_get_traces_enabled ()) { - gchar *printable; +trace_message (QmiDevice *self, + QmiMessage *message, + gboolean sent_or_received, + const gchar *message_str, + QmiMessageContext *message_context) +{ + gchar *printable; + const gchar *prefix_str; + const gchar *action_str; + gchar *vendor_str = NULL; + + if (!qmi_utils_get_traces_enabled ()) + return; - printable = __qmi_utils_str_hex (((GByteArray *)message)->data, - ((GByteArray *)message)->len, - ':'); - g_debug ("[%s] Received message...\n" - ">>>>>> RAW:\n" - ">>>>>> length = %u\n" - ">>>>>> data = %s\n", - self->priv->path_display, - ((GByteArray *)message)->len, - printable); - g_free (printable); + if (sent_or_received) { + prefix_str = "<<<<<< "; + action_str = "sent"; + } else { + prefix_str = "<<<<<< "; + action_str = "received"; + } + + printable = __qmi_utils_str_hex (((GByteArray *)message)->data, + ((GByteArray *)message)->len, + ':'); + g_debug ("[%s] %s message...\n" + "%sRAW:\n" + "%s length = %u\n" + "%s data = %s\n", + self->priv->path_display, action_str, + prefix_str, + prefix_str, ((GByteArray *)message)->len, + prefix_str, printable); + g_free (printable); + + if (message_context) { + guint16 vendor_id; + + vendor_id = qmi_message_context_get_vendor_id (message_context); + if (vendor_id != QMI_MESSAGE_VENDOR_GENERIC) + vendor_str = g_strdup_printf ("vendor-specific (0x%04x)", vendor_id); + } + + printable = qmi_message_get_printable_full (message, message_context, prefix_str); + g_debug ("[%s] %s %s %s (translated)...\n%s", + self->priv->path_display, + action_str, + vendor_str ? vendor_str : "generic", + message_str, + printable); + g_free (printable); - printable = qmi_message_get_printable (message, ">>>>>> "); - g_debug ("[%s] Received message (translated)...\n%s", - self->priv->path_display, - printable); - g_free (printable); - } + g_free (vendor_str); +} +static void +process_message (QmiDevice *self, + QmiMessage *message) +{ if (qmi_message_is_indication (message)) { + /* Indication traces translated without an explicit vendor */ + trace_message (self, message, FALSE, "indication", NULL); + /* Generic emission of the indication */ g_signal_emit (self, signals[SIGNAL_INDICATION], 0, message); @@ -1647,16 +1689,23 @@ process_message (QmiDevice *self, Transaction *tr; tr = device_match_transaction (self, message); - if (!tr) + if (!tr) { + /* Unmatched transactions translated without an explicit context */ + trace_message (self, message, FALSE, "response", NULL); g_debug ("[%s] No transaction matched in received message", self->priv->path_display); - else + } else { + /* Matched transactions translated with the same context as the request */ + trace_message (self, message, FALSE, "response", tr->message_context); /* Report the reply message */ transaction_complete_and_free (tr, message, NULL); + } return; } + /* Unexpected message types translated without an explicit context */ + trace_message (self, message, FALSE, "unexpected message", NULL); g_debug ("[%s] Message received but it is neither an indication nor a response. Skipping it.", self->priv->path_display); } @@ -2755,19 +2804,19 @@ mbim_command (QmiDevice *self, /* Command */ /** - * qmi_device_command_finish: + * qmi_device_command_full_finish: * @self: a #QmiDevice. * @res: a #GAsyncResult. * @error: Return location for error or %NULL. * - * Finishes an operation started with qmi_device_command(). + * Finishes an operation started with qmi_device_command_full(). * * Returns: a #QmiMessage response, or #NULL if @error is set. The returned value should be freed with qmi_message_unref(). */ QmiMessage * -qmi_device_command_finish (QmiDevice *self, - GAsyncResult *res, - GError **error) +qmi_device_command_full_finish (QmiDevice *self, + GAsyncResult *res, + GError **error) { if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) return NULL; @@ -2794,9 +2843,10 @@ transaction_early_error (QmiDevice *self, } /** - * qmi_device_command: + * qmi_device_command_full: * @self: a #QmiDevice. * @message: the message to send. + * @message_context: the context of the message. * @timeout: maximum time, in seconds, to wait for the response. * @cancellable: a #GCancellable, or %NULL. * @callback: a #GAsyncReadyCallback to call when the operation is finished. @@ -2804,16 +2854,22 @@ transaction_early_error (QmiDevice *self, * * Asynchronously sends a #QmiMessage to the device. * + * The message will be processed according to the specific @message_context + * given. + * * When the operation is finished @callback will be called. You can then call - * qmi_device_command_finish() to get the result of the operation. + * qmi_device_command_full_finish() to get the result of the operation. + * + * If no @context given, the behavior is the same as qmi_device_command(). */ void -qmi_device_command (QmiDevice *self, - QmiMessage *message, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +qmi_device_command_full (QmiDevice *self, + QmiMessage *message, + QmiMessageContext *message_context, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GError *error = NULL; Transaction *tr; @@ -2835,7 +2891,7 @@ qmi_device_command (QmiDevice *self, self->priv->client_ctl))); } - tr = transaction_new (self, message, cancellable, callback, user_data); + tr = transaction_new (self, message, message_context, cancellable, callback, user_data); /* Device must be open */ if (!self->priv->istream || !self->priv->ostream) { @@ -2896,27 +2952,7 @@ qmi_device_command (QmiDevice *self, /* From now on, if we want to complete the transaction with an early error, * it needs to be removed from the tracking table as well. */ - if (qmi_utils_get_traces_enabled ()) { - gchar *printable; - - printable = __qmi_utils_str_hex (((GByteArray *)message)->data, - ((GByteArray *)message)->len, - ':'); - g_debug ("[%s] Sent message...\n" - "<<<<<< RAW:\n" - "<<<<<< length = %u\n" - "<<<<<< data = %s\n", - self->priv->path_display, - ((GByteArray *)message)->len, - printable); - g_free (printable); - - printable = qmi_message_get_printable (message, "<<<<<< "); - g_debug ("[%s] Sent message (translated)...\n%s", - self->priv->path_display, - printable); - g_free (printable); - } + trace_message (self, message, TRUE, "request", message_context); #if defined MBIM_QMUX_ENABLED if (self->priv->mbimdev) { @@ -2950,6 +2986,56 @@ qmi_device_command (QmiDevice *self, } /*****************************************************************************/ +/* Generic command */ + +/** + * qmi_device_command_finish: + * @self: a #QmiDevice. + * @res: a #GAsyncResult. + * @error: Return location for error or %NULL. + * + * Finishes an operation started with qmi_device_command(). + * + * Returns: a #QmiMessage response, or #NULL if @error is set. The returned value should be freed with qmi_message_unref(). + * + * Deprecated: 1.18. + */ +QmiMessage * +qmi_device_command_finish (QmiDevice *self, + GAsyncResult *res, + GError **error) +{ + return qmi_device_command_full_finish (self, res, error); +} + +/** + * qmi_device_command: + * @self: a #QmiDevice. + * @message: the message to send. + * @timeout: maximum time, in seconds, to wait for the response. + * @cancellable: a #GCancellable, or %NULL. + * @callback: a #GAsyncReadyCallback to call when the operation is finished. + * @user_data: the data to pass to callback function. + * + * Asynchronously sends a generic #QmiMessage to the device with no context. + * + * When the operation is finished @callback will be called. You can then call + * qmi_device_command_finish() to get the result of the operation. + * + * Deprecated: 1.18: Use qmi_device_command_full() instead. + */ +void +qmi_device_command (QmiDevice *self, + QmiMessage *message, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + qmi_device_command_full (self, message, NULL, timeout, cancellable, callback, user_data); +} + +/*****************************************************************************/ /* New QMI device */ /** diff --git a/src/libqmi-glib/qmi-device.h b/src/libqmi-glib/qmi-device.h index 957efac..51e07ae 100644 --- a/src/libqmi-glib/qmi-device.h +++ b/src/libqmi-glib/qmi-device.h @@ -17,7 +17,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright (C) 2012-2015 Aleksander Morgado <aleksander@aleksander.es> + * Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es> */ #ifndef _LIBQMI_GLIB_QMI_DEVICE_H_ @@ -32,6 +32,7 @@ #include "qmi-enums.h" #include "qmi-message.h" +#include "qmi-message-context.h" #include "qmi-client.h" G_BEGIN_DECLS @@ -171,15 +172,28 @@ gboolean qmi_device_set_instance_id_finish (QmiDevice *self, guint16 *link_id, GError **error); -void qmi_device_command (QmiDevice *self, - QmiMessage *message, - guint timeout, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -QmiMessage *qmi_device_command_finish (QmiDevice *self, - GAsyncResult *res, - GError **error); +G_DEPRECATED +void qmi_device_command (QmiDevice *self, + QmiMessage *message, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +G_DEPRECATED +QmiMessage *qmi_device_command_finish (QmiDevice *self, + GAsyncResult *res, + GError **error); + +void qmi_device_command_full (QmiDevice *self, + QmiMessage *message, + QmiMessageContext *message_context, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +QmiMessage *qmi_device_command_full_finish (QmiDevice *self, + GAsyncResult *res, + GError **error); /** * QmiDeviceServiceVersionInfo: diff --git a/src/libqmi-glib/qmi-message-context.c b/src/libqmi-glib/qmi-message-context.c new file mode 100644 index 0000000..96f7a67 --- /dev/null +++ b/src/libqmi-glib/qmi-message-context.c @@ -0,0 +1,123 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * libqmi-glib -- GLib/GIO based library to control QMI devices + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Aleksander Morgado <aleksander@aleksander.es> + */ + +#include <glib.h> + +#include "qmi-message-context.h" + +/*****************************************************************************/ +/* Basic context */ + +struct _QmiMessageContext { + volatile gint ref_count; + + /* Vendor ID */ + guint16 vendor_id; +}; + +/** + * qmi_message_context_new: + * + * Create a new empty #QmiMessageContext. + * + * Returns: (transfer full): a newly created #QmiMessageContext. The returned value should be freed with qmi_message_context_unref(). + */ +QmiMessageContext * +qmi_message_context_new (void) +{ + QmiMessageContext *self; + + self = g_slice_new0 (QmiMessageContext); + self->ref_count = 1; + return self; +} + +GType +qmi_message_context_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) { + GType g_define_type_id = + g_boxed_type_register_static (g_intern_static_string ("QmiMessageContext"), + (GBoxedCopyFunc) qmi_message_context_ref, + (GBoxedFreeFunc) qmi_message_context_unref); + + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/** + * qmi_message_context_ref: + * @self: a #QmiMessageContext. + * + * Atomically increments the reference count of @self by one. + * + * Returns: (transfer full) the new reference to @self. + */ +QmiMessageContext * +qmi_message_context_ref (QmiMessageContext *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + g_atomic_int_inc (&self->ref_count); + return self; +} + +/** + * qmi_message_context_unref: + * @self: a #QmiMessageContext. + * + * Atomically decrements the reference count of @self by one. + * If the reference count drops to 0, @self is completely disposed. + */ +void +qmi_message_context_unref (QmiMessageContext *self) +{ + g_return_if_fail (self != NULL); + + if (g_atomic_int_dec_and_test (&self->ref_count)) { + g_slice_free (QmiMessageContext, self); + } +} + +/*****************************************************************************/ +/* Vendor ID */ + +void +qmi_message_context_set_vendor_id (QmiMessageContext *self, + guint16 vendor_id) +{ + g_return_if_fail (self != NULL); + + self->vendor_id = vendor_id; +} + +guint16 +qmi_message_context_get_vendor_id (QmiMessageContext *self) +{ + g_return_val_if_fail (self != NULL, QMI_MESSAGE_VENDOR_GENERIC); + return self->vendor_id; +} diff --git a/src/libqmi-glib/qmi-message-context.h b/src/libqmi-glib/qmi-message-context.h new file mode 100644 index 0000000..2dcf2ec --- /dev/null +++ b/src/libqmi-glib/qmi-message-context.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * libqmi-glib -- GLib/GIO based library to control QMI devices + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Aleksander Morgado <aleksander@aleksander.es> + */ + +#ifndef _LIBQMI_GLIB_QMI_MESSAGE_CONTEXT_H_ +#define _LIBQMI_GLIB_QMI_MESSAGE_CONTEXT_H_ + +#if !defined (__LIBQMI_GLIB_H_INSIDE__) && !defined (LIBQMI_GLIB_COMPILATION) +#error "Only <libqmi-glib.h> can be included directly." +#endif + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +/** + * QmiMessageContext: + * + * An opaque type representing a QMI message context. + * + * The context defines non-standard features of the QMI message associated with + * it, which may be required for a correct processing. + * + * When a context is given when sending a request with qmi_device_command_full(), + * the same context will then be applied for the associated response. + */ +typedef struct _QmiMessageContext QmiMessageContext; + +GType qmi_message_context_get_type (void); + +/*****************************************************************************/ +/* Basic context */ + +QmiMessageContext *qmi_message_context_new (void); +QmiMessageContext *qmi_message_context_ref (QmiMessageContext *self); +void qmi_message_context_unref (QmiMessageContext *self); + +/*****************************************************************************/ +/* Vendor ID */ + +/** + * QMI_MESSAGE_VENDOR_GENERIC: + * + * Generic vendor id (0x0000). + */ +#define QMI_MESSAGE_VENDOR_GENERIC 0x0000 + +void qmi_message_context_set_vendor_id (QmiMessageContext *self, + guint16 vendor_id); +guint16 qmi_message_context_get_vendor_id (QmiMessageContext *self); + +G_END_DECLS + +#endif /* _LIBQMI_GLIB_QMI_MESSAGE_CONTEXT_H_ */ diff --git a/src/libqmi-glib/qmi-message.c b/src/libqmi-glib/qmi-message.c index 23afa29..bbf08b6 100644 --- a/src/libqmi-glib/qmi-message.c +++ b/src/libqmi-glib/qmi-message.c @@ -24,7 +24,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright (C) 2012-2015 Aleksander Morgado <aleksander@aleksander.es> + * Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es> */ #include <glib.h> @@ -2077,20 +2077,27 @@ get_generic_printable (QmiMessage *self, } /** - * qmi_message_get_printable: + * qmi_message_get_printable_full: * @self: a #QmiMessage. + * @context: a #QmiMessageContext. * @line_prefix: prefix string to use in each new generated line. * * Gets a printable string with the contents of the whole QMI message. * - * If known, the printable string will contain translated TLV values as well as the raw - * data buffer contents. + * If known, the printable string will contain translated TLV values as well as + * the raw data buffer contents. + * + * The translation of the contents may be specific to the @context provided, + * e.g. for vendor-specific messages. + * + * If no @context given, the behavior is the same as qmi_message_get_printable(). * * Returns: (transfer full): a newly allocated string, which should be freed with g_free(). */ gchar * -qmi_message_get_printable (QmiMessage *self, - const gchar *line_prefix) +qmi_message_get_printable_full (QmiMessage *self, + QmiMessageContext *context, + const gchar *line_prefix) { GString *printable; gchar *qmi_flags_str; @@ -2134,40 +2141,40 @@ qmi_message_get_printable (QmiMessage *self, contents = NULL; switch (qmi_message_get_service (self)) { case QMI_SERVICE_CTL: - contents = __qmi_message_ctl_get_printable (self, line_prefix); + contents = __qmi_message_ctl_get_printable (self, context, line_prefix); break; case QMI_SERVICE_DMS: - contents = __qmi_message_dms_get_printable (self, line_prefix); + contents = __qmi_message_dms_get_printable (self, context, line_prefix); break; case QMI_SERVICE_WDS: - contents = __qmi_message_wds_get_printable (self, line_prefix); + contents = __qmi_message_wds_get_printable (self, context, line_prefix); break; case QMI_SERVICE_NAS: - contents = __qmi_message_nas_get_printable (self, line_prefix); + contents = __qmi_message_nas_get_printable (self, context, line_prefix); break; case QMI_SERVICE_WMS: - contents = __qmi_message_wms_get_printable (self, line_prefix); + contents = __qmi_message_wms_get_printable (self, context, line_prefix); break; case QMI_SERVICE_PDC: - contents = __qmi_message_pdc_get_printable (self, line_prefix); + contents = __qmi_message_pdc_get_printable (self, context, line_prefix); break; case QMI_SERVICE_PDS: - contents = __qmi_message_pds_get_printable (self, line_prefix); + contents = __qmi_message_pds_get_printable (self, context, line_prefix); break; case QMI_SERVICE_PBM: - contents = __qmi_message_pbm_get_printable (self, line_prefix); + contents = __qmi_message_pbm_get_printable (self, context, line_prefix); break; case QMI_SERVICE_UIM: - contents = __qmi_message_uim_get_printable (self, line_prefix); + contents = __qmi_message_uim_get_printable (self, context, line_prefix); break; case QMI_SERVICE_OMA: - contents = __qmi_message_oma_get_printable (self, line_prefix); + contents = __qmi_message_oma_get_printable (self, context, line_prefix); break; case QMI_SERVICE_WDA: - contents = __qmi_message_wda_get_printable (self, line_prefix); + contents = __qmi_message_wda_get_printable (self, context, line_prefix); break; case QMI_SERVICE_VOICE: - contents = __qmi_message_voice_get_printable (self, line_prefix); + contents = __qmi_message_voice_get_printable (self, context, line_prefix); break; default: break; @@ -2182,19 +2189,48 @@ qmi_message_get_printable (QmiMessage *self, } /** - * qmi_message_get_version_introduced: + * qmi_message_get_printable: * @self: a #QmiMessage. + * @line_prefix: prefix string to use in each new generated line. + * + * Gets a printable string with the contents of the whole QMI message. + * + * If known, the printable string will contain translated TLV values as well as the raw + * data buffer contents. + * + * Returns: (transfer full): a newly allocated string, which should be freed with g_free(). + * + * Deprecated: 1.18: Use qmi_message_get_printable_full() instead. + */ +gchar * +qmi_message_get_printable (QmiMessage *self, + const gchar *line_prefix) +{ + return qmi_message_get_printable_full (self, NULL, line_prefix); +} + +/** + * qmi_message_get_version_introduced_full: + * @self: a #QmiMessage. + * @context: a #QmiMessageContext. * @major: (out) return location for the major version. * @minor: (out) return location for the minor version. * - * Gets, if known, the service version in which the given message was first introduced. + * Gets, if known, the service version in which the given message was first + * introduced. + * + * The lookup of the version may be specific to the @context provided, e.g. for + * vendor-specific messages. + * + * If no @context given, the behavior is the same as qmi_message_get_version_introduced(). * * Returns: %TRUE if @major and @minor are set, %FALSE otherwise. */ gboolean -qmi_message_get_version_introduced (QmiMessage *self, - guint *major, - guint *minor) +qmi_message_get_version_introduced_full (QmiMessage *self, + QmiMessageContext *context, + guint *major, + guint *minor) { switch (qmi_message_get_service (self)) { case QMI_SERVICE_CTL: @@ -2204,34 +2240,55 @@ qmi_message_get_version_introduced (QmiMessage *self, return TRUE; case QMI_SERVICE_DMS: - return __qmi_message_dms_get_version_introduced (self, major, minor); + return __qmi_message_dms_get_version_introduced (self, context, major, minor); case QMI_SERVICE_WDS: - return __qmi_message_wds_get_version_introduced (self, major, minor); + return __qmi_message_wds_get_version_introduced (self, context, major, minor); case QMI_SERVICE_NAS: - return __qmi_message_nas_get_version_introduced (self, major, minor); + return __qmi_message_nas_get_version_introduced (self, context, major, minor); case QMI_SERVICE_WMS: - return __qmi_message_wms_get_version_introduced (self, major, minor); + return __qmi_message_wms_get_version_introduced (self, context, major, minor); case QMI_SERVICE_PDS: - return __qmi_message_pds_get_version_introduced (self, major, minor); + return __qmi_message_pds_get_version_introduced (self, context, major, minor); case QMI_SERVICE_PBM: - return __qmi_message_pbm_get_version_introduced (self, major, minor); + return __qmi_message_pbm_get_version_introduced (self, context, major, minor); case QMI_SERVICE_UIM: - return __qmi_message_uim_get_version_introduced (self, major, minor); + return __qmi_message_uim_get_version_introduced (self, context, major, minor); case QMI_SERVICE_OMA: - return __qmi_message_oma_get_version_introduced (self, major, minor); + return __qmi_message_oma_get_version_introduced (self, context, major, minor); case QMI_SERVICE_WDA: - return __qmi_message_wda_get_version_introduced (self, major, minor); + return __qmi_message_wda_get_version_introduced (self, context, major, minor); default: /* For the still unsupported services, cannot do anything */ return FALSE; } } + +/** + * qmi_message_get_version_introduced: + * @self: a #QmiMessage. + * @major: (out) return location for the major version. + * @minor: (out) return location for the minor version. + * + * Gets, if known, the service version in which the given message was first + * introduced. + * + * Returns: %TRUE if @major and @minor are set, %FALSE otherwise. + * + * Deprecated: 1.18: Use qmi_message_get_version_introduced_full() instead. + */ +gboolean +qmi_message_get_version_introduced (QmiMessage *self, + guint *major, + guint *minor) +{ + return qmi_message_get_version_introduced_full (self, NULL, major, minor); +} diff --git a/src/libqmi-glib/qmi-message.h b/src/libqmi-glib/qmi-message.h index 4f21560..7ca240e 100644 --- a/src/libqmi-glib/qmi-message.h +++ b/src/libqmi-glib/qmi-message.h @@ -24,7 +24,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright (C) 2012-2015 Aleksander Morgado <aleksander@aleksander.es> + * Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es> */ #ifndef _LIBQMI_GLIB_QMI_MESSAGE_H_ @@ -39,6 +39,7 @@ #include "qmi-utils.h" #include "qmi-enums.h" #include "qmi-errors.h" +#include "qmi-message-context.h" G_BEGIN_DECLS @@ -51,6 +52,13 @@ G_BEGIN_DECLS */ typedef GByteArray QmiMessage; +/** + * QMI_MESSAGE_VENDOR_GENERIC: + * + * Generic vendor id (0x0000). + */ +#define QMI_MESSAGE_VENDOR_GENERIC 0x0000 + /*****************************************************************************/ /* QMI Message life cycle */ @@ -79,10 +87,19 @@ gsize qmi_message_get_length (QmiMessage *self); const guint8 *qmi_message_get_raw (QmiMessage *self, gsize *length, GError **error); -gboolean qmi_message_get_version_introduced (QmiMessage *self, - guint *major, - guint *minor); +/*****************************************************************************/ +/* Version support from the database */ + +G_DEPRECATED +gboolean qmi_message_get_version_introduced (QmiMessage *self, + guint *major, + guint *minor); + +gboolean qmi_message_get_version_introduced_full (QmiMessage *self, + QmiMessageContext *context, + guint *major, + guint *minor); /*****************************************************************************/ /* TLV builder & writer */ @@ -250,9 +267,14 @@ void qmi_message_set_transaction_id (QmiMessage *self, /*****************************************************************************/ /* Printable helpers */ +G_DEPRECATED gchar *qmi_message_get_printable (QmiMessage *self, const gchar *line_prefix); +gchar *qmi_message_get_printable_full (QmiMessage *self, + QmiMessageContext *context, + const gchar *line_prefix); + gchar *qmi_message_get_tlv_printable (QmiMessage *self, const gchar *line_prefix, guint8 type, diff --git a/src/libqmi-glib/qmi-proxy.c b/src/libqmi-glib/qmi-proxy.c index 5077041..592ed8b 100644 --- a/src/libqmi-glib/qmi-proxy.c +++ b/src/libqmi-glib/qmi-proxy.c @@ -608,6 +608,9 @@ process_message (QmiProxy *self, * complete, otherwise the remote clients will lose the reply if they * configured a timeout bigger than this internal one. We should likely * make this value configurable per-client, instead of a hardcoded value. + * + * Note: the proxy will not translate vendor-specific messages in its + * logs (as it doesn't have the orignal message context with the vendor id). */ qmi_device_command (client->device, message, |