diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-04-20 13:34:16 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-07-03 15:47:21 +0200 |
commit | 6d8225abd2494e348cac2115c695417e2903c5fe (patch) | |
tree | dee46c19382d7673287561ef47bad104827f4c44 /src | |
parent | 02467a15bdca99c6cd80cac62414ca725fd3a277 (diff) | |
download | external_libqmi-6d8225abd2494e348cac2115c695417e2903c5fe.zip external_libqmi-6d8225abd2494e348cac2115c695417e2903c5fe.tar.gz external_libqmi-6d8225abd2494e348cac2115c695417e2903c5fe.tar.bz2 |
client-ctl: new `QmiClientCtl' to handle the CTL service
The `QmiDevice' will create one of these objects and keep it around, to be
used as the generic client in the CTL service.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/libqmi-glib.h | 1 | ||||
-rw-r--r-- | src/qmi-client-ctl.c | 132 | ||||
-rw-r--r-- | src/qmi-client-ctl.h | 66 | ||||
-rw-r--r-- | src/qmi-device.c | 186 | ||||
-rw-r--r-- | src/qmi-device.h | 18 | ||||
-rw-r--r-- | src/qmi-message-ctl.c | 4 | ||||
-rw-r--r-- | src/qmi-message-ctl.h | 5 |
8 files changed, 342 insertions, 77 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index b7326c5..d1be081 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ qmi-enum-types.c: qmi-enums.h qmi-enum-types.h $(top_srcdir)/build-aux/qmi-enum- # Additional dependencies qmi-device.c: qmi-error-types.h qmi-client.c: qmi-error-types.h qmi-enum-types.h +qmi-client-ctl.c: qmi-error-types.h qmi-message.c: qmi-error-types.h qmi-message-ctl.c: qmi-error-types.h @@ -50,7 +51,8 @@ libqmi_glib_la_SOURCES = \ qmi-message.h qmi-message.c \ qmi-message-ctl.h qmi-message-ctl.c \ qmi-device.h qmi-device.c \ - qmi-client.h qmi-client.c + qmi-client.h qmi-client.c \ + qmi-client-ctl.h qmi-client-ctl.c libqmi_glib_la_LIBADD = \ $(LIBQMI_GLIB_LIBS) @@ -61,4 +63,5 @@ include_HEADERS = \ qmi-errors.h qmi-error-types.h \ qmi-enums.h qmi-enum-types.h \ qmi-device.h \ - qmi-client.h + qmi-client.h \ + qmi-client-ctl.h diff --git a/src/libqmi-glib.h b/src/libqmi-glib.h index 7a73a0c..9dfd9b8 100644 --- a/src/libqmi-glib.h +++ b/src/libqmi-glib.h @@ -29,5 +29,6 @@ #include "qmi-device.h" #include "qmi-client.h" +#include "qmi-client-ctl.h" #endif /* _LIBQMI_GLIB_H_ */ diff --git a/src/qmi-client-ctl.c b/src/qmi-client-ctl.c new file mode 100644 index 0000000..6df326a --- /dev/null +++ b/src/qmi-client-ctl.c @@ -0,0 +1,132 @@ +/* -*- 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) 2012 Aleksander Morgado <aleksander@lanedo.com> + */ + +#include <gio/gio.h> + +#include "qmi-error-types.h" +#include "qmi-client-ctl.h" + +G_DEFINE_TYPE (QmiClientCtl, qmi_client_ctl, QMI_TYPE_CLIENT); + +/*****************************************************************************/ +/* Get version info */ + +/** + * qmi_client_ctl_get_version_info_finish: + * @res: a #GAsyncResult. + * @error: a #GError. + * + * Finishes an operation started with qmi_client_ctl_get_version_info(). + * + * Returns: A #GArray of #QmiCtlVersionInfo, or #NULL if @error is set. + */ +GArray * +qmi_client_ctl_get_version_info_finish (QmiClientCtl *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return NULL; + + return g_array_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void +version_info_ready (QmiDevice *device, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + QmiMessage *reply; + GArray *services; + + reply = qmi_device_command_finish (device, res, &error); + if (!reply) { + g_prefix_error (&error, "Version info check failed: "); + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + return; + } + + /* Parse version reply */ + services = qmi_message_ctl_version_info_reply_parse (reply, &error); + if (!services) { + g_prefix_error (&error, "Version info reply parsing failed: "); + g_simple_async_result_take_error (simple, error); + } else + g_simple_async_result_set_op_res_gpointer (simple, + services, + (GDestroyNotify)g_array_unref); + + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +/** + * qmi_client_ctl_get_version_info: + * @self: a #QmiClientCtl. + * @timeout: maximum time to wait to get the operation completed. + * @cancellable: optional #GCancellable object, #NULL to ignore. + * @callback: a #GAsyncReadyCallback to call when the operation is finished. + * @user_data: the data to pass to callback function. + * + * Get list of supported services. + * When the query is finished, @callback will be called. You can then call + * qmi_client_ctl_get_version_info_finish() to get the the result of the operation. + */ +void +qmi_client_ctl_get_version_info (QmiClientCtl *self, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + QmiMessage *request; + + result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + qmi_client_ctl_get_version_info); + + request = qmi_message_ctl_version_info_new (qmi_client_get_next_transaction_id (QMI_CLIENT (self))); + qmi_device_command (qmi_client_peek_device (QMI_CLIENT (self)), + request, + timeout, + cancellable, + (GAsyncReadyCallback)version_info_ready, + result); + qmi_message_unref (request); +} + +/*****************************************************************************/ + +static void +qmi_client_ctl_init (QmiClientCtl *self) +{ +} + +static void +qmi_client_ctl_class_init (QmiClientCtlClass *klass) +{ +} diff --git a/src/qmi-client-ctl.h b/src/qmi-client-ctl.h new file mode 100644 index 0000000..58f599c --- /dev/null +++ b/src/qmi-client-ctl.h @@ -0,0 +1,66 @@ +/* -*- 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) 2012 Aleksander Morgado <aleksander@lanedo.com> + */ + +#ifndef _LIBQMI_GLIB_QMI_CLIENT_CTL_H_ +#define _LIBQMI_GLIB_QMI_CLIENT_CTL_H_ + +#include <glib-object.h> + +#include "qmi-client.h" +#include "qmi-message-ctl.h" + +G_BEGIN_DECLS + +#define QMI_TYPE_CLIENT_CTL (qmi_client_ctl_get_type ()) +#define QMI_CLIENT_CTL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QMI_TYPE_CLIENT_CTL, QmiClientCtl)) +#define QMI_CLIENT_CTL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QMI_TYPE_CLIENT_CTL, QmiClientCtlClass)) +#define QMI_IS_CLIENT_CTL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), QMI_TYPE_CLIENT_CTL)) +#define QMI_IS_CLIENT_CTL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), QMI_TYPE_CLIENT_CTL)) +#define QMI_CLIENT_CTL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), QMI_TYPE_CLIENT_CTL, QmiClientCtlClass)) + +typedef struct _QmiClientCtl QmiClientCtl; +typedef struct _QmiClientCtlClass QmiClientCtlClass; + +struct _QmiClientCtl { + QmiClient parent; + gpointer priv_unused; +}; + +struct _QmiClientCtlClass { + QmiClientClass parent; +}; + +GType qmi_client_ctl_get_type (void); + +/* Version info */ +void qmi_client_ctl_get_version_info (QmiClientCtl *self, + guint timeout, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GArray *qmi_client_ctl_get_version_info_finish (QmiClientCtl *self, + GAsyncResult *res, + GError **error); + +G_END_DECLS + +#endif /* _LIBQMI_GLIB_QMI_CLIENT_CTL_H_ */ diff --git a/src/qmi-device.c b/src/qmi-device.c index b321de7..5459ab6 100644 --- a/src/qmi-device.c +++ b/src/qmi-device.c @@ -23,7 +23,8 @@ #include <gio/gio.h> #include "qmi-device.h" -#include "qmi-message-ctl.h" +#include "qmi-message.h" +#include "qmi-client-ctl.h" #include "qmi-utils.h" #include "qmi-error-types.h" #include "qmi-enum-types.h" @@ -36,6 +37,7 @@ G_DEFINE_TYPE_EXTENDED (QmiDevice, qmi_device, G_TYPE_OBJECT, 0, enum { PROP_0, PROP_FILE, + PROP_CLIENT_CTL, PROP_LAST }; @@ -47,6 +49,9 @@ struct _QmiDevicePrivate { gchar *path; gchar *path_display; + /* Implicit CTL client */ + QmiClientCtl *client_ctl; + /* I/O channel, set when the file is open */ GIOChannel *iochannel; guint watch_id; @@ -54,9 +59,6 @@ struct _QmiDevicePrivate { /* HT to keep track of ongoing transactions */ GHashTable *transactions; - - /* Transaction ID for the CTL service */ - guint8 ctl_transaction_id; }; #define BUFFER_SIZE 2048 @@ -224,24 +226,6 @@ device_match_transaction (QmiDevice *self, /*****************************************************************************/ -static guint8 -device_get_ctl_transaction_id (QmiDevice *self) -{ - guint8 next; - - next = self->priv->ctl_transaction_id; - - /* Don't go further than 8bits in the CTL service */ - if (self->priv->ctl_transaction_id == G_MAXUINT8) - self->priv->ctl_transaction_id = 0x01; - else - self->priv->ctl_transaction_id++; - - return next; -} - -/*****************************************************************************/ - /** * qmi_device_get_file: * @self: a #QmiDevice. @@ -264,6 +248,44 @@ qmi_device_get_file (QmiDevice *self) } /** + * qmi_device_peek_client_ctl: + * @self: a #QmiDevice. + * + * Get the #QmiClientCtl handled by this #QmiDevice, without increasing the reference count + * on the returned object. + * + * Returns: a #GFile. Do not free the returned object, it is owned by @self. + */ +QmiClientCtl * +qmi_device_peek_client_ctl (QmiDevice *self) +{ + g_return_val_if_fail (QMI_IS_DEVICE (self), NULL); + + return self->priv->client_ctl; +} + +/** + * qmi_device_get_client_ctl: + * @self: a #QmiDevice. + * + * Get the #QmiClientCtl handled by this #QmiDevice. + * + * Returns: a #QmiClientCtl that must be freed with g_object_unref(). + */ +QmiClientCtl * +qmi_device_get_client_ctl (QmiDevice *self) +{ + QmiClientCtl *client_ctl = NULL; + + g_return_val_if_fail (QMI_IS_DEVICE (self), NULL); + + g_object_get (G_OBJECT (self), + QMI_DEVICE_CLIENT_CTL, &client_ctl, + NULL); + return client_ctl; +} + +/** * qmi_device_peek_file: * @self: a #QmiDevice. * @@ -523,17 +545,17 @@ qmi_device_open_finish (QmiDevice *self, } static void -version_info_ready (QmiDevice *self, +version_info_ready (QmiClientCtl *client_ctl, GAsyncResult *res, GSimpleAsyncResult *simple) { + QmiDevice *self; GError *error = NULL; - QmiMessage *reply; GArray *services; + guint i; - reply = qmi_device_command_finish (self, res, &error); - - if (!reply) { + services = qmi_client_ctl_get_version_info_finish (client_ctl, res, &error); + if (!services) { g_prefix_error (&error, "Version info check failed: "); g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); @@ -541,35 +563,28 @@ version_info_ready (QmiDevice *self, return; } - /* Parse version reply */ - services = qmi_message_ctl_version_info_reply_parse (reply, &error); - if (!services) { - g_prefix_error (&error, "Version info reply parsing failed: "); - g_simple_async_result_take_error (simple, error); - } else { - guint i; + /* Recover the QmiDevice */ + self = QMI_DEVICE (g_async_result_get_source_object (G_ASYNC_RESULT (simple))); - g_debug ("[%s] QMI Device supports %u services:", - self->priv->path_display, - services->len); - for (i = 0; i < services->len; i++) { - QmiCtlVersionInfoService *service; - - service = &g_array_index (services, QmiCtlVersionInfoService, i); - g_debug ("[%s] %s (%u.%u)", - self->priv->path_display, - qmi_service_get_string (service->service_type), - service->major_version, - service->minor_version); - } + g_debug ("[%s] QMI Device supports %u services:", + self->priv->path_display, + services->len); + for (i = 0; i < services->len; i++) { + QmiCtlVersionInfo *service; - g_array_unref (services); - g_simple_async_result_set_op_res_gboolean (simple, TRUE); + service = &g_array_index (services, QmiCtlVersionInfo, i); + g_debug ("[%s] %s (%u.%u)", + self->priv->path_display, + qmi_service_get_string (service->service_type), + service->major_version, + service->minor_version); } + g_array_unref (services); + g_simple_async_result_set_op_res_gboolean (simple, TRUE); g_simple_async_result_complete (simple); g_object_unref (simple); - qmi_message_unref (reply); + g_object_unref (self); } /** @@ -591,7 +606,6 @@ qmi_device_open (QmiDevice *self, { GSimpleAsyncResult *result; GError *error = NULL; - QmiMessage *version_info_request; g_return_if_fail (QMI_IS_DEVICE (self)); @@ -609,15 +623,13 @@ qmi_device_open (QmiDevice *self, return; } - /* Send version info check */ + /* Query version info */ g_debug ("Checking version info..."); - version_info_request = qmi_message_ctl_version_info_new (device_get_ctl_transaction_id (self)); - qmi_device_command (self, - version_info_request, - timeout, - cancellable, - (GAsyncReadyCallback)version_info_ready, - result); + qmi_client_ctl_get_version_info (self->priv->client_ctl, + timeout, + cancellable, + (GAsyncReadyCallback)version_info_ready, + result); } /*****************************************************************************/ @@ -845,6 +857,31 @@ initable_init_finish (GAsyncInitable *initable, } static void +client_ctl_ready (GAsyncInitable *initable, + GAsyncResult *res, + InitContext *ctx) +{ + GError *error = NULL; + GObject *obj; + + obj = g_async_initable_new_finish (initable, res, &error); + if (!obj) { + g_prefix_error (&error, + "Couldn't create CTL client: "); + g_simple_async_result_take_error (ctx->result, error); + init_context_complete_and_free (ctx); + return; + } + + /* Keep the client */ + ctx->self->priv->client_ctl = QMI_CLIENT_CTL (obj); + + /* Done we are */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + init_context_complete_and_free (ctx); +} + +static void query_info_async_ready (GFile *file, GAsyncResult *res, InitContext *ctx) @@ -870,12 +907,18 @@ query_info_async_ready (GFile *file, init_context_complete_and_free (ctx); return; } - g_object_unref (info); - /* Done we are */ - g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); - init_context_complete_and_free (ctx); + /* Create the implicit CTL client + * We are giving already the CID of the CTL client, the default one */ + g_async_initable_new_async (QMI_TYPE_CLIENT_CTL, + G_PRIORITY_DEFAULT, + ctx->cancellable, + (GAsyncReadyCallback)client_ctl_ready, + ctx, + QMI_CLIENT_DEVICE, ctx->self, + QMI_CLIENT_SERVICE, QMI_SERVICE_CTL, + NULL); } static void @@ -935,6 +978,10 @@ set_property (GObject *object, self->priv->path = g_file_get_path (self->priv->file); self->priv->path_display = g_filename_display_name (self->priv->path); break; + case PROP_CLIENT_CTL: + /* Not writable */ + g_assert_not_reached (); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -953,6 +1000,9 @@ get_property (GObject *object, case PROP_FILE: g_value_set_object (value, self->priv->file); break; + case PROP_CLIENT_CTL: + g_value_set_object (value, self->priv->client_ctl); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -965,7 +1015,6 @@ qmi_device_init (QmiDevice *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), QMI_TYPE_DEVICE, QmiDevicePrivate); - self->priv->ctl_transaction_id = 0x01; } static void @@ -974,6 +1023,7 @@ dispose (GObject *object) QmiDevice *self = QMI_DEVICE (object); g_clear_object (&self->priv->file); + g_clear_object (&self->priv->client_ctl); G_OBJECT_CLASS (qmi_device_parent_class)->dispose (object); } @@ -1024,4 +1074,12 @@ qmi_device_class_init (QmiDeviceClass *klass) G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_FILE, properties[PROP_FILE]); + + properties[PROP_CLIENT_CTL] = + g_param_spec_object (QMI_DEVICE_CLIENT_CTL, + "CTL client", + "Implicit CTL client", + QMI_TYPE_CLIENT_CTL, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_CLIENT_CTL, properties[PROP_CLIENT_CTL]); } diff --git a/src/qmi-device.h b/src/qmi-device.h index d89f443..8d20489 100644 --- a/src/qmi-device.h +++ b/src/qmi-device.h @@ -25,13 +25,14 @@ #include <glib-object.h> - G_BEGIN_DECLS /* Forward reference of the QMI message, we don't want to include qmi-message.h * as it is not installable */ typedef struct _QmiMessage QmiMessage; +typedef struct _QmiClientCtl QmiClientCtl; + #define QMI_TYPE_DEVICE (qmi_device_get_type ()) #define QMI_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QMI_TYPE_DEVICE, QmiDevice)) #define QMI_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QMI_TYPE_DEVICE, QmiDeviceClass)) @@ -43,7 +44,8 @@ typedef struct _QmiDevice QmiDevice; typedef struct _QmiDeviceClass QmiDeviceClass; typedef struct _QmiDevicePrivate QmiDevicePrivate; -#define QMI_DEVICE_FILE "device-file" +#define QMI_DEVICE_FILE "device-file" +#define QMI_DEVICE_CLIENT_CTL "device-client-ctl" struct _QmiDevice { GObject parent; @@ -63,11 +65,13 @@ void qmi_device_new (GFile *file, QmiDevice *qmi_device_new_finish (GAsyncResult *res, GError **error); -GFile *qmi_device_get_file (QmiDevice *self); -GFile *qmi_device_peek_file (QmiDevice *self); -const gchar *qmi_device_get_path (QmiDevice *self); -const gchar *qmi_device_get_path_display (QmiDevice *self); -gboolean qmi_device_is_open (QmiDevice *self); +GFile *qmi_device_get_file (QmiDevice *self); +GFile *qmi_device_peek_file (QmiDevice *self); +QmiClientCtl *qmi_device_get_client_ctl (QmiDevice *self); +QmiClientCtl *qmi_device_peek_client_ctl (QmiDevice *self); +const gchar *qmi_device_get_path (QmiDevice *self); +const gchar *qmi_device_get_path_display (QmiDevice *self); +gboolean qmi_device_is_open (QmiDevice *self); void qmi_device_open (QmiDevice *self, guint timeout, diff --git a/src/qmi-message-ctl.c b/src/qmi-message-ctl.c index d804434..76df9b0 100644 --- a/src/qmi-message-ctl.c +++ b/src/qmi-message-ctl.c @@ -84,13 +84,13 @@ qmi_message_ctl_version_info_reply_parse (QmiMessage *self, result = g_array_sized_new (FALSE, FALSE, - sizeof (QmiCtlVersionInfoService), + sizeof (QmiCtlVersionInfo), service_list->count); for (i = 0, svc = &(service_list->services[0]); i < service_list->count; i++, svc++) { - QmiCtlVersionInfoService service; + QmiCtlVersionInfo service; service.service_type = (QmiService)svc->service_type; service.major_version = le16toh (svc->major_version); diff --git a/src/qmi-message-ctl.h b/src/qmi-message-ctl.h index 7eedb0c..36e4b53 100644 --- a/src/qmi-message-ctl.h +++ b/src/qmi-message-ctl.h @@ -32,14 +32,15 @@ G_BEGIN_DECLS /* Version info */ + typedef struct { QmiService service_type; guint16 major_version; guint16 minor_version; -} QmiCtlVersionInfoService; +} QmiCtlVersionInfo; QmiMessage *qmi_message_ctl_version_info_new (guint8 transaction_id); -/* array of QmiCtlVersionInfoService */ +/* array of QmiCtlVersionInfo */ GArray *qmi_message_ctl_version_info_reply_parse (QmiMessage *self, GError **error); |